0ca383dae6
Create run_codegen.sh (pre-TF: env check, validate, resolve, adapt). Create run_postapply.sh (post-TF: Checkov, confidence, HITL, outbox, SSM, uptime). Add variable 'enabled' (bool, default true) + count=var.enabled?1:0 to all 12 L1 modules (alb, cloudfront, ecr, ecs-cluster, ecs-service, iam-role, kms-key, rds, s3, uptime, vpc, waf). Fix all cross-resource references with [0] indexing. Update interface.json for all modules to declare 'enabled' input. Fix stale artifact path /tmp/acdl_platform_run_v18 → /tmp/nova_platform_run (REQ-238). run_platform.sh remains as backward-compat shim for local-dev usage. ---ci--- project: acdl phase: 4 milestone: v1.20 status: execute requirements: [REQ-233, REQ-234, REQ-235, REQ-236, REQ-237, REQ-238] ---/ci---
148 lines
4.9 KiB
Bash
Executable File
148 lines
4.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# scripts/run_codegen.sh — pre-Terraform codegen for the Nova platform pipeline.
|
||
#
|
||
# Performs steps 0–3b of run_platform.sh:
|
||
# 0. Environment onboarding check
|
||
# 1. Validate contract against contract.schema.json
|
||
# 2. Resolve contract → Target Stack instance (contract_resolver.py)
|
||
# 3. Adapter compiles stack → Terraform (adapter.py)
|
||
# 3b. Structural validation of emitted TF (offline)
|
||
#
|
||
# Emits Terraform files to $NOVA_WORK_DIR/tf/{main.tf,terraform.tf,providers.tf}
|
||
# and prints the work dir path for the caller (workflow or run_platform.sh)
|
||
# to use for native terraform init/validate/plan/apply steps.
|
||
#
|
||
# Usage:
|
||
# run_codegen.sh <contract.yml> [--environment <name>] [--check-only]
|
||
#
|
||
# When --check-only is passed, exits 0 after structural validation (no AWS).
|
||
# Otherwise, loads AWS credentials from .env.secrets if not already set,
|
||
# and exits 0 with the work dir ready for terraform.
|
||
#
|
||
set -euo pipefail
|
||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||
CALLER_CWD="$(pwd)"
|
||
cd "$ROOT"
|
||
|
||
CHECK_ONLY=0
|
||
ENVIRONMENT_OVERRIDE=""
|
||
CONTRACT=""
|
||
|
||
while [ $# -gt 0 ]; do
|
||
case "$1" in
|
||
--check-only) CHECK_ONLY=1; shift ;;
|
||
--environment) shift; ENVIRONMENT_OVERRIDE="$1"; shift ;;
|
||
--environment=*) ENVIRONMENT_OVERRIDE="${1#--environment=}"; shift ;;
|
||
-h|--help)
|
||
echo "Usage: run_codegen.sh <contract.yml> [--environment <name>] [--check-only]"
|
||
exit 0 ;;
|
||
*) CONTRACT="$1"; shift ;;
|
||
esac
|
||
done
|
||
|
||
[ -n "$CONTRACT" ] || { echo "FAIL: no contract file specified" >&2; exit 1; }
|
||
|
||
# Resolve relative contract path against caller's CWD
|
||
if ! [[ "$CONTRACT" = /* ]]; then
|
||
CONTRACT="$CALLER_CWD/$CONTRACT"
|
||
fi
|
||
[ -f "$CONTRACT" ] || { echo "FAIL: contract not found: $CONTRACT" >&2; exit 1; }
|
||
|
||
if [ -n "$ENVIRONMENT_OVERRIDE" ]; then
|
||
export NOVA_ENVIRONMENT_OVERRIDE="$ENVIRONMENT_OVERRIDE"
|
||
fi
|
||
|
||
CONTRACT_ID="${NOVA_CONTRACT_ID:-11111111-1111-1111-1111-111111111111}"
|
||
WORK="${NOVA_WORK_DIR:-/tmp/nova_platform_run}"
|
||
TF_DIR="$WORK/tf"
|
||
rm -rf "$WORK"; mkdir -p "$TF_DIR"
|
||
|
||
echo "=== Step 0: environment onboarding check ==="
|
||
if [ -n "$ENVIRONMENT_OVERRIDE" ]; then
|
||
python3 core/environment_check.py --env="$ENVIRONMENT_OVERRIDE" || {
|
||
echo "FAIL: environment onboarding check failed for $ENVIRONMENT_OVERRIDE" >&2
|
||
exit 1
|
||
}
|
||
else
|
||
python3 core/environment_check.py || true
|
||
fi
|
||
|
||
echo ""
|
||
echo "=== Step 1: validate contract against contract.schema.json ==="
|
||
python3 -c "
|
||
import json, sys, yaml
|
||
from jsonschema import validate
|
||
schema = json.load(open('schemas/contract.schema.json'))
|
||
doc = yaml.safe_load(open('$CONTRACT'))
|
||
validate(instance=doc, schema=schema)
|
||
print(f'contract valid: {doc.get(\"name\", \"unnamed\")} (env={doc.get(\"environment\",\"dev\")})')
|
||
"
|
||
|
||
echo ""
|
||
echo "=== Step 2: resolve contract → Target Stack instance ==="
|
||
python3 -c "
|
||
import json, sys
|
||
sys.path.insert(0, '$ROOT')
|
||
from core.contract_resolver import resolve
|
||
stack = resolve('$CONTRACT', environment_override='${ENVIRONMENT_OVERRIDE}' or None)
|
||
json.dump(stack, open('$WORK/stack.json', 'w'), indent=2)
|
||
print(f'stack resolved: {stack[\"stack\"][\"name\"]} ({len(stack[\"resources\"])} resource(s))')
|
||
"
|
||
|
||
echo ""
|
||
echo "=== Step 3: adapter compiles stack → $TF_DIR/*.tf ==="
|
||
python3 -c "
|
||
import json, sys
|
||
sys.path.insert(0, '$ROOT')
|
||
from adapters.terraform.adapter import TerraformAdapter
|
||
stack = json.load(open('$WORK/stack.json'))
|
||
adapter = TerraformAdapter()
|
||
adapter.compile(stack, '$TF_DIR')
|
||
print('adapter: main.tf + terraform.tf + providers.tf written')
|
||
"
|
||
|
||
if [ "$CHECK_ONLY" = "1" ]; then
|
||
echo ""
|
||
echo "=== Step 3b: validate adapter output structure (offline) ==="
|
||
python3 -c "
|
||
import json, os
|
||
d = json.load(open('$WORK/stack.json'))
|
||
assert d['stack']['name'], 'stack name missing'
|
||
assert len(d['resources']) >= 1, 'expected at least 1 resource'
|
||
tf_dir = '$TF_DIR'
|
||
for f in ('main.tf', 'terraform.tf', 'providers.tf'):
|
||
assert os.path.isfile(os.path.join(tf_dir, f)), f'{f} missing'
|
||
main = open(os.path.join(tf_dir, 'main.tf')).read()
|
||
assert len(main) > 0, 'main.tf is empty'
|
||
tf = open(os.path.join(tf_dir, 'terraform.tf')).read()
|
||
assert 'backend' in tf
|
||
assert 'required_version' in tf
|
||
prov = open(os.path.join(tf_dir, 'providers.tf')).read()
|
||
assert 'provider \"aws\"' in prov
|
||
print(f\"adapter output: OK ({d['stack']['name']}, {len(d['resources'])} resource(s))\")
|
||
"
|
||
echo ""
|
||
echo "=== CODEGEN CHECK OK ==="
|
||
echo "contract → resolver → stack → adapter → structure validated (offline, no AWS)"
|
||
echo "WORK_DIR=$WORK"
|
||
exit 0
|
||
fi
|
||
|
||
# Load AWS credentials if not already set (for non-check-only modes)
|
||
if [ -z "${AWS_ACCESS_KEY_ID:-}" ] || [ -z "${AWS_SECRET_ACCESS_KEY:-}" ]; then
|
||
ENV_FILE="$ROOT/.env.secrets"
|
||
if [ -f "$ENV_FILE" ]; then
|
||
set -a
|
||
. "$ENV_FILE"
|
||
set +a
|
||
export AWS_ACCESS_KEY_ID="$NOVA_AWS_ACCESS_KEY_ID"
|
||
export AWS_SECRET_ACCESS_KEY="$NOVA_AWS_SECRET_ACCESS_KEY"
|
||
export AWS_DEFAULT_REGION="$AWS_DEFAULT_REGION"
|
||
fi
|
||
fi
|
||
|
||
echo ""
|
||
echo "=== CODEGEN OK ==="
|
||
echo "Terraform files ready in: $TF_DIR"
|
||
echo "WORK_DIR=$WORK"
|