style: capitalize "Relicario" in prose / UI / CLI help

Brand name uses capital R in user-facing text — extension UI strings,
CLI clap help / descriptions / error prose, markdown docs. Lowercase
preserved for the binary command, crate names, npm package, file
paths, env vars, and code identifiers.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
adlee-was-taken
2026-05-01 17:29:10 -04:00
parent 79b10d6a18
commit 39ae2ecbf3
44 changed files with 91 additions and 91 deletions

View File

@@ -1,12 +1,12 @@
# relicario import / export — design
# Relicario import / export — design
Date: 2026-04-27
Status: design (not yet implemented)
Scope: backup / restore (round-trippable to relicario itself) + LastPass CSV import. Migration **out** to other tools is explicitly out of scope.
Scope: backup / restore (round-trippable to Relicario itself) + LastPass CSV import. Migration **out** to other tools is explicitly out of scope.
## Motivation
Self-hosting a password vault without a backup story is unacceptable for production use. Today, a relicario user has no way to:
Self-hosting a password vault without a backup story is unacceptable for production use. Today, a Relicario user has no way to:
1. **Snapshot** their vault for disaster recovery (git remote going away, repo corruption, account loss).
2. **Onboard** from an existing manager — there's no migration path for a user with credentials in another tool.
@@ -18,13 +18,13 @@ The following choices were brainstormed and approved before this spec was writte
| # | Decision |
|---|---|
| D1 | Two features, one spec: backup/restore round-trippable to relicario, plus a LastPass CSV importer. Migration out is out of scope. |
| D1 | Two features, one spec: backup/restore round-trippable to Relicario, plus a LastPass CSV importer. Migration out is out of scope. |
| D2 | Backup file format: single-file `.relbak` container. Magic header + version + salt + nonce + AEAD-encrypted, zstd-compressed JSON envelope with base64'd binary blobs. |
| D3 | AEAD: XChaCha20-Poly1305 (same primitive used for vault items, but the backup format uses its own envelope with magic header + version byte; it does **not** reuse the `crypto.rs` `encrypt`/`decrypt` helpers, which assume the vault-master-key format). KDF: Argon2id with the same parameters as v1 of the live vault (m=64MiB, t=3, p=4) — but the params are tied to **backup format version**, not read from the vault's `params.json`. |
| D4 | Backup passphrase is independent of the vault passphrase. User picks one at export; user types it at restore. Reusing the vault passphrase is allowed but not auto-filled. |
| D5 | Reference image inclusion is optional. `--include-image` flag (CLI) / checkbox (UI). When included, the image is base64'd into the encrypted envelope — never in the clear inside the file. |
| D6 | Git history (`.git/`) is included **by default**. `--no-history` opt-out for users who want a smaller file at the cost of audit trail and remote URL. |
| D7 | Restore semantics: refuse if the target directory already contains a relicario vault. Restore is a fresh round-trip operation, not a merge. |
| D7 | Restore semantics: refuse if the target directory already contains a Relicario vault. Restore is a fresh round-trip operation, not a merge. |
| D8 | Backup passphrase strength: zxcvbn score ≥ 3, same gate as `init`. Backup is single-factor (one passphrase decrypts the container), so it must be at least as strong as a vault factor. |
| D9 | The user is responsible for deleting the backup file after restore is verified. The encryption protects it in transit / at rest while it exists; it is not a defense against forensic recovery of deleted copies. Documented in CLI help text and the extension UI. |
| D10 | LastPass import: parse the standard LastPass CSV (`url,username,password,totp,extra,name,grouping,fav`). Logins → `Login` items (with embedded TOTP if present); rows with `url == http://sn``SecureNote`; structured LastPass notes (cards, SSH keys, addresses) are **not** auto-parsed — they fall through as `SecureNote` with `extra` as the body. |
@@ -215,7 +215,7 @@ Future format v2 may change these; v1 readers will see `version != 0x01` and pro
## LastPass field mapping
| LastPass column | relicario destination | Notes |
| LastPass column | Relicario destination | Notes |
|---|---|---|
| `name` | `Item.title` | Required; row skipped with warning if missing |
| `grouping` | `Item.group` | `None` if empty |
@@ -246,11 +246,11 @@ Atomicity: output uses the existing `atomic_write` helper (write `.tmp` → rena
| Error | Detection | User-facing message | Recovery |
|---|---|---|---|
| Bad magic | First 4 bytes ≠ `"RBAK"` | `"not a relicario backup file"` | Verify file |
| Unsupported version | Version byte > current (1) | `"backup created by a newer relicario; upgrade required"` | Update binary |
| Bad magic | First 4 bytes ≠ `"RBAK"` | `"not a Relicario backup file"` | Verify file |
| Unsupported version | Version byte > current (1) | `"backup created by a newer Relicario; upgrade required"` | Update binary |
| Wrong backup passphrase | AEAD authentication fails | `"wrong backup passphrase, or the file is corrupt"` (deliberately ambiguous) | Retry |
| Target dir already has a vault | `target/.relicario/` exists | `"target dir already contains a relicario vault; restore refuses to overwrite — use an empty directory"` | Choose empty dir |
| Schema mismatch | envelope.schema_version != current | `"backup is schema v<N>; this relicario reads v<M>"` | Use matching binary |
| Target dir already has a vault | `target/.relicario/` exists | `"target dir already contains a Relicario vault; restore refuses to overwrite — use an empty directory"` | Choose empty dir |
| Schema mismatch | envelope.schema_version != current | `"backup is schema v<N>; this Relicario reads v<M>"` | Use matching binary |
| Mid-restore crash | (no detection) | — | User deletes target dir, retries |
Atomicity: best-effort. If interrupted mid-write, target dir has partial files — user cleans up and retries. Documented limitation. Restore is rare enough that engineering atomic-rename of multiple files is not worth the complexity.