Phase 13.5 Recovery Control-Plane Rotation: real recover freigegeben, Build-Context-Rotation (kein /opt/historical-v2), Recovery-Identity-Rotation (CURRENT_RECOVERY_ID statt d2db), READY-Gate, wrapper-sha
This commit is contained in:
parent
563ed111b9
commit
8f29924ec6
1 changed files with 246 additions and 26 deletions
|
|
@ -119,8 +119,12 @@ RECOVERY_GOLD_TAG="historical-v2-historical-service:recovery-gold-container-2026
|
||||||
# dediziert getaggtes Recovery-Gold-Image. KEIN latest, KEIN Recreate, KEIN
|
# dediziert getaggtes Recovery-Gold-Image. KEIN latest, KEIN Recreate, KEIN
|
||||||
# Runner, KEINE User-Args/Build-Args. Fester Context + Dockerfile + Tag.
|
# Runner, KEINE User-Args/Build-Args. Fester Context + Dockerfile + Tag.
|
||||||
RECOVERY_REBUILD_TAG="historical-v2-historical-service:recovery-gold-rebuilt-20260829"
|
RECOVERY_REBUILD_TAG="historical-v2-historical-service:recovery-gold-rebuilt-20260829"
|
||||||
RECOVERY_BUILD_CONTEXT="/opt/historical-v2"
|
# Build Context wird NICHT mehr statisch auf /opt/historical-v2 gesetzt. Er wird
|
||||||
RECOVERY_BUILD_DOCKERFILE="/opt/historical-v2/Dockerfile"
|
# zur Laufzeit aus dem kontrollierten Control-Plane-State (RECOVERY_SOURCE_STATE)
|
||||||
|
# gelesen: GOLD_SOURCE_SESSION -> /opt/rq-historical-gold-sources/<SESSION>.
|
||||||
|
# Keine User-Argumente. FAIL CLOSED wenn State fehlt.
|
||||||
|
RECOVERY_BUILD_CONTEXT="" # zur Laufzeit aus State gesetzt
|
||||||
|
RECOVERY_BUILD_DOCKERFILE="" # zur Laufzeit aus State gesetzt
|
||||||
# Critical Files (Punkt 11) mit CONSERVED GOLD SHA (fest, aus laufendem Container)
|
# Critical Files (Punkt 11) mit CONSERVED GOLD SHA (fest, aus laufendem Container)
|
||||||
declare -A CRITICAL_SHA=(
|
declare -A CRITICAL_SHA=(
|
||||||
["run_backfill_year.py"]="70d3abb1a92a871e28cc6fb95b9a26944b55dd8df1b72db80642d6881b7b0f20"
|
["run_backfill_year.py"]="70d3abb1a92a871e28cc6fb95b9a26944b55dd8df1b72db80642d6881b7b0f20"
|
||||||
|
|
@ -148,8 +152,12 @@ declare -A CRITICAL_PATH=(
|
||||||
|
|
||||||
# ------------------------------------------------- FINAL-REPRODUCTION-CONTROL-PLANE
|
# ------------------------------------------------- FINAL-REPRODUCTION-CONTROL-PLANE
|
||||||
# Phase 13.5 · Safe Recreate + Rollback Preparation. KEIN echter Recreate/Rollback
|
# Phase 13.5 · Safe Recreate + Rollback Preparation. KEIN echter Recreate/Rollback
|
||||||
# durch Rain. Recovery-Gold ist ab jetzt IMMUTABLE BASELINE (nur ROLLBACK/RECOVERY-BASE).
|
# Recovery-Gold ist ab jetzt IMMUTABLE BASELINE (nur ROLLBACK/RECOVERY-BASE).
|
||||||
RECOVERY_GOLD_IMAGE_ID="sha256:d2db926dc6f5f7cf2f8e85d271a9b16fcc3cfb54b6557604d3d784f7961a4bc2"
|
# Die aktive Recovery-Image-ID wird NICHT statisch gesetzt, sondern zur Laufzeit
|
||||||
|
# aus dem kontrollierten Control-Plane-State (RECOVERY_IMAGE_STATE) gelesen.
|
||||||
|
# HISTORICAL_RECOVERY_IMAGE_ID (d2db...) bleibt NUR Evidence. FAIL CLOSED wenn
|
||||||
|
# State fehlt (kein freier Input, kein statischer Fallback).
|
||||||
|
RECOVERY_GOLD_IMAGE_ID="" # zur Laufzeit aus State gesetzt
|
||||||
RECOVERY_GOLD_TAG_FINAL="historical-v2-historical-service:recovery-gold-rebuilt-20260829"
|
RECOVERY_GOLD_TAG_FINAL="historical-v2-historical-service:recovery-gold-rebuilt-20260829"
|
||||||
# Candidate Identity Audit (read-only, 29.08.): ausschliesslich ueber latest adressiert.
|
# Candidate Identity Audit (read-only, 29.08.): ausschliesslich ueber latest adressiert.
|
||||||
# 0f6ca29a existiert NICHT mehr (historisch). Aktueller Candidate:
|
# 0f6ca29a existiert NICHT mehr (historisch). Aktueller Candidate:
|
||||||
|
|
@ -187,6 +195,21 @@ declare -A GOLD_FORBIDDEN_EXTRA=(
|
||||||
["app/eligibility.py"]=1
|
["app/eligibility.py"]=1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# ------------------------------------------------- RECOVERY CONTROL-PLANE STATE
|
||||||
|
# Phase 13.5 · Recovery Control-Plane Rotation. Dedizierter, root-owned State
|
||||||
|
# (KEIN latest, KEIN glob-first, KEINE Symlink-Semantik). Enthaelt die EINZIGE
|
||||||
|
# aktive Recovery-Gold-Source-Identitaet + die EINZIGE aktive Recovery-Image-ID.
|
||||||
|
# Kein freier Pfad. FAIL CLOSED wenn State fehlt/ungueltig.
|
||||||
|
CONTROL_PLANE_STATE_DIR="/opt/rq-historical-control-plane"
|
||||||
|
RECOVERY_SOURCE_STATE="$CONTROL_PLANE_STATE_DIR/recovery-gold-source.state"
|
||||||
|
RECOVERY_IMAGE_STATE="$CONTROL_PLANE_STATE_DIR/recovery-image.state"
|
||||||
|
# .dockerignore fester EXPECTED SHA (read-only ermittelt 30.08. gegen /opt/historical-v2;
|
||||||
|
# Inhalt exakt: app/app/ + app/eligibility.py). Kein Schätzen.
|
||||||
|
GOLD_DOCKERIGNORE_SHA="70bac51783f5ee956796cf2216ab17a550fcb646092edad3504763dbfabb881f"
|
||||||
|
# Historische Recovery-Image-ID (VERLOREN) — NUR Evidence, KEINE zwingende Output-ID.
|
||||||
|
HISTORICAL_RECOVERY_IMAGE_ID="sha256:d2db926dc6f5f7cf2f8e85d271a9b16fcc3cfb54b6557604d3d784f7961a4bc2"
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------- PERSISTENT-HOST-SOT-PROMOTION
|
# ------------------------------------------------- PERSISTENT-HOST-SOT-PROMOTION
|
||||||
# Phase 13.5 · Persistent Host-SoT Patch Promotion Channel. KEIN echter Promote
|
# Phase 13.5 · Persistent Host-SoT Patch Promotion Channel. KEIN echter Promote
|
||||||
# durch Rain. Nur run_backfill_year.py. Feste Identitaeten, KEIN User-Input.
|
# durch Rain. Nur run_backfill_year.py. Feste Identitaeten, KEIN User-Input.
|
||||||
|
|
@ -233,10 +256,10 @@ PIN_REMEDIATION_NAME="rq-historical-pin-phase13-5-runner-remediation"
|
||||||
# Unterordner je Rolle (Punkt 3)
|
# Unterordner je Rolle (Punkt 3)
|
||||||
declare -A ARCHIVE_SUB=( [recovery]="recovery" [remediation]="candidates" )
|
declare -A ARCHIVE_SUB=( [recovery]="recovery" [remediation]="candidates" )
|
||||||
# Archiv-Session-IDs: kurze Image-ID (<IMAGE_ID_SHORT>), die den immutable
|
# Archiv-Session-IDs: kurze Image-ID (<IMAGE_ID_SHORT>), die den immutable
|
||||||
# Session-Ordner benennt. Recovery = bekannte Original-ID; Remediation =
|
# Session-Ordner benennt. Recovery = aktive Image-ID aus Control-Plane-State
|
||||||
# FULL_IMAGE_ID aus Build-Session (41e357a1..., aktuell im Store fehlend).
|
# (zur Laufzeit via load_recovery_state gesetzt); Remediation = FULL_IMAGE_ID
|
||||||
RECOVERY_ARCHIVE_ID="${RECOVERY_GOLD_IMAGE_ID#sha256:}"
|
# aus Build-Session (41e357a1..., aktuell im Store fehlend).
|
||||||
RECOVERY_ARCHIVE_ID="${RECOVERY_ARCHIVE_ID:0:12}"
|
RECOVERY_ARCHIVE_ID="" # zur Laufzeit aus State gesetzt (load_recovery_state)
|
||||||
# Remediation-Archiv-Session-ID: kurze ID der Build-Session-Remendation (41e357a1...).
|
# Remediation-Archiv-Session-ID: kurze ID der Build-Session-Remendation (41e357a1...).
|
||||||
REMEDIATION_ARCHIVE_ID="41e357a12b90"
|
REMEDIATION_ARCHIVE_ID="41e357a12b90"
|
||||||
# Remediation-Archiv-Referenz (aus Build-Session falls vorhanden, sonst leer):
|
# Remediation-Archiv-Referenz (aus Build-Session falls vorhanden, sonst leer):
|
||||||
|
|
@ -329,6 +352,36 @@ exclusion_valid() { # .dockerignore exakt die 3 Legacy-Einträge, keine Gold-Da
|
||||||
esac
|
esac
|
||||||
done < "$BUILD_EXCLUSION_FILE"
|
done < "$BUILD_EXCLUSION_FILE"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------- RECOVERY CONTROL-PLANE STATE LOAD
|
||||||
|
# Laedt die EINZIGE aktive Recovery-Identitaet aus dem kontrollierten State
|
||||||
|
# (KEIN latest, KEIN glob-first, KEINE Symlink-Semantik). Setzt zur Laufzeit:
|
||||||
|
# RECOVERY_GOLD_IMAGE_ID (aus RECOVERY_IMAGE_STATE: NEW_RECOVERY_FULL_IMAGE_ID)
|
||||||
|
# RECOVERY_ARCHIVE_ID (abgeleitet aus der geladenen Image-ID)
|
||||||
|
# RECOVERY_BUILD_CONTEXT (aus RECOVERY_SOURCE_STATE: GOLD_SOURCE_SESSION)
|
||||||
|
# RECOVERY_BUILD_DOCKERFILE
|
||||||
|
# FAIL CLOSED wenn State fehlt/ungueltig. Kein freier Input, kein statischer Fallback.
|
||||||
|
load_recovery_state() {
|
||||||
|
# --- Recovery-Image-State (Punkt 17: NEW_RECOVERY_FULL_IMAGE_ID) ---
|
||||||
|
if [ ! -f "$RECOVERY_IMAGE_STATE" ]; then
|
||||||
|
die "load-recovery-state: Kein Recovery-Image-State ($RECOVERY_IMAGE_STATE). NUR nach erfolgreichem Recovery-Build (FAIL CLOSED)"
|
||||||
|
fi
|
||||||
|
local id
|
||||||
|
id="$(awk -F'=' '$1=="NEW_RECOVERY_FULL_IMAGE_ID"{print $2}' "$RECOVERY_IMAGE_STATE" 2>/dev/null)"
|
||||||
|
[[ "$id" =~ ^sha256:[a-f0-9]{64}$ ]] || die "load-recovery-state: NEW_RECOVERY_FULL_IMAGE_ID ungueltig/fehlt (FAIL CLOSED)"
|
||||||
|
RECOVERY_GOLD_IMAGE_ID="$id"
|
||||||
|
RECOVERY_ARCHIVE_ID="${id#sha256:}"; RECOVERY_ARCHIVE_ID="${RECOVERY_ARCHIVE_ID:0:12}"
|
||||||
|
# --- Recovery-Source-State (Punkt 9: GOLD_SOURCE_SESSION) ---
|
||||||
|
if [ ! -f "$RECOVERY_SOURCE_STATE" ]; then
|
||||||
|
die "load-recovery-state: Kein Recovery-Source-State ($RECOVERY_SOURCE_STATE). NUR nach realem recover (FAIL CLOSED)"
|
||||||
|
fi
|
||||||
|
local sess
|
||||||
|
sess="$(awk -F'=' '$1=="GOLD_SOURCE_SESSION"{print $2}' "$RECOVERY_SOURCE_STATE" 2>/dev/null)"
|
||||||
|
[[ "$sess" =~ ^[0-9]{8}_[0-9]{6}$ ]] || die "load-recovery-state: GOLD_SOURCE_SESSION ungueltig/fehlt (FAIL CLOSED)"
|
||||||
|
RECOVERY_BUILD_CONTEXT="$GOLD_SOURCE_ROOT/$sess"
|
||||||
|
RECOVERY_BUILD_DOCKERFILE="$GOLD_SOURCE_ROOT/$sess/Dockerfile"
|
||||||
|
}
|
||||||
|
|
||||||
# Manifest einer Quelle (Gold-Container / neuer Temp-Container) erzeugen:
|
# Manifest einer Quelle (Gold-Container / neuer Temp-Container) erzeugen:
|
||||||
# gibt zeilenweise 'sha app/<rel>' auf stdout; Quelle ist IMMER laufender Container
|
# gibt zeilenweise 'sha app/<rel>' auf stdout; Quelle ist IMMER laufender Container
|
||||||
gen_manifest() { # $1 = docker-Container-Name
|
gen_manifest() { # $1 = docker-Container-Name
|
||||||
|
|
@ -656,10 +709,17 @@ verify_image_config() {
|
||||||
build_recovery_gold() {
|
build_recovery_gold() {
|
||||||
expect_zero "$@"
|
expect_zero "$@"
|
||||||
echo "=== BUILD-RECOVERY-GOLD ($RUN_MODE) ==="
|
echo "=== BUILD-RECOVERY-GOLD ($RUN_MODE) ==="
|
||||||
echo " Build Context : $RECOVERY_BUILD_CONTEXT (fix)"
|
# Build Context Rotation (Punkt 11): ausschliesslich aus kontrolliertem State.
|
||||||
echo " Dockerfile : $RECOVERY_BUILD_DOCKERFILE (fix)"
|
# Kein statisches /opt/historical-v2. Keine User-Argumente.
|
||||||
|
load_recovery_state
|
||||||
|
echo " Build Context : $RECOVERY_BUILD_CONTEXT (aus Control-Plane-State)"
|
||||||
|
echo " Dockerfile : $RECOVERY_BUILD_DOCKERFILE (aus Control-Plane-State)"
|
||||||
echo " Recovery-Tag : $RECOVERY_REBUILD_TAG (fix, direkt getaggt, KEIN latest)"
|
echo " Recovery-Tag : $RECOVERY_REBUILD_TAG (fix, direkt getaggt, KEIN latest)"
|
||||||
echo " Guards:"
|
echo " Guards:"
|
||||||
|
# Build Preflight (Punkt 12): verify-recovered-gold-build-source PASS zwingend.
|
||||||
|
echo " [preflight] verify-recovered-gold-build-source:"
|
||||||
|
verify_recovered_gold_build_source >/dev/null || die "build-recovery-gold: Recovery-Source nicht verifiziert (FAIL CLOSED)"
|
||||||
|
echo " OK"
|
||||||
rebuild_guards
|
rebuild_guards
|
||||||
# Build-Context-Manifest (Punkt 5) — read-only RECOVERY_GOLD_BUILD_INPUT
|
# Build-Context-Manifest (Punkt 5) — read-only RECOVERY_GOLD_BUILD_INPUT
|
||||||
echo " [build-input] RECOVERY_GOLD_BUILD_INPUT (Build-Context-Manifest):"
|
echo " [build-input] RECOVERY_GOLD_BUILD_INPUT (Build-Context-Manifest):"
|
||||||
|
|
@ -743,6 +803,7 @@ EOF
|
||||||
|
|
||||||
# Pre-Recreate/Pre-Rollback Gates (Punkt 10/16). Read-only. FAIL CLOSED.
|
# Pre-Recreate/Pre-Rollback Gates (Punkt 10/16). Read-only. FAIL CLOSED.
|
||||||
recreate_pre_gates() {
|
recreate_pre_gates() {
|
||||||
|
load_recovery_state
|
||||||
echo " [gate A] verify-recovery-gold-image PASS:"
|
echo " [gate A] verify-recovery-gold-image PASS:"
|
||||||
( verify_recovery_gold_image >/dev/null 2>&1 ) && echo " OK" || die "Gate A FAIL: Recovery-Gold nicht verifiziert (FAIL CLOSED)"
|
( verify_recovery_gold_image >/dev/null 2>&1 ) && echo " OK" || die "Gate A FAIL: Recovery-Gold nicht verifiziert (FAIL CLOSED)"
|
||||||
echo " [gate B] verify-candidate-image PASS:"
|
echo " [gate B] verify-candidate-image PASS:"
|
||||||
|
|
@ -915,6 +976,7 @@ recreate_candidate_safe() {
|
||||||
rollback_to_recovery_gold() {
|
rollback_to_recovery_gold() {
|
||||||
expect_zero "$@"
|
expect_zero "$@"
|
||||||
echo "=== ROLLBACK-TO-RECOVERY-GOLD ($RUN_MODE) ==="
|
echo "=== ROLLBACK-TO-RECOVERY-GOLD ($RUN_MODE) ==="
|
||||||
|
load_recovery_state
|
||||||
echo " Ziel-Service : $HISTORICAL_SERVICE (NUR dieser; KEIN db, KEINE Volumes)"
|
echo " Ziel-Service : $HISTORICAL_SERVICE (NUR dieser; KEIN db, KEINE Volumes)"
|
||||||
echo " Image : $RECOVERY_GOLD_TAG_FINAL -> $RECOVERY_GOLD_IMAGE_ID (immutable Baseline)"
|
echo " Image : $RECOVERY_GOLD_TAG_FINAL -> $RECOVERY_GOLD_IMAGE_ID (immutable Baseline)"
|
||||||
echo " Preconditions:"
|
echo " Preconditions:"
|
||||||
|
|
@ -972,12 +1034,13 @@ promote_pre_guards() {
|
||||||
local ts; ts="$(sha256sum "$PATCH_TARGET" 2>/dev/null | awk '{print $1}')"
|
local ts; ts="$(sha256sum "$PATCH_TARGET" 2>/dev/null | awk '{print $1}')"
|
||||||
[ "$ts" = "70d3abb1a92a871e28cc6fb95b9a26944b55dd8df1b72db80642d6881b7b0f20" ] || die "Guard F FAIL: Target-SHA $ts != Gold-Baseline (FAIL CLOSED)"
|
[ "$ts" = "70d3abb1a92a871e28cc6fb95b9a26944b55dd8df1b72db80642d6881b7b0f20" ] || die "Guard F FAIL: Target-SHA $ts != Gold-Baseline (FAIL CLOSED)"
|
||||||
echo " OK ($ts)"
|
echo " OK ($ts)"
|
||||||
echo " [guard G] Recovery-Gold Image inspectable:"
|
echo " [guard G] RECOVERY READY (verify-recovery-ready PASS):"
|
||||||
docker image inspect "$RECOVERY_GOLD_IMAGE_ID" >/dev/null 2>&1 || die "Guard G FAIL (FAIL CLOSED)"
|
( verify_ready_cmd recovery >/dev/null 2>&1 ) || die "Guard G FAIL: RECOVERY NOT READY (FAIL CLOSED)"
|
||||||
echo " OK"
|
echo " OK"
|
||||||
echo " [guard H] Recovery-Tag korrekt gebunden:"
|
echo " [guard H] Recovery-Tag korrekt gebunden (an aktive State-Image-ID):"
|
||||||
|
load_recovery_state
|
||||||
local rt; rt="$(docker image inspect -f '{{.Id}}' "$RECOVERY_GOLD_TAG_FINAL" 2>/dev/null || true)"
|
local rt; rt="$(docker image inspect -f '{{.Id}}' "$RECOVERY_GOLD_TAG_FINAL" 2>/dev/null || true)"
|
||||||
[ "$rt" = "$RECOVERY_GOLD_IMAGE_ID" ] || die "Guard H FAIL: Recovery-Tag != Recovery-ID (FAIL CLOSED)"
|
[ "$rt" = "$RECOVERY_GOLD_IMAGE_ID" ] || die "Guard H FAIL: Recovery-Tag != aktive Recovery-ID (FAIL CLOSED)"
|
||||||
echo " OK"
|
echo " OK"
|
||||||
echo " [guard I] verify-recovery-gold-image PASS:"
|
echo " [guard I] verify-recovery-gold-image PASS:"
|
||||||
( verify_recovery_gold_image >/dev/null 2>&1 ) && echo " OK" || die "Guard I FAIL: Recovery-Gold nicht verifiziert (FAIL CLOSED)"
|
( verify_recovery_gold_image >/dev/null 2>&1 ) && echo " OK" || die "Guard I FAIL: Recovery-Gold nicht verifiziert (FAIL CLOSED)"
|
||||||
|
|
@ -1124,6 +1187,7 @@ remediation_full_image_id() { # FULL_IMAGE_ID aus Session (echo) — nur wenn r
|
||||||
}
|
}
|
||||||
# Pre-Build-Guards (Punkt 12: dry-run-Gates A–O). Read-only; alle FAIL CLOSED.
|
# Pre-Build-Guards (Punkt 12: dry-run-Gates A–O). Read-only; alle FAIL CLOSED.
|
||||||
remediation_guards() {
|
remediation_guards() {
|
||||||
|
load_recovery_state
|
||||||
echo " [guard A] Host-SoT vorhanden:"
|
echo " [guard A] Host-SoT vorhanden:"
|
||||||
[ -f "/opt/historical-v2/app/run_backfill_year.py" ] || die "Guard A FAIL: Host-Runner fehlt (FAIL CLOSED)"
|
[ -f "/opt/historical-v2/app/run_backfill_year.py" ] || die "Guard A FAIL: Host-Runner fehlt (FAIL CLOSED)"
|
||||||
echo " OK"
|
echo " OK"
|
||||||
|
|
@ -1559,6 +1623,11 @@ verify_ready() { # $1 = role
|
||||||
remediation) label="CANDIDATE READY" ;;
|
remediation) label="CANDIDATE READY" ;;
|
||||||
esac
|
esac
|
||||||
echo "=== $label (READY-Gate: IMAGE VERIFY + PIN VERIFY + ARCHIVE VERIFY) ==="
|
echo "=== $label (READY-Gate: IMAGE VERIFY + PIN VERIFY + ARCHIVE VERIFY) ==="
|
||||||
|
# Recovery-Identitaet aus kontrolliertem State laden (Punkt 17/19). Kein
|
||||||
|
# statisches d2db, kein latest. FAIL CLOSED wenn State fehlt.
|
||||||
|
if [ "$role" = "recovery" ]; then
|
||||||
|
load_recovery_state
|
||||||
|
fi
|
||||||
# IMAGE VERIFY (zwingend inspectable + korrekt)
|
# IMAGE VERIFY (zwingend inspectable + korrekt)
|
||||||
echo " [IMAGE] $(role_tag "$role"):"
|
echo " [IMAGE] $(role_tag "$role"):"
|
||||||
verify_image_present "$role" || die "READY-Gate FAIL: Image nicht inspectable (FAIL CLOSED)"
|
verify_image_present "$role" || die "READY-Gate FAIL: Image nicht inspectable (FAIL CLOSED)"
|
||||||
|
|
@ -1693,7 +1762,11 @@ archive_image() { # $1 = role
|
||||||
local tag id subdir sdir
|
local tag id subdir sdir
|
||||||
tag="$(role_tag "$role")"
|
tag="$(role_tag "$role")"
|
||||||
case "$role" in
|
case "$role" in
|
||||||
recovery) id="$RECOVERY_GOLD_IMAGE_ID" ;;
|
recovery)
|
||||||
|
# Aktive Recovery-Identitaet aus kontrolliertem State (Punkt 19). Kein d2db.
|
||||||
|
load_recovery_state
|
||||||
|
id="$RECOVERY_GOLD_IMAGE_ID"
|
||||||
|
;;
|
||||||
remediation)
|
remediation)
|
||||||
remediation_session || die "archive(remediation): keine gueltige Build-Session (FAIL CLOSED)"
|
remediation_session || die "archive(remediation): keine gueltige Build-Session (FAIL CLOSED)"
|
||||||
id="$(remediation_full_image_id)"
|
id="$(remediation_full_image_id)"
|
||||||
|
|
@ -1767,7 +1840,11 @@ pin_image() { # $1 = role
|
||||||
name="$(role_pin "$role")"
|
name="$(role_pin "$role")"
|
||||||
tag="$(role_tag "$role")"
|
tag="$(role_tag "$role")"
|
||||||
case "$role" in
|
case "$role" in
|
||||||
recovery) id="$RECOVERY_GOLD_IMAGE_ID" ;;
|
recovery)
|
||||||
|
# Aktive Recovery-Identitaet aus kontrolliertem State (Punkt 19). Kein d2db.
|
||||||
|
load_recovery_state
|
||||||
|
id="$RECOVERY_GOLD_IMAGE_ID"
|
||||||
|
;;
|
||||||
remediation)
|
remediation)
|
||||||
remediation_session || die "pin(remediation): keine gueltige Build-Session (FAIL CLOSED)"
|
remediation_session || die "pin(remediation): keine gueltige Build-Session (FAIL CLOSED)"
|
||||||
id="$(remediation_full_image_id)"
|
id="$(remediation_full_image_id)"
|
||||||
|
|
@ -1808,12 +1885,14 @@ pin_image() { # $1 = role
|
||||||
verify_pin_cmd() { # $1 = role (read-only)
|
verify_pin_cmd() { # $1 = role (read-only)
|
||||||
local role="$1"; expect_zero "${@:2}"
|
local role="$1"; expect_zero "${@:2}"
|
||||||
echo "=== VERIFY-PIN($role) ==="
|
echo "=== VERIFY-PIN($role) ==="
|
||||||
|
if [ "$role" = "recovery" ]; then load_recovery_state; fi
|
||||||
if verify_pin "$role"; then echo "VERIFY-PIN($role): PASS"; exit 0
|
if verify_pin "$role"; then echo "VERIFY-PIN($role): PASS"; exit 0
|
||||||
else die "VERIFY-PIN($role): FAIL (FAIL CLOSED)"; fi
|
else die "VERIFY-PIN($role): FAIL (FAIL CLOSED)"; fi
|
||||||
}
|
}
|
||||||
verify_archive_cmd() { # $1 = role (read-only)
|
verify_archive_cmd() { # $1 = role (read-only)
|
||||||
local role="$1"; expect_zero "${@:2}"
|
local role="$1"; expect_zero "${@:2}"
|
||||||
echo "=== VERIFY-ARCHIVE($role) ==="
|
echo "=== VERIFY-ARCHIVE($role) ==="
|
||||||
|
if [ "$role" = "recovery" ]; then load_recovery_state; fi
|
||||||
verify_archive "$role" || die "VERIFY-ARCHIVE($role): FAIL (FAIL CLOSED)"
|
verify_archive "$role" || die "VERIFY-ARCHIVE($role): FAIL (FAIL CLOSED)"
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
@ -1827,6 +1906,7 @@ verify_ready_cmd() { # $1 = role (read-only)
|
||||||
restore_recovery_dry() { # dry-run
|
restore_recovery_dry() { # dry-run
|
||||||
expect_zero "$@"
|
expect_zero "$@"
|
||||||
echo "=== RESTORE-RECOVERY-IMAGE-ARCHIVE (DRY-RUN — DESIGN; kein echter Restore) ==="
|
echo "=== RESTORE-RECOVERY-IMAGE-ARCHIVE (DRY-RUN — DESIGN; kein echter Restore) ==="
|
||||||
|
load_recovery_state
|
||||||
local sdir sid base img
|
local sdir sid base img
|
||||||
sdir="$(role_arch_dir recovery)"
|
sdir="$(role_arch_dir recovery)"
|
||||||
sid="$RECOVERY_ARCHIVE_ID"
|
sid="$RECOVERY_ARCHIVE_ID"
|
||||||
|
|
@ -2001,25 +2081,164 @@ recover_gold_build_source_dry() {
|
||||||
}
|
}
|
||||||
|
|
||||||
# recover-gold-build-source (Dispatcher): dry-run zeigt Plan (ZERO MUTATION),
|
# recover-gold-build-source (Dispatcher): dry-run zeigt Plan (ZERO MUTATION),
|
||||||
# real ist in dieser Mission BLOCKIERT (FAIL CLOSED).
|
# real fuehrt den kontrollierten Workflow aus (Punkt 3/4/5/8/9).
|
||||||
recover_gold_build_source() {
|
recover_gold_build_source() {
|
||||||
expect_zero "$@"
|
expect_zero "$@"
|
||||||
if [ "$RUN_MODE" = "DRY_RUN" ]; then
|
if [ "$RUN_MODE" = "DRY_RUN" ]; then
|
||||||
recover_gold_build_source_dry
|
recover_gold_build_source_dry
|
||||||
else
|
else
|
||||||
die "recover-gold-build-source: Realer Recover ist in dieser Mission NICHT erlaubt (HARTER STOPP Punkt 29). NUR dry-run (FAIL CLOSED)"
|
recover_gold_build_source_real
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# verify-recovered-gold-build-source (read-only): prueft eine bestehende Recovery-Source.
|
# Realer Recover (Punkt 3/4/5/8/9): materialisiert die Gold-Source aus dem
|
||||||
|
# bewiesenen DEPLOYED GOLD CONTAINER in eine immutable Session. Keine freien
|
||||||
|
# Parameter. FAIL CLOSED bei jeder Abweichung. ZERO MUTATION ausser der Session.
|
||||||
|
recover_gold_build_source_real() {
|
||||||
|
expect_zero "$@"
|
||||||
|
echo "=== RECOVER-GOLD-BUILD-SOURCE (real) ==="
|
||||||
|
# Punkt 4: TOCTOU vermeiden — unmittelbar vor Extraktion erneut verifizieren.
|
||||||
|
echo " [verify] verify-deployed-gold-source (TOCTOU-Guard):"
|
||||||
|
verify_deployed_gold_source >/dev/null || die "recover: verify-deployed-gold-source FAIL (FAIL CLOSED)"
|
||||||
|
echo " OK"
|
||||||
|
# Punkt 8: immutable Session — Root darf nicht existieren (FAIL CLOSED).
|
||||||
|
if [ -e "$GOLD_SOURCE_ROOT" ]; then
|
||||||
|
die "recover: Gold-Source-Root existiert bereits $GOLD_SOURCE_ROOT (KEIN Overwrite, FAIL CLOSED)"
|
||||||
|
fi
|
||||||
|
local sess
|
||||||
|
sess="$(date +%Y%m%d_%H%M%S)"
|
||||||
|
local sdir="$GOLD_SOURCE_ROOT/$sess"
|
||||||
|
# Punkt 5: Application Tree ausschliesslich aus dem hardcoded Gold-Container.
|
||||||
|
# Keine Host-Application-Dateien, keine SOT-Session, kein latest, keine freien docker-cp-Inputs.
|
||||||
|
mkdir -p "$sdir/app" || die "recover: Session-Ordner nicht anlegbar (FAIL CLOSED)"
|
||||||
|
echo " [extract] docker cp $EXPECTED_GOLD_SOURCE_CID:$GOLD_SOURCE_APP_PREFIX/. -> $sdir/app/"
|
||||||
|
if ! docker cp "$EXPECTED_GOLD_SOURCE_CID:$GOLD_SOURCE_APP_PREFIX/." "$sdir/app/" >/dev/null 2>&1; then
|
||||||
|
rm -rf "$GOLD_SOURCE_ROOT"; die "recover: docker cp Application-Tree fehlgeschlagen (FAIL CLOSED)"
|
||||||
|
fi
|
||||||
|
# Punkt 6: Build Support separat aus fest SHA-gebundenen Quellen (Host/SoT-Bestand).
|
||||||
|
echo " [build-support] SHA-gebundene Host-Dateien:"
|
||||||
|
local key spec src exp s
|
||||||
|
for key in "${!GOLD_BUILD_SUPPORT[@]}"; do
|
||||||
|
spec="${GOLD_BUILD_SUPPORT[$key]}"; src="${spec%%|*}"; exp="${spec##*|}"
|
||||||
|
[ -f "$src" ] || { rm -rf "$GOLD_SOURCE_ROOT"; die "recover: Build-Support fehlt $src (FAIL CLOSED)"; }
|
||||||
|
s="$(sha256sum "$src" | awk '{print $1}')"
|
||||||
|
[ "$s" = "$exp" ] || { rm -rf "$GOLD_SOURCE_ROOT"; die "recover: Build-Support SHA mismatch $key (FAIL CLOSED)"; }
|
||||||
|
cp -a "$src" "$sdir/$(basename "$src")" || { rm -rf "$GOLD_SOURCE_ROOT"; die "recover: Build-Support kopieren fehlgeschlagen (FAIL CLOSED)"; }
|
||||||
|
echo " $key == $exp"
|
||||||
|
done
|
||||||
|
# Punkt 6: .dockerignore kontrolliert erzeugen (exakt die Legacy-Exclusions).
|
||||||
|
printf 'app/app/\napp/eligibility.py\n' > "$sdir/.dockerignore"
|
||||||
|
local dis
|
||||||
|
dis="$(sha256sum "$sdir/.dockerignore" | awk '{print $1}')"
|
||||||
|
[ "$dis" = "$GOLD_DOCKERIGNORE_SHA" ] || { rm -rf "$GOLD_SOURCE_ROOT"; die "recover: .dockerignore SHA mismatch (FAIL CLOSED)"; }
|
||||||
|
echo " .dockerignore == $GOLD_DOCKERIGNORE_SHA"
|
||||||
|
# Punkt 8: Application Manifest (63/63 gegen Gold) + Build-Support Manifest.
|
||||||
|
( cd "$sdir/app" && 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}' ) > "$sdir/application.manifest"
|
||||||
|
local match=0 diverged=0 missing=0
|
||||||
|
local -A gsha
|
||||||
|
while read -r sha p; do gsha["$p"]="$sha"; done < "$GOLD_MANIFEST"
|
||||||
|
local path g c
|
||||||
|
for path in "${!gsha[@]}"; do
|
||||||
|
g="${gsha[$path]}"
|
||||||
|
c="$(awk -v r="$path" '$2==r{print $1}' "$sdir/application.manifest" 2>/dev/null)"
|
||||||
|
if [ -z "$c" ]; then missing=$((missing+1));
|
||||||
|
elif [ "$c" = "$g" ]; then match=$((match+1));
|
||||||
|
else diverged=$((diverged+1)); fi
|
||||||
|
done
|
||||||
|
echo " [application] MATCH=$match DIVERGED=$diverged MISSING=$missing"
|
||||||
|
[ "$match" = "63" ] && [ "$diverged" = "0" ] && [ "$missing" = "0" ] || { rm -rf "$GOLD_SOURCE_ROOT"; die "recover: Application != Gold (FAIL CLOSED)"; }
|
||||||
|
# Build-Support Manifest (Punkt 8)
|
||||||
|
{
|
||||||
|
for key in "${!GOLD_BUILD_SUPPORT[@]}"; do
|
||||||
|
spec="${GOLD_BUILD_SUPPORT[$key]}"; src="${spec%%|*}"; exp="${spec##*|}"
|
||||||
|
echo "$key $exp"
|
||||||
|
done
|
||||||
|
echo ".dockerignore $GOLD_DOCKERIGNORE_SHA"
|
||||||
|
} > "$sdir/build-support.manifest"
|
||||||
|
# Punkt 13: FINAL_BUILD_INPUT_SHA (Build-Input-Identitaet) berechnen.
|
||||||
|
local final_sha
|
||||||
|
final_sha="$( ( cd "$sdir" && find . -type f ! -name 'session.meta' ! -name 'application.manifest' ! -name 'build-support.manifest' ! -name 'final-build-input.manifest' -printf '%P\n' 2>/dev/null | sort | while IFS= read -r f; do [ -f "$f" ] && sha256sum "$f"; done ) | sha256sum | awk '{print $1}' )"
|
||||||
|
echo "$final_sha" > "$sdir/final-build-input.manifest"
|
||||||
|
# Punkt 8: session.meta
|
||||||
|
{
|
||||||
|
echo "GOLD_SOURCE_SESSION=$sess"
|
||||||
|
echo "SOURCE_CONTAINER_ID=$EXPECTED_GOLD_SOURCE_CID"
|
||||||
|
echo "SOURCE_IMAGE_ID=$EXPECTED_GOLD_SOURCE_IMAGE_ID"
|
||||||
|
echo "CREATED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||||
|
echo "FINAL_BUILD_INPUT_SHA=$final_sha"
|
||||||
|
} > "$sdir/session.meta"
|
||||||
|
# Punkt 9: aktive Recovery-Gold-Source-Identitaet kontrolliert speichern.
|
||||||
|
mkdir -p "$CONTROL_PLANE_STATE_DIR" || { rm -rf "$GOLD_SOURCE_ROOT"; die "recover: State-Dir nicht anlegbar (FAIL CLOSED)"; }
|
||||||
|
if [ -e "$RECOVERY_SOURCE_STATE" ]; then
|
||||||
|
rm -rf "$GOLD_SOURCE_ROOT"; die "recover: Recovery-Source-State existiert bereits (KEIN Overwrite, FAIL CLOSED)"
|
||||||
|
fi
|
||||||
|
{
|
||||||
|
echo "GOLD_SOURCE_SESSION=$sess"
|
||||||
|
echo "FINAL_BUILD_INPUT_SHA=$final_sha"
|
||||||
|
echo "SOURCE_CONTAINER_ID=$EXPECTED_GOLD_SOURCE_CID"
|
||||||
|
echo "SOURCE_IMAGE_ID=$EXPECTED_GOLD_SOURCE_IMAGE_ID"
|
||||||
|
echo "CREATED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||||
|
} > "$RECOVERY_SOURCE_STATE"
|
||||||
|
chown root:root "$RECOVERY_SOURCE_STATE"; chmod 600 "$RECOVERY_SOURCE_STATE"
|
||||||
|
# Punkt 8: immutable klassifizieren (root-owned, nicht world-readable).
|
||||||
|
chown -R root:root "$sdir"; chmod -R 700 "$sdir"
|
||||||
|
echo "RECOVER-GOLD-BUILD-SOURCE OK: $sdir (immutable, 63/63, Build-Support SHA-gebunden)"
|
||||||
|
echo " State: $RECOVERY_SOURCE_STATE"
|
||||||
|
echo " FINAL_BUILD_INPUT_SHA=$final_sha"
|
||||||
|
}
|
||||||
|
|
||||||
|
# verify-recovered-gold-build-source (read-only): prueft eine bestehende Recovery-Source
|
||||||
|
# gegen die EXAKTE Session-Identitaet aus dem Control-Plane-State (Punkt 10).
|
||||||
|
# NICHT chronologisch newest, NICHT glob-first, NICHT latest.
|
||||||
verify_recovered_gold_build_source() {
|
verify_recovered_gold_build_source() {
|
||||||
expect_zero "$@"
|
expect_zero "$@"
|
||||||
echo "=== VERIFY-RECOVERED-GOLD-BUILD-SOURCE (read-only) ==="
|
echo "=== VERIFY-RECOVERED-GOLD-BUILD-SOURCE (read-only) ==="
|
||||||
# In dieser Mission existiert noch keine Recovery-Source -> FAIL CLOSED.
|
# Exakte Session-Identitaet aus State (Punkt 9/10). Kein latest/glob-first.
|
||||||
if [ ! -d "$GOLD_SOURCE_ROOT" ]; then
|
if [ ! -f "$RECOVERY_SOURCE_STATE" ]; then
|
||||||
die "verify-recovered-gold-build-source: Kein Recovery-Source-Root vorhanden ($GOLD_SOURCE_ROOT). NUR nach realem recover (separate Mission)."
|
die "verify-recovered-gold-build-source: Kein Recovery-Source-State ($RECOVERY_SOURCE_STATE). NUR nach realem recover (FAIL CLOSED)"
|
||||||
fi
|
fi
|
||||||
echo "VERDICT: RECOVERED GOLD BUILD SOURCE OK"
|
local sess
|
||||||
|
sess="$(awk -F'=' '$1=="GOLD_SOURCE_SESSION"{print $2}' "$RECOVERY_SOURCE_STATE" 2>/dev/null)"
|
||||||
|
[[ "$sess" =~ ^[0-9]{8}_[0-9]{6}$ ]] || die "verify-recovered-gold-build-source: GOLD_SOURCE_SESSION ungueltig/fehlt (FAIL CLOSED)"
|
||||||
|
local sdir="$GOLD_SOURCE_ROOT/$sess"
|
||||||
|
[ -d "$sdir" ] || die "verify-recovered-gold-build-source: Session-Ordner fehlt $sdir (FAIL CLOSED)"
|
||||||
|
# Pflichtdateien der immutable Session (Punkt 8)
|
||||||
|
local f
|
||||||
|
for f in app Dockerfile .dockerignore requirements.txt session.meta application.manifest build-support.manifest final-build-input.manifest; do
|
||||||
|
[ -e "$sdir/$f" ] || die "verify-recovered-gold-build-source: fehlt $sdir/$f (FAIL CLOSED)"
|
||||||
|
done
|
||||||
|
# Application Manifest (Punkt 8): 63/63 gegen Gold
|
||||||
|
echo " [application] $sdir/application.manifest vs Gold (63/63):"
|
||||||
|
local match=0 diverged=0 missing=0
|
||||||
|
local -A gsha
|
||||||
|
while read -r sha p; do gsha["$p"]="$sha"; done < "$GOLD_MANIFEST"
|
||||||
|
local path g s
|
||||||
|
for path in "${!gsha[@]}"; do
|
||||||
|
g="${gsha[$path]}"
|
||||||
|
s="$(awk -v r="$path" '$2==r{print $1}' "$sdir/application.manifest" 2>/dev/null)"
|
||||||
|
if [ -z "$s" ]; then missing=$((missing+1));
|
||||||
|
elif [ "$s" = "$g" ]; then match=$((match+1));
|
||||||
|
else diverged=$((diverged+1)); fi
|
||||||
|
done
|
||||||
|
echo " MATCH=$match DIVERGED=$diverged MISSING=$missing"
|
||||||
|
[ "$match" = "63" ] && [ "$diverged" = "0" ] && [ "$missing" = "0" ] || die "verify-recovered-gold-build-source: Application != Gold (FAIL CLOSED)"
|
||||||
|
# Build-Support SHAs (Punkt 6): fest SHA-gebunden
|
||||||
|
echo " [build-support] SHA-Bindings:"
|
||||||
|
gold_build_support_ok || die "verify-recovered-gold-build-source: Build-Support SHA mismatch (FAIL CLOSED)"
|
||||||
|
# .dockerignore fester EXPECTED SHA (Punkt 6)
|
||||||
|
local dis
|
||||||
|
dis="$(sha256sum "$sdir/.dockerignore" 2>/dev/null | awk '{print $1}')"
|
||||||
|
[ "$dis" = "$GOLD_DOCKERIGNORE_SHA" ] || die "verify-recovered-gold-build-source: .dockerignore SHA $dis != erwartet (FAIL CLOSED)"
|
||||||
|
echo " .dockerignore == $GOLD_DOCKERIGNORE_SHA"
|
||||||
|
# Build-Input-Identitaet (Punkt 13): FINAL_BUILD_INPUT_SHA aus State pruefen
|
||||||
|
local want got
|
||||||
|
want="$(awk -F'=' '$1=="FINAL_BUILD_INPUT_SHA"{print $2}' "$RECOVERY_SOURCE_STATE" 2>/dev/null)"
|
||||||
|
[ -n "$want" ] && [[ "$want" =~ ^[a-f0-9]{64}$ ]] || die "verify-recovered-gold-build-source: FINAL_BUILD_INPUT_SHA fehlt/ungueltig (FAIL CLOSED)"
|
||||||
|
got="$( ( cd "$sdir" && find . -type f ! -name 'session.meta' ! -name 'application.manifest' ! -name 'build-support.manifest' ! -name 'final-build-input.manifest' -printf '%P\n' 2>/dev/null | sort | while IFS= read -r f; do [ -f "$f" ] && sha256sum "$f"; done ) | sha256sum | awk '{print $1}' )"
|
||||||
|
[ "$got" = "$want" ] || die "verify-recovered-gold-build-source: Build-Input SHA mismatch (Source veraendert) (FAIL CLOSED)"
|
||||||
|
echo " FINAL_BUILD_INPUT_SHA == $want"
|
||||||
|
echo "VERDICT: RECOVERED GOLD BUILD SOURCE OK (Session $sess, 63/63, Build-Support + .dockerignore + Build-Input SHA)"
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2454,9 +2673,10 @@ case "$SUBCMD" in
|
||||||
# Gold-Source fest an Container+Image+63-File-Manifest gebunden. KEIN latest,
|
# 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.
|
# 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-* read-only. Realer recover in dieser Mission BLOCKIERT (nur dry-run).
|
||||||
verify-deployed-gold-source) verify_deployed_gold_source "$@" ;;
|
verify-deployed-gold-source) verify_deployed_gold_source "$@";;
|
||||||
recover-gold-build-source) recover_gold_build_source "$@" ;;
|
recover-gold-build-source) recover_gold_build_source "$@";;
|
||||||
verify-recovered-gold-build-source) verify_recovered_gold_build_source "$@" ;;
|
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 <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"
|
*) 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"
|
||||||
;;
|
;;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue