test(cli): assert .relkey never enters git tree + init failure-path coverage + display polish

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01McMF5pUJbCMricmFEnf2sG
This commit is contained in:
adlee-was-taken
2026-06-25 23:43:31 -04:00
parent 2daa3502e9
commit 23c8bbea65
3 changed files with 67 additions and 6 deletions

View File

@@ -70,3 +70,64 @@ fn init_keyfile_writes_relkey_and_keyfile_params() {
".relkey must be gitignored: {gitignore}"
);
}
/// SECURITY INVARIANT: the in-the-clear .relkey second factor must NEVER enter
/// the git tree — not in the init commit, and not even after an aggressive `git add -A`.
/// The remote/server must only ever receive opaque ciphertext, never the secret.
#[test]
fn relkey_secret_never_enters_git_tree() {
let dir = tempfile::tempdir().unwrap();
relicario(&dir)
.args(["init", "--key-file", "vault.relkey"])
.env("RELICARIO_TEST_PASSPHRASE", "correct horse")
.assert()
.success();
let git_tracked = |label: &str| {
let out = Command::new("git")
.current_dir(dir.path())
.args(["ls-files"])
.output()
.expect("run git ls-files");
let files = String::from_utf8_lossy(&out.stdout).into_owned();
assert!(
!files.contains("vault.relkey"),
"{label}: key file leaked into git tree:\n{files}"
);
};
// Not in the init commit.
git_tracked("after init commit");
// Survives an aggressive add -A (gitignore must hold).
let status = Command::new("git")
.current_dir(dir.path())
.args(["add", "-A"])
.status()
.expect("run git add -A");
assert!(status.success(), "git add -A failed");
git_tracked("after git add -A");
}
/// init with no second factor must fail with a clear, actionable error.
#[test]
fn init_without_a_factor_fails() {
let dir = tempfile::tempdir().unwrap();
relicario(&dir)
.args(["init"])
.env("RELICARIO_TEST_PASSPHRASE", "correct horse")
.assert()
.failure()
.stderr(predicates::str::contains("either --image"));
}
/// --image and --key-file are mutually exclusive (clap rejects before the handler).
#[test]
fn init_with_both_factors_fails() {
let dir = tempfile::tempdir().unwrap();
relicario(&dir)
.args(["init", "--image", "carrier.jpg", "--key-file", "vault.relkey"])
.env("RELICARIO_TEST_PASSPHRASE", "correct horse")
.assert()
.failure();
}