From 3e65c36cce79dd2aba51f04b92a085f8c951bf0c Mon Sep 17 00:00:00 2001 From: root Date: Sun, 30 Aug 2026 17:31:47 +0000 Subject: [PATCH] Phase 13.5: Orphan Remediation Staging Cleanup Control-Plane Hotfix (cleanup-partial-remediation-staging) --- .../control-plane/cp2a2_2b/rq-historical | 135 +++++++++++++++++- 1 file changed, 133 insertions(+), 2 deletions(-) diff --git a/red-queen-architecture/control-plane/cp2a2_2b/rq-historical b/red-queen-architecture/control-plane/cp2a2_2b/rq-historical index 2fec557..2ae85c6 100755 --- a/red-queen-architecture/control-plane/cp2a2_2b/rq-historical +++ b/red-queen-architecture/control-plane/cp2a2_2b/rq-historical @@ -2327,6 +2327,136 @@ verify_ready_cmd() { # $1 = role (read-only) exit 0 } +# cleanup-partial-remediation-staging (Phase 13.5 ยท Orphan Remediation Staging Cleanup) +# Kontrollierter Cleanup eines NACHWEISLICH verwaisten Remediation-Staging-Ordners. +# KEINE freie Pfadangabe. Zielidentitaet vollstaendig aus kontrolliertem State +# (Gold-Source-Session) abgeleitet. Fail-closed bei jeder Abweichung. +# Safety-Model (Punkt 3-8): Path Hard Gates, Session Binding an feste autorisierte +# Gold-Source-Session, Orphan-Proof (kein aktiver Image State/Image/Archive/Pin/Prozess/Mount), +# Content-Verify gegen erwartetes Build-Input, Build-Support-Verify, Build-Input-SHA. +# ============================================================================= +cleanup_partial_remediation_staging() { + expect_zero "$@" + echo "=== CLEANUP-PARTIAL-REMEDIATION-STAGING ($RUN_MODE) ===" + # Session Binding: feste autorisierte Gold-Source-Session aus kontrolliertem State + load_remediation_source_state + echo " SOURCE_SESSION=$REMEDIATION_SESSION_ID" + # Punkt 4: Session muss exakt die feste autorisierte Gold-Source-Session sein + [ "$REMEDIATION_SESSION_ID" = "20260830_104127" ] || die "cleanup: Session $REMEDIATION_SESSION_ID != autorisierte 20260830_104127 (FAIL CLOSED)" + local sdir base + sdir="$REMEDIATION_STAGING_ROOT" + base="$REMEDIATION_STAGING_DIR" + echo " STAGING_PATH=$base" + # --- PATH HARD GATES (Punkt 3) --- + # 1. Pfad ist absolut + case "$base" in /*) ;; *) die "cleanup: Pfad nicht absolut $base (FAIL CLOSED)";; esac + # 2. Pfad exakt aus State abgeleitet + [ "$base" = "$REMEDIATION_STAGING_ROOT/$REMEDIATION_SESSION_ID" ] || die "cleanup: Pfad nicht exakt aus State (FAIL CLOSED)" + # 3. Parent exakt Staging-Root + [ "$sdir" = "/opt/rq-historical-remediation-staging" ] || die "cleanup: Parent nicht exakt Staging-Root (FAIL CLOSED)" + # 4. Ziel ist nicht / + [ "$base" != "/" ] || die "cleanup: Ziel ist / (FAIL CLOSED)" + # 5. Ziel ist nicht Parent selbst + [ "$base" != "$sdir" ] || die "cleanup: Ziel ist Parent selbst (FAIL CLOSED)" + # 6. Ziel enthaelt keine .. + case "$base" in *..*) die "cleanup: Ziel enthaelt .. (FAIL CLOSED)";; esac + # 7. Ziel ist kein Symlink + [ ! -L "$base" ] || die "cleanup: Ziel ist Symlink (FAIL CLOSED)" + # 8. Parent ist kein Symlink + [ ! -L "$sdir" ] || die "cleanup: Parent ist Symlink (FAIL CLOSED)" + # 9. Ziel ist Directory + [ -d "$base" ] || die "cleanup: Ziel ist kein Directory (FAIL CLOSED)" + # 10. kein Mountpoint (Ziel + Parent) + if mountpoint -q "$base" 2>/dev/null; then die "cleanup: Ziel ist Mountpoint (FAIL CLOSED)"; fi + if mountpoint -q "$sdir" 2>/dev/null; then die "cleanup: Parent ist Mountpoint (FAIL CLOSED)"; fi + # 11. kein Bind Mount / Docker Volume Mount + if grep -q " $base " /proc/mounts 2>/dev/null; then die "cleanup: Ziel ist Bind/Volume Mount (FAIL CLOSED)"; fi + if grep -q " $sdir " /proc/mounts 2>/dev/null; then die "cleanup: Parent ist Bind/Volume Mount (FAIL CLOSED)"; fi + echo " PATH_GATES=PASS" + # --- ORPHAN CLASSIFICATION (Punkt 5) --- + # A) Kein aktiver Remediation Image State (stale State mit fehlendem Image = kein aktiver) + if remediation_session; then + local sid; sid="$(remediation_full_image_id)" + if docker image inspect "$sid" >/dev/null 2>&1; then + die "cleanup: aktiver Remediation Image State mit existierendem Image $sid (FAIL CLOSED)" + else + echo " A) Remediation Image State stale (Image $sid fehlt) -> kein aktiver State" + fi + else + echo " A) Kein Remediation Image State" + fi + # B) Kein aktuelles Remediation Image aus dieser Build-Session + if docker images --format '{{.Repository}}:{{.Tag}}' | grep -q "candidate-phase13-5-runner-remediation"; then + die "cleanup: Remediation Image existiert (FAIL CLOSED)" + fi + echo " B) Kein Remediation Image" + # C) Kein Remediation Archive + local arch_dir="$ARCHIVE_ROOT/candidates" + if [ -d "$arch_dir" ] && [ -n "$(ls -A "$arch_dir" 2>/dev/null)" ]; then + die "cleanup: Remediation Archive existiert (FAIL CLOSED)" + fi + echo " C) Kein Remediation Archive" + # D) Kein Remediation Pin + if docker ps -a --format '{{.Names}}' | grep -q "rq-historical-pin-phase13-5-runner-remediation"; then + die "cleanup: Remediation Pin existiert (FAIL CLOSED)" + fi + echo " D) Kein Remediation Pin" + # E) Kein laufender Build-/Runner-Prozess + if ps aux | grep -E "docker build|run_backfill" | grep -v grep >/dev/null 2>&1; then + die "cleanup: Build-/Runner-Prozess aktiv (FAIL CLOSED)" + fi + echo " E) Kein Build-/Runner-Prozess" + # F) Kein Docker Build mit diesem Context + if docker ps --format '{{.Names}}' | grep -qE "build|remediation"; then + die "cleanup: Build-Container aktiv (FAIL CLOSED)" + fi + echo " F) Kein Docker Build" + # G/H) historical-service/db nutzen Staging nicht als Mount + for c in historical-service historical-db; do + if docker inspect "$c" --format '{{range .Mounts}}{{.Source}}{{println}}{{end}}' 2>/dev/null | grep -q "$sdir"; then + die "cleanup: $c mountet Staging (FAIL CLOSED)" + fi + done + echo " G/H) Kein Service/DB Mount" + echo " ORPHAN_STAGING=CONFIRMED" + # --- CONTENT-VALIDIERUNG (Punkt 6) --- + # Staging gegen erwartetes Build-Input (Gold-Source + Overlay) + remediation_staging_matches_expected || die "cleanup: Staging != erwartetes Build-Input (FAIL CLOSED)" + # 62+1 Klassifikation + remediation_expected_manifest_ok || die "cleanup: erwartetes Build-Input nicht exakt (FAIL CLOSED)" + echo " CONTENT_VERIFY=PASS (MATCH=$RM_MATCH AUTH=$RM_AUTH UNAUTH=$RM_UNAUTH MISSING=$RM_MISSING EXTRA=$RM_EXTRA)" + # repository.py == Gold + local repo_sha + repo_sha="$(sha256sum "$base/app/persistence/repository.py" | awk '{print $1}')" + [ "$repo_sha" = "8fff892f52a612f464b5be21c66ef7787a47f2d7d049f815ef87837553c2a228" ] || die "cleanup: repository.py != Gold (FAIL CLOSED)" + echo " repository.py=8fff892f (Gold)" + # --- BUILD SUPPORT VALIDIEREN (Punkt 7) --- + local gs="$GOLD_SOURCE_ROOT/$REMEDIATION_SESSION_ID" + for bf in Dockerfile requirements.txt docker-compose.yml .dockerignore; do + local gs_sha st_sha + gs_sha="$(sha256sum "$gs/$bf" 2>/dev/null | awk '{print $1}')" + st_sha="$(sha256sum "$base/$bf" 2>/dev/null | awk '{print $1}')" + [ -n "$gs_sha" ] && [ "$gs_sha" = "$st_sha" ] || die "cleanup: Build-Support $bf != Gold (FAIL CLOSED)" + done + echo " BUILD_SUPPORT_VERIFY=PASS" + # --- EXPECTED BUILD INPUT SHA (Punkt 8) --- + local ebi; ebi="$(remediation_expected_build_input_sha "$base")" + [ "$ebi" = "75555a411b64e0ac0ef0f8502180ee0a331bab93748515d24b5c8d8f255f2d84" ] || die "cleanup: Build-Input-SHA $ebi != erwartet (FAIL CLOSED)" + echo " REMEDIATION_BUILD_INPUT_SHA=$ebi" + # --- ACTION --- + if [ "$RUN_MODE" = "DRY_RUN" ]; then + echo " ACTION=WOULD_REMOVE_STAGING" + echo "DRY_RUN_PASS: cleanup-partial-remediation-staging wuerde $base entfernen (keine Aktion)." + exit 0 + fi + mode_or_die + # MUTATION: kontrollierter Cleanup des verwaisten Staging-Ordners + rm -rf -- "$base" || die "cleanup: Entfernen fehlgeschlagen (FAIL CLOSED)" + [ ! -e "$base" ] || die "cleanup: Ziel nach Entfernen noch vorhanden (FAIL CLOSED)" + echo "CLEANUP-PARTIAL-REMEDIATION-STAGING OK: $base entfernt" + echo " Retry bereit: build-runner-remediation wird neues Staging materialisieren." +} + # restore-recovery-image-archive (DESIGN; realer Restore NICHT in dieser Mission ausfuehren) restore_recovery_dry() { # dry-run expect_zero "$@" @@ -2676,7 +2806,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|cleanup-partial-recovery-archive|recover-gold-build-source) ;; + 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|cleanup-partial-recovery-archive|cleanup-partial-remediation-staging|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|cleanup-partial-recovery-archive zulaessig" ;; esac fi @@ -3088,6 +3218,7 @@ case "$SUBCMD" in verify-recovery-archive) verify_archive_cmd recovery "$@" ;; verify-remediation-archive) verify_archive_cmd remediation "$@" ;; cleanup-partial-recovery-archive) cleanup_partial_recovery_archive "$@" ;; + cleanup-partial-remediation-staging) cleanup_partial_remediation_staging "$@" ;; verify-recovery-pin) verify_pin_cmd recovery "$@" ;; verify-remediation-pin) verify_pin_cmd remediation "$@" ;; verify-recovery-ready) verify_ready_cmd recovery "$@" ;; @@ -3104,6 +3235,6 @@ case "$SUBCMD" in verify-recovered-gold-build-source) verify_recovered_gold_build_source "$@";; wrapper-sha) expect_zero "$@"; sha256sum /usr/local/bin/rq-historical ;; - *) die "Aufruf: ps|inspect|logs|run|code |hashes|code-list|stage-dir|stage-check |test |search-writes|healthcheck|backup |deploy |rollback |build-def|build-files|host-manifest|host-code

|container-manifest|container-code

|tree-diff|backup-sot|sot-session|recover-sot |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|cleanup-partial-recovery-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" + *) die "Aufruf: ps|inspect|logs|run|code |hashes|code-list|stage-dir|stage-check |test |search-writes|healthcheck|backup |deploy |rollback |build-def|build-files|host-manifest|host-code

|container-manifest|container-code

|tree-diff|backup-sot|sot-session|recover-sot |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|cleanup-partial-recovery-archive|cleanup-partial-remediation-staging|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