f12f6edd23
VERIFY: structural — 2 helpers extracted (sourced, G-112); behavioral — CI PASS + regression gate 18V+4S PASS (G-111, D-118); quality — run_platform.sh ~80 lines smaller. ---ci--- project: acdl phase: 9 milestone: v1.16 status: complete phase_role: execution requirements: covered: [REQ-173] partial: [] ---/ci---
60 lines
2.8 KiB
Bash
60 lines
2.8 KiB
Bash
#!/usr/bin/env bash
|
|
# scripts/run_decommission.sh — decommission mode (extracted from run_platform.sh, P9/REQ-173).
|
|
# Sourced by run_platform.sh (G-112: source, not invoke — shares CONTRACT/WORK/ROOT env).
|
|
# Exits 0 on completion; caller exits after sourcing.
|
|
|
|
echo ""
|
|
echo "=== Decommission Step 1: validate change request against CMDB ==="
|
|
[ -n "$CHANGE_REQUEST_ID" ] || fail "change request ID required for decommission mode"
|
|
CONSUMER_REPO="${GITHUB_REPOSITORY:-$(python3 -c "import yaml; c=yaml.safe_load(open('$CONTRACT')); print(c.get('id','unknown'))" 2>/dev/null || echo 'unknown')}"
|
|
python3 -c "
|
|
import json, sys
|
|
sys.path.insert(0, '$ROOT')
|
|
# In a real deployment, this invokes the Lambda. For local/CI, we simulate.
|
|
cr_id = '$CHANGE_REQUEST_ID'
|
|
repo = '$CONSUMER_REPO'
|
|
print(f'validate_change_request: crId={cr_id} repo={repo}')
|
|
# The Lambda action would be:
|
|
# payload = {'action': 'validate_change_request', 'changeRequestId': cr_id, 'consumerRepo': repo}
|
|
# result = invoke_lambda(payload)
|
|
# For now, just print the intent (the actual validation happens via the Lambda in CI/prod)
|
|
print('change request validation: PASS (simulated for local mode)')
|
|
"
|
|
echo ""
|
|
echo "=== Decommission Step 2: disable deletion protection (HITL SRE gate) ==="
|
|
echo "This step requires SRE approval via GitHub environment 'decommission-gate-sre'."
|
|
echo "The contract is resolved with deletion_protection=false injected."
|
|
python3 core/contract_resolver.py "$CONTRACT" "$WORK/stack.json" 2>/dev/null || fail "resolver failed"
|
|
python3 -c "
|
|
import json, sys
|
|
sys.path.insert(0, '$ROOT')
|
|
from core.contract_resolver import resolve, decommission_transform
|
|
stack = resolve('$CONTRACT', '$ROOT')
|
|
# Step 2: disable deletion protection only (counts still as-is)
|
|
for res in stack['resources']:
|
|
if 'nfrs' not in res:
|
|
res['nfrs'] = {}
|
|
res['nfrs']['deletion_protection'] = False
|
|
with open('$WORK/stack-decommission-step1.json', 'w') as f:
|
|
json.dump(stack, f, indent=2)
|
|
print(f'decommission step 1: {len(stack[\"resources\"])} resources with deletion_protection=false')
|
|
"
|
|
echo ""
|
|
echo "=== Decommission Step 3: zero counts (HITL SRE gate) ==="
|
|
echo "This step requires a second SRE approval via GitHub environment 'decommission-destroy-sre'."
|
|
python3 -c "
|
|
import json, sys
|
|
sys.path.insert(0, '$ROOT')
|
|
from core.contract_resolver import resolve, decommission_transform
|
|
stack = resolve('$CONTRACT', '$ROOT')
|
|
stack = decommission_transform(stack)
|
|
with open('$WORK/stack-decommission-step2.json', 'w') as f:
|
|
json.dump(stack, f, indent=2)
|
|
zeroed = sum(1 for r in stack['resources'] if r.get('nfrs',{}).get('deletion_protection') is False)
|
|
print(f'decommission step 2: {zeroed} resources with deletion_protection=false + counts=0')
|
|
"
|
|
echo ""
|
|
echo "=== Decommission Step 4: confirm ==="
|
|
echo "The terraform apply for step 2 + step 3 would now destroy all resources."
|
|
echo "=== DECOMMISSION READY ==="
|
|
exit 0 |