v0.5.0 Plan A — Security Fixes + Repo Cleanup. 7 commits, ~800 net
insertions across the Rust workspace. Four items delivered:
- S1 (HIGH-severity authentication bypass fix): rewrite verify_commit
in relicario-server. The previous implementation accepted any
GOODSIG/Good signature line on stderr, ignoring whether the signing
key was registered or revoked. The new implementation:
* builds a temp gpg.ssh.allowedSignersFile from devices.json at the
commit (no global git-config mutation)
* parses the SHA-256 fingerprint from `git verify-commit --raw`
stderr via regex
* checks revocation FIRST (revoked entries may have been removed
from devices.json), with the historical-commit case
(committer_ts < revoked_at) explicitly allowed
* uses committer date (GIT_COMMITTER_DATE / `git show -s
--format=%ct`), not author date or wall clock
* tightened the bootstrap guard to require BOTH devices and revoked
to be empty (closes an empty-devices.json privilege-escalation
route present in the original code)
* 4 acceptance integration tests build real on-disk repos with
SSH-signed commits and verify each scenario
- S2 (tar archive path-traversal hardening): replace
tar::Archive::unpack with safe_unpack_git_archive. Located in
relicario-core (per-spec, so integration tests can reach it without
the bytes-in/bytes-out invariant breaking). Validates each entry's
type (rejects symlinks/hardlinks), path components (rejects '..',
RootDir, Windows drive Prefix), and declared size (rejects
individual or cumulative > 100×compressed-or-1-GiB whichever is
lower). The CLI's restore path adds a paranoid OS-level
starts_with(.git/) check on the joined destination as
defense-in-depth even after textual validation. 5 acceptance tests
cover path traversal, symlinks, oversized headers (header claim of
2 GiB tested without allocating disk).
- S3 (RELICARIO_* env-var audit): docs/SECURITY.md gains a
"Configuration env vars" section enumerating each variable, its
purpose, and trust assumption. Active-in-all-builds variables
(RELICARIO_IMAGE, RELICARIO_GITEA_*) are documented; debug-only
variables (RELICARIO_NO_GROUPS_CACHE, RELICARIO_TEST_*) are gated
behind cfg(debug_assertions) so the env-var lookup is removed from
--release binaries.
- C1 (stale feature branch prune): 5 merged feature branches and
3 worktrees pruned interactively per dev report.
- Bonus: 4d02a50 fixes pre-existing clippy warnings across
crates/relicario-{core,cli} (deref operators, Option::is_none_or
vs map_or(true, ...), iter_mut().enumerate() patterns,
div_ceil()) so the workspace builds clean under `-D warnings`.
Merge resolution: docs/SECURITY.md had a conflict where main's F11/F12
(Device Authentication paragraph naming relicario-server + simplified
"Device registration is optional" line) collided with Plan A's S3
section. Resolved by keeping both — F11/F12's wording for the
Device Authentication section, then Plan A's "Configuration env vars"
section appended below.
Cargo.lock regenerated. The previous committed lock was stale since
commit 8855078 (--totp-qr); cargo test on both devs' worktrees
produced identical regenerated locks. Plan A genuinely added regex +
tempfile to relicario-server (both already transitively present from
relicario-cli), so no new top-level deps; the Cargo.lock churn is
catch-up of crate-version bumps that have happened since the last
commit-of-record.
Tests: 248 cargo tests pass; extension tests unchanged (336/8 with 8
pre-existing device-auth scaffolding failures).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds csv = "1" to relicario-core; introduces
ImportCsvHeader and ImportCsvFormat. Foundation for the
import_lastpass module landing in Task 2.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Reads the vault layout from disk, prompts for backup passphrase
(zxcvbn-gated, independent of the live vault key), tars .git/
unless --no-history, optionally bundles the reference JPEG, and
atomic-writes the .relbak. Leaves .relicario/last_backup marker
for cmd_status.
Adds zstd, tar, base64 to relicario-core; introduces
BackupBadMagic / BackupUnsupportedVersion / BackupSchemaMismatch.
Foundation for the backup module landing in Task 2.
generate_device_keypair returns an ed25519 keypair as JSON with hex pubkey
and base64 private key. get_field_history extracts tracked field history
from a decrypted item for the popup's history view.
Co-Authored-By: Claude <noreply@anthropic.com>
Uses assert_cmd + tempfile to spin up a fresh vault per test.
Covers init layout, add/list/get mask semantics, rm/restore/purge cycle,
and generate smoke. Adds RELICARIO_TEST_PASSPHRASE env-var hatch in
unlock_interactive and cmd_init so tests don't need a TTY.
Also fixes read_params in session.rs to correctly parse the nested
params.json format (kdf sub-object) rather than trying to deserialize
the whole file as KdfParams.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The getrandom crate (transitive dep via rand/argon2) requires the
"js" feature flag to compile for wasm32-unknown-unknown targets.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>