0fea29cdbb
---ci--- project: acdl phase: 12 milestone: v1.2 status: verify verdict: VERIFIED requirements: covered: [REQ-30] ---/ci--- Phase 12 plan-as-execute + verify. scripts/verify_phase12.sh green (22 assertions). All Wave 1 + Wave 2 tasks complete: - T-12.1: run_spike_*.sh -> run_platform.sh (D-048, --plan-only flag) - T-12.2: spike_runner_policy.json expanded (ECS + ECR + ELB + IAM + EC2) - T-12.3: idempotency documented in bootstrap scripts - T-12.4: P1-1 redacted (no live AWS key IDs in .ciagent/) - T-12.5: P1-B fixed (PERSONAS.md platform/registry -> modules-ir/registry.json) Subagent confirmed run_platform.sh --plan-only runs against real AWS, exit 0. Ready to ship v1.2.2.
116 lines
5.2 KiB
Bash
Executable File
116 lines
5.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# scripts/run_platform.sh - the ACDL platform pipeline (consolidated from
|
|
# the v1.1 spike scripts run_spike_e2e.sh + run_spike_plan.sh per D-048).
|
|
#
|
|
# Default: full end-to-end pipeline (contract resolution -> IR -> terraform
|
|
# plan (real AWS) -> Checkov -> PolicyCheckResult -> confidence signal ->
|
|
# evidence event to DynamoDB outbox).
|
|
# --plan-only: contract resolution + adapter + terraform init/validate/plan
|
|
# (steps 1-4), then exit.
|
|
#
|
|
# Uses the rotated spike key (D-039/D-047) from gitignored .env.secrets.
|
|
# Plan-only (no apply); -lock=false per D-P09-1.
|
|
set -euo pipefail
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
cd "$ROOT"
|
|
|
|
PLAN_ONLY=0
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--plan-only) PLAN_ONLY=1 ;;
|
|
*) echo "FAIL: unknown argument: $arg" >&2; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
fail() { echo "FAIL: $*" >&2; exit 1; }
|
|
|
|
ENV_FILE="$ROOT/.env.secrets"
|
|
[ -f "$ENV_FILE" ] || fail ".env.secrets missing (run scripts/rotate_spike_key.sh)"
|
|
set -a
|
|
. "$ENV_FILE"
|
|
set +a
|
|
export AWS_ACCESS_KEY_ID="$ACDL_AWS_ACCESS_KEY_ID"
|
|
export AWS_SECRET_ACCESS_KEY="$ACDL_AWS_SECRET_ACCESS_KEY"
|
|
export AWS_DEFAULT_REGION="$AWS_DEFAULT_REGION"
|
|
|
|
CONTRACT="contracts/spike.yaml"
|
|
CONTRACT_ID="11111111-1111-1111-1111-111111111111" # spike fixed UUID
|
|
WORK="/tmp/spike_e2e"
|
|
rm -rf "$WORK"; mkdir -p "$WORK"
|
|
|
|
echo "=== Step 1+2: resolve contract -> IR (validates contract schema + IR schema) ==="
|
|
python3 acdl_platform/contract_resolver.py "$CONTRACT" "$WORK/spike_ir.json" || fail "contract resolution failed"
|
|
python3 -c "import json; d=json.load(open('$WORK/spike_ir.json')); print(f\"IR: {d['stack']['name']} {d['stack']['kind']} {len(d['resources'])} resource(s)\")"
|
|
|
|
echo "=== Step 3: adapter compiles IR -> terraform/spike/*.tf (regenerate) ==="
|
|
python3 adapters/terraform/adapter.py "$WORK/spike_ir.json" terraform/spike || fail "adapter failed"
|
|
echo "adapter: emitted terraform/spike/{main.tf,terraform.tf,providers.tf}"
|
|
|
|
echo "=== Step 4: terraform init + validate + plan -lock=false (real AWS) ==="
|
|
cd terraform/spike
|
|
terraform init -reconfigure -lock=false -input=false >> "$WORK/tf.log" 2>&1 || fail "terraform init failed"
|
|
terraform validate >> "$WORK/tf.log" 2>&1 || fail "terraform validate failed"
|
|
terraform plan -lock=false -input=false -out=tfplan >> "$WORK/tf.log" 2>&1 || fail "terraform plan failed"
|
|
echo "terraform plan OK (1 to add, 0 to change, 0 to destroy expected)"
|
|
cd "$ROOT"
|
|
|
|
if [ "$PLAN_ONLY" = "1" ]; then
|
|
echo ""
|
|
echo "=== PLATFORM PLAN OK ==="
|
|
exit 0
|
|
fi
|
|
|
|
echo "=== Step 5: run Checkov on terraform/spike/main.tf ==="
|
|
checkov -f terraform/spike/main.tf --framework terraform -o json --soft-fail > "$WORK/checkov.json" 2> "$WORK/checkov.err"
|
|
[ -s "$WORK/checkov.json" ] || fail "checkov produced no output"
|
|
echo "checkov: $(python3 -c "import json; d=json.load(open('$WORK/checkov.json')); print(len(d.get('results',{}).get('failed_checks',[])), 'failed,', len(d.get('results',{}).get('passed_checks',[])), 'passed')")"
|
|
|
|
echo "=== Step 6: Checkov adapter -> PolicyCheckResult list ==="
|
|
python3 adapters/terraform/policy/checkov_adapter.py "$WORK/checkov.json" "$CONTRACT_ID" > "$WORK/pcr.json" || fail "checkov adapter failed"
|
|
PCR_COUNT=$(python3 -c "import json; print(len(json.load(open('$WORK/pcr.json'))))")
|
|
echo "PolicyCheckResult: $PCR_COUNT record(s)"
|
|
|
|
echo "=== Step 7: confidence signal compute ==="
|
|
python3 <<PY > "$WORK/signal.json" || fail "confidence signal failed"
|
|
import json
|
|
import acdl_platform.confidence_signal as c
|
|
pcr = json.load(open("$WORK/pcr.json"))
|
|
inputs = {
|
|
"policy": pcr,
|
|
"validation": {"schema": True, "ir_resolved": True, "tf_validated": True, "tf_planned": True},
|
|
"freshness": {"age_days": 0, "max_age_days": 7},
|
|
"source": {"submitter": "spike", "commit_sha": "spike-sha", "signed": False},
|
|
"history": {"prior_rollbacks": 0, "prior_policy_fails": 0},
|
|
"nfrs": {"conformance": None},
|
|
}
|
|
sig = c.compute("$CONTRACT_ID", "dev", inputs)
|
|
print(json.dumps({"score": sig.score, "band": sig.band, "perInput": sig.perInput, "reasonCodes": sig.reasonCodes}, indent=2))
|
|
PY
|
|
BAND=$(python3 -c "import json; print(json.load(open('$WORK/signal.json'))['band'])")
|
|
SCORE=$(python3 -c "import json; print(round(json.load(open('$WORK/signal.json'))['score'],3))")
|
|
echo "confidence: score=$SCORE band=$BAND"
|
|
[ "$BAND" = "pass" ] || fail "confidence band is $BAND, expected pass for dev"
|
|
|
|
echo "=== Step 8: write evidence event to DynamoDB outbox ==="
|
|
python3 <<PY > "$WORK/event.json" || fail "event build failed"
|
|
import json, datetime
|
|
sig = json.load(open("$WORK/signal.json"))
|
|
event = {
|
|
"contractId": "$CONTRACT_ID",
|
|
"eventType": "CONFIDENCE_COMPUTED",
|
|
"ts": datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
|
"environment": "dev",
|
|
"stack": "l2-static-asset",
|
|
"score": sig["score"],
|
|
"band": sig["band"],
|
|
"prev_event_hash": "GENESIS",
|
|
}
|
|
print(json.dumps(event, indent=2))
|
|
PY
|
|
python3 acdl_platform/outbox_writer.py "$WORK/event.json" > "$WORK/outbox_item.json" || fail "outbox write failed"
|
|
echo "outbox: $(python3 -c "import json; d=json.load(open('$WORK/outbox_item.json')); print('contractId=', d['contractId'], 'hash=', d['hash'][:16]+'...')")"
|
|
|
|
echo ""
|
|
echo "=== PLATFORM E2E OK ==="
|
|
echo "contract=$CONTRACT -> IR -> terraform plan -> Checkov -> confidence ($BAND) -> outbox"
|
|
exit 0 |