fips205-slhdsa-verified/verification/drill.sh

86 lines
3.9 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# drill.sh — the post-flight drill as a BUTTON.
#
# Motivation (2026-07-23): mid-session model degradation is a recurring,
# operator-observed reality. Five manual drills over this campaign each
# re-verified the latest work window; every substantive check they ran was
# MECHANICAL. This script is that battery as one deterministic button, per
# the estate's standing philosophy: enforcement lives in buttons, never in
# model quality. A degraded window cannot fake this — it either exits 0 or
# it does not.
#
# Run it after ANY work window (flip suspected or not). What it cannot
# cover — fidelity review of NEWLY-written specs against their extracted
# ground truth and upstream sources — remains the bespoke, intelligent part
# of the drill, and is required exactly once per new artifact, recorded in
# the artifact's commit message.
#
# 1. hygiene — worktree clean; local == remote head
# 2. honesty — no sorry/admit/axiom outside gen/*External; drafts/ (if
# present) is the only place sorries may live
# 3. the claim — check.sh green (model + proofs + axiom audit)
# 4. the gates — check-selftest.sh green (audit gates genuinely reject
# a dead file and a smuggled axiom)
# 5. reproducibility (--full) — extract.sh regenerates gen/ byte-identical
set -uo pipefail
HERE="$(cd "$(dirname "$0")" && pwd)"
REPO="$(cd "$HERE/.." && pwd)"
cd "$REPO"
FULL="${1:-}"
fail=0
step() { echo; echo "── $1"; }
step "1. hygiene: worktree + heads"
if [ -n "$(git status --porcelain)" ]; then
echo "✗ worktree not clean:"; git status --short; fail=1
else echo "✓ worktree clean"; fi
BR=$(git branch --show-current)
L=$(git rev-parse HEAD); R=$(git ls-remote -q origin "$BR" | cut -f1)
if [ "$L" = "$R" ]; then echo "✓ local == remote ($(git rev-parse --short HEAD))"
else echo "✗ local $L != remote $R"; fail=1; fi
step "2. honesty: sorry/admit/axiom placement"
BAD=$(grep -rlnE "sorry|admit" verification/Proofs/*.lean 2>/dev/null || true)
if [ -n "$BAD" ]; then echo "✗ sorry/admit in Proofs/: $BAD"; fail=1
else echo "✓ Proofs/ free of sorry/admit"; fi
# Tripwire only: column-0 declarations. The REAL gate is check.sh Phase 3
# (the #print-axioms cone audit), which catches any smuggled axiom wherever
# it hides — this grep just fails faster on the obvious case.
AX=$(grep -rlE "^axiom " verification/Proofs/*.lean 2>/dev/null || true)
if [ -n "$AX" ]; then echo "✗ axiom declared under Proofs/: $AX (H4: axioms live in gen/*External only)"; fail=1
else echo "✓ no axiom declarations under Proofs/"; fi
step "3. the claim: check.sh"
if verification/check.sh > /tmp/drill-check.out 2>&1; then
tail -3 /tmp/drill-check.out | sed 's/^/ /'
echo "✓ check.sh green"
else echo "✗ check.sh FAILED:"; tail -12 /tmp/drill-check.out | sed 's/^/ /'; fail=1; fi
step "4. the gates: check-selftest.sh"
if verification/check-selftest.sh > /tmp/drill-selftest.out 2>&1; then
grep -E "attack" /tmp/drill-selftest.out | sed 's/^/ /'
echo "✓ self-test green (both gates reject their attacks)"
else echo "✗ SELF-TEST FAILED:"; tail -8 /tmp/drill-selftest.out | sed 's/^/ /'; fail=1; fi
if [ "$FULL" = "--full" ]; then
step "5. reproducibility: extract.sh regen byte-identity"
if verification/extract.sh > /tmp/drill-extract.out 2>&1 \
&& [ -z "$(git status --porcelain verification/gen/)" ]; then
echo "✓ regenerated gen/ byte-identical to committed"
else
echo "✗ regen diverged or failed:"; git status --short verification/gen/ | sed 's/^/ /'
git checkout -q -- verification/gen/ 2>/dev/null || true; fail=1
fi
fi
echo
if [ "$fail" = 0 ]; then
echo "DRILL GREEN — the mechanical battery holds. Remaining human/model duty:"
echo "fidelity review of any NEW spec vs its extracted + upstream ground truth."
exit 0
else
echo "DRILL RED — at least one mechanical check failed. Fix before any claim."
exit 1
fi