Files
acdl/terraform/platform
Jon Chery 0e6ecae26d feat(P4): Nova rebrand — AWS resource migration (REQ-163)
Rename all acdl-* AWS resources → nova-* across terraform (DynamoDB,
Secrets Manager, Lambda, SNS, SG, KMS alias, ECS, ECR, IAM user/policy,
state bucket, ALB, VPC/subnet names). Lambda default table names → nova-*
(D-111). State bucket backend → nova-tfstate (-migrate-state documented).
New docs/NOVA_AWS_MIGRATION.md runbook (staged migration + rollback).
New scripts/migrate_dynamodb_data.py (scan+copy, dry-run default).
acdl-deploy- → nova-deploy- role ARN in deploy workflows. Test fixtures
updated; terraform validate + pytest + run_ci.sh PASS.

---ci---
project: acdl
phase: 4
milestone: v1.15
status: execute
---/ci---
2026-07-30 01:54:26 +00:00
..

Nova Platform Infrastructure (D-051)

Terraform configuration for the platform-side infrastructure that ingests consumer deployment contracts and (Phase 25) reports errors as GitHub issues.

This stack is separate from terraform/spike/ (the consumer stack spike) and terraform/microservice/ (the demo microservice). It manages resources that live in the platform AWS account and serve all consumers — the contract ingestion pipeline and the secrets it needs.

What it deploys

Resource Name Purpose
aws_dynamodb_table nova-contracts Stores submitted consumer contracts. PK consumerRepo, SK contractId#submittedAt. SSE via CMK, PITR enabled.
aws_kms_key + aws_kms_alias alias/nova-platform Customer-managed key — encrypts DynamoDB SSE, Secrets Manager, and SSM. Key rotation enabled.
aws_secretsmanager_secret nova/github-token GitHub PAT used by the Lambda to create issues on the platform repo (D-055, wired in Phase 25).
aws_iam_role + aws_iam_role_policy nova-contract-ingestor-role Execution role for the Lambda — DynamoDB write, Secrets Manager read, KMS decrypt, CloudWatch logs.
aws_lambda_function nova-contract-ingestor Python 3.12 Lambda. Handler contract_ingestor.lambda_handler. Source: core/lambda/contract_ingestor.py, packaged as contract_ingestor.zip.
aws_lambda_function_url Function URL with AWS_IAM authorization. Consumers invoke it via SigV4-signed requests.

State

Key Value
Backend S3
Bucket nova-tfstate-581513795199-us-east-1
State key platform/terraform.tfstate
Region us-east-1

The state key is distinct from spike/terraform.tfstate and microservice/terraform.tfstate — the three stacks are independent.

Apply

# Package the Lambda source first (from the repo root):
cd core/lambda
zip contract_ingestor.zip contract_ingestor.py
cd ../../terraform/platform

terraform init
terraform plan
terraform apply

The Lambda's filename points at contract_ingestor.zip in the working directory (terraform/platform/); either place the zip there or adjust the path. source_code_hash = filebase64sha256("contract_ingestor.zip") forces a redeploy whenever the package changes.

Cross-account invocation model

The Lambda is invoked cross-account by consumer pipelines. The flow:

  1. Onboarding. When a consumer repo is onboarded, the platform team applies consumer_invoke_policy.json to the consumer's deploy role. The policy grants lambda:InvokeFunctionUrl on the Lambda ARN, scoped via ABAC — the condition aws:PrincipalTag/nova:owner == ${consumerRepo} ensures a repo can only invoke when it is the owner it claims to be.
  2. Runtime. The consumer's deploy workflow (running in the consumer AWS account under the consumer's deploy role) signs the Function URL request with SigV4 using its deploy-role credentials. The IAM auth on the Function URL validates the signature and the ABAC condition.
  3. Lambda. The Lambda parses the JSON body, validates the fields, and writes the contract to nova-contracts.

This is a one-way channel (D-051): the consumer pushes contracts to the platform; the platform never reaches back into the consumer account. Error reporting (D-055, action: "report_error") flows over the same channel and is implemented in Phase 25 (GitHub issue creation on the platform repo).