#!/usr/bin/env bash # scripts/run_lifecycle_test.sh — run a single L1 module lifecycle test. # # Usage: run_lifecycle_test.sh [ci-vpc-outputs.json] # # This script wraps run_platform.sh for the modules-lifecycle pipeline. # If the module is VPC-dependent and a ci-vpc-outputs.json is provided, # it generates a temporary contract with the CI VPC outputs injected. # # The CI VPC is short-lived (created/destroyed by the pipeline), separate # from the long-lived platform VPC. # # Lifecycle mode (REQ-134): the ACDL_LIFECYCLE_MODE env var selects the # tier. Default "plan" runs `run_platform.sh --plan-only` (fast, no AWS # mutation, validates the contract->resolver->adapter->plan chain for # every module). Set to "full" to run the real `--apply` (terraform apply # against live AWS). The CI variable is passed via the workflow input # `lifecycle_mode`. set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "$ROOT" MODULE="$1" EXAMPLE="$2" # simple or complex CI_VPC_OUTPUTS="${3:-}" # Lifecycle mode: "plan" (default, fast) or "full" (real apply against AWS). LIFECYCLE_MODE="${ACDL_LIFECYCLE_MODE:-plan}" CONTRACT="modules/l1/${MODULE}/examples/${EXAMPLE}.yml" # VPC-dependent modules that need CI VPC outputs injected VPC_DEPENDENT="alb ecs-service rds uptime" # If the module is VPC-dependent and we have CI VPC outputs, inject them # (only meaningful in full mode; plan mode ignores VPC outputs) if [ "$LIFECYCLE_MODE" = "full" ] && echo "$VPC_DEPENDENT" | grep -qw "$MODULE" && [ -n "$CI_VPC_OUTPUTS" ] && [ -f "$CI_VPC_OUTPUTS" ]; then # Generate a temporary contract with CI VPC outputs injected TMP_CONTRACT="/tmp/acdl-lifecycle-${MODULE}-${EXAMPLE}.yml" python3 -c " import yaml, json, sys # Load the original contract with open('$CONTRACT') as f: contract = yaml.safe_load(f) # Load CI VPC outputs (terraform output -json format: {key: {value: ...}}) with open('$CI_VPC_OUTPUTS') as f: raw = json.load(f) vpc = {k: v['value'] if isinstance(v, dict) and 'value' in v else v for k, v in raw.items()} vpc_id = vpc.get('vpc_id', '') subnet_ids = vpc.get('subnet_ids', '') sg_id = vpc.get('ecs_security_group_id', '') cluster_arn = vpc.get('cluster_arn', '') module_name = '$MODULE' inputs = contract['infrastructure'][module_name]['inputs'] # Inject VPC-dependent inputs based on the module if module_name == 'alb': inputs['subnets'] = subnet_ids inputs['vpc_id'] = vpc_id inputs['security_group'] = sg_id elif module_name == 'ecs-service': inputs['subnets'] = subnet_ids inputs['security_group'] = sg_id inputs['cluster_arn'] = cluster_arn elif module_name == 'rds': inputs['subnet_ids'] = subnet_ids elif module_name == 'uptime': inputs['subnets'] = subnet_ids inputs['security_group'] = sg_id inputs['cluster_arn'] = cluster_arn with open('$TMP_CONTRACT', 'w') as f: yaml.dump(contract, f) print('$TMP_CONTRACT') " CONTRACT="$TMP_CONTRACT" fi # Run the platform lifecycle command (plan-only by default; full = apply). if [ "$LIFECYCLE_MODE" = "full" ]; then bash scripts/run_platform.sh --apply "$CONTRACT" else bash scripts/run_platform.sh --plan-only "$CONTRACT" fi