refactor(modules): remove thin-composition layer; rewrite all module READMEs

The L2 thin-composition layer (composition.json + contract_resolver.py +
contract schema + sample contracts) has been removed completely. The
implementation was unsatisfactory and is deferred for a later redesign.

- Delete: composition.json x2, contract_resolver.py, contracts/ x2,
  contract.schema.json
- Patch: run_platform.sh now loads a pre-existing IR instance instead of
  resolving a contract (the downstream adapter/checkov/confidence/outbox
  pipeline is unchanged)
- Prune: L2 entries removed from registry.json (L1 entries unchanged)
- Rewrite: all 7 L1 module READMEs in plain language (no jargon), each
  with Resources/Inputs/Outputs/Usage/Compliance-extension-points/Versioning
  sections derived from interface.json
- Add: 2 L2 placeholder READMEs noting the composition is under redesign
- Add: modules-ir/README.md catalog index + README-TEMPLATE.md

---ci---
project: acdl
phase: 17
milestone: v1.3
status: execute
---/ci---
This commit is contained in:
Jon Chery
2026-07-22 13:54:40 +00:00
parent f874879973
commit 3508671377
19 changed files with 565 additions and 767 deletions
+57 -42
View File
@@ -1,55 +1,70 @@
# l1-alb — Application Load Balancer primitive (multi-resource L1)
# l1-alb — Application Load Balancer (load balancer + target group + listener)
An L1 module for an Application Load Balancer (load balancer + target
group + listener). Substrate-agnostic (the IR types are
`aws:elbv2:loadbalancer`, `aws:elbv2:listener`, `aws:elbv2:targetgroup`,
not Terraform resource types). This is a multi-resource L1: the
interface declares the group's inputs/outputs plus a `resources` array
listing the IR types it emits. The IR instance (Phase 14/15) will have
multiple `resources` entries all with `module: "l1-alb@1.0.0"`.
> **Module kind:** L1 primitive | **Version:** 1.0.0
## Interface (the IR-typed contract)
An Application Load Balancer with a target group and a listener. This is
a multi-resource module: it creates a load balancer, a target group, and
a listener that forwards traffic to the target group. The target group
is what `l1-ecs-service` registers its tasks with.
See `interface.json`: inputs `name` (string), `subnets` (string,
comma-separated, ref to l1-vpc), `security_group` (string), `port`
(number, default 80), `protocol` (string, default "HTTP"), `region`
(string); outputs `lb_arn` (arn) + `listener_arn` (arn) +
`target_group_arn` (arn); no NFRs.
## Resources
The `resources` array lists the emitted IR types:
| Resource | Type | Purpose |
|----------|------|---------|
| load_balancer | `aws_lb` | Application load balancer in the VPC subnets |
| target_group | `aws_lb_target_group` | Target group for the ECS service tasks |
| listener | `aws_lb_listener` | Listener forwarding the LB port to the target group |
- `aws:elbv2:loadbalancer` — application load balancer in the VPC
subnets.
- `aws:elbv2:targetgroup` — target group for the ECS service tasks.
- `aws:elbv2:listener` — listener forwarding the LB port to the target
group.
## Inputs
## IR → Terraform mapping (performed by the adapter)
| Name | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `name` | string | yes | — | Name tag for the load balancer and child resources |
| `subnets` | string | yes | — | Comma-separated subnet ids (from `l1-vpc`) |
| `security_group` | string | yes | — | Security group id for the load balancer |
| `port` | number | no | 80 | Listener port |
| `protocol` | string | no | `HTTP` | Listener protocol |
| `region` | string | yes | — | AWS region the load balancer is created in |
The Terraform adapter (`adapters/terraform/adapter.py`) translates each
emitted IR resource to Terraform:
## Outputs
| IR | Terraform |
|----|-----------|
| `resource.type = aws:elbv2:loadbalancer` | `resource "aws_lb" "<id>" { ... }` |
| `resource.inputs.name` | `name = <value>` arg |
| `resource.inputs.subnets` | `subnets = [<value>]` arg (comma-split) |
| `resource.inputs.security_group` | `security_groups = [<value>]` arg (comma-split) |
| `resource.outputs.lb_arn` | `output "lb_arn" { value = aws_lb.<id>.id }` |
| `resource.type = aws:elbv2:targetgroup` | `resource "aws_lb_target_group" "<id>" { ... }` |
| `resource.inputs.port` | `port = <value>` arg |
| `resource.inputs.protocol` | `protocol = <value>` arg |
| `resource.outputs.target_group_arn` | `output "target_group_arn" { value = aws_lb_target_group.<id>.arn }` |
| `resource.type = aws:elbv2:listener` | `resource "aws_lb_listener" "<id>" { ... }` |
| `resource.inputs.lb_arn` | `load_balancer_arn = <value>` arg (identity) |
| `resource.inputs.port` | `port = <value>` arg |
| `resource.inputs.protocol` | `protocol = <value>` arg |
| `resource.outputs.listener_arn` | `output "listener_arn" { value = aws_lb_listener.<id>.id }` |
| Name | Type | Description |
|------|------|-------------|
| `lb_arn` | arn | The load balancer ARN |
| `listener_arn` | arn | The listener ARN |
| `target_group_arn` | arn | The target group ARN |
The adapter is a thin layer (ARCHITECTURE.md §12.2); it does not own L1
content — it only translates.
## Usage
## Versioning (W3.D)
```json
{
"id": "alb",
"type": "aws:elbv2:loadbalancer",
"module": "l1-alb@1.0.0",
"inputs": {
"name": "acdl-microservice",
"subnets": "ref:vpc.subnet_ids",
"security_group": "ref:roles.role_arn",
"port": 8080,
"protocol": "HTTP",
"region": "us-east-1"
}
}
```
The `target_group_arn` output is referenced by `l1-ecs-service` as its
`lb_target_group_arn` input to wire the service to the ALB.
## Compliance extension points
- **TLS / HTTPS listener** — add `aws_acm_certificate` + `ssl_policy` + `certificate_arn` for encryption in transit (SOC2 CC6.1, PCI-DSS 4.1, HIPAA §164.312(e)(1), GDPR Art.32).
- **Access logs** — add `access_logs { bucket = ..., prefix = ... }` to the load balancer (SOX, SOC2 CC7.2, DORA ICT audit trail).
- **Security group rules** — add ingress/egress rules restricting traffic to known sources (SOC2 CC6.6, PCI-DSS 1.2).
- **Health check** — add a `health_check` block to the target group (SOC2 CC7.3 monitoring, DORA operational resilience).
- **WAF** — add `aws_wafv2_web_acl_association` for application-layer protection (SOC2 CC7.6, PCI-DSS 6.5, DORA ICT risk).
- **Deregistration delay** — add `deregistration_delay` for graceful draining (SOC2 CC9.1 resilience).
## Versioning
`1.0.0` — interface MAJOR, behavior MINOR, lifecycle PATCH. MAJOR bumps
require a new registry entry (immutable publication); old entries enter
+46 -20
View File
@@ -1,31 +1,57 @@
# l1-ecr — ECR repository primitive
# l1-ecr — ECR repository
An L1 module for an ECR repository that hosts the ECS task image.
Single-purpose, substrate-agnostic (the IR type is
`aws:ecr:repository`, not a Terraform resource type).
> **Module kind:** L1 primitive | **Version:** 1.0.0
## Interface (the IR-typed contract)
A single ECR repository that hosts the container image for the ECS
task. The simplest container-registry module — one resource, two
inputs, two outputs.
See `interface.json`: inputs `name` + `region` (strings), outputs
`repository_url` (string) + `repository_arn` (arn), no NFRs.
## Resources
## IR → Terraform mapping (performed by the adapter)
| Resource | Type | Purpose |
|----------|------|---------|
| repository | `aws_ecr_repository` | The ECR repository |
The Terraform adapter (`adapters/terraform/adapter.py`) translates this
L1's IR shape to Terraform:
## Inputs
| IR | Terraform |
|----|-----------|
| `resource.type = aws:ecr:repository` | `resource "aws_ecr_repository" "<id>" { ... }` |
| `resource.inputs.name` | `name = <value>` arg |
| `resource.inputs.region` | `provider "aws" { region = <value> }` |
| `resource.outputs.repository_url` | `output "repository_url" { value = aws_ecr_repository.<id>.repository_url }` |
| `resource.outputs.repository_arn` | `output "repository_arn" { value = aws_ecr_repository.<id>.arn }` |
| Name | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `name` | string | yes | — | The ECR repository name |
| `region` | string | yes | — | AWS region the repository is created in |
The adapter is a thin layer (ARCHITECTURE.md §12.2); it does not own L1
content — it only translates.
## Outputs
## Versioning (W3.D)
| Name | Type | Description |
|------|------|-------------|
| `repository_url` | string | The ECR repository URL |
| `repository_arn` | arn | The ECR repository ARN |
## Usage
```json
{
"id": "ecr",
"type": "aws:ecr:repository",
"module": "l1-ecr@1.0.0",
"inputs": {
"name": "acdl-microservice",
"region": "us-east-1"
}
}
```
The `repository_url` output is used to build the `image` input for
`l1-ecs-service` (e.g. `<repository_url>:latest`).
## Compliance extension points
- **Image scanning** — add `image_scanning_configuration { scan_on_push = true }` for vulnerability scanning (SOC2 CC7.6, DORA ICT risk testing, HIPAA security monitoring).
- **Encryption** — add `encryption_configuration { encryption_type = "KMS", kms_key = ... }` with a customer-managed key (SOC2 CC6.1, HIPAA §164.312(a)(2)(iv), GDPR Art.32).
- **Image tag immutability** — add `image_tag_mutability = "IMMUTABLE"` to prevent tag overwriting (SOX §802, SOC2 CC6.1 integrity, DORA audit integrity).
- **Lifecycle policy** — add `aws_ecr_lifecycle_policy` to enforce image retention / cleanup (GDPR Art.5(2) data minimization, SOC2 CC5.2).
- **Access policy** — add a repository policy restricting pull/push to known roles (SOC2 CC6.1, HIPAA §164.308(a)(4)).
## Versioning
`1.0.0` — interface MAJOR, behavior MINOR, lifecycle PATCH. MAJOR bumps
require a new registry entry (immutable publication); old entries enter
+44 -20
View File
@@ -1,31 +1,55 @@
# l1-ecs-cluster — ECS Fargate cluster primitive
# l1-ecs-cluster — ECS Fargate cluster
An L1 module for an ECS Fargate cluster. Single-purpose,
substrate-agnostic (the IR type is `aws:ecs:cluster`, not a Terraform
resource type).
> **Module kind:** L1 primitive | **Version:** 1.0.0
## Interface (the IR-typed contract)
An ECS Fargate cluster. The simplest ECS module — one resource, two
inputs, two outputs. The cluster is the container orchestration
boundary that `l1-ecs-service` references for task placement.
See `interface.json`: inputs `name` + `region` (strings), outputs
`cluster_arn` (arn) + `cluster_id` (string), no NFRs.
## Resources
## IR → Terraform mapping (performed by the adapter)
| Resource | Type | Purpose |
|----------|------|---------|
| cluster | `aws_ecs_cluster` | The ECS Fargate cluster |
The Terraform adapter (`adapters/terraform/adapter.py`) translates this
L1's IR shape to Terraform:
## Inputs
| IR | Terraform |
|----|-----------|
| `resource.type = aws:ecs:cluster` | `resource "aws_ecs_cluster" "<id>" { ... }` |
| `resource.inputs.name` | `name = <value>` arg |
| `resource.inputs.region` | `provider "aws" { region = <value> }` |
| `resource.outputs.cluster_arn` | `output "cluster_arn" { value = aws_ecs_cluster.<id>.arn }` |
| `resource.outputs.cluster_id` | `output "cluster_id" { value = aws_ecs_cluster.<id>.id }` |
| Name | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `name` | string | yes | — | The ECS cluster name |
| `region` | string | yes | — | AWS region the cluster is created in |
The adapter is a thin layer (ARCHITECTURE.md §12.2); it does not own L1
content — it only translates.
## Outputs
## Versioning (W3.D)
| Name | Type | Description |
|------|------|-------------|
| `cluster_arn` | arn | The ECS cluster ARN |
| `cluster_id` | string | The ECS cluster id (name) |
## Usage
```json
{
"id": "cluster",
"type": "aws:ecs:cluster",
"module": "l1-ecs-cluster@1.0.0",
"inputs": {
"name": "acdl-microservice",
"region": "us-east-1"
}
}
```
The `cluster_arn` output is referenced by `l1-ecs-service` as its
`cluster_arn` input.
## Compliance extension points
- **Container Insights** — add `configuration { container_insights = "enabled" }` for observability (SOC2 CC7.3, DORA ICT risk monitoring).
- **CloudWatch Logs** — add a log group with retention policy for cluster-level audit logs (SOX, SOC2 CC7.2, HIPAA §164.312(b)).
- **Encryption** — add `settings { name = "containerInsights", value = "enabled" }` and KMS-based encryption for container data (HIPAA §164.312(a)(2)(iv), GDPR Art.32).
## Versioning
`1.0.0` — interface MAJOR, behavior MINOR, lifecycle PATCH. MAJOR bumps
require a new registry entry (immutable publication); old entries enter
+64 -41
View File
@@ -1,54 +1,77 @@
# l1-ecs-service — ECS Fargate service primitive (multi-resource L1)
# l1-ecs-service — ECS Fargate service (task definition + service)
An L1 module for an ECS Fargate service (task definition + service).
Substrate-agnostic (the IR types are `aws:ecs:task_definition` and
`aws:ecs:service`, not Terraform resource types). This is a
multi-resource L1: the interface declares the group's inputs/outputs
plus a `resources` array listing the IR types it emits. The IR instance
(Phase 14/15) will have multiple `resources` entries all with
`module: "l1-ecs-service@1.0.0"`.
> **Module kind:** L1 primitive | **Version:** 1.0.0
## Interface (the IR-typed contract)
An ECS Fargate service with its task definition. Runs a container image
on Fargate, optionally behind an ALB target group. This is a
multi-resource module: it creates a task definition and a service that
runs it.
See `interface.json`: inputs `image` (string, ECR image URL), `port`
(number), `cpu` (number, default 256), `memory` (number, default 512),
`env` (optional JSON map string), `cluster_arn` (arn, ref to
l1-ecs-cluster), `subnets` (string, ref to l1-vpc), `security_group`
(string), `lb_target_group_arn` (arn, optional, ref to l1-alb), `region`
(string); outputs `service_arn` (arn) + `task_def_arn` (arn); no NFRs.
## Resources
The `resources` array lists the emitted IR types:
| Resource | Type | Purpose |
|----------|------|---------|
| task_definition | `aws_ecs_task_definition` | Fargate task definition with container image, CPU, memory, port, env |
| service | `aws_ecs_service` | Fargate service running the task definition in a cluster + subnets |
- `aws:ecs:task_definition` — Fargate task definition. The adapter
jsonencodes `image`/`port`/`env` into `container_definitions`.
- `aws:ecs:service` — Fargate service running the task definition in the
cluster + subnets (+ optional ALB target group wiring).
## Inputs
## IR → Terraform mapping (performed by the adapter)
| Name | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `image` | string | yes | — | ECR image URL for the task container |
| `port` | number | yes | — | Container port the service listens on |
| `cpu` | number | no | 256 | Task CPU units (Fargate) |
| `memory` | number | no | 512 | Task memory in MiB (Fargate) |
| `env` | string | no | — | Environment variables as a JSON map string |
| `cluster_arn` | arn | yes | — | ECS cluster ARN (from `l1-ecs-cluster`) |
| `subnets` | string | yes | — | Comma-separated subnet ids (from `l1-vpc`) |
| `security_group` | string | yes | — | Security group id for the service ENIs |
| `lb_target_group_arn` | arn | no | — | Optional ALB target group ARN (from `l1-alb`) |
| `region` | string | yes | — | AWS region the service is created in |
The Terraform adapter (`adapters/terraform/adapter.py`) translates each
emitted IR resource to Terraform:
## Outputs
| IR | Terraform |
|----|-----------|
| `resource.type = aws:ecs:task_definition` | `resource "aws_ecs_task_definition" "<id>" { ... }` |
| `resource.inputs.image` + `port` + `env` | `container_definitions = jsonencode(...)` (adapter-built) |
| `resource.inputs.cpu` | `cpu = <value>` arg |
| `resource.inputs.memory` | `memory = <value>` arg |
| `resource.outputs.task_def_arn` | `output "task_def_arn" { value = aws_ecs_task_definition.<id>.arn }` |
| `resource.type = aws:ecs:service` | `resource "aws_ecs_service" "<id>" { ... }` |
| `resource.inputs.cluster_arn` | `cluster = <value>` arg (identity) |
| `resource.inputs.subnets` | `network_configuration { subnets = [...] }` (emit as-is) |
| `resource.inputs.security_group` | `network_configuration { security_groups = [...] }` (emit as-is) |
| `resource.inputs.lb_target_group_arn` | `load_balancer { target_group_arn = <value> }` (emit as-is) |
| `resource.outputs.service_arn` | `output "service_arn" { value = aws_ecs_service.<id>.id }` |
| Name | Type | Description |
|------|------|-------------|
| `service_arn` | arn | The ECS service ARN |
| `task_def_arn` | arn | The ECS task definition ARN |
The adapter is a thin layer (ARCHITECTURE.md §12.2); it does not own L1
content — it only translates. The `container_definitions` JSON is built
by the adapter from the IR `image`/`port`/`env` inputs (the one
transformation the adapter owns for ECS task definitions).
## Usage
## Versioning (W3.D)
```json
{
"id": "service",
"type": "aws:ecs:task_definition",
"module": "l1-ecs-service@1.0.0",
"inputs": {
"image": "581513795199.dkr.ecr.us-east-1.amazonaws.com/acdl-microservice:latest",
"port": 8080,
"cpu": 256,
"memory": 512,
"cluster_arn": "ref:cluster.cluster_arn",
"subnets": "ref:vpc.subnet_ids",
"security_group": "ref:roles.role_arn",
"region": "us-east-1"
}
}
```
The `image`, `port`, and `env` inputs are compiled into a
`container_definitions` JSON block by the adapter. The service is
placed in the cluster with the given subnets and security group, and
optionally wired to the ALB target group if `lb_target_group_arn` is
provided.
## Compliance extension points
- **CloudWatch Logs** — add `logConfiguration` to the container definition with a log group + retention policy (SOX, SOC2 CC7.2, HIPAA §164.312(b), DORA ICT incident logging).
- **Task execution role separation** — add a separate `aws_iam_role` for execution vs. the task role (SOC2 CC6.3 segregation of duties at runtime).
- **Secrets injection** — add `secrets` block referencing AWS Secrets Manager / SSM Parameter Store with KMS encryption (SOC2 CC6.1, HIPAA §164.312(a)(2)(iv)).
- **Execute command** — add `enable_execute_command` with KMS encryption for session audit (SOC2 CC7.2).
- **Deployment circuit breaker** — add `deployment_circuit_breaker` block for resilience (SOC2 CC9.1, DORA operational resilience).
- **Health check** — add a `health_check` block to the target group (currently missing despite the contract schema having a healthcheck field).
## Versioning
`1.0.0` — interface MAJOR, behavior MINOR, lifecycle PATCH. MAJOR bumps
require a new registry entry (immutable publication); old entries enter
+52 -24
View File
@@ -1,35 +1,63 @@
# l1-iam-role — IAM role primitive
# l1-iam-role — IAM role
An L1 module for an IAM role (used as the ECS task execution role).
Single-purpose, substrate-agnostic (the IR type is `aws:iam:role`, not a
Terraform resource type).
> **Module kind:** L1 primitive | **Version:** 1.0.0
## Interface (the IR-typed contract)
A single IAM role with an assume-role policy and optional managed
policy attachments. Used as the ECS task execution role.
See `interface.json`: inputs `role_name` (string), `assume_role_policy`
(JSON string), `managed_policies` (optional comma-separated ARNs),
`region` (string); outputs `role_arn` (arn) + `role_id` (string), no
NFRs.
## Resources
## IR → Terraform mapping (performed by the adapter)
| Resource | Type | Purpose |
|----------|------|---------|
| role | `aws_iam_role` | The IAM role with assume-role policy |
The Terraform adapter (`adapters/terraform/adapter.py`) translates this
L1's IR shape to Terraform:
## Inputs
| IR | Terraform |
|----|-----------|
| `resource.type = aws:iam:role` | `resource "aws_iam_role" "<id>" { ... }` |
| `resource.inputs.role_name` | `name = <value>` arg |
| `resource.inputs.assume_role_policy` | `assume_role_policy = <value>` arg (JSON string) |
| `resource.inputs.managed_policies` | `managed_policy_arns = [<arns>]` arg (comma-split) |
| `resource.inputs.region` | `provider "aws" { region = <value> }` |
| `resource.outputs.role_arn` | `output "role_arn" { value = aws_iam_role.<id>.arn }` |
| `resource.outputs.role_id` | `output "role_id" { value = aws_iam_role.<id>.id }` |
| Name | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `role_name` | string | yes | — | The IAM role name |
| `assume_role_policy` | string | yes | — | Assume-role policy document (JSON string) |
| `managed_policies` | string | no | — | Comma-separated list of managed policy ARNs to attach |
| `region` | string | yes | — | AWS region the role is created in |
The adapter is a thin layer (ARCHITECTURE.md §12.2); it does not own L1
content — it only translates.
## Outputs
## Versioning (W3.D)
| Name | Type | Description |
|------|------|-------------|
| `role_arn` | arn | The IAM role ARN |
| `role_id` | string | The IAM role id |
## Usage
```json
{
"id": "roles",
"type": "aws:iam:role",
"module": "l1-iam-role@1.0.0",
"inputs": {
"role_name": "acdl-microservice-exec",
"assume_role_policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ecs-tasks.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}",
"managed_policies": "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy",
"region": "us-east-1"
}
}
```
The `assume_role_policy` is a JSON string — the adapter jsonencodes it
into the Terraform `assume_role_policy` argument. The
`managed_policies` input is a comma-separated list of ARNs, emitted as
`managed_policy_arns = [...]`.
## Compliance extension points
- **Permissions boundary** — add `permissions_boundary` to enforce least-privilege guardrails (SOC2 CC6.1, SOX ITGC, DORA ICT access control).
- **Inline policy** — add `aws_iam_role_policy` for fine-grained least-privilege instead of broad managed policies (SOC2 CC6.1, HIPAA §164.308(a)(4)).
- **MFA conditions** — add `condition` blocks requiring MFA for assume-role (SOC2 CC6.1, HIPAA §164.312(d)).
- **Source IP / region conditions** — add `aws:SourceIp` / `aws:RequestedRegion` conditions for data residency enforcement (GDPR Art.44-49, DORA ICT third-party risk).
- **Access Analyzer** — add `aws_accessanalyzer_analyzer` to verify least-privilege (SOC2 CC6.1, GDPR Art.32).
- **Role separation** — add a separate task role vs. execution role (SOC2 CC6.3 segregation of duties).
## Versioning
`1.0.0` — interface MAJOR, behavior MINOR, lifecycle PATCH. MAJOR bumps
require a new registry entry (immutable publication); old entries enter
+49 -26
View File
@@ -1,39 +1,62 @@
# l1-s3 — S3 bucket primitive
# l1-s3 — S3 bucket
The first real L1 module for the v1.1 spike. Single-purpose,
substrate-agnostic (the IR type is `aws:s3:bucket`, not a Terraform
resource type).
> **Module kind:** L1 primitive | **Version:** 1.0.0
## Interface (the IR-typed contract)
A single S3 bucket for object storage. The simplest module — one
resource, two inputs, two outputs. Versioning is enabled by default.
See `interface.json`: inputs `bucket_name` + `region` (strings), outputs
`bucket_arn` (arn) + `bucket_name` (string), NFR `versioning` (bool,
default true).
## Resources
## IR → Terraform mapping (performed by the adapter)
| Resource | Type | Purpose |
|----------|------|---------|
| bucket | `aws_s3_bucket` | The S3 bucket itself |
The Terraform adapter (`adapters/terraform/adapter.py`) translates this
L1's IR shape to Terraform:
## Inputs
| IR | Terraform |
|----|-----------|
| `resource.type = aws:s3:bucket` | `resource "aws_s3_bucket" "<id>" { ... }` |
| `resource.inputs.bucket_name` | `bucket = <value>` arg |
| `resource.inputs.region` | `provider "aws" { region = <value> }` |
| `resource.outputs.bucket_arn` | `output "bucket_arn" { value = aws_s3_bucket.<id>.arn }` |
| `resource.outputs.bucket_name` | `output "bucket_name" { value = aws_s3_bucket.<id>.id }` |
| Name | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `bucket_name` | string | yes | — | Globally-unique S3 bucket name |
| `region` | string | yes | — | AWS region the bucket is created in |
The adapter is a thin layer (ARCHITECTURE.md §12.2); it does not own L1
content — it only translates.
## Outputs
## Spike instance
| Name | Type | Description |
|------|------|-------------|
| `bucket_arn` | arn | The S3 bucket ARN |
| `bucket_name` | string | The bucket name (echoes the input) |
`spike_instance.json` is a concrete stack instance (with values
`bucket_name=acdl-spike-bucket`, `region=us-east-1`) that validates
against `schemas/ir.schema.json`. The adapter consumes this instance
(not the interface contract) to emit Terraform.
## NFRs
## Versioning (W3.D)
| Name | Type | Default | Description |
|------|------|---------|-------------|
| `versioning` | boolean | true | Enable S3 versioning |
## Usage
```json
{
"id": "s3",
"type": "aws:s3:bucket",
"module": "l1-s3@1.0.0",
"inputs": {
"bucket_name": "acdl-spike-bucket",
"region": "us-east-1"
}
}
```
A concrete instance is at `spike_instance.json` (used by the platform
pipeline as the regression baseline).
## Compliance extension points
- **Encryption at rest** — add `aws_s3_bucket_server_side_encryption_configuration` with a customer-managed KMS key (SOC2 CC6.1, HIPAA §164.312(a)(2)(iv), GDPR Art.32).
- **Object Lock** — add `aws_s3_bucket_object_lock_configuration` in compliance mode with 7-year retention for immutable evidence (SOX §802, DORA audit trail).
- **Access logging** — add `aws_s3_bucket_logging` to a target logging bucket (SOC2 CC7.2).
- **Public access block** — add `aws_s3_bucket_public_access_block` to prevent data exfiltration (SOC2 CC6.1, GDPR Art.32).
- **Lifecycle policy** — add `aws_s3_bucket_lifecycle_configuration` for retention enforcement (GDPR Art.5(2), HIPAA §164.530(j)).
## Versioning
`1.0.0` — interface MAJOR, behavior MINOR, lifecycle PATCH. MAJOR bumps
require a new registry entry (immutable publication); old entries enter
+53 -38
View File
@@ -1,51 +1,66 @@
# l1-vpc — VPC primitive (multi-resource L1)
# l1-vpc — VPC with subnets and routing
An L1 module for a VPC with subnets and a route table. Substrate-agnostic
(the IR types are `aws:ec2:vpc`, `aws:ec2:subnet`, `aws:ec2:routetable`,
not Terraform resource types). This is a multi-resource L1: the
interface declares the group's inputs/outputs plus a `resources` array
listing the IR types it emits. The IR instance (Phase 14/15) will have
multiple `resources` entries all with `module: "l1-vpc@1.0.0"`.
> **Module kind:** L1 primitive | **Version:** 1.0.0
## Interface (the IR-typed contract)
A VPC with one subnet per availability zone and a route table with a
default route through an internet gateway. The networking foundation
that other modules (ALB, ECS service) reference for subnet ids.
See `interface.json`: inputs `cidr` (string, e.g. "10.0.0.0/16"), `azs`
(string, comma-separated, e.g. "us-east-1a,us-east-1b"), `name` (string,
used for tagging), `region` (string); outputs `vpc_id` (string),
`subnet_ids` (string, comma-separated), `igw_id` (string); no NFRs.
## Resources
The `resources` array lists the emitted IR types:
| Resource | Type | Purpose |
|----------|------|---------|
| vpc | `aws_vpc` | The VPC itself |
| subnet | `aws_subnet` | One subnet per availability zone |
| route_table | `aws_route_table` | Route table with default route 0.0.0.0/0 |
| internet_gateway | `aws_internet_gateway` | IGW for public internet access |
| route_table_association | `aws_route_table_association` | Binds subnet to route table |
- `aws:ec2:vpc` — the VPC itself (cidr → cidr_block, name → tag).
- `aws:ec2:subnet` — one subnet per availability zone (`azs` split on
comma); inputs include the parent VPC id.
- `aws:ec2:routetable` — route table bound to the VPC with an internet
gateway + default route (0.0.0.0/0 → igw).
## Inputs
## IR → Terraform mapping (performed by the adapter)
| Name | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `cidr` | string | yes | — | VPC CIDR block, e.g. `10.0.0.0/16` |
| `azs` | string | yes | — | Comma-separated availability zones, e.g. `us-east-1a,us-east-1b` |
| `name` | string | yes | — | Name tag for the VPC and child resources |
| `region` | string | yes | — | AWS region the VPC is created in |
The Terraform adapter (`adapters/terraform/adapter.py`) translates each
emitted IR resource to Terraform:
## Outputs
| IR | Terraform |
|----|-----------|
| `resource.type = aws:ec2:vpc` | `resource "aws_vpc" "<id>" { ... }` |
| `resource.inputs.cidr` | `cidr_block = <value>` arg |
| `resource.inputs.name` | `tags = { Name = <value> }` (emit as-is) |
| `resource.outputs.vpc_id` | `output "vpc_id" { value = aws_vpc.<id>.id }` |
| `resource.type = aws:ec2:subnet` | `resource "aws_subnet" "<id>" { ... }` |
| `resource.inputs.cidr` | `cidr_block = <value>` arg |
| `resource.inputs.az` | `availability_zone = <value>` arg |
| `resource.outputs.subnet_id` | `output "subnet_id" { value = aws_subnet.<id>.id }` |
| `resource.type = aws:ec2:routetable` | `resource "aws_route_table" "<id>" { ... }` |
| `resource.inputs.vpc_id` | `vpc_id = <value>` arg |
| Name | Type | Description |
|------|------|-------------|
| `vpc_id` | string | The VPC id |
| `subnet_ids` | string | Comma-separated subnet ids |
The internet gateway + default route are emitted as part of the route
table resource's IR (the `igw_id` output is wired via the route table's
inputs). The adapter is a thin layer (ARCHITECTURE.md §12.2); it does
not own L1 content — it only translates.
## Usage
## Versioning (W3.D)
```json
{
"id": "vpc",
"type": "aws:ec2:vpc",
"module": "l1-vpc@1.0.0",
"inputs": {
"cidr": "10.0.0.0/16",
"azs": "us-east-1a,us-east-1b",
"name": "acdl-microservice",
"region": "us-east-1"
}
}
```
The `azs` input is split on comma; one subnet is created per zone. The
route table gets a default route `0.0.0.0/0` → internet gateway. Other
modules reference `subnet_ids` for their network placement.
## Compliance extension points
- **VPC Flow Logs** — add `aws_flow_log` + CloudWatch Logs group / S3 destination (SOX ITGC, SOC2 CC7.2, HIPAA §164.312(b), DORA ICT risk logging).
- **Private subnets + NAT gateway** — add private subnets with a NAT gateway so ECS tasks don't need public IPs (SOC2 CC6.6, PCI-DSS 1.3, HIPAA network isolation).
- **VPC endpoints** — add S3, ECR, KMS, DynamoDB, CloudWatch interface/gateway endpoints to keep traffic off the public internet (SOC2 CC6.7, GDPR Art.32(1)(a), DORA ICT third-party risk).
- **Security groups** — add `aws_security_group` as a first-class sub-resource (currently missing; needed for all regulated deployments) (SOC2 CC6.6, PCI-DSS 1.2).
- **Network ACLs** — add `aws_network_acl` for subnet-level segmentation (PCI-DSS 1.3).
## Versioning
`1.0.0` — interface MAJOR, behavior MINOR, lifecycle PATCH. MAJOR bumps
require a new registry entry (immutable publication); old entries enter