"""Create the ACDL v1.1 spike AWS state backend (idempotent). - S3 bucket acdl-tfstate--us-east-1 (versioning enabled). - DynamoDB table acdl-outbox (PAY_PER_REQUEST; PK contractId, SK eventType#eventTs) — used for BOTH Terraform state locking AND the evidence outbox (D-P08-1). Run with the bootstrap root key in env: ACDL_BOOTSTRAP_AWS_ACCESS_KEY_ID / ACDL_BOOTSTRAP_AWS_SECRET_ACCESS_KEY AWS_DEFAULT_REGION (defaults to us-east-1) Writes terraform/bootstrap/.bootstrap_state.json (gitignored bookkeeping). Idempotent: re-running this script against an already-bootstrapped account exits 0 without duplicating resources. The S3 state bucket is guarded by a head_bucket probe (skips creation if it exists), bucket versioning is re-PUT on every run (PutBucketVersioning is itself idempotent), and the DynamoDB outbox table is guarded by a describe_table probe (skips creation on ResourceNotFoundException). The bootstrap-state marker file is always overwritten with the current run's timestamp (it is bookkeeping, not a resource). """ import datetime import json import os import sys import boto3 REGION = os.environ.get("AWS_DEFAULT_REGION", "us-east-1") STATE_BUCKET = "acdl-tfstate-581513795199-us-east-1" OUTBOX_TABLE = "acdl-outbox" ACCOUNT_ID = "581513795199" def main(): session = boto3.Session( aws_access_key_id=os.environ["ACDL_BOOTSTRAP_AWS_ACCESS_KEY_ID"], aws_secret_access_key=os.environ["ACDL_BOOTSTRAP_AWS_SECRET_ACCESS_KEY"], region_name=REGION, ) s3 = session.client("s3", region_name=REGION) dyn = session.client("dynamodb", region_name=REGION) # --- S3 state bucket (idempotent) --- try: s3.head_bucket(Bucket=STATE_BUCKET) print(f"s3: bucket {STATE_BUCKET} already exists") except Exception: kwargs = {"Bucket": STATE_BUCKET} if REGION != "us-east-1": kwargs["CreateBucketConfiguration"] = {"LocationConstraint": REGION} s3.create_bucket(**kwargs) print(f"s3: created bucket {STATE_BUCKET}") # Enable versioning (idempotent) s3.put_bucket_versioning( Bucket=STATE_BUCKET, VersioningConfiguration={"Status": "Enabled"}, ) print(f"s3: versioning enabled on {STATE_BUCKET}") # --- DynamoDB outbox table (idempotent) --- try: dyn.describe_table(TableName=OUTBOX_TABLE) print(f"dynamodb: table {OUTBOX_TABLE} already exists") except dyn.exceptions.ResourceNotFoundException: dyn.create_table( TableName=OUTBOX_TABLE, BillingMode="PAY_PER_REQUEST", AttributeDefinitions=[ {"AttributeName": "contractId", "AttributeType": "S"}, {"AttributeName": "eventType#eventTs", "AttributeType": "S"}, ], KeySchema=[ {"AttributeName": "contractId", "KeyType": "HASH"}, {"AttributeName": "eventType#eventTs", "KeyType": "RANGE"}, ], ) print(f"dynamodb: created table {OUTBOX_TABLE}") dyn.get_waiter("table_exists").wait(TableName=OUTBOX_TABLE) marker = { "account_id": ACCOUNT_ID, "bucket_name": STATE_BUCKET, "table_name": OUTBOX_TABLE, "region": REGION, "created_at": datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), } with open(os.path.join(os.path.dirname(__file__), ".bootstrap_state.json"), "w") as fh: json.dump(marker, fh, indent=2) print("bootstrap state marker written:", marker) if __name__ == "__main__": main()