Phase 13.5: Deploy verified partial-archive control-plane patch (cleanup-partial-remediation-archive + active remediation image state validation)
This commit is contained in:
parent
3e65c36cce
commit
ce58a067ee
1 changed files with 173 additions and 9 deletions
|
|
@ -276,7 +276,9 @@ declare -A ARCHIVE_SUB=( [recovery]="recovery" [remediation]="candidates" )
|
|||
# aus Build-Session (41e357a1..., aktuell im Store fehlend).
|
||||
RECOVERY_ARCHIVE_ID="" # zur Laufzeit aus State gesetzt (load_recovery_state)
|
||||
# Remediation-Archiv-Session-ID: kurze ID der Build-Session-Remendation (41e357a1...).
|
||||
REMEDIATION_ARCHIVE_ID="41e357a12b90"
|
||||
# (RAIN Hotfix) Statische REMEDIATION_ARCHIVE_ID ENTFERNT — historische 41e357a12b90
|
||||
# darf keine aktive Archive-Identity sein. Aktive ID ausschliesslich aus der aktuellen,
|
||||
# inspectable Build-Session ableiten (remediation_session / remediation_full_image_id).
|
||||
# Remediation-Archiv-Referenz (aus Build-Session falls vorhanden, sonst leer):
|
||||
# wird zur Laufzeit per remediation_full_image_id() aufgeloest.
|
||||
# Pin-Referenz-Ziel (Schicht A): exakt diese Image-ID muss der Pin-Container referenzieren.
|
||||
|
|
@ -1453,11 +1455,18 @@ rollback_runner_patch() {
|
|||
# KEIN echter Build/Recreate durch Rain. Red Queen fuehrt nach Freigabe aus.
|
||||
# Helfer: Read-only-Session-Bestand ("Build-Session vorhanden?") — muss zusaetzlich
|
||||
# FULL_IMAGE_ID tragen, da Verify/Recreate nur der gespeicherten Image-ID vertrauen.
|
||||
remediation_session() { # 0 wenn giltige Build-Session mit FULL_IMAGE_ID vorhanden
|
||||
remediation_session() { # 0 NUR wenn AKTUELL erfolgreicher Build-State mit inspectable Image existiert
|
||||
# (RAIN Hotfix §9/§10) Eine historische/stale FULL_IMAGE_ID darf KEINE aktive Identity
|
||||
# sein. Nur wenn das referenzierte Image im Docker-Store tatsaechlich inspectable ist,
|
||||
# ist die Session "aktiv und aktuell". Sonst -> NO ACTIVE REMEDIATION IMAGE STATE.
|
||||
[ -f "$REMEDIATION_SESSION_META" ] || return 1
|
||||
grep -q '^FULL_IMAGE_ID=sha256:[a-f0-9]\{64\}$' "$REMEDIATION_SESSION_META" || return 1
|
||||
[ "$(stat -c '%F' "$REMEDIATION_SESSION_META")" = "regular file" ] || return 1
|
||||
[ -L "$REMEDIATION_SESSION_META" ] && return 1
|
||||
local rid
|
||||
rid="$(grep '^FULL_IMAGE_ID=' "$REMEDIATION_SESSION_META" | cut -d= -f2)"
|
||||
# NO ACTIVE fallback: historische ID ist nur Evidence. Image muss inspectable sein.
|
||||
docker image inspect "$rid" >/dev/null 2>&1 || return 1
|
||||
return 0
|
||||
}
|
||||
remediation_full_image_id() { # FULL_IMAGE_ID aus Session (echo) — nur wenn rem_remediation_session OK
|
||||
|
|
@ -2390,12 +2399,25 @@ cleanup_partial_remediation_staging() {
|
|||
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"
|
||||
# C) VALID-Archive-Semantik (RAIN Hotfix §4): NICHT nackte Directory-Existence.
|
||||
# VALID -> strikt DENY (gueltiges Archive blockiert Staging-Cleanup).
|
||||
# PARTIAL -> erst sanktionierten cleanup-partial-remediation-archive ausfuehren,
|
||||
# dann Retry (Lifecycle-getrennt, bevorzugte Variante).
|
||||
# NO -> kein Blocker, Staging-Cleanup faehrt fort.
|
||||
# INVALID/UNKNOWN -> FAIL CLOSED.
|
||||
local cls
|
||||
cls="$(remediation_archive_classification)"
|
||||
case "$cls" in
|
||||
VALID) die "cleanup: VALID Remediation Archive existiert — Cleanup strikt DENY (FAIL CLOSED)" ;;
|
||||
PARTIAL)
|
||||
echo " C) PARTIAL_ARCHIVE_PRESENT=YES"
|
||||
echo " PARTIAL_ARCHIVE_CLASSIFICATION=SAFE_ORPHAN"
|
||||
die "cleanup: PARTIAL Remediation Archive vorhanden — zuerst cleanup-partial-remediation-archive, dann Retry (Lifecycle-getrennt)" ;;
|
||||
INVALID) die "cleanup: Archive-Zustand INVALID — FAIL CLOSED, kein automatischer Umgang" ;;
|
||||
UNKNOWN) die "cleanup: Archive-Zustand UNKNOWN — FAIL CLOSED, kein automatischer Umgang" ;;
|
||||
NO) echo " C) Remediation Archive = NO (kein VALID-Archive-Blocker)" ;;
|
||||
*) die "cleanup: ungueltige Archive-Klassifikation (FAIL CLOSED)" ;;
|
||||
esac
|
||||
# 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)"
|
||||
|
|
@ -2457,6 +2479,147 @@ cleanup_partial_remediation_staging() {
|
|||
echo " Retry bereit: build-runner-remediation wird neues Staging materialisieren."
|
||||
}
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# cleanup-partial-remediation-archive (Phase 13.5 · RAIN Hotfix)
|
||||
# Kontrollierter Cleanup eines NACHWEISLICH unvollstaendigen / verwaisten
|
||||
# Remediation-Archive-Ordners. KEINE freie Pfadangabe, KEINE freie Session.
|
||||
# Zielidentitaet vollstaendig aus kontrolliertem State / Build-Session abgeleitet.
|
||||
# Sicher entfernbar NUR klar klassifizierbare PARTIAL-Orphans. Valid/Invalid/
|
||||
# Unknown/aktive Zustände -> FAIL CLOSED.
|
||||
# =============================================================================
|
||||
# --- Archive-Zustands-Klassifikation (Mission §2) ---
|
||||
# A) NO_ARCHIVE : kein Archive-Ziel vorhanden.
|
||||
# B) PARTIAL_ARCHIVE : Verzeichnis vorhanden, aber mind. ein Pflichtartefakt fehlt
|
||||
# oder ist unvollstaendig (z.B. image.tar fehlt/leer).
|
||||
# C) VALID_ARCHIVE : alle Pflichtartefakte da UND konsistent gebunden UND verify PASS.
|
||||
# D) INVALID_ARCHIVE : vollstaendig erscheinend, aber SHA/Metadata/Binding falsch.
|
||||
# E) UNKNOWN_ARCHIVE_STATE : nicht sicher klassifizierbar.
|
||||
# Fail-closed: VALID blockiert Cleanup; PARTIAL separat bereinigbar; INVALID/UNKNOWN FAIL.
|
||||
remediation_archive_classification() { # echo: NO|PARTIAL|VALID|INVALID|UNKNOWN
|
||||
local sdir base img meta manifest runtime
|
||||
sdir="$(role_arch_dir remediation)" # = $ARCHIVE_ROOT/candidates
|
||||
local sid
|
||||
if remediation_session; then
|
||||
local ridsess; ridsess="$(remediation_full_image_id)"
|
||||
sid="${ridsess#sha256:}"; sid="${sid:0:12}"
|
||||
else
|
||||
sid=""
|
||||
fi
|
||||
echo " REMEDIATION_ARCHIVE_BASE=$sdir" >&2
|
||||
[ -d "$sdir" ] || { echo "NO"; return; }
|
||||
if [ -n "$sid" ]; then
|
||||
base="$sdir/$sid"
|
||||
else
|
||||
local found="" cnt=0
|
||||
for d in "$sdir"/*/; do
|
||||
[ -d "$d" ] || continue
|
||||
cnt=$((cnt+1)); found="${d%/}"; found="${found##*/}"
|
||||
done
|
||||
if [ "$cnt" = "0" ]; then echo "NO"; return; fi
|
||||
base="$sdir/$found"
|
||||
fi
|
||||
[ -d "$base" ] || { echo "NO"; return; }
|
||||
img="$base/image.tar"; meta="$base/session.meta"; manifest="$base/app.manifest"; runtime="$base/runtime-config.txt"
|
||||
# --- VALID-Pruefung (Mission §3) ---
|
||||
local ok=1
|
||||
[ -f "$img" ] && [ ! -L "$img" ] && [ -s "$img" ] || ok=0
|
||||
[ -f "$meta" ] && [ ! -L "$meta" ] || ok=0
|
||||
[ -f "$manifest" ] && [ ! -L "$manifest" ] || ok=0
|
||||
[ -f "$runtime" ] && [ ! -L "$runtime" ] || ok=0
|
||||
if [ "$ok" = "1" ]; then
|
||||
local want got
|
||||
want="$(awk -F'=' '$1=="ARCHIVE_SHA256"{print $2}' "$meta" 2>/dev/null)"
|
||||
got="$(sha256sum "$img" 2>/dev/null | awk '{print $1}')"
|
||||
if [ -n "$want" ] && [[ "$want" =~ ^[a-f0-9]{64}$ ]] && [ "$got" = "$want" ]; then
|
||||
local role
|
||||
role=remediation
|
||||
if ( verify_archive remediation ) >/dev/null 2>&1; then echo "VALID"; return; fi
|
||||
echo "INVALID"; return
|
||||
fi
|
||||
echo "INVALID"; return
|
||||
fi
|
||||
# --- PARTIAL vs UNKNOWN (RAIN Hotfix: fail-closed-Semantik) ---
|
||||
# PARTIAL nur wenn klar unvollstaendig/orphan: image.tar fehlt oder ist leer.
|
||||
# (NICHT bei blosser Anomalie — Symlink/widerspruechliche Metadata ist UNKNOWN.)
|
||||
if [ ! -f "$img" ] || [ ! -s "$img" ]; then
|
||||
echo "PARTIAL"; return
|
||||
fi
|
||||
# Sonst: image.tar vorhanden+valide, aber Metadata/Manifest/Runtime unvollstaendig
|
||||
# oder widerspruechlich -> nicht sicher klassifizierbar -> UNKNOWN (fail closed).
|
||||
echo "UNKNOWN"; return
|
||||
}
|
||||
|
||||
# cleanup-partial-remediation-archive — dry-run + real (Mission §5/§6/§7)
|
||||
cleanup_partial_remediation_archive() {
|
||||
expect_zero "$@"
|
||||
echo "=== CLEANUP-PARTIAL-REMEDIATION-ARCHIVE ($RUN_MODE) ==="
|
||||
local sdir sid base
|
||||
sdir="$(role_arch_dir remediation)" # = $ARCHIVE_ROOT/candidates
|
||||
if remediation_session; then
|
||||
local ridsess; ridsess="$(remediation_full_image_id)"
|
||||
sid="${ridsess#sha256:}"; sid="${sid:0:12}"
|
||||
else
|
||||
sid=""
|
||||
fi
|
||||
if [ -n "$sid" ]; then
|
||||
base="$sdir/$sid"
|
||||
else
|
||||
local found="" cnt=0
|
||||
for d in "$sdir"/*/; do
|
||||
[ -d "$d" ] || continue
|
||||
cnt=$((cnt+1)); found="${d%/}"; found="${found##*/}"
|
||||
done
|
||||
if [ "$cnt" = "0" ]; then die "cleanup-partial-remediation-archive: kein Archive-Ordner (FAIL CLOSED)"; fi
|
||||
if [ "$cnt" != "1" ]; then die "cleanup-partial-remediation-archive: mehrere Candidate-Ordner — Ziel nicht eindeutig (FAIL CLOSED)"; fi
|
||||
sid="$found"; base="$sdir/$sid"
|
||||
fi
|
||||
echo " TARGET=$base"
|
||||
# --- SAFETY GATES (Mission §6) ---
|
||||
[ "$sdir" = "$ARCHIVE_ROOT/candidates" ] || die "cleanup-partial: Root != $ARCHIVE_ROOT/candidates (FAIL CLOSED)"
|
||||
[[ "$sid" =~ ^[a-f0-9]{12}$ ]] || die "cleanup-partial: Ordnername ungueltig '$sid' (FAIL CLOSED)"
|
||||
[ -e "$base" ] || { echo " PARTIAL_ARCHIVE=NO (kein Ziel)"; echo "DRY_RUN_PASS: nichts zu entfernen."; exit 0; }
|
||||
[ ! -L "$base" ] || die "cleanup-partial: Ziel ist Symlink (FAIL CLOSED)"
|
||||
if mountpoint -q "$base" 2>/dev/null; then die "cleanup-partial: Ziel ist Mountpoint (FAIL CLOSED)"; fi
|
||||
if mountpoint -q "$sdir" 2>/dev/null; then die "cleanup-partial: Parent ist Mountpoint (FAIL CLOSED)"; fi
|
||||
if grep -qE " $base( |$)" /proc/mounts 2>/dev/null; then die "cleanup-partial: Ziel ist Bind/Volume Mount (FAIL CLOSED)"; fi
|
||||
if ps aux 2>/dev/null | grep -E "docker save|docker build|docker tag" | grep -v grep | grep -q "$sdir"; then
|
||||
die "cleanup-partial: Build-/Save-Prozess aktiv (FAIL CLOSED)"
|
||||
fi
|
||||
if docker ps --format '{{.Names}}' 2>/dev/null | grep -qE "build|remediation"; then
|
||||
die "cleanup-partial: Build-Container aktiv (FAIL CLOSED)"
|
||||
fi
|
||||
# --- KLASSIFIKATION (Mission §2/§7) ---
|
||||
local cls
|
||||
cls="$(remediation_archive_classification)"
|
||||
echo " CLASSIFICATION=$cls"
|
||||
case "$cls" in
|
||||
VALID) die "cleanup-partial: Archive ist VALID/verify PASS — Cleanup strikt DENY (FAIL CLOSED)" ;;
|
||||
INVALID) die "cleanup-partial: Archive INVALID (voll, aber SHA/Metadata/Binding falsch) — FAIL CLOSED, kein Cleanup" ;;
|
||||
UNKNOWN) die "cleanup-partial: Archive-Zustand UNKNOWN — FAIL CLOSED, kein Cleanup" ;;
|
||||
PARTIAL) : ;;
|
||||
NO) echo " PARTIAL_ARCHIVE=NO"; echo "DRY_RUN_PASS: kein partielles Archive."; exit 0 ;;
|
||||
*) die "cleanup-partial: ungueltige Klassifikation (FAIL CLOSED)" ;;
|
||||
esac
|
||||
echo " PARTIAL_ARCHIVE=CONFIRMED"
|
||||
echo " IMAGE_TAR=$( [ -f "$base/image.tar" ] && [ -s "$base/image.tar" ] && echo PRESENT || echo ABSENT )"
|
||||
echo " ACTIVE_REMEDIATION_IMAGE=$( if remediation_session && docker image inspect "$(remediation_full_image_id)" >/dev/null 2>&1; then echo PRESENT; else echo NONE; fi )"
|
||||
echo " ACTIVE_PIN=$( docker ps -a --format '{{.Names}}' 2>/dev/null | grep -Eq 'rq-historical-pin-phase13-5-runner-remediation' && echo PRESENT || echo NONE )"
|
||||
echo " ACTIVE_CONTAINER=$( docker ps --format '{{.Names}}' 2>/dev/null | grep -q 'remediation' && echo PRESENT || echo NONE )"
|
||||
echo " VALID_ARCHIVE=NO"
|
||||
if [ "$RUN_MODE" = "DRY_RUN" ]; then
|
||||
echo " ACTION=WOULD_REMOVE_PARTIAL_REMEDIATION_ARCHIVE"
|
||||
echo "DRY_RUN_PASS: cleanup-partial-remediation-archive wuerde $base entfernen (keine Aktion)."
|
||||
echo " ZERO MUTATION."
|
||||
exit 0
|
||||
fi
|
||||
mode_or_die
|
||||
rm -rf -- "$base" || die "cleanup-partial: Entfernen fehlgeschlagen (FAIL CLOSED)"
|
||||
[ ! -e "$base" ] || die "cleanup-partial: Ziel nach Entfernen noch vorhanden (FAIL CLOSED)"
|
||||
echo "CLEANUP-PARTIAL-REMEDIATION-ARCHIVE OK: $base entfernt"
|
||||
echo " Retry bereit: cleanup-partial-remediation-staging ist nun logisch freigegeben."
|
||||
}
|
||||
|
||||
# restore-recovery-image-archive (DESIGN; realer Restore NICHT in dieser Mission ausfuehren)
|
||||
restore_recovery_dry() { # dry-run
|
||||
expect_zero "$@"
|
||||
|
|
@ -2806,7 +2969,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|cleanup-partial-remediation-staging|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|cleanup-partial-remediation-archive|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
|
||||
|
|
@ -3219,6 +3382,7 @@ case "$SUBCMD" in
|
|||
verify-remediation-archive) verify_archive_cmd remediation "$@" ;;
|
||||
cleanup-partial-recovery-archive) cleanup_partial_recovery_archive "$@" ;;
|
||||
cleanup-partial-remediation-staging) cleanup_partial_remediation_staging "$@" ;;
|
||||
cleanup-partial-remediation-archive) cleanup_partial_remediation_archive "$@" ;;
|
||||
verify-recovery-pin) verify_pin_cmd recovery "$@" ;;
|
||||
verify-remediation-pin) verify_pin_cmd remediation "$@" ;;
|
||||
verify-recovery-ready) verify_ready_cmd recovery "$@" ;;
|
||||
|
|
|
|||
Loading…
Reference in a new issue