#!/usr/bin/env bash
# tests/creds-matrix/run-tests.sh -- harness for scripts/creds-matrix.py (D-137 tier 1).
#
# One case per invariant, each named for the REAL defect it encodes. Fixtures are
# mutations of a minimal valid artifact set, and every case asserts BOTH the exit code and
# an output regex -- a check that fires with the wrong message is a check nobody can act on.
#
# Gauntlet contract (scripts/run-tests-all.sh:22 registers by glob and shows only tail -1):
# the LAST line self-describes, and failure detail lines lead with a bare FAIL so the
# runner's `^\s*(FAIL|\[XX\]|MISS|LEAK|COUNT)` excerpt matches them.
set -uo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO="$(cd "$HERE/../.." && pwd)"
CHECK="$REPO/scripts/creds-matrix.py"
TMPROOT="${TMPDIR:-/tmp}/creds-matrix-tests.$$"
mkdir -p "$TMPROOT"
trap 'rm -rf "$TMPROOT"' EXIT
P=0; F=0
ok() { P=$((P+1)); echo " [ok] $1"; }
no() { F=$((F+1)); echo "FAIL $1"; }
# ---- minimal VALID fixture set -------------------------------------------------------
mkenv() {
local d; d="$(mktemp -d "$TMPROOT/env.XXXXXX")"
mkdir -p "$d/creds-manifests"
cat > "$d/matrix.tsv" <<'EOF'
alpha-key per-site vr1-office1 jumphost alpha_ed25519 ssh service consolidated stage2 operator-terminal - n-alpha
alpha-key per-site vr1-office1 jumphost alpha_ed25519.pub none service consolidated stage2 operator-terminal - n-alpha
EOF
cat > "$d/creds-manifests/vr1-office1.manifest" <<'EOF'
alpha_ed25519 600 local
alpha_ed25519.pub 644 local
EOF
cat > "$d/notes.md" <<'EOF'
## n-alpha
The alpha service keypair.
EOF
echo "$d"
}
run() { # run <env-dir> [extra args...] -> sets RC, writes $1/out
local d="$1"; shift
python3 "$CHECK" --matrix "$d/matrix.tsv" --manifest-dir "$d/creds-manifests" \
--notes "$d/notes.md" --repo "$REPO" \
--locations "$d/locations" "$@" > "$d/out" 2>&1
RC=$?
}
# A tier-2 fixture: a declared LOCAL location holding the baseline keypair.
mkloc() { # mkloc <env-dir>
local d="$1"; mkdir -p "$d/store"
printf 'x\n' > "$d/store/alpha_ed25519"; chmod 600 "$d/store/alpha_ed25519"
printf 'x\n' > "$d/store/alpha_ed25519.pub"; chmod 644 "$d/store/alpha_ed25519.pub"
printf 'jumphost vr1-office1 local %s/store/*\n' "$d" > "$d/locations"
}
row() { printf '%s\n' "$1" >> "$2/matrix.tsv"; }
note() { printf '\n## %s\nfixture note.\n' "$1" >> "$2/notes.md"; }
echo "=== creds-matrix harness ==="
# T1 -- the baseline must actually PASS, or every other case proves nothing.
D=$(mkenv); run "$D"
[ "$RC" = 0 ] && grep -q '^PASS: creds-matrix' "$D/out" \
&& ok "T1 a consistent matrix/manifest/notes set -> PASS, exit 0" \
|| { no "T1 the valid baseline must pass (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T2 -- a field containing whitespace silently shifts every later column.
D=$(mkenv); row 'beta pass singleton vr1-office1 jumphost beta.txt api service consolidated stage2 operator-terminal - -' "$D"
run "$D"
[ "$RC" = 1 ] && grep -q 'field(s), want 12' "$D/out" \
&& ok "T2 a row with a whitespace-bearing field -> field-count FAIL" \
|| { no "T2 whitespace in a field must be caught (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T3 -- bare `dc0` is the drifting form that has meant two different things per DC.
D=$(mkenv); row 'beta per-DC dc0 jumphost beta.txt api service off-manifest-known stage3 operator-terminal - -' "$D"
run "$D"
[ "$RC" = 1 ] && grep -q 'not region-qualified' "$D/out" \
&& ok "T3 a bare 'dc0' site-key -> REJECTED (region-qualified discipline)" \
|| { no "T3 bare dc0 must be rejected (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T4 -- an invented custody token would silently escape every custody-conditioned rule.
D=$(mkenv); row 'beta singleton vr1-office1 jumphost beta.txt api service probably-fine stage2 operator-terminal - -' "$D"
run "$D"
[ "$RC" = 1 ] && grep -q "custody 'probably-fine' invalid" "$D/out" \
&& ok "T4 an unknown custody token -> enum FAIL" \
|| { no "T4 custody enum must be closed (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T5 -- the SAME identity declared twice at one location is a real duplication error.
D=$(mkenv); row 'alpha-key per-site vr1-office1 jumphost alpha_ed25519 ssh service consolidated stage2 operator-terminal - n-alpha' "$D"
run "$D"
[ "$RC" = 1 ] && grep -q 'duplicate (id,site,host-role,filename)' "$D/out" \
&& ok "T5 one identity declared twice at one location -> duplicate FAIL" \
|| { no "T5 same-identity duplication must be caught (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T6 -- REGRESSION: two DIFFERENT identities may share one file (the Vault init artifact
# holds both the unseal shares and the root token). Keying dedup on location alone
# false-failed this.
D=$(mkenv)
row 'vault-shares singleton - jumphost vault-init none service off-manifest-known vr0-phase02 operator-terminal - -' "$D"
row 'vault-root singleton - jumphost vault-init none service off-manifest-known vr0-phase02 operator-terminal - -' "$D"
run "$D"
[ "$RC" = 0 ] && grep -q '^PASS: creds-matrix' "$D/out" && ! grep -q 'FAIL.*duplicate' "$D/out" \
&& ok "T6 two identities sharing one file -> allowed (Vault init regression)" \
|| { no "T6 distinct identities may share a file (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T7 -- SEC-021's class: the register expects a credential the manifest never declared.
D=$(mkenv); row 'gamma per-site vr1-office1 jumphost gamma.txt api service consolidated stage2 operator-terminal SEC-021 -' "$D"
run "$D"
[ "$RC" = 1 ] && grep -q "EXPECTED-BUT-ABSENT: 'gamma.txt'" "$D/out" \
&& ok "T7 expected by the matrix, absent from the manifest -> EXPECTED-BUT-ABSENT (SEC-021 class)" \
|| { no "T7 expected-but-absent must fire (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T8 -- the undeclared-secret class SEC-009/-020 kept missing, now from the other side.
D=$(mkenv); printf 'delta.txt 600 local\n' >> "$D/creds-manifests/vr1-office1.manifest"
run "$D"
[ "$RC" = 1 ] && grep -q "UNEXPECTED-EXTRA: manifest declares 'delta.txt'" "$D/out" \
&& ok "T8 declared in the manifest, unknown to the matrix -> UNEXPECTED-EXTRA" \
|| { no "T8 unexpected-extra must fire (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T9 -- THE FALSE GREEN. An empty matrix examines no site, so a site-scoped loop finds
# nothing undeclared and reports CLEAN while every declared credential sits unregistered.
# Same defect netbox/sandbox-fidelity-check.py:131-143 records: an upper bound
# masquerading as an assertion. The site set must be the UNION of both sides.
D=$(mkenv); printf '# every row removed\n' > "$D/matrix.tsv"
run "$D"
[ "$RC" = 1 ] && grep -q 'UNEXPECTED-EXTRA' "$D/out" \
&& ok "T9 an EMPTY matrix against populated manifests -> FAILS (the false-green regression)" \
|| { no "T9 an empty matrix must not read clean (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T10 -- a mint-ref that points past EOF is stale provenance, the drift class tier 3 exists for.
D=$(mkenv); row 'beta singleton vr1-office1 headend beta.txt api service off-manifest-known stage2 script:scripts/creds-audit.sh:99999 - -' "$D"
run "$D"
[ "$RC" = 1 ] && grep -q 'points past EOF' "$D/out" \
&& ok "T10 a mint-ref line past EOF -> stale-provenance FAIL" \
|| { no "T10 out-of-range mint-ref must be caught (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T11 -- a mint-ref naming a file that no longer exists (the rename/retire class).
D=$(mkenv); row 'beta singleton vr1-office1 headend beta.txt api service off-manifest-known stage2 script:scripts/no-such-script.sh:1 - -' "$D"
run "$D"
[ "$RC" = 1 ] && grep -q 'mint-ref target does not exist' "$D/out" \
&& ok "T11 a mint-ref to a deleted file -> FAIL" \
|| { no "T11 missing mint-ref target must be caught (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T12 -- research FINDING 1: ssh-keygen has ZERO hits repo-wide, so 12 declared secrets
# have no mint command. Those rows are the DEBT the register exists to surface -- they
# must be ADMITTED and reported, never treated as parse errors.
D=$(mkenv); run "$D"
[ "$RC" = 0 ] && grep -q 'provenance debt: 2 row(s) are mint-ref=operator-terminal' "$D/out" \
&& ok "T12 operator-terminal rows -> admitted and reported as debt, not parse errors" \
|| { no "T12 operator-terminal must be admitted + counted (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T13 -- a per-DC credential existing at one DC only (the SEC-021 divergence shape).
D=$(mkenv)
row 'dc0-power per-DC vr1-dc0 jumphost vr1-dc0-power_ed25519 ssh service consolidated stage3 operator-terminal - -' "$D"
mkdir -p "$D/creds-manifests"; printf 'vr1-dc0-power_ed25519 600 local\n' > "$D/creds-manifests/vr1-dc0.manifest"
run "$D"
[ "$RC" = 1 ] && grep -q 'S5 ASYMMETRY' "$D/out" \
&& ok "T13 a per-DC credential at one DC only -> ASYMMETRY FAIL (SEC-021 shape)" \
|| { no "T13 per-DC asymmetry must fire (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T14 -- narrowing to one DC cannot silently 'pass' a check that needs both.
D=$(mkenv); run "$D" --dc vr1-dc1
[ "$RC" = 0 ] && grep -q 'symmetry needs BOTH DCs, so the check is SKIPPED' "$D/out" \
&& ok "T14 --dc narrows -> symmetry SKIPPED explicitly, never silently passed" \
|| { no "T14 --dc must skip symmetry out loud (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T15 -- D-137 ruling 5: ONE IDENTITY SERVES ONE PRINCIPAL TYPE. This is the live SEC-020
# conflation (`admin` is both the human GUI login and the automation identity).
D=$(mkenv)
row 'shared-ident singleton vr1-office1 headend shared.pass gui human off-manifest-known stage2 operator-terminal - -' "$D"
row 'shared-ident singleton vr1-office1 headend shared.apikey api service off-manifest-known stage2 operator-terminal - -' "$D"
run "$D"
[ "$RC" = 1 ] && grep -q 'IDENTITY CONFLATION' "$D/out" \
&& ok "T15 one identity serving human AND service -> ruling-5 CONFLATION FAIL" \
|| { no "T15 ruling-5 invariant must fire (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T16 -- a non-credential index file (principal '-') must not fault the ruling-5 check.
D=$(mkenv)
row 'folder-readme per-site vr1-office1 jumphost README none - consolidated - - - -' "$D"
printf 'README 600 local\n' >> "$D/creds-manifests/vr1-office1.manifest"
run "$D"
[ "$RC" = 0 ] && ! grep -q 'IDENTITY CONFLATION' "$D/out" \
&& ok "T16 a principal='-' index file -> skipped by ruling 5, not faulted" \
|| { no "T16 principal '-' must be skipped (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T17 -- a notes-ref with no entry means ruling-2 governance prose was silently dropped.
D=$(mkenv); row 'beta singleton vr1-office1 headend beta.txt api service off-manifest-known stage2 operator-terminal - n-nonexistent' "$D"
run "$D"
[ "$RC" = 1 ] && grep -q "notes-ref 'n-nonexistent' has no" "$D/out" \
&& ok "T17 a dangling notes-ref -> FAIL (ruling-2 prose must not be droppable)" \
|| { no "T17 dangling notes-ref must be caught (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T18 -- an orphan note is prose that survived the row it documented (the other direction).
D=$(mkenv); note 'n-orphan' "$D"
run "$D"
[ "$RC" = 1 ] && grep -q "orphan note 'n-orphan'" "$D/out" \
&& ok "T18 a note referenced by no row -> orphan FAIL" \
|| { no "T18 orphan notes must be caught (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T19 -- the mode column is DERIVED (.pub -> 644, else 600), so a hand-edited manifest
# mode is drift. This is what makes manifests generated artifacts per ruling 2.
D=$(mkenv); sed -i 's/^alpha_ed25519.pub 644/alpha_ed25519.pub 600/' "$D/creds-manifests/vr1-office1.manifest"
run "$D"
[ "$RC" = 1 ] && grep -qE 'FIELD DRIFT|render drift' "$D/out" \
&& ok "T19 a hand-edited manifest mode -> render/field DRIFT FAIL" \
|| { no "T19 mode drift must be caught (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T20 -- rows with no host artifact (filename '-') must skip existence-shaped checks
# rather than fault: the juju-<dc> superuser password is stored NOWHERE by ruling.
D=$(mkenv)
row 'nowhere-user singleton vr1-office1 - - api service off-manifest-known stage5 operator-terminal - -' "$D"
run "$D"
[ "$RC" = 0 ] \
&& ok "T20 a filename='-' row (credential with no host artifact) -> skipped, not faulted" \
|| { no "T20 no-artifact rows must be skipped (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T21 -- a tier that did not run must announce itself. A silent pass is the exact
# false-green this design exists to prevent. Tier 2 is built, so --all RUNS it and only
# tier 3 self-announces; a default run announces tier 2 as NOT RUN.
D=$(mkenv); mkloc "$D"; run "$D" --all
[ "$RC" = 0 ] && grep -q 'tier 2 (EXISTENCE)' "$D/out" \
&& grep -q 'tier 3 (VALIDITY)' "$D/out" \
&& ok "T21a --all runs every built tier (2 and 3) -> no silent skip" \
|| { no "T21a --all tier reporting (rc=$RC)"; sed 's/^/ /' "$D/out"; }
D=$(mkenv); mkloc "$D"; run "$D"
[ "$RC" = 0 ] && grep -q 'tier 2 (EXISTENCE) NOT RUN' "$D/out" \
&& ok "T21b a default run announces tier 2 as NOT RUN -> never a silent skip" \
|| { no "T21b default run must announce tier 2 (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T22 -- METADATA ONLY. The checker must never gain a content-reading verb; it inspects
# existence, mode, and declared provenance. Mirrors tests/creds-audit/run-tests.sh:71-73.
grep -qE '\b(cat|head|tail|less|more|od|xxd|hexdump)\b' "$CHECK" \
&& no "T22 the checker contains a content-reading verb -- it must inspect metadata only" \
|| ok "T22 metadata-only: no cat/head/tail/od/xxd in the checker"
# T23 -- --render must emit a GENERATED banner, so nobody hand-edits a derived manifest.
D=$(mkenv); run "$D" --render
[ "$RC" = 0 ] && grep -q 'GENERATED from creds-matrix.tsv' "$D/out" \
&& grep -qE 'alpha_ed25519\.pub +644 +local' "$D/out" \
&& ok "T23 --render emits a GENERATED banner and the derived modes" \
|| { no "T23 --render output shape (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T24 -- the REAL tree must be RED, and red for the RIGHT CLASSES. Compared against a
# checked-in baseline of finding CLASSES rather than literal strings: the old form grepped
# for "IDENTITY CONFLATION", so REMEDIATING that defect -- the fix the plan, the notes and
# the changelog all prescribe -- would have deleted the string and turned the GAUNTLET red
# for whoever did the right thing. The cheapest response at that moment is to edit the
# test, which is exactly when the "do not go green by deleting rows" guard stops existing.
# With a baseline, remediation REQUIRES updating expected-findings.txt in the same commit:
# a recorded decision instead of a mystery breakage.
python3 "$CHECK" 2>&1 | python3 "$HERE/classify-findings.py" > "$TMPROOT/actual.txt"; RRC=${PIPESTATUS[0]}
if diff -u "$HERE/expected-findings.txt" "$TMPROOT/actual.txt" > "$TMPROOT/diff.txt" 2>&1; then
[ "$RRC" = 1 ] \
&& ok "T24 the real tree is RED with exactly the baselined finding classes" \
|| no "T24 the real tree must exit 1 (rc=$RRC)"
else
no "T24 finding CLASSES drifted from tests/creds-matrix/expected-findings.txt -- if you"
echo " FIXED a defect, update the baseline in the SAME commit; if a NEW class"
echo " appeared, that is a regression. Diff (expected vs actual):"
sed 's/^/ /' "$TMPROOT/diff.txt"
fi
# ---- tier 2 (EXISTENCE) ---------------------------------------------------------------
# T25 -- the tier-2 baseline: everything expected is present at its declared location.
D=$(mkenv); mkloc "$D"; run "$D" --tier2
[ "$RC" = 0 ] && grep -q 'E1/E3 existence' "$D/out" \
&& ok "T25 every expected artifact present at a declared location -> tier 2 clean" \
|| { no "T25 tier-2 baseline must pass (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T26 -- the register's whole reason for existing: a credential that SHOULD be there and
# is not. Absence is invisible to a discovery sweep; only an expected-state register sees it.
D=$(mkenv); mkloc "$D"; rm "$D/store/alpha_ed25519"; run "$D" --tier2
[ "$RC" = 1 ] && grep -q "E1 EXPECTED-BUT-ABSENT: alpha-key 'alpha_ed25519'" "$D/out" \
&& ok "T26 an expected credential missing from disk -> E1 EXPECTED-BUT-ABSENT" \
|| { no "T26 absence must be detectable (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T27 -- a credential whose mint-stage has not been reached is DEFERRED, not failed --
# and the caller declares that, never the script (GA-R1: no status claim lives in code).
D=$(mkenv); mkloc "$D"; rm "$D/store/alpha_ed25519"; run "$D" --tier2 --pending-stage stage2
[ "$RC" = 0 ] && grep -q 'deferred as not-yet-minted' "$D/out" \
&& ok "T27 --pending-stage defers a not-yet-minted credential instead of failing it" \
|| { no "T27 pending-stage deferral (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T28 -- the SEC-020/-022 class from the other side: a real secret sitting at a declared
# location that no matrix row accounts for.
D=$(mkenv); mkloc "$D"; printf 'x\n' > "$D/store/stray.apikey"; run "$D" --tier2
[ "$RC" = 1 ] && grep -q "E3 UNDECLARED: 'stray.apikey'" "$D/out" \
&& ok "T28 an undeclared secret at a declared location -> E3 UNDECLARED" \
|| { no "T28 undeclared detection (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T29 -- a group-readable private key is an exposure, not a cosmetic difference.
D=$(mkenv); mkloc "$D"; chmod 640 "$D/store/alpha_ed25519"; run "$D" --tier2
[ "$RC" = 1 ] && grep -q 'E2 MODE' "$D/out" \
&& ok "T29 a private key at the wrong mode -> E2 MODE FAIL" \
|| { no "T29 mode enforcement (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T30 -- ruling 3 is absolute: with no declared-location list there is no bound, so
# discovery must REFUSE to run rather than fall back to walking anything.
D=$(mkenv); mkloc "$D"; rm "$D/locations"; run "$D" --tier2
[ "$RC" = 1 ] && grep -q 'no declared-location list' "$D/out" \
&& ok "T30 a missing locations list -> tier 2 REFUSES to run (ruling 3 is absolute)" \
|| { no "T30 must refuse unbounded discovery (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T31 -- remote locations are opt-in, and their omission must be VISIBLE. A local-only
# run that quietly ignored the headend would reproduce the SEC-022 blind spot exactly.
D=$(mkenv); mkloc "$D"
printf 'headend vr1-office1 some-host /root/secrets/*\n' >> "$D/locations"
run "$D" --tier2
[ "$RC" = 0 ] && grep -q 'remote location(s) SKIPPED' "$D/out" \
&& ok "T31 remote locations omitted without --remote -> announced, not silently dropped" \
|| { no "T31 remote omission must be visible (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T32 -- an unreachable host must SKIP explicitly. Treating 'could not look' as 'nothing
# there' is the false-green that makes a credential audit worthless.
D=$(mkenv); mkloc "$D"
printf 'headend vr1-office1 no-such-host.invalid /root/secrets/*\n' >> "$D/locations"
run "$D" --tier2 --remote
[ "$RC" = 0 ] && grep -q 'UNREACHABLE' "$D/out" \
&& grep -q 'never a pass' "$D/out" \
&& ok "T32 an unreachable host -> explicit UNREACHABLE skip, never counted as clean" \
|| { no "T32 unreachable must skip loudly (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T33 -- FALSE-GREEN REGRESSION: a declared location that EXISTS but cannot be listed.
# A shell glob over an unreadable directory does not expand, so a naive probe finds no
# files and reports "nothing undeclared here" about a directory it never opened. The
# region secrets dir (SEC-020) is exactly such a directory.
D=$(mkenv); mkloc "$D"; mkdir -p "$D/locked"; printf 'x\n' > "$D/locked/hidden.key"
chmod 000 "$D/locked"
printf 'jumphost vr1-office1 local %s/locked/*\n' "$D" >> "$D/locations"
run "$D" --tier2
chmod 755 "$D/locked"
[ "$RC" = 1 ] && grep -q 'E0 UNREADABLE' "$D/out" \
&& ok "T33 an unreadable declared location -> UNREADABLE FAIL, never an empty listing" \
|| { no "T33 unreadable must not read as empty (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T34 -- a declared location that simply does not exist yet is a SKIP, not a failure.
D=$(mkenv); mkloc "$D"
printf 'jumphost vr1-office1 local %s/not-created-yet/*\n' "$D" >> "$D/locations"
run "$D" --tier2
[ "$RC" = 0 ] && grep -q 'does not exist -- SKIPPED' "$D/out" \
&& ok "T34 a not-yet-created declared location -> explicit SKIP, not a failure" \
|| { no "T34 absent location handling (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# ---- committee-derived regressions (2026-07-26) ---------------------------------------
# T36 -- THE SITE COLLISION. Two sites, one role, the SAME basename: dc1 has the file,
# dc0 does not. Keyed on role alone, dc1's copy satisfied dc0's row and the absence was
# invisible -- which is exactly how SEC-021's dc0 opnsense-api.txt passed a green sweep.
# The old fixtures declared only ONE location per role, so this was structurally
# unreachable by the test set.
D=$(mkenv); mkloc "$D"
mkdir -p "$D/dc0store" "$D/dc1store"
printf 'x\n' > "$D/dc1store/shared.txt"; chmod 600 "$D/dc1store/shared.txt"
printf 'jumphost vr1-dc0 local %s/dc0store/*\n' "$D" >> "$D/locations"
printf 'jumphost vr1-dc1 local %s/dc1store/*\n' "$D" >> "$D/locations"
row 'shared-cred per-DC vr1-dc0 jumphost shared.txt api service off-manifest-known stage3 operator-terminal - -' "$D"
row 'shared-cred per-DC vr1-dc1 jumphost shared.txt api service off-manifest-known stage3 operator-terminal - -' "$D"
run "$D" --tier2
[ "$RC" = 1 ] && grep -q "E1 EXPECTED-BUT-ABSENT: shared-cred 'shared.txt' expected at jumphost/vr1-dc0" "$D/out" \
&& ok "T36 same basename, two sites, absent at one -> E1 fires for THAT site (site-collision)" \
|| { no "T36 site-scoped existence must fire (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T37 -- ruling 3's bound is ABSOLUTE, so an EMPTY list must refuse exactly like a missing
# one. Previously an empty file parsed to [] (not None), skipped the refusal, and then
# affirmed existence over zero probed locations.
D=$(mkenv); mkloc "$D"; : > "$D/locations"; run "$D" --tier2
[ "$RC" = 1 ] && grep -q 'is EMPTY' "$D/out" \
&& ok "T37 an EMPTY declared-location list -> REFUSES, never affirms over zero locations" \
|| { no "T37 empty locations must refuse (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T38 -- a register with no rows asserts nothing, but every check reported clean over the
# empty set and the run exited 0.
D=$(mkenv); printf '# all rows removed\n' > "$D/matrix.tsv"; run "$D"
[ "$RC" = 1 ] && grep -q 'S1 FLOOR' "$D/out" \
&& ok "T38 a ZERO-row matrix -> FLOOR failure, not a clean run" \
|| { no "T38 empty matrix must not be clean (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T39 -- mode enforcement used to apply only to custody=consolidated, leaving 43 of 77
# rows -- including the SEC-020 region dir and the SEC-022 shadow stores -- unchecked.
D=$(mkenv); mkloc "$D"
printf 'x\n' > "$D/store/exposed_ed25519"; chmod 644 "$D/store/exposed_ed25519"
row 'exposed singleton vr1-office1 jumphost exposed_ed25519 ssh service off-manifest-known stage2 operator-terminal - -' "$D"
run "$D" --tier2
[ "$RC" = 1 ] && grep -q 'E2 WORLD-READABLE' "$D/out" \
&& ok "T39 a world-readable secret at NON-consolidated custody -> caught" \
|| { no "T39 world-readable secrets must be caught at any custody (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T40 -- S5's SECOND direction. T13 only ever populated the dc0 side, so deleting the
# dc1->dc0 comparison left the harness fully green: an upper bound masquerading as an
# assertion, in the check whose entire job is symmetry.
D=$(mkenv)
row 'dc1-only per-DC vr1-dc1 jumphost vr1-dc1-only_ed25519 ssh service off-manifest-known stage3 operator-terminal - -' "$D"
printf 'vr1-dc1-only_ed25519 600 local\n' > "$D/creds-manifests/vr1-dc1.manifest"
run "$D"
[ "$RC" = 1 ] && grep -q 'S5 ASYMMETRY: vr1-dc1' "$D/out" \
&& ok "T40 a dc1-ONLY per-DC credential -> ASYMMETRY fires on the second direction too" \
|| { no "T40 S5 must assert BOTH directions (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T41 -- literal-file locations previously skipped the absent/unreadable determination
# entirely, so an unreadable directory read as "fully probed, nothing there".
D=$(mkenv); mkloc "$D"; mkdir -p "$D/lockedf"; printf 'x\n' > "$D/lockedf/k.key"; chmod 000 "$D/lockedf"
printf 'jumphost vr1-office1 local %s/lockedf/k.key\n' "$D" >> "$D/locations"
run "$D" --tier2; chmod 755 "$D/lockedf"
[ "$RC" = 1 ] && grep -q 'E0 UNREADABLE' "$D/out" \
&& ok "T41 an unreadable dir behind a LITERAL-file location -> UNREADABLE, not silent ok" \
|| { no "T41 literal paths need state detection too (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T42 -- the declared path reaches a remote shell, so its charset is a security boundary:
# ruling 3 calls the bound absolute, and an unvalidated `;` would execute on the host --
# under sudo when --privileged is passed.
D=$(mkenv); mkloc "$D"
printf 'jumphost vr1-office1 local /tmp/x;id\n' >> "$D/locations"
run "$D" --tier2
[ "$RC" = 1 ] && grep -q 'shell metacharacter' "$D/out" \
&& ok "T42 a shell metacharacter in a declared path -> REJECTED before any probe" \
|| { no "T42 unsafe declared paths must be rejected (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T43 -- a row whose (role, site) has no declared location can never be verified. It used
# to `continue` with no counter and no [ok], contradicting the module's own contract that
# nothing passes silently.
D=$(mkenv); mkloc "$D"
row 'orphan-scope singleton vr1-office1 unit thing.txt api service off-manifest-known stage6 operator-terminal - -' "$D"
run "$D" --tier2
[ "$RC" = 1 ] && grep -q 'E4 UNCHECKABLE' "$D/out" \
&& ok "T43 a row with no declared location for its scope -> disclosed, not silently skipped" \
|| { no "T43 uncheckable rows must be disclosed (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T44 -- per-tenant/per-node rows name an instance they cannot know at authoring time.
# Exact matching made the five tenant rows unmatchable, so the first onboard would have
# produced five false absences AND five false undeclared findings on the SAME real files.
D=$(mkenv); mkloc "$D"
printf 'x\n' > "$D/store/acme-handover.txt"; chmod 600 "$D/store/acme-handover.txt"
row 'tenant-thing per-tenant vr1-office1 jumphost <client>-handover.txt api service off-manifest-known tenant-onboard operator-terminal - -' "$D"
run "$D" --tier2
[ "$RC" = 0 ] && grep -q 'E1/E3 existence' "$D/out" \
&& ok "T44 a <client> instance placeholder matches the real basename (no false absent+undeclared pair)" \
|| { no "T44 instance templating must match (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# ---- tier 3 (VALIDITY) ------------------------------------------------------------------
# T45 -- the same artifact copied to two scopes, byte-identical -> clean.
mk3() { # mk3 <env-dir> <bytesA> <bytesB>
local d="$1"; mkdir -p "$d/s1" "$d/s2"
printf '%s\n' "$2" > "$d/s1/twin.key"; chmod 600 "$d/s1/twin.key"
printf '%s\n' "$3" > "$d/s2/twin.key"; chmod 600 "$d/s2/twin.key"
printf 'jumphost vr1-dc0 local %s/s1/*\n' "$d" >> "$d/locations"
printf 'jumphost vr1-dc1 local %s/s2/*\n' "$d" >> "$d/locations"
row 'twin per-DC vr1-dc0 jumphost twin.key ssh service off-manifest-known stage3 operator-terminal - -' "$d"
row 'twin per-DC vr1-dc1 jumphost twin.key ssh service off-manifest-known stage3 operator-terminal - -' "$d"
}
D=$(mkenv); mkloc "$D"; mk3 "$D" same same; run "$D" --tier2 --tier3
grep -q 'V1 provenance: all copies byte-identical' "$D/out" \
&& ok "T45 identical copies of one artifact -> V1 clean" \
|| { no "T45 identical copies should verify"; sed 's/^/ /' "$D/out"; }
# T46 -- THE POINT OF TIER 3. SEC-020: "any future rotation MUST update both copies in one
# operation or the region copy becomes a stale trap." That warning was unchecked prose from
# the day it was written; the sha256 equality behind it was a ONE-TIME manual act.
D=$(mkenv); mkloc "$D"; mk3 "$D" original rotated; run "$D" --tier2 --tier3
[ "$RC" = 1 ] && grep -q 'V1 PROVENANCE DRIFT' "$D/out" && grep -q 'STALE TRAP' "$D/out" \
&& ok "T46 one copy rotated and the other not -> V1 PROVENANCE DRIFT (the SEC-020 trap)" \
|| { no "T46 drift must be caught (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T47 -- REGRESSION for a false positive this check shipped with in draft: an identity's
# DISTINCT artifacts (a password, its API key, its CLI profile) are not byte-copies of each
# other. Keying digests by scope let them overwrite one another and report drift between
# unrelated files. Verified by hand against the live hosts: the digests actually matched.
D=$(mkenv); mkloc "$D"; mkdir -p "$D/multi"
printf 'pw\n' > "$D/multi/thing.pass"; chmod 600 "$D/multi/thing.pass"
printf 'key\n' > "$D/multi/thing.apikey"; chmod 600 "$D/multi/thing.apikey"
printf 'jumphost vr1-office1 local %s/multi/*\n' "$D" >> "$D/locations"
row 'one-ident singleton vr1-office1 jumphost thing.pass gui human off-manifest-known stage2 operator-terminal - -' "$D"
row 'one-ident singleton vr1-office1 jumphost thing.apikey api human off-manifest-known stage2 operator-terminal - -' "$D"
run "$D" --tier2 --tier3
! grep -q 'V1 PROVENANCE DRIFT' "$D/out" \
&& ok "T47 distinct artifacts of ONE identity are not compared (draft false positive)" \
|| { no "T47 distinct artifacts must not be diffed"; sed 's/^/ /' "$D/out"; }
# T48 -- REGRESSION for the second draft false positive: the same credential in a DIFFERENT
# SERIALIZATION. The netbox token is a raw file on the VM and an assembled env file on the
# jumphost; they are the same secret and are NOT byte-identical by design.
D=$(mkenv); mkloc "$D"; mkdir -p "$D/raw" "$D/wrapped"
printf 'tok\n' > "$D/raw/api.token"; chmod 600 "$D/raw/api.token"
printf 'URL=x\nTOK=tok\n' > "$D/wrapped/w.env"; chmod 600 "$D/wrapped/w.env"
printf 'netbox vr1-office1 local %s/raw/*\n' "$D" >> "$D/locations"
printf 'jumphost vr1-office1 local %s/wrapped/*\n' "$D" >> "$D/locations"
row 'wrapped-tok singleton vr1-office1 netbox api.token api service source-of-record stage2 operator-terminal - -' "$D"
row 'wrapped-tok singleton vr1-office1 jumphost w.env api service consolidated stage2 operator-terminal - -' "$D"
printf 'w.env 600 local\n' >> "$D/creds-manifests/vr1-office1.manifest"
run "$D" --tier2 --tier3
! grep -q 'V1 PROVENANCE DRIFT' "$D/out" \
&& ok "T48 same credential, different SERIALIZATION -> not compared (draft false positive)" \
|| { no "T48 re-serialized copies must not be diffed"; sed 's/^/ /' "$D/out"; }
# T49 -- but a copy DECLARED byte-identical under a different name IS compared. This is
# SEC-020's exact shape (admin.pass on the region, maas-admin-password on the jumphost)
# and it is the case tier 3 exists for, so it must not fall into T48's skip.
D=$(mkenv); mkloc "$D"; mkdir -p "$D/src" "$D/cpy"
printf 'v1\n' > "$D/src/orig.pass"; chmod 600 "$D/src/orig.pass"
printf 'v2\n' > "$D/cpy/work.pass"; chmod 600 "$D/cpy/work.pass"
printf 'netbox vr1-office1 local %s/src/*\n' "$D" >> "$D/locations"
printf 'jumphost vr1-office1 local %s/cpy/*\n' "$D" >> "$D/locations"
row 'declared-twin singleton vr1-office1 netbox orig.pass gui human source-of-record stage2 operator-terminal - -' "$D"
row 'declared-twin singleton vr1-office1 jumphost work.pass gui human verbatim-copy stage2 operator-terminal - -' "$D"
printf 'work.pass 600 local\n' >> "$D/creds-manifests/vr1-office1.manifest"
run "$D" --tier2 --tier3
[ "$RC" = 1 ] && grep -q 'V1 PROVENANCE DRIFT' "$D/out" \
&& ok "T49 a DECLARED verbatim copy under a different name IS compared (SEC-020 shape)" \
|| { no "T49 verbatim-copy pairs must be compared (rc=$RC)"; sed 's/^/ /' "$D/out"; }
# T50 -- a tier that did not run must announce itself, like tiers 2 and 3 elsewhere.
D=$(mkenv); mkloc "$D"; run "$D" --tier2
grep -q 'tier 3 (VALIDITY) NOT RUN' "$D/out" \
&& ok "T50 tier 3 omitted -> announced, never a silent skip" \
|| { no "T50 tier 3 must self-announce"; sed 's/^/ /' "$D/out"; }
# T51 -- DIGESTS ONLY, NEVER CONTENT. The plan's hard constraint. sha256sum is the mandated
# mechanism and is allowed; what must never appear is a verb that brings bytes back. This
# extends T22's list, which would not have caught a content transfer added alongside a
# legitimate digest call.
grep -q 'sha256sum' "$CHECK" \
&& ok "T51a the provenance path uses sha256sum (digest, not content)" \
|| no "T51a tier 3 must compare digests"
grep -qE '\b(scp|rsync|base64|dd)\b' "$CHECK" \
&& no "T51b the checker gained a content-TRANSFER verb -- digests only" \
|| ok "T51b no content-transfer verb anywhere in the checker"
echo
if [ "$F" = 0 ]; then echo "creds-matrix: $P/$P PASS"; exit 0; fi
echo "creds-matrix: FAILURES: $F (passed $P)"; exit 1