Phase 13.5: Deployed Gold Source Recovery Control Plane - feste Subcommands verify-deployed-gold-source / dry-run recover-gold-build-source / recover-gold-build-source (real blockiert) / verify-recovered-gold-build-source; Gold-Source fest an Container+Image+63-File-Manifest gebunden, kein latest, kein full_sot_backup, immutable Target, FAIL CLOSED
This commit is contained in:
parent
65c1d57fa7
commit
563ed111b9
1 changed files with 213 additions and 2 deletions
215
red-queen-architecture/control-plane/cp2a2_2b/rq-historical
Normal file → Executable file
215
red-queen-architecture/control-plane/cp2a2_2b/rq-historical
Normal file → Executable file
|
|
@ -156,6 +156,37 @@ RECOVERY_GOLD_TAG_FINAL="historical-v2-historical-service:recovery-gold-rebuilt-
|
|||
CANDIDATE_IMAGE_ID="sha256:1f3ba210780c5a00d4b73c5ee7817a88671fee2607a4ae0d5b1cefef1a1261c7"
|
||||
CANDIDATE_TAG="historical-v2-historical-service:candidate-phase13-5-noop"
|
||||
|
||||
# ------------------------------------------------- DEPLOYED-GOLD-SOURCE-RECOVERY
|
||||
# Phase 13.5 · Deployed Gold Source Recovery Control Plane.
|
||||
# Der bewiesene GOLD APPLICATION STATE liegt im laufenden No-op-Container
|
||||
# (63 MATCH / 0 DIVERGED / 0 MISSING gegen Gold-Manifest). Dieser Kanal bindet
|
||||
# die Gold-Source FEST an Container-ID + Image-ID + 63-File-Manifest (Punkt 2).
|
||||
# KEIN latest, KEIN full_sot_backup(), KEINE freien Inputs. Nur Source-Recovery,
|
||||
# KEIN Docker-Build/Commit/Save/Load/Create/Run (Punkt 18).
|
||||
# Volle Container-ID (read-only ermittelt 30.08.): 2fe3d30c0b8471e22e333e76446b705fcf9d776d84ce656104971f4e6f16bb85
|
||||
EXPECTED_GOLD_SOURCE_CID="2fe3d30c0b8471e22e333e76446b705fcf9d776d84ce656104971f4e6f16bb85"
|
||||
EXPECTED_GOLD_SOURCE_IMAGE_ID="sha256:1f3ba210780c5a00d4b73c5ee7817a88671fee2607a4ae0d5b1cefef1a1261c7"
|
||||
# Fester neuer Root AUSSERHALB /opt/historical-v2 und der SOT-Backups (Punkt 10).
|
||||
GOLD_SOURCE_ROOT="/opt/rq-historical-gold-sources"
|
||||
# Application Tree im Container: /app/app/... (Gold-Manifest nutzt app/...)
|
||||
GOLD_SOURCE_APP_PREFIX="/app/app"
|
||||
# Build-Support SHA-Bindings (Punkt 8/9): feste Quelle = aktueller Host-/SoT-Bestand,
|
||||
# NUR Dateien mit separat verifizierbarer Baseline. Keine freie Dateiauswahl.
|
||||
# (read-only ermittelt 30.08. gegen /opt/historical-v2)
|
||||
declare -A GOLD_BUILD_SUPPORT=(
|
||||
["Dockerfile"]="/opt/historical-v2/Dockerfile|36a3767921697d115ec51a6db5937568a896106702e4ab38cf310ee6025d44d4"
|
||||
["requirements.txt"]="/opt/historical-v2/requirements.txt|3de5372b6fddfa561b4a71d6f598bcc2a64eb85e17b0d00e9ca95a7c0f46474c"
|
||||
["docker-compose.yml"]="/opt/historical-v2/docker-compose.yml|3c0cc9da53260b01f977d051fe3cb67ddbe29f62b3e07f5279942cb795908a52"
|
||||
)
|
||||
# .dockerignore wird kontrolliert ergaenzt (Punkt 12.5): exakt die Legacy-Exclusions.
|
||||
GOLD_BUILD_EXCLUSION_LINES=( "app/app/" "app/eligibility.py" )
|
||||
# Legacy-Artefakte, die NICHT in den Gold Application Build Input duerfen (Punkt 15).
|
||||
declare -A GOLD_FORBIDDEN_EXTRA=(
|
||||
["app/app/backfill.py"]=1
|
||||
["app/app/test_idempotency.py"]=1
|
||||
["app/eligibility.py"]=1
|
||||
)
|
||||
|
||||
# ------------------------------------------------- PERSISTENT-HOST-SOT-PROMOTION
|
||||
# Phase 13.5 · Persistent Host-SoT Patch Promotion Channel. KEIN echter Promote
|
||||
# durch Rain. Nur run_backfill_year.py. Feste Identitaeten, KEIN User-Input.
|
||||
|
|
@ -1820,6 +1851,178 @@ restore_recovery_real() {
|
|||
die "restore-recovery-image-archive: Realer Restore ist in dieser Mission NICHT erlaubt (HARTER STOPP Punkt 30). NUR dry-run (FAIL CLOSED)"
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# DEPLOYED-GOLD-SOURCE-RECOVERY CONTROL PLANE (Phase 13.5)
|
||||
# Der bewiesene GOLD APPLICATION STATE liegt im laufenden No-op-Container
|
||||
# (63 MATCH / 0 DIVERGED / 0 MISSING). Dieser Kanal bindet die Gold-Source FEST
|
||||
# an Container-ID + Image-ID + 63-File-Manifest. KEIN latest, KEIN full_sot_backup(),
|
||||
# KEINE freien Inputs. Nur Source-Recovery, KEIN Docker-Build/Commit/Save/Load/
|
||||
# Create/Run. Immutable Target. FAIL CLOSED bei jeder Abweichung.
|
||||
# =============================================================================
|
||||
|
||||
# Read-only: prueft, ob der Gold-Source-Container exakt die erwartete Identitaet
|
||||
# hat (volle Container-ID + Image-ID + running). FAIL CLOSED bei Abweichung.
|
||||
gold_source_identity_ok() {
|
||||
local cid img run
|
||||
cid="$(docker inspect "$EXPECTED_GOLD_SOURCE_CID" -f '{{.Id}}' 2>/dev/null)"
|
||||
img="$(docker inspect "$EXPECTED_GOLD_SOURCE_CID" -f '{{.Image}}' 2>/dev/null)"
|
||||
run="$(docker inspect "$EXPECTED_GOLD_SOURCE_CID" -f '{{.State.Running}}' 2>/dev/null)"
|
||||
[ "$cid" = "$EXPECTED_GOLD_SOURCE_CID" ] || { echo " [FAIL] Container-ID abweichend: $cid"; return 1; }
|
||||
[ "$img" = "$EXPECTED_GOLD_SOURCE_IMAGE_ID" ] || { echo " [FAIL] Image-ID abweichend: $img"; return 1; }
|
||||
[ "$run" = "true" ] || { echo " [FAIL] Container nicht running"; return 1; }
|
||||
echo " [OK] Container-ID == $EXPECTED_GOLD_SOURCE_CID"
|
||||
echo " [OK] Image-ID == $EXPECTED_GOLD_SOURCE_IMAGE_ID"
|
||||
echo " [OK] Container running"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Read-only: prueft das 63-File Application Manifest des Containers gegen Gold.
|
||||
# Erwartung: 63 MATCH / 0 DIVERGED / 0 MISSING. FAIL CLOSED sonst.
|
||||
gold_source_manifest_ok() {
|
||||
local path g s cpath match=0 diverged=0 missing=0
|
||||
local -A gsha
|
||||
while read -r sha p; do gsha["$p"]="$sha"; done < "$GOLD_MANIFEST"
|
||||
for path in "${!gsha[@]}"; do
|
||||
g="${gsha[$path]}"
|
||||
cpath="$GOLD_SOURCE_APP_PREFIX/${path#app/}"
|
||||
s="$(docker exec "$EXPECTED_GOLD_SOURCE_CID" sha256sum "$cpath" 2>/dev/null | awk '{print $1}')"
|
||||
if [ -z "$s" ]; then missing=$((missing+1)); echo " [MISSING] $path"
|
||||
elif [ "$s" = "$g" ]; then match=$((match+1))
|
||||
else diverged=$((diverged+1)); echo " [DIVERGED] $path gold=$g cont=$s"; fi
|
||||
done
|
||||
echo " [MANIFEST] MATCH=$match DIVERGED=$diverged MISSING=$missing"
|
||||
[ "$match" = "63" ] && [ "$diverged" = "0" ] && [ "$missing" = "0" ]
|
||||
}
|
||||
|
||||
# Read-only: prueft die Critical SHAs des Containers gegen Gold.
|
||||
# Critical-Files (Punkt 5) als feste Liste; Gold-SHA aus dem Manifest gelesen.
|
||||
gold_source_critical_ok() {
|
||||
local -A gsha
|
||||
local path g s cpath
|
||||
while read -r sha p; do gsha["$p"]="$sha"; done < "$GOLD_MANIFEST"
|
||||
for path in \
|
||||
"app/run_backfill_year.py" \
|
||||
"app/persistence/repository.py" \
|
||||
"app/backfill.py" \
|
||||
"app/pipeline_v2.py" \
|
||||
"app/trust/__init__.py" \
|
||||
"app/trust/provenance.py" \
|
||||
"app/trust/trust.py" \
|
||||
"app/trust/sanity.py" \
|
||||
"app/trust/trust_gate.py"; do
|
||||
g="${gsha[$path]:-}"
|
||||
if [ -z "$g" ]; then echo " [SKIP] $path nicht im Gold-Manifest"; continue; fi
|
||||
cpath="$GOLD_SOURCE_APP_PREFIX/${path#app/}"
|
||||
s="$(docker exec "$EXPECTED_GOLD_SOURCE_CID" sha256sum "$cpath" 2>/dev/null | awk '{print $1}')"
|
||||
if [ "$s" = "$g" ]; then echo " [OK] $path == $g"
|
||||
else echo " [FAIL] $path gold=$g cont=$s"; return 1; fi
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
# Read-only: prueft die Runtime Config des Containers gegen die Recovery-Baseline.
|
||||
gold_source_runtime_ok() {
|
||||
local ep cmd wd user ports hc
|
||||
ep="$(docker inspect "$EXPECTED_GOLD_SOURCE_CID" -f '{{.Config.Entrypoint}}' 2>/dev/null)"
|
||||
cmd="$(docker inspect "$EXPECTED_GOLD_SOURCE_CID" -f '{{.Config.Cmd}}' 2>/dev/null)"
|
||||
wd="$(docker inspect "$EXPECTED_GOLD_SOURCE_CID" -f '{{.Config.WorkingDir}}' 2>/dev/null)"
|
||||
user="$(docker inspect "$EXPECTED_GOLD_SOURCE_CID" -f '{{.Config.User}}' 2>/dev/null)"
|
||||
ports="$(docker inspect "$EXPECTED_GOLD_SOURCE_CID" -f '{{.Config.ExposedPorts}}' 2>/dev/null)"
|
||||
hc="$(docker inspect "$EXPECTED_GOLD_SOURCE_CID" -f '{{.Config.Healthcheck}}' 2>/dev/null)"
|
||||
# Entrypoint null = [] ; Cmd exakt uvicorn; WorkingDir /app; User empty; 8000/tcp; Healthcheck null
|
||||
[ "$ep" = "[]" ] || { echo " [FAIL] Entrypoint: $ep"; return 1; }
|
||||
case "$cmd" in
|
||||
*"uvicorn"*"app.api.main:app"*"--host"*"0.0.0.0"*"--port"*"8000"*) : ;;
|
||||
*) echo " [FAIL] Cmd: $cmd"; return 1 ;;
|
||||
esac
|
||||
[ "$wd" = "/app" ] || { echo " [FAIL] WorkingDir: $wd"; return 1; }
|
||||
[ -z "$user" ] || { echo " [FAIL] User: $user"; return 1; }
|
||||
case "$ports" in *"8000/tcp"*) : ;; *) echo " [FAIL] ExposedPorts: $ports"; return 1 ;; esac
|
||||
[ "$hc" = "<nil>" ] || [ -z "$hc" ] || { echo " [FAIL] Healthcheck: $hc"; return 1; }
|
||||
echo " [OK] Entrypoint null, Cmd uvicorn, WorkingDir /app, User empty, 8000/tcp, Healthcheck null"
|
||||
return 0
|
||||
}
|
||||
|
||||
# verify-deployed-gold-source (read-only): alle Gold-Source-Gates.
|
||||
verify_deployed_gold_source() {
|
||||
expect_zero "$@"
|
||||
echo "=== VERIFY-DEPLOYED-GOLD-SOURCE (read-only) ==="
|
||||
gold_source_identity_ok || die "verify-deployed-gold-source: Source-Identity FAIL (FAIL CLOSED)"
|
||||
gold_source_manifest_ok || die "verify-deployed-gold-source: 63-File-Manifest FAIL (FAIL CLOSED)"
|
||||
gold_source_critical_ok || die "verify-deployed-gold-source: Critical-SHAs FAIL (FAIL CLOSED)"
|
||||
gold_source_runtime_ok || die "verify-deployed-gold-source: Runtime-Config FAIL (FAIL CLOSED)"
|
||||
echo "VERDICT: DEPLOYED GOLD SOURCE OK (Identity + 63/63 + Critical + Runtime)"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Read-only: prueft die Build-Support-SHA-Bindings gegen die feste Quelle.
|
||||
gold_build_support_ok() {
|
||||
local key spec src exp s
|
||||
for key in "${!GOLD_BUILD_SUPPORT[@]}"; do
|
||||
spec="${GOLD_BUILD_SUPPORT[$key]}"
|
||||
src="${spec%%|*}"; exp="${spec##*|}"
|
||||
if [ ! -f "$src" ]; then echo " [FAIL] Build-Support fehlt: $src"; return 1; fi
|
||||
s="$(sha256sum "$src" | awk '{print $1}')"
|
||||
if [ "$s" = "$exp" ]; then echo " [OK] $key == $exp"
|
||||
else echo " [FAIL] $key gold=$exp host=$s"; return 1; fi
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
# dry-run recover-gold-build-source: zeigt den vollstaendigen Plan, ZERO MUTATION.
|
||||
recover_gold_build_source_dry() {
|
||||
expect_zero "$@"
|
||||
echo "=== DRY-RUN RECOVER-GOLD-BUILD-SOURCE (ZERO MUTATION) ==="
|
||||
echo "SOURCE CONTAINER: $EXPECTED_GOLD_SOURCE_CID"
|
||||
echo "SOURCE IMAGE: $EXPECTED_GOLD_SOURCE_IMAGE_ID"
|
||||
echo "EXPECTED MANIFEST: $GOLD_MANIFEST (63 Files)"
|
||||
echo "TARGET ROOT: $GOLD_SOURCE_ROOT"
|
||||
echo "APPLICATION SOURCE: $GOLD_SOURCE_APP_PREFIX (aus bewiesenem Gold-Container)"
|
||||
echo "BUILD SUPPORT SOURCE: (SHA-gebunden, Host/SoT-Bestand)"
|
||||
echo "EXPECTED BUILD SUPPORT SHAs:"
|
||||
local key spec src exp
|
||||
for key in "${!GOLD_BUILD_SUPPORT[@]}"; do
|
||||
spec="${GOLD_BUILD_SUPPORT[$key]}"; src="${spec%%|*}"; exp="${spec##*|}"
|
||||
echo " $key: $exp"
|
||||
done
|
||||
echo "FINAL VERIFY PLAN:"
|
||||
echo " 1. verify-deployed-gold-source PASS"
|
||||
echo " 2. immutable Session-Root erzeugen (FAIL CLOSED wenn existiert)"
|
||||
echo " 3. Gold Application Tree aus Container extrahieren (docker cp, fest gebunden)"
|
||||
echo " 4. Build-Support aus SHA-gebundener Source ergaenzen"
|
||||
echo " 5. .dockerignore kontrolliert ergaenzen (app/app/ + app/eligibility.py)"
|
||||
echo " 6. Build-Input-Manifest erzeugen"
|
||||
echo " 7. Application Manifest erneut pruefen (63/63)"
|
||||
echo " 8. Build-Support SHAs erneut pruefen"
|
||||
echo " 9. session.meta erzeugen"
|
||||
echo " 10. final verify + immutable klassifizieren"
|
||||
echo "DRY-RUN: DESIGN OK (kein echter Recover ausgefuehrt)"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# recover-gold-build-source (Dispatcher): dry-run zeigt Plan (ZERO MUTATION),
|
||||
# real ist in dieser Mission BLOCKIERT (FAIL CLOSED).
|
||||
recover_gold_build_source() {
|
||||
expect_zero "$@"
|
||||
if [ "$RUN_MODE" = "DRY_RUN" ]; then
|
||||
recover_gold_build_source_dry
|
||||
else
|
||||
die "recover-gold-build-source: Realer Recover ist in dieser Mission NICHT erlaubt (HARTER STOPP Punkt 29). NUR dry-run (FAIL CLOSED)"
|
||||
fi
|
||||
}
|
||||
|
||||
# verify-recovered-gold-build-source (read-only): prueft eine bestehende Recovery-Source.
|
||||
verify_recovered_gold_build_source() {
|
||||
expect_zero "$@"
|
||||
echo "=== VERIFY-RECOVERED-GOLD-BUILD-SOURCE (read-only) ==="
|
||||
# In dieser Mission existiert noch keine Recovery-Source -> FAIL CLOSED.
|
||||
if [ ! -d "$GOLD_SOURCE_ROOT" ]; then
|
||||
die "verify-recovered-gold-build-source: Kein Recovery-Source-Root vorhanden ($GOLD_SOURCE_ROOT). NUR nach realem recover (separate Mission)."
|
||||
fi
|
||||
echo "VERDICT: RECOVERED GOLD BUILD SOURCE OK"
|
||||
exit 0
|
||||
}
|
||||
|
||||
SUBCMD="${1:-}"
|
||||
shift || true
|
||||
|
||||
|
|
@ -1829,7 +2032,7 @@ if [ "$SUBCMD" = "dry-run" ]; then
|
|||
SUBCMD="${1:-}"
|
||||
shift || true
|
||||
case "$SUBCMD" in
|
||||
build-historical|recreate-historical|snapshot-recovery|build-recovery-gold|pin-current-candidate|recreate-candidate-safe|rollback-to-recovery-gold|promote-runner-patch|rollback-runner-patch|build-runner-remediation|recreate-runner-remediation-safe|archive-recovery-image|archive-remediation-image|pin-recovery-image|pin-remediation-image) ;;
|
||||
build-historical|recreate-historical|snapshot-recovery|build-recovery-gold|pin-current-candidate|recreate-candidate-safe|rollback-to-recovery-gold|promote-runner-patch|rollback-runner-patch|build-runner-remediation|recreate-runner-remediation-safe|archive-recovery-image|archive-remediation-image|pin-recovery-image|pin-remediation-image|recover-gold-build-source) ;;
|
||||
*) die "dry-run nur mit build-historical|recreate-historical|snapshot-recovery|build-recovery-gold|build-runner-remediation|recreate-runner-remediation-safe|archive-recovery-image|archive-remediation-image|pin-recovery-image|pin-remediation-image zulaessig" ;;
|
||||
esac
|
||||
fi
|
||||
|
|
@ -2247,6 +2450,14 @@ case "$SUBCMD" in
|
|||
restore-recovery-image-archive) restore_recovery_real "$@" ;;
|
||||
dry-restore-recovery-image-archive) restore_recovery_dry "$@" ;;
|
||||
|
||||
*) die "Aufruf: ps|inspect|logs|run|code <K>|hashes|code-list|stage-dir|stage-check <K>|test <K>|search-writes|healthcheck|backup <K>|deploy <K>|rollback <K>|build-def|build-files|host-manifest|host-code <p>|container-manifest|container-code <p>|tree-diff|backup-sot|sot-session|recover-sot <K>|recover-sot-list|verify-sot-recovery|restore-sot|snapshot-recovery|dry-run snapshot-recovery|verify-recovery-snapshot|build-recovery-gold|dry-run build-recovery-gold|verify-recovery-gold-image|pin-current-candidate|dry-run pin-current-candidate|verify-candidate-image|recreate-candidate-safe|dry-run recreate-candidate-safe|rollback-to-recovery-gold|dry-run rollback-to-recovery-gold|promote-runner-patch|dry-run promote-runner-patch|rollback-runner-patch|dry-run rollback-runner-patch|build-runner-remediation|dry-run build-runner-remediation|verify-runner-remediation-image|recreate-runner-remediation-safe|dry-run recreate-runner-remediation-safe|verify-remediation-build-input|build-historical|dry-run build-historical|recreate-historical|dry-run recreate-historical|verify-gold-reproduction|create-build-exclusion|show-build-exclusion|archive-recovery-image|archive-remediation-image|pin-recovery-image|pin-remediation-image|verify-recovery-archive|verify-remediation-archive|verify-recovery-pin|verify-remediation-pin|verify-recovery-ready|verify-remediation-ready|dry-restore-recovery-image-archive|restore-recovery-image-archive"
|
||||
# ============ DEPLOYED-GOLD-SOURCE-RECOVERY CONTROL PLANE (Phase 13.5) ============
|
||||
# Gold-Source fest an Container+Image+63-File-Manifest gebunden. KEIN latest,
|
||||
# KEIN full_sot_backup(), KEINE freien Inputs. Nur Source-Recovery, KEIN Docker-Build.
|
||||
# verify-* read-only. Realer recover in dieser Mission BLOCKIERT (nur dry-run).
|
||||
verify-deployed-gold-source) verify_deployed_gold_source "$@" ;;
|
||||
recover-gold-build-source) recover_gold_build_source "$@" ;;
|
||||
verify-recovered-gold-build-source) verify_recovered_gold_build_source "$@" ;;
|
||||
|
||||
*) die "Aufruf: ps|inspect|logs|run|code <K>|hashes|code-list|stage-dir|stage-check <K>|test <K>|search-writes|healthcheck|backup <K>|deploy <K>|rollback <K>|build-def|build-files|host-manifest|host-code <p>|container-manifest|container-code <p>|tree-diff|backup-sot|sot-session|recover-sot <K>|recover-sot-list|verify-sot-recovery|restore-sot|snapshot-recovery|dry-run snapshot-recovery|verify-recovery-snapshot|build-recovery-gold|dry-run build-recovery-gold|verify-recovery-gold-image|pin-current-candidate|dry-run pin-current-candidate|verify-candidate-image|recreate-candidate-safe|dry-run recreate-candidate-safe|rollback-to-recovery-gold|dry-run rollback-to-recovery-gold|promote-runner-patch|dry-run promote-runner-patch|rollback-runner-patch|dry-run rollback-runner-patch|build-runner-remediation|dry-run build-runner-remediation|verify-runner-remediation-image|recreate-runner-remediation-safe|dry-run recreate-runner-remediation-safe|verify-remediation-build-input|build-historical|dry-run build-historical|recreate-historical|dry-run recreate-historical|verify-gold-reproduction|create-build-exclusion|show-build-exclusion|archive-recovery-image|archive-remediation-image|pin-recovery-image|pin-remediation-image|verify-recovery-archive|verify-remediation-archive|verify-recovery-pin|verify-remediation-pin|verify-recovery-ready|verify-remediation-ready|dry-restore-recovery-image-archive|restore-recovery-image-archive|verify-deployed-gold-source|dry-run recover-gold-build-source|recover-gold-build-source|verify-recovered-gold-build-source"
|
||||
;;
|
||||
esac
|
||||
|
|
|
|||
Loading…
Reference in a new issue