Move docs/architecture/overview.md to ARCHITECTURE.md at the repo root — it is the primary cross-codebase architecture doc (four-codebase diagram, inter-codebase contracts, secrets map, build matrix, test strategy, where-to-look table) and belongs at the root alongside STATUS.md, ROADMAP.md, etc. Update relative paths inside the file (../../crates/ → crates/, etc.). Update CHANGELOG.md's one active reference to the old path. Add a "Living docs — update discipline" table to CLAUDE.md that maps every ALLCAPS.md file to the area it covers and the trigger for updating it. This closes the loop on the ALLCAPS.md documentation system. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
219 lines
12 KiB
Markdown
219 lines
12 KiB
Markdown
# Changelog
|
||
|
||
## v0.5.0 — 2026-05-02
|
||
|
||
Three release trains roll into one tag — backup/restore + LastPass
|
||
import (originally v0.3.0), device authentication (originally v0.4.0),
|
||
and the v0.5.0 polish + harden bundle (security fixes + UX fixes +
|
||
two confirmed bugs).
|
||
|
||
### Security
|
||
|
||
- **Pre-receive hook now actually verifies signatures (audit S1, HIGH).**
|
||
Earlier `relicario-server` builds accepted any commit with a
|
||
`Good signature` line on stderr regardless of which key signed it —
|
||
device-auth was a no-op. The hook now builds an `allowed_signers`
|
||
file from `devices.json` at the commit (via `GIT_CONFIG_*` env, no
|
||
global git-config mutation), parses the SSH SHA-256 fingerprint out
|
||
of `git verify-commit --raw` stderr, and rejects unregistered keys or
|
||
revoked keys whose committer-date is at or after the revocation
|
||
timestamp. Bootstrap mode is preserved only when **both**
|
||
`devices.json` AND `revoked.json` are empty (closes an
|
||
empty-devices.json privilege-escalation route).
|
||
- **Backup-restore tar unpacking hardened (audit S2).** `relicario
|
||
backup restore` no longer trusts `tar::Archive::unpack`'s defaults.
|
||
A new `relicario_core::safe_unpack_git_archive` validates each
|
||
entry's path components (rejects `..`, absolute paths, Windows
|
||
drive prefixes), rejects symlinks/hardlinks, and caps total
|
||
uncompressed size at the lower of 100×compressed-bytes or 1 GiB.
|
||
The CLI restore path adds a paranoid `dest.starts_with(.git/)`
|
||
check after path-joining as defense-in-depth.
|
||
- **`RELICARIO_*` env-var surface audited (audit S3).** `docs/SECURITY.md`
|
||
gains a per-variable trust table. `RELICARIO_NO_GROUPS_CACHE` (a
|
||
developer escape hatch, not a user knob) is now
|
||
`cfg(debug_assertions)`-gated and is a no-op in `--release` builds;
|
||
the env-var lookup is removed from the binary by the optimiser.
|
||
|
||
### Fixed
|
||
|
||
- **Strength meter no longer goes stale after the regenerate button (B1).**
|
||
Programmatic `input.value = newPassword` doesn't fire `input`
|
||
events; the regenerate handler now dispatches a synthetic
|
||
`InputEvent('input', { bubbles: true })` so the meter listener
|
||
re-rates the new value.
|
||
- **Snake_case error codes no longer leak into the UI (B2 / P4).**
|
||
Errors like `vault_locked`, `origin_mismatch`, `unauthorized_sender`
|
||
used to render verbatim in the fullscreen vault tab and (in some
|
||
cases) the popup. New `extension/src/shared/error-copy.ts` central
|
||
registry maps every service-worker error code to friendly
|
||
title/body/CTA copy; the popup and fullscreen tab consume the
|
||
same map. The fullscreen lock screen's `vault_locked` block now
|
||
reads `Vault locked / Unlock your vault to continue. / [Unlock
|
||
vault]`. A generated test enumerates the live error codes via
|
||
grep so the registry can't drift.
|
||
|
||
### Added
|
||
|
||
- **Sidebar logo in the fullscreen vault tab.** The
|
||
`vault-sidebar__header` now renders the 16-optimized SVG logo
|
||
inline before the "Relicario" wordmark (20×20 px, `flex-shrink: 0`
|
||
so it survives narrow-pane wraps). Popup unaffected.
|
||
- **Password coloring (P1).** Revealed passwords in the popup
|
||
item-detail, fullscreen item view, field-history viewer, and
|
||
generator preview render digits and symbols in distinct colors.
|
||
Defaults: blue digits, red symbols. Users can override via the
|
||
new Display section in settings (color pickers + live preview
|
||
swatch + reset). Defaults round-trip via
|
||
`chrome.storage.sync.password_display_scheme`; cross-device when
|
||
Chrome sync is enabled.
|
||
- **Setup wizard hands off to the fullscreen vault tab on completion
|
||
(P2).** Both create-new and attach-existing flows now open
|
||
`vault.html` in a new tab and best-effort close the setup tab
|
||
after device registration succeeds — replaces the prior
|
||
setup-tab-stays-open terminal screen.
|
||
- **Sync now button** in the extension settings view — surfaces the
|
||
previously hidden `{ type: 'sync' }` SW message to users with success /
|
||
error feedback.
|
||
- **Device registration from the popup.** The "Register this device"
|
||
button on the devices view now opens an inline name input and (on
|
||
confirm) generates a keypair via WASM, persists the private key + name
|
||
locally, and writes the device to the remote — no setup-wizard detour.
|
||
Backed by a new `register_this_device` SW message.
|
||
- **`relicario settings generator-defaults`** — view-and-edit access to the
|
||
generator defaults stored in `VaultSettings`. Flags: `--random` /
|
||
`--bip39` to switch mode, `--length`, `--words`, `--symbols`,
|
||
`--separator` to update fields of the active mode.
|
||
- **`relicario edit` now supports TOTP items.** Issuer, label, and secret
|
||
rotation work; rotated secrets are pushed to `field_history` (key:
|
||
`core:totp_secret`).
|
||
- **`relicario history <query>`** — view captured field history. Values
|
||
are masked by default; `--show` reveals them; `--field <name>` filters
|
||
to one synthetic key (e.g. `login_password`, `totp_secret`).
|
||
- **`relicario detach <query> <aid>`** — remove an individual attachment
|
||
from an item. Refuses to drop a Document item's primary attachment
|
||
(use `purge` instead).
|
||
- **`relicario status`** — vault summary: root path, item count
|
||
(active / trashed), attachment count + total bytes, registered device
|
||
count, last commit (`%h %s`).
|
||
- **Backup & restore.** New `relicario backup export <out.relbak>` and
|
||
`relicario backup restore <in.relbak> [<dir>]` commands. The `.relbak`
|
||
format is a single encrypted file: Argon2id-derived key from a
|
||
user-chosen backup passphrase (independent of the vault factor),
|
||
XChaCha20-Poly1305 ciphertext, zstd-compressed JSON envelope.
|
||
Reference image and `.git/` history are opt-in inclusions
|
||
(`--include-image`, `--no-history`).
|
||
- **Vault-tab Backup & Restore panel.** Export downloads the
|
||
`.relbak` via `chrome.downloads`. Restore takes a file + backup
|
||
passphrase + new-remote config and writes the vault into a fresh
|
||
empty repo (refuses to clobber existing). Git history is never
|
||
bundled from the extension — CLI is the source of full backups.
|
||
- **LastPass CSV import.** New `relicario import lastpass <csv>`
|
||
command + vault-tab Import panel (`vault.html#import`).
|
||
Logins map to `Login` items; rows with `url == "http://sn"`
|
||
map to `SecureNote` (extra column → body verbatim, structured
|
||
data preserved as-is for manual re-categorization). TOTP
|
||
secrets in the `totp` column are base32-decoded into
|
||
`LoginCore.totp`; bad base32 surfaces a warning and the login
|
||
is imported without TOTP. Failed rows (missing `name`, missing
|
||
password on a login) are skipped with a per-row warning.
|
||
Each row gets a freshly-minted ID — re-running the import
|
||
creates duplicates rather than corrupting state.
|
||
- **Popup deep link to the Import panel.** `settings-vault`
|
||
gains an "import" section with a `LastPass CSV →` button
|
||
next to the existing `Backup & restore →` button.
|
||
- **`relicario status` shows last export age.** New `Last export:
|
||
<human-readable>` line reading `.relicario/last_backup` (a marker
|
||
file `cmd_backup_export` writes on success). Reads "never" for
|
||
fresh vaults, "4 days ago" otherwise.
|
||
|
||
### Changed
|
||
|
||
- **Form layout in the fullscreen vault tab is now visually consistent
|
||
(P3).** Notes, custom-fields disclosure, attachments disclosure, and
|
||
form-actions in fullscreen logins now sit inside a `.form-lower`
|
||
wrapper with the same `max-width: 960px; margin: 0 auto` envelope as
|
||
the `.form-grid` cards above. Removes the visual rhythm break at the
|
||
2-col → full-width transition. The popup surface is unchanged.
|
||
- **Documentation refreshed for v0.5.0 (doc audit, 14 findings).**
|
||
`ARCHITECTURE.md` now describes four codebases (the
|
||
`relicario-server` pre-receive hook crate is no longer invisible);
|
||
`CLAUDE.md` project tree and roadmap reflect current state;
|
||
`docs/SECURITY.md` names the server crate and its `verify-commit` /
|
||
`generate-hook` subcommands and notes the without-the-hook-it's-
|
||
advisory caveat; `docs/ARCHITECTURE.md` shows `settings.enc` as a
|
||
parallel artifact in the vault-creation flow; the foundational
|
||
design spec gains a "historical" status banner pointing readers at
|
||
the current docs.
|
||
- `relicario generate` now consults `VaultSettings.generator_defaults` when
|
||
invoked inside an initialized vault. Explicit flags (`--length`,
|
||
`--bip39`, `--words`, `--symbols`, `--separator`) override the vault
|
||
default. Outside a vault, behavior is unchanged (length 20, safe symbol
|
||
set, 5 BIP39 words, space separator).
|
||
|
||
### Known limitations
|
||
|
||
- **Mid-restore failure leaves the target remote in a half-written
|
||
state.** `cmd_backup_restore` and the vault-tab Restore panel both
|
||
write artifacts sequentially via `writeFileCreateOnly`. If the
|
||
process is interrupted partway, a retry against the same remote
|
||
refuses to clobber. Workaround: delete the partial repo and retry.
|
||
- **Cross-tool backup compatibility.** CLI-exported backups stored
|
||
attachments at `<item_id>/<aid>.enc`; extension stores at flat
|
||
`<aid>.bin`. The `.relbak` envelope canonicalizes to `<item_id>/<aid>`
|
||
keys and each tool translates at the boundary. Round-trip works in
|
||
both directions.
|
||
|
||
### Internal
|
||
|
||
- 5 stale local feature branches and 3 worktrees pruned (audit C1).
|
||
- Pre-existing clippy warnings cleaned up across `relicario-{core,cli}`
|
||
(deref operators, `Option::is_none_or` over `map_or(true, ...)`,
|
||
`iter_mut().enumerate()` patterns, `div_ceil()`) so the workspace
|
||
builds clean under `-D warnings`.
|
||
- `Cargo.lock` regenerated and committed; was stale since the
|
||
`--totp-qr` commit.
|
||
- Refactored `cmd_add` and `cmd_edit` in the CLI: each `ItemCore` variant
|
||
now has its own `build_*_item` / `edit_*` helper. Pure mechanical
|
||
extraction; behavior unchanged. The dispatcher matches and delegates.
|
||
- Extracted pure helpers (`escapeHtml`, `ratePassphrase`, `scheduleRate`,
|
||
`entropyText`, `STRENGTH_LABELS`) from `extension/src/setup/setup.ts`
|
||
into `setup-helpers.ts`. State-coupled `updateStrengthUi` stays in
|
||
`setup.ts` since it walks live wizard state. Setup.ts went from
|
||
1205 → 1137 lines.
|
||
|
||
## v0.2.0 — 2026-04-27
|
||
|
||
### Fixed
|
||
|
||
- **Setup wizard could silently overwrite an existing vault.** Pointing the
|
||
wizard at a remote that already contained a Relicario vault would clobber
|
||
`manifest.enc`, `.relicario/salt`, and friends with no warning. The wizard
|
||
now probes the remote after the connection test and refuses to create a
|
||
new vault on top of an existing one. Affected users whose vault was wiped
|
||
by this bug should restore from the git history of the affected repo
|
||
(`git log` + `git checkout <pre-init-sha> -- .`).
|
||
- **New devices registered during initial setup were silently dropped.** The
|
||
wizard's Step 5 fired `add_device` over a service-worker channel that
|
||
required an unlocked vault, which is unavailable mid-wizard. Device pubkeys
|
||
now write directly to `.relicario/devices.json` from the wizard.
|
||
- **Wizard-created vaults were missing `settings.enc`.** The CLI's `init`
|
||
writes a default-`VaultSettings` `settings.enc` alongside `manifest.enc`,
|
||
but the wizard skipped it, causing every `get_vault_settings` SW call to
|
||
404. The wizard now encrypts and writes `settings.enc` using a new
|
||
`default_vault_settings_json` WASM helper that keeps defaults in sync
|
||
with Rust core.
|
||
|
||
### Added
|
||
|
||
- **Attach this device to an existing vault — purely from the GUI.** New
|
||
Step 0 mode picker splits the wizard into "create new vault" and "attach
|
||
this device." The attach path takes a passphrase + reference image, fetches
|
||
the existing manifest, verifies the credentials by decrypting it, and only
|
||
then registers a new device key. No CLI required for multi-device setup.
|
||
- `GitHost.lastCommit(path)` and `GitHost.writeFileCreateOnly(path, ...)`.
|
||
- `default_vault_settings_json()` WASM export.
|
||
|
||
## v0.1.0 — 2026-04-22
|
||
|
||
Initial release.
|