Files
acdl/docs/consumer-guide.md
T
Jon Chery dca35c78ec feat(P22): rename static-asset→static-assets + cloudfront/waf primitives + production stack + @v1.6 bump
---ci---
phase: 22
title: rename-and-production-static-assets-stack
status: complete
verification:
  - scripts/run_ci.sh: PASS (CI PIPELINE OK)
  - python3 -m pytest tests/ -v: 175 passed
  - scripts/run_platform.sh --check-only: PASS (PLATFORM CHECK OK)
  - grep -R "static-asset[^s]" . (excl .git/): 0 hits
  - grep -R "static-asset$" . (excl .git/): 0 hits
  - floating git tags v1.6 + v1 point at v1.6.0 (a90a756)
changed_files:
  - Task 1 (rename): contracts/static-asset.yaml→static-assets.yaml (git mv); modules/l2/static-asset→static-assets (git mv); sed replaceAll static-asset→static-assets in 22 files (README, docs, scripts/run_platform.sh, pipelines/deploy.yaml, modules/registry.json, tests/*, .ciagent/* historical narrative)
  - Task 2 (cloudfront primitive): modules/l1/cloudfront/interface.json + README.md
  - Task 3 (waf primitive): modules/l1/waf/interface.json + README.md
  - Task 4 (registry): modules/registry.json (+cloudfront, +waf, static-assets renamed)
  - Task 5 (augment static-assets): modules/l2/static-assets/composition.json (s3+cloudfront+waf, depth 1); modules/l1/s3/interface.json +instance.json (+bucket_regional_domain_name output); modules/l2/static-assets/README.md (production stack docs)
  - Task 6 (adapter): adapters/terraform/adapter.py (+TYPE_MAP/INPUT_MAP/OUTPUT_MAP for cloudfront distribution+OAC+wafv2 webacl; special handling in _emit_resource for OAC defaults, distribution origin/cache_behavior/restrictions/viewer_certificate/web_acl_id, waf scope/default_action/visibility_config/managed rules)
  - Task 7 (contract schema): no change needed (generic inputs object; new module names match ^[a-z][a-z0-9-]*$)
  - Task 8 (@v1.6 bump): contracts/static-assets.yaml, .gitea/.github/workflows/deploy.yml (ref: v1.6 + header comments), docs/consumer-guide.md, docs/contracts/index.md, docs/pipeline/versioning.md, docs/pipeline/index.md, docs/architecture.md, README.md, modules/l2/microservice/README.md, tests/test_environment_check.py, tests/test_pipeline_contract.py
  - Task 9 (floating tags): git tag -f v1.6 v1.6.0; git tag -f v1 v1.6.0
  - Task 10 (tests): tests/test_adapter.py (registry 11 entries/9 L1/2 L2; cloudfront+waf type map tests; TestS3Output bucket_regional_domain_name; TestStaticAssetsStack 4 tests); tests/test_contract_resolver.py (+s3/cloudfront/waf resource assertions)
generated:
  - terraform/spike/main.tf + terraform.tf (regenerated by run_platform.sh --check-only; reflect static-assets production stack + backend key spike/static-assets/)
notes:
  - D-048 full rewrite of .ciagent/ historical narrative (verbatim phase descriptions, REQ-25/27/50, D-036) — produces intentional tautologies (e.g. "Rename static-assets → static-assets") per the decision to override the v1.6 preservation precedent.
  - cloudfront interface.json resources array ordered distribution-first so the resolver (first-match wire resolution) routes bucket_regional_domain_name/waf_web_acl_arn/region to the distribution; the OAC gets adapter-provided defaults (name=acdl-oac, origin_type=s3, signing_behavior=always).
  - .ciagent/ @v1.4 references left as historical record (D-048 scope was static-asset rename only; @v1.4 is historical narrative of Phase 20).
  - s3 OUTPUT_MAP bucket_regional_domain_name not added (identity fallback in adapt() already handles it; OUTPUT_MAP documents non-identity mappings only).
---ci---
2026-07-22 19:56:52 +00:00

13 KiB

Consumer Guide — Declare intent, deploy to AWS

This guide walks a consumer through creating their pipeline and defining a contract that deploys any ACDL module to AWS. It is generic across all modules in the registry; static-assets is the worked example, but every step applies to microservice and any future module.

The model

Consumers have their own repos and consume ACDL by referencing uses: the central pipeline definitions. The consumer declares a contract (which module, which environment, which inputs); the ACDL platform owns the pipelines, modules, substrate adapter, and evidence stream.

You do not write infrastructure modules, workflow YAML, or adapter code. You write a contract YAML file and the platform does the rest. Your repository contains only your application code, your contracts, and your CI definitions.

flowchart LR
    A["your repo<br/>(app code + contracts + CI definitions)"] -->|uses: acdl/.github/workflows/deploy.yml@v1.6| B
    B["platform runners<br/>(modules + pipelines + adapters + schemas)"] -->|contract -&gt; resolver -&gt; stack -&gt; adapter<br/>-&gt; security checks -&gt; infrastructure plan -&gt; policy checks<br/>-&gt; confidence -&gt; apply -&gt; evidence event| C
    C["your resources in AWS"]

Versioning the uses: reference

The central deployment pipeline is always versioned with floating MAJOR and MINOR tags (e.g. acdl/pipelines/deploy.yaml@v1.6). Version constraints cannot be expressed inside the contract, so the tag in uses: is the only immutability lever a consumer has. See Versioning for the full rationale.

Unversioned references are discouraged. Do not use @main or a bare acdl/pipelines/deploy.yaml.

Prerequisites

These are the only prerequisites for a consumer repo. You do not need an AWS account, infrastructure tooling, or a runner key — those are platform-managed. See Environments.

  • A consumer GitHub repository for your application code + contracts.
  • A platform-managed environment bound to your repo. The platform team provisions the AWS account, network, state backend, and IAM role. If no environment is bound, your first pipeline run emits a friendly onboarding prompt. See Environments.
  • Authorization to reference the central pipeline. Onboarding grants your repo the right to uses: acdl/.github/workflows/deploy.yml@v1.6. Contact the platform team if you have not been onboarded.

Step 1 — Create a consumer repo

Create a repository for your application. The top level holds your app code; your contract lives at .acdl/contract.yaml. Example for a static site:

my-static-site/
  index.html
  assets/
    style.css
    logo.png
  .acdl/
    contract.yaml
  .github/
    workflows/
      deploy.yml

Example for a microservice:

my-microservice/
  app.py
  Dockerfile
  .acdl/
    contract.yaml
  .github/
    workflows/
      deploy.yml

Your app code lives at the top level. Your contract lives at .acdl/contract.yaml regardless of the module you deploy. Your CI definition lives at .github/workflows/deploy.yml.

Step 2 — Reference the central pipeline

In your contract YAML, declare uses: pointing at the central ACDL deployment pipeline with a versioned tag (floating MAJOR + MINOR):

uses: acdl/pipelines/deploy.yaml@v1.6

This tells the platform to run the standard deployment pipeline: validate-contract → resolve-stack → security checks → infrastructure plan → policy checks → confidence → evidence event → apply.

Step 3 — Define the contract

Write .acdl/contract.yaml. The static-assets example:

uses: acdl/pipelines/deploy.yaml@v1.6
module: static-assets
environment: dev
inputs:
  bucket_name: my-static-site-assets
  region: us-east-1

A microservice example:

uses: acdl/pipelines/deploy.yaml@v1.6
module: microservice
environment: dev
inputs:
  image: my-registry/my-microservice:latest
  port: 8080
  env:
    LOG_LEVEL: info

Contract fields

Field Type Required Description
uses string yes Reference to the central deployment pipeline, versioned with a floating MAJOR+MINOR tag (e.g. acdl/pipelines/deploy.yaml@v1.6). Bare or @main references are discouraged. See Versioning.
module string yes Module name from the registry — any primitive or module (e.g. static-assets, microservice, s3). See the module catalog.
environment string yes The platform-managed environment to deploy to (e.g. dev). See Environments.
inputs object yes Module-specific inputs (see the module's README).

Module inputs

Each module declares its inputs in its interface.json (primitives) or composition.json (modules). Consult the module catalog for the full list, or read the module's own README under modules/l1/<name>/ or modules/l2/<name>/.

The contract is validated against the contract schema. An invalid contract (missing field, unknown module, wrong type) fails at the validate-contract stage with a clear error.

Step 4 — Run the pipeline

You do not run platform scripts locally for the happy path. The central deploy workflow is a reusable workflow that the platform runners fetch and execute for you.

The consumer CI definition

Add a thin workflow file to your repo that invokes the reusable ACDL deploy workflow with a versioned tag (.github/workflows/deploy.yml):

name: deploy
on:
  push:
    branches: [main]
jobs:
  deploy:
    uses: acdl/.github/workflows/deploy.yml@v1.6
    with:
      contract: .acdl/contract.yaml

That is the entire consumer-side workflow. When you push to main:

  1. The platform runner resolves uses: acdl/.github/workflows/deploy.yml@v1.6 to the reusable workflow at the pinned tag.
  2. A platform-provided runner checks out your repo.
  3. The runner checks out the ACDL platform repo into the workspace — this is how the pipeline fetches the platform code at run time. You never clone the platform repo yourself.
  4. The runner installs the runtime dependencies the platform requires.
  5. The runner invokes scripts/run_platform.sh against your .acdl/contract.yaml.

You see the streamed output (infrastructure plan, policy-check results, confidence signal) in your run logs. The --check-only and --plan-only flags are platform-side modes visible in the pipeline logs; you do not pass them yourself — the reusable workflow selects the mode based on the environment in your contract (dev = full apply; higher environments hold for attestation).

Local validation (optional)

A consumer may clone the ACDL platform repo to run --check-only against their contract before pushing — this is optional and not required for the happy path. If you do this, the runtime dependencies must be installed locally, and any AWS credentials follow the Credentials override model: a static key in .env.secrets (gitignored) is rotated out of band by you — the platform guarantees daily rotation for platform-runner runs, not for locally-held copies.

bash scripts/run_platform.sh --check-only path/to/your/.acdl/contract.yaml

Step 5 — What the pipeline does

Each stage of the central deployment pipeline:

flowchart TD
    S1["validate-contract<br/>schema check"] --> S2
    S2["resolve-stack<br/>contract -&gt; Target Stack"] --> S3
    S3["security checks<br/>(adapter)"] --> S4
    S4["infrastructure plan<br/>(adapter compiles the stack)"] --> S5
    S5["policy checks<br/>(adapter -&gt; PolicyCheckResult)"] --> S6
    S6["confidence<br/>score + band (dev &gt;= 0.50)"] --> S7
    S7["evidence event<br/>to the audit outbox"] --> S8
    S8["infrastructure apply<br/>(dev only)"]
  1. validate-contract — validates your contract YAML against the contract schema. Fails fast on missing fields, unknown modules, or wrong types.
  2. resolve-stack — the contract resolver resolves your contract to a Target Stack instance. It loads the module's pattern, expands its children, wires your contract inputs to the children's inputs, and emits a stack JSON instance.
  3. security checks (adapter) — security checks run on the resolved stack before any infrastructure is planned.
  4. infrastructure plan (adapter) — the substrate adapter compiles the stack to an infrastructure plan. You see the plan in your run logs.
  5. policy checks (adapter) — policy checks run on the plan. The results are normalized to PolicyCheckResult records. Each result has a severity, rule ID, and pass/fail status.
  6. confidence — the confidence signal computes a score from 6 inputs (policy, validation, freshness, source, history, NFRs). For dev, the threshold is ≥ 0.50. If the band is pass, the pipeline proceeds.
  7. evidence event — a hash-chained evidence event is written to the audit outbox.
  8. infrastructure apply (dev only) — the infrastructure plan is applied, creating the resources in your AWS account. An evidence event for the apply is recorded.

Step 6 — What gets created

After a successful dev run, the resources declared by your module's pattern exist in your AWS account, and an evidence event is recorded.

For the static-assets example:

  • An S3 bucket named my-static-site-assets in us-east-1 with versioning enabled.
  • A CloudFront distribution with the S3 bucket as the origin (via Origin Access Control) and HTTPS redirection.
  • A WAFv2 Web ACL (CloudFront-scoped) associated with the distribution.
  • An evidence event in the audit outbox with the contract ID, stack name (static-assets), confidence score, and band.
  • A confidence band of pass (score ≥ 0.50 for dev).

For other modules, consult the module's README (modules/l1/<name>/README.md or modules/l2/<name>/README.md) for the exact resources created.

Step 7 — Upload your content (static-assets example)

The platform provisions the infrastructure; you upload your content. For the static-assets module:

aws s3 sync ./assets s3://my-static-site-assets/ --acl public-read

For a microservice, the platform provisions the ECS service and ALB; you push your container image to the ECR repo the platform created.

Step 8 — Promote to qa / prod

Change environment in your contract (keeping the same versioned uses:):

uses: acdl/pipelines/deploy.yaml@v1.6
environment: qa   # QA attestation + confidence >= 0.75

Higher environments require human attestation (a platform-runner deployment approval) and higher confidence thresholds. See Environments for the full table.

Step 9 — Compliance extensions

Each module lists compliance extension points for the future compliance milestone (GDPR, SOX, SOC2, HIPAA, DORA). See each module's README under modules/l1/<name>/README.md or modules/l2/<name>/README.md for the per-module extension points. Common examples:

  • KMS key — shared encryption key for SSE.
  • S3 access logs — access logging to a separate audit bucket.
  • Object Lock — 7-year immutable retention for evidence.
  • Public access block — prevent data exfiltration.

Reference

Resource Path Description
Central deployment pipeline contract pipelines/deploy.yaml The pipeline stages your contract references.
Reusable deploy workflow .github/workflows/deploy.yml The workflow your repo invokes via uses:.
Contract schema schemas/contract.schema.json JSON Schema for consumer contracts.
Stack schema schemas/stack.schema.json JSON Schema for the resolved stack instance.
Module catalog modules/ All primitives and modules.
Sample contract contracts/static-assets.yaml The reference example contract (uses @v1.6).
Contract resolver core/contract_resolver.py Resolves contracts to stack instances.
Substrate adapter adapters/terraform/adapter.py Compiles stack instances to infrastructure.
Platform pipeline runner scripts/run_platform.sh The pipeline runner (platform-side; consumers do not invoke it directly).
Environments environments/ Platform-managed environments + onboarding.
Versioning pipeline/versioning The uses: tag + module versioning.
Platform README README.md How the platform works + how to run the platform repo locally.
Credentials & zero-trust README.md#credentials--zero-trust The OIDC/ABAC default + static-key override model.