Phase 13.5: Authorized Remediation Divergence Verify Fix - verify-runner-remediation-image nutzt gemeinsame authorized_gold_delta-Policy (exakt 1 autorisierte Runner-Divergenz, alles andere FAIL CLOSED); Candidate-vs-Host-SoT direkter Vergleich; verify_critical_files runner-Flag
This commit is contained in:
parent
6194868100
commit
8187a4bc1d
1 changed files with 69 additions and 26 deletions
|
|
@ -526,10 +526,14 @@ gen_host_manifest() {
|
|||
}
|
||||
|
||||
# read-only: Critical-Files-SHAs Recovery-Image + laufender Gold-Container + Gold-Baseline (Punkt 11)
|
||||
# $2 (optional) = "runner" -> erlaubt die EINE autorisierte Runner-Divergenz im IMAGE:
|
||||
# run_backfill_year.py image=RUNNER_REMEDIATION_SHA (Container bleibt Gold).
|
||||
# Nur fuer verify-runner-remediation-image; alle anderen Aufrufer bleiben strikt 0-Divergenz.
|
||||
verify_critical_files() {
|
||||
# $1 = Basisverzeichnis mit app/ (kopierter Recovery-Tree) ODER leer -> nur Container+Baseline
|
||||
local tmpc tmpdir k path imgsha csha
|
||||
local base_dir="${1:-}"
|
||||
local allow_runner="${2:-}"
|
||||
local img_shas=""
|
||||
if [ -n "$base_dir" ]; then
|
||||
# Recovery-Image-SHAs aus kopiertem Tree. Der Tree ist prefixlos (docker cp
|
||||
|
|
@ -549,6 +553,12 @@ verify_critical_files() {
|
|||
is=$(echo "$img_shas" | grep -oE "${k}:[a-f0-9]+|${k}:MISSING" | cut -d: -f2)
|
||||
img="$is"
|
||||
fi
|
||||
# Autorisierte Runner-Divergenz: NUR run_backfill_year.py, NUR im Image, NUR auf RUNNER_REMEDIATION_SHA.
|
||||
if [ "$allow_runner" = "runner" ] && [ "$k" = "run_backfill_year.py" ] \
|
||||
&& [ "$img" = "$RUNNER_REMEDIATION_SHA" ] && [ "$csha" = "$gold" ]; then
|
||||
printf ' AUTH %-22s image=%s container=%s gold=%s (autorisierte Runner-Divergenz)\n' "$k" "${img:0:12}" "${csha:0:12}" "${gold:0:12}"
|
||||
continue
|
||||
fi
|
||||
if [ "$csha" = "$gold" ] && { [ -z "$base_dir" ] || [ "$img" = "$gold" ]; }; then
|
||||
printf ' MATCH %-22s container=%s gold=%s\n' "$k" "${csha:0:12}" "${gold:0:12}"
|
||||
else
|
||||
|
|
@ -1106,41 +1116,55 @@ remediation_guards() {
|
|||
echo " [guard O] kein freier Parameter/User-Input:"
|
||||
echo " OK (keine Argumente akzeptiert)"
|
||||
}
|
||||
# Read-only Build-Input-Check: nur app/run_backfill_year.py darf vom Gold-Manifest
|
||||
# divergieren (und zwar exakt auf RUNNER_REMEDIATION_SHA). alles andere -> FAIL.
|
||||
verify_remediation_build_input() {
|
||||
local hm gold d=0 m=0 x=0 mat=0 extra_ok=0 runner_seen=0
|
||||
hm="$(mktemp)"; gen_host_manifest > "$hm"
|
||||
# ---- GEMEINSAME AUTHORIZED-GOLD-DELTA-POLICY (Phase 13.5) ----
|
||||
# Einzige autorisierte Divergenz gegen GOLD_MANIFEST:
|
||||
# app/run_backfill_year.py ALT=RUNNER_GOLD_SHA -> NEU=RUNNER_REMEDIATION_SHA
|
||||
# (exakte Pfad- UND SHA-Bindung; KEINE generische "1 Divergenz ok"-Lockerung).
|
||||
# Setzt globale Zaehler AD_MATCH/AD_AUTH/AD_UNAUTH/AD_MISSING/AD_EXTRA und
|
||||
# AD_RET (ok|fail). fail wenn UNAUTH>0 || MISSING>0 || EXTRA>0.
|
||||
# Wird von verify_remediation_build_input UND verify_runner_remediation_image
|
||||
# verwendet -> EINE Policy, keine unterschiedlichen Policies.
|
||||
authorized_gold_delta() {
|
||||
local new="$1" gold goldrel goldsha nsha nrel found
|
||||
AD_MATCH=0; AD_AUTH=0; AD_UNAUTH=0; AD_MISSING=0; AD_EXTRA=0
|
||||
while read -r goldsha goldrel; do
|
||||
goldrel="${goldrel#./}"; [ -n "$goldrel" ] || continue
|
||||
local nsha
|
||||
nsha="$(awk -v r="$goldrel" '$2==r{print $1}' "$hm")"
|
||||
if [ -z "$nsha" ]; then m=$((m+1))
|
||||
elif [ "$nsha" = "$goldsha" ]; then mat=$((mat+1))
|
||||
nsha="$(awk -v r="$goldrel" '$2==r{print $1}' "$new")"
|
||||
if [ -z "$nsha" ]; then AD_MISSING=$((AD_MISSING+1))
|
||||
elif [ "$nsha" = "$goldsha" ]; then AD_MATCH=$((AD_MATCH+1))
|
||||
else
|
||||
if [ "$goldrel" = "app/run_backfill_year.py" ]; then
|
||||
runner_seen=1
|
||||
if [ "$nsha" = "$RUNNER_REMEDIATION_SHA" ]; then extra_ok=1; else die "BUILD-INPUT FAIL: Runner divergiert auf unerwartete SHA $nsha"; fi
|
||||
if [ "$goldrel" = "app/run_backfill_year.py" ] \
|
||||
&& [ "$goldsha" = "$RUNNER_GOLD_SHA" ] \
|
||||
&& [ "$nsha" = "$RUNNER_REMEDIATION_SHA" ]; then
|
||||
AD_AUTH=$((AD_AUTH+1))
|
||||
else
|
||||
echo " DIVERGED(UNERWARTET) $goldrel"; d=$((d+1))
|
||||
AD_UNAUTH=$((AD_UNAUTH+1))
|
||||
fi
|
||||
fi
|
||||
done < "$GOLD_MANIFEST"
|
||||
while read -r nsha nrel; do
|
||||
nrel="${nrel#./}"
|
||||
local found
|
||||
found="$(awk -v r="$nrel" '$2==r{print $1}' "$GOLD_MANIFEST")"
|
||||
if [ -z "$found" ]; then
|
||||
case "$nrel" in
|
||||
app/app/backfill.py|app/app/test_idempotency.py|app/eligibility.py) ;;
|
||||
*) echo " EXTRA(UNERLAUBT) $nrel"; x=$((x+1)) ;;
|
||||
*) AD_EXTRA=$((AD_EXTRA+1)) ;;
|
||||
esac
|
||||
fi
|
||||
done < "$hm"
|
||||
done < "$new"
|
||||
AD_RET="ok"
|
||||
[ $AD_UNAUTH -eq 0 ] && [ $AD_MISSING -eq 0 ] && [ $AD_EXTRA -eq 0 ] || AD_RET="fail"
|
||||
}
|
||||
# Read-only Build-Input-Check: nur app/run_backfill_year.py darf vom Gold-Manifest
|
||||
# divergieren (und zwar exakt auf RUNNER_REMEDIATION_SHA). alles andere -> FAIL.
|
||||
verify_remediation_build_input() {
|
||||
local hm
|
||||
hm="$(mktemp)"; gen_host_manifest > "$hm"
|
||||
authorized_gold_delta "$hm"
|
||||
rm -f "$hm"
|
||||
echo " Gold $((mat+d+m)): MATCH=$mat DIVERGED=$d MISSING=$m ; unerlaubte EXTRA=$x ; autorisierte Runner-Divergenz=$extra_ok"
|
||||
[ "$runner_seen" = "1" ] && [ "$extra_ok" = "1" ] || die "BUILD-INPUT FAIL: autorisierte Runner-Divergenz fehlt (FAIL CLOSED)"
|
||||
[ $d -eq 0 ] && [ $m -eq 0 ] && [ $x -eq 0 ] || die "BUILD-INPUT FAIL: unerwartete Divergenz (FAIL CLOSED)"
|
||||
echo " Gold $((AD_MATCH+AD_AUTH+AD_UNAUTH+AD_MISSING)): MATCH=$AD_MATCH AUTHORIZED_DIVERGED=$AD_AUTH UNAUTHORIZED_DIVERGED=$AD_UNAUTH MISSING=$AD_MISSING ; unerlaubte EXTRA=$AD_EXTRA"
|
||||
[ "$AD_AUTH" = "1" ] || die "BUILD-INPUT FAIL: autorisierte Runner-Divergenz fehlt (FAIL CLOSED)"
|
||||
[ "$AD_RET" = "ok" ] || die "BUILD-INPUT FAIL: unerwartete Divergenz (FAIL CLOSED)"
|
||||
return 0
|
||||
}
|
||||
# ---- build-runner-remediation (DRY_RUN = kein Build; KEIN Overwrite) ----
|
||||
|
|
@ -1202,13 +1226,32 @@ verify_runner_remediation_image() {
|
|||
tmpf="$(mktemp)"
|
||||
( cd "$tmpdir/appapp" && find . -type f -name '*.py' ! -path '*/__pycache__/*' -printf '%P\n' 2>/dev/null | sort \
|
||||
| while IFS= read -r rel; do [ -f "$rel" ] && sha256sum "$rel"; done | awk '{print $1" app/"$2}' ) > "$tmpf"
|
||||
classify_and_report "$tmpf"; local gret="$G_RET"; rm -f "$tmpf"
|
||||
if [ "$gret" != "ok" ]; then
|
||||
rm -rf "$tmpdir"; die "verify: Image != Gold-Manifest (unzulaessige Divergenz) (FAIL CLOSED)"
|
||||
fi
|
||||
echo " Image vs GOLD (63 MATCH / 0 DIVERGED / 0 MISSING / 0 unerlaubte EXTRA)"
|
||||
# [Gold-Delta] Image vs GOLD_MANIFEST: exakt 1 autorisierte Runner-Divergenz erlaubt.
|
||||
authorized_gold_delta "$tmpf"
|
||||
echo " Image vs GOLD: MATCH=$AD_MATCH AUTHORIZED_DIVERGED=$AD_AUTH UNAUTHORIZED_DIVERGED=$AD_UNAUTH MISSING=$AD_MISSING unerlaubte EXTRA=$AD_EXTRA"
|
||||
[ "$AD_AUTH" = "1" ] || { rm -rf "$tmpdir"; die "verify: Gold-Delta != exakt 1 autorisierte Runner-Divergenz (FAIL CLOSED)"; }
|
||||
[ "$AD_RET" = "ok" ] || { rm -rf "$tmpdir"; die "verify: Image != Gold-Manifest (unzulaessige Divergenz) (FAIL CLOSED)"; }
|
||||
# [Candidate vs Host-SoT] Image-App-Manifest == Host-SoT-App-Manifest (direkter
|
||||
# Manifest-zu-Manifest-Vergleich, OHNE Gold-Bezug; vollstaendig MATCH).
|
||||
# Host-only-Legacy-Dateien (im Image via .dockerignore ausgeschlossen) sind erlaubt.
|
||||
local hmf cmiss cextra
|
||||
hmf="$(mktemp)"; gen_host_manifest > "$hmf"
|
||||
cmiss=0; cextra=0
|
||||
while read -r hsha hrel; do
|
||||
hrel="${hrel#./}"; [ -n "$hrel" ] || continue
|
||||
case "$hrel" in
|
||||
app/app/backfill.py|app/app/test_idempotency.py|app/eligibility.py) continue ;;
|
||||
esac
|
||||
isha="$(awk -v r="$hrel" '$2==r{print $1}' "$tmpf")"
|
||||
if [ -z "$isha" ]; then cmiss=$((cmiss+1))
|
||||
elif [ "$isha" != "$hsha" ]; then cextra=$((cextra+1)); fi
|
||||
done < "$hmf"
|
||||
rm -f "$hmf"
|
||||
echo " Candidate vs Host-SoT: MATCH (direkt) MISSING=$cmiss DIVERGED=$cextra"
|
||||
[ "$cmiss" = "0" ] && [ "$cextra" = "0" ] || { rm -rf "$tmpdir"; die "verify: Candidate != Host-SoT (FAIL CLOSED)"; }
|
||||
rm -f "$tmpf"
|
||||
echo " [Critical-Files] $REMEDIATION_TAG vs gold:"
|
||||
verify_critical_files "$tmpdir/appapp"
|
||||
verify_critical_files "$tmpdir/appapp" runner
|
||||
rm -rf "$tmpdir"
|
||||
echo " [Runner] Image vs Host-SoT persistent:"
|
||||
local ir; ir="$(docker run --rm --entrypoint /bin/sh "$imgid" -c "sha256sum /app/app/run_backfill_year.py 2>/dev/null" | awk '{print $1}')" || ir=""
|
||||
|
|
@ -1230,7 +1273,7 @@ verify_runner_remediation_image() {
|
|||
local srunner; srunner="$(grep '^HOST_SOT_RUNNER_SHA=' "$REMEDIATION_SESSION_META" | cut -d= -f2)"
|
||||
[ "$srunner" = "$RUNNER_REMEDIATION_SHA" ] || die "verify: Session-Runner != erwartet (FAIL CLOSED)"
|
||||
echo " OK ($srunner)"
|
||||
echo "VERDICT: REMEDIATION IMAGE OK (63 MATCH / 0 DIVERGED / 0 MISSING / 0 unerlaubte EXTRA; Runner=Host-SoT; Critical-SHAs + Config PASS)"
|
||||
echo "VERDICT: REMEDIATION IMAGE OK (Candidate==Host-SoT; Gold-Delta exakt 1 autorisierte Runner-Divergenz; Critical-SHAs + Config PASS)"
|
||||
exit 0
|
||||
}
|
||||
# ---- recreate-runner-remediation-safe (NUR historical-service; nur Red Queen) ----
|
||||
|
|
|
|||
Loading…
Reference in a new issue