From 414c02b902efa110b986659a461b4826985ff0df Mon Sep 17 00:00:00 2001 From: Brian Majewski Date: Sun, 7 Jun 2026 15:22:58 -0700 Subject: [PATCH] fix: pre-landing review fixes for verify (test assertions, ekeys discard, double-report, docs) Pre-landing review (0 critical, all informational) auto-fixes: - Tighten external-corrupt test to assert the decrypt-fail message, not any external finding (was *"external"*, now *"does not decrypt"*). - Pin the verified-count in the nested+external happy-path test so a silent under-count (exit 0 while skipping a blob) is caught. - Account for an unsafe dotenv entry in `expected` so a matching stray blob isn't double-reported as both unsafe and orphan. - Discard the unused external `keys` read field (read -r etype epath _). - Document the optional [project] positional in the README verify row. Deferred to EGB-701 (stage-2 dedup): the external blob-path literal and the find-walk overlap with cmd_rekey/cmd_list. Full suite 210/210. --- README.md | 2 +- secrets | 8 ++++++-- test/manifest.bats | 6 +++++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fc6c1c7..e79fc15 100644 --- a/README.md +++ b/README.md @@ -169,7 +169,7 @@ secrets clear | `secrets list` | Show all projects that have stored secrets | | `secrets rm ` | Delete a project's secrets from the store | | `secrets rekey` | Generate a new encryption key and re-encrypt everything | -| `secrets verify` | Check the current project's `.secrets.json` against the store (missing/orphaned blobs) and decrypt every blob | +| `secrets verify [project]` | Check the current project's `.secrets.json` against the store (missing/orphaned blobs) and decrypt every blob. `[project]` overrides the store directory name; the manifest is still read from the current directory | | `secrets verify --all` | Decrypt-test every blob in every project — a store-wide integrity sweep | ### Automatic project detection diff --git a/secrets b/secrets index 61ea874..5ed68a5 100755 --- a/secrets +++ b/secrets @@ -1980,6 +1980,9 @@ _verify_project() { if ! _validate_dotenv_rel_path "$rel" 2>/dev/null; then echo "FINDING: unsafe dotenv path in $SECRETS_JSON_NAME: '$rel' (will be refused)." >&2 findings=$((findings + 1)) + # Still account for it so a matching stray blob isn't ALSO flagged as an + # orphan (one bad entry → one finding, not two). + expected="$expected$rel.age"$'\n' continue fi expected="$expected$rel.age"$'\n' @@ -1997,8 +2000,9 @@ _verify_project() { done < <(jq -r '.dotenv // [] | .[]' "$manifest") # ── external entries: missing-blob + decrypt ── - local etype epath ekeys slug erel eblob - while IFS=$'\t' read -r etype epath ekeys; do + # verify only needs type + path to locate the blob; keys are irrelevant here. + local etype epath slug erel eblob + while IFS=$'\t' read -r etype epath _; do [ -n "$etype" ] || continue slug=$(_secrets_files_slug "$epath") erel="external/$slug.$etype.age" diff --git a/test/manifest.bats b/test/manifest.bats index 3719e8e..9df5bfa 100644 --- a/test/manifest.bats +++ b/test/manifest.bats @@ -754,6 +754,9 @@ m_nojq_path() { "$SECRETS_BIN" push >/dev/null 2>&1 run "$SECRETS_BIN" verify [ "$status" -eq 0 ] + # Pin the count so a silent under-count (e.g. skipping the nested or external + # blob while still exiting 0) is caught: 3 dotenv + 1 external = 4. + [[ "$output" == *"4 blob(s) verified"* ]] || false } @test "verify: declared-but-missing blob is a finding (exit 1)" { @@ -870,7 +873,8 @@ m_nojq_path() { printf 'garbage' > "$SECRETS_DIR/verifyextcorrupt/external/"*.age run "$SECRETS_BIN" verify [ "$status" -eq 1 ] - [[ "$output" == *"external"* ]] || false + # Pin the decrypt-fail branch specifically, not just any external finding. + [[ "$output" == *"does not decrypt"* ]] || false } @test "verify: an unsafe dotenv path in the manifest is a finding (exit 1)" {