refactor(P57): contract surface redesign + rename + .yml repo-wide

Contract surface redesign:
- New top-level fields: id (3-6 char acronym → stack.name), name (full → stack.title),
  infrastructure (map keyed by module name, replaces module:)
- Drop uses: field (dead reference; version pin lives in CI workflow uses: line)
- Drop top-level module/inputs (now nested under infrastructure map)
- Per-module optional version (defaults to latest published from registry)
- Multi-module contracts: one file deploys N modules in one pipeline run,
  resource IDs namespaced with module name to avoid collisions
- stack.schema.json: add optional title field for display name

Rename:
- pipelines/deploy.yaml → pipelines/contract.yml (declarative spec, not a pipeline)
- pipelines/ci.yaml → pipelines/ci.yml
- All 44 .yaml files → .yml repo-wide (contracts, module examples, kyverno policies)
- .acdl/contract.yaml → .acdl/contract.yml

Resolver (core/contract_resolver.py):
- Rewrite resolve() to loop infrastructure map, default version to latest,
  merge module fragments into one stack with namespaced resource IDs
- _latest_version() picks highest non-deprecated from registry
- _namespace_resources() prefixes IDs + rewrites ref: expressions for multi-module
- Single-module path: unprefixed IDs (backward compatible)

Verification:
- 494 tests pass (0 contract-shape failures)
- Local E2E passes (contract → resolver → adapter → local ECS HTTP 200 → outbox)

---ci---
project: acdl
phase: 57
milestone: v1.10.2
status: execute
---/ci---
This commit is contained in:
Jon Chery
2026-07-27 21:37:40 +00:00
parent 7f36df5610
commit 031887ec56
127 changed files with 1597 additions and 1100 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
# ACDL CI Pipeline — Gitea Actions (dev environment) # ACDL CI Pipeline — Gitea Actions (dev environment)
# #
# This workflow implements the central pipeline contract: # This workflow implements the central pipeline contract:
# pipelines/ci.yaml (validated against schemas/pipeline.schema.json) # pipelines/ci.yml (validated against schemas/pipeline.schema.json)
# #
# The same contract is implemented by .github/workflows/ci.yml (GitHub # The same contract is implemented by .github/workflows/ci.yml (GitHub
# Actions, production). Both files must be byte-identical — the only # Actions, production). Both files must be byte-identical — the only
+3 -3
View File
@@ -1,7 +1,7 @@
# ACDL Reusable Deploy Workflow — Gitea Actions (dev environment) # ACDL Reusable Deploy Workflow — Gitea Actions (dev environment)
# #
# This reusable workflow implements the central deployment pipeline contract: # This reusable workflow implements the central deployment pipeline contract:
# pipelines/deploy.yaml (validated against schemas/deploy-pipeline.schema.json) # pipelines/contract.yml (validated against schemas/deploy-pipeline.schema.json)
# #
# The same contract is implemented by .github/workflows/deploy.yml (GitHub # The same contract is implemented by .github/workflows/deploy.yml (GitHub
# Actions, production). Both files must be byte-identical — the only # Actions, production). Both files must be byte-identical — the only
@@ -26,7 +26,7 @@
# platform log) for auditability. # platform log) for auditability.
# #
# Inputs: # Inputs:
# contract — path to the consumer's contract YAML (default .acdl/contract.yaml) # contract — path to the consumer's contract YAML (default .acdl/contract.yml)
# mode — full | plan-only | check-only (default full; dev = full apply, # mode — full | plan-only | check-only (default full; dev = full apply,
# higher environments hold for HITL — the calling repo or the # higher environments hold for HITL — the calling repo or the
# forge environment gate enforces that) # forge environment gate enforces that)
@@ -51,7 +51,7 @@ on:
contract: contract:
description: Path to the consumer contract YAML (in the consumer repo) description: Path to the consumer contract YAML (in the consumer repo)
type: string type: string
default: .acdl/contract.yaml default: .acdl/contract.yml
mode: mode:
description: Pipeline mode — full (apply), plan-only, check-only, or decommission description: Pipeline mode — full (apply), plan-only, check-only, or decommission
type: string type: string
+1 -1
View File
@@ -1,7 +1,7 @@
# ACDL CI Pipeline — Gitea Actions (dev environment) # ACDL CI Pipeline — Gitea Actions (dev environment)
# #
# This workflow implements the central pipeline contract: # This workflow implements the central pipeline contract:
# pipelines/ci.yaml (validated against schemas/pipeline.schema.json) # pipelines/ci.yml (validated against schemas/pipeline.schema.json)
# #
# The same contract is implemented by .github/workflows/ci.yml (GitHub # The same contract is implemented by .github/workflows/ci.yml (GitHub
# Actions, production). Both files must be byte-identical — the only # Actions, production). Both files must be byte-identical — the only
+3 -3
View File
@@ -1,7 +1,7 @@
# ACDL Reusable Deploy Workflow — Gitea Actions (dev environment) # ACDL Reusable Deploy Workflow — Gitea Actions (dev environment)
# #
# This reusable workflow implements the central deployment pipeline contract: # This reusable workflow implements the central deployment pipeline contract:
# pipelines/deploy.yaml (validated against schemas/deploy-pipeline.schema.json) # pipelines/contract.yml (validated against schemas/deploy-pipeline.schema.json)
# #
# The same contract is implemented by .github/workflows/deploy.yml (GitHub # The same contract is implemented by .github/workflows/deploy.yml (GitHub
# Actions, production). Both files must be byte-identical — the only # Actions, production). Both files must be byte-identical — the only
@@ -26,7 +26,7 @@
# platform log) for auditability. # platform log) for auditability.
# #
# Inputs: # Inputs:
# contract — path to the consumer's contract YAML (default .acdl/contract.yaml) # contract — path to the consumer's contract YAML (default .acdl/contract.yml)
# mode — full | plan-only | check-only (default full; dev = full apply, # mode — full | plan-only | check-only (default full; dev = full apply,
# higher environments hold for HITL — the calling repo or the # higher environments hold for HITL — the calling repo or the
# forge environment gate enforces that) # forge environment gate enforces that)
@@ -51,7 +51,7 @@ on:
contract: contract:
description: Path to the consumer contract YAML (in the consumer repo) description: Path to the consumer contract YAML (in the consumer repo)
type: string type: string
default: .acdl/contract.yaml default: .acdl/contract.yml
mode: mode:
description: Pipeline mode — full (apply), plan-only, check-only, or decommission description: Pipeline mode — full (apply), plan-only, check-only, or decommission
type: string type: string
+3 -3
View File
@@ -5,7 +5,7 @@
# #
# Shell reproducibility: scripts/run_ci.sh runs lint + test + check-only locally. # Shell reproducibility: scripts/run_ci.sh runs lint + test + check-only locally.
# The integration-test stage runs run_platform.sh --check-only for every # The integration-test stage runs run_platform.sh --check-only for every
# contracts/*.yaml file. The schema-validation stage validates schemas, module # contracts/*.yml file. The schema-validation stage validates schemas, module
# interfaces, compositions, and example contracts. # interfaces, compositions, and example contracts.
name: acdl-platform-test name: acdl-platform-test
@@ -62,7 +62,7 @@ jobs:
run: pip install jsonschema pyyaml boto3 run: pip install jsonschema pyyaml boto3
- name: Run platform check-only for every sample contract - name: Run platform check-only for every sample contract
run: | run: |
for contract in contracts/*.yaml; do for contract in contracts/*.yml; do
echo "--- Testing $contract ---" echo "--- Testing $contract ---"
bash scripts/run_platform.sh --check-only "$contract" bash scripts/run_platform.sh --check-only "$contract"
done done
@@ -139,7 +139,7 @@ jobs:
except Exception as e: except Exception as e:
print(f'{example}: SKIP (not a contract or invalid: {e})') print(f'{example}: SKIP (not a contract or invalid: {e})')
# Also validate all sample contracts in contracts/ # Also validate all sample contracts in contracts/
for contract_file in glob.glob('contracts/*.yaml'): for contract_file in glob.glob('contracts/*.yml'):
contract = yaml.safe_load(open(contract_file)) contract = yaml.safe_load(open(contract_file))
jsonschema.validate(contract, schema) jsonschema.validate(contract, schema)
print(f'{contract_file}: valid contract') print(f'{contract_file}: valid contract')
+12 -12
View File
@@ -26,9 +26,9 @@ There are two kinds of repository in the ACDL model:
A **consumer never clones it.** A **consumer never clones it.**
- **Consumer repo (yours).** A consumer repo contains only: - **Consumer repo (yours).** A consumer repo contains only:
1. **Its application code** — the service or site being deployed. 1. **Its application code** — the service or site being deployed.
2. **One or more contracts** — small YAML files at `.acdl/contract.yaml` 2. **One or more contracts** — small YAML files at `.acdl/contract.yml`
that reference the central pipeline, name a module, select an that declare infrastructure (one or more modules by name + version),
environment, and supply module-specific inputs. select an environment, and supply module-specific inputs.
3. **One or more CI definitions** — thin `.github/workflows/*.yml` files 3. **One or more CI definitions** — thin `.github/workflows/*.yml` files
that `uses:` the central reusable deploy workflow, pointing at the that `uses:` the central reusable deploy workflow, pointing at the
appropriate environment + contract. appropriate environment + contract.
@@ -93,9 +93,9 @@ intent via a contract; the platform delivers the deployment through the
same contract schema, the same policy envelope, and the same evidence same contract schema, the same policy envelope, and the same evidence
stream. stream.
Consumers have their own repos and consume ACDL by referencing `uses:` the Consumers have their own repos and consume ACDL by writing a contract that
central pipeline definitions. A consumer declares a contract (module + declares infrastructure. A consumer declares a contract (id + name +
environment + inputs); the platform resolves it to a stack instance, environment + infrastructure); the platform resolves it to a stack instance,
compiles it, runs security + policy checks, computes a confidence signal, compiles it, runs security + policy checks, computes a confidence signal,
writes an evidence event to the audit outbox, and applies the writes an evidence event to the audit outbox, and applies the
infrastructure. infrastructure.
@@ -104,7 +104,7 @@ infrastructure.
```mermaid ```mermaid
flowchart TD flowchart TD
A["consumer contract<br/>(uses + module + environment + inputs)"] --> B A["consumer contract<br/>(id + name + environment + infrastructure)"] --> B
B["schema validation<br/>(contract schema)"] --> C B["schema validation<br/>(contract schema)"] --> C
C["resolve to Target Stack<br/>(contract resolver)"] --> D C["resolve to Target Stack<br/>(contract resolver)"] --> D
D["security checks<br/>(adapter)"] --> E D["security checks<br/>(adapter)"] --> E
@@ -155,7 +155,7 @@ ACDL_BOOTSTRAP_AWS_ACCESS_KEY_ID=... ACDL_BOOTSTRAP_AWS_SECRET_ACCESS_KEY=... \
# 3. Run the full platform pipeline (contract -> environment check -> stack -> # 3. Run the full platform pipeline (contract -> environment check -> stack ->
# adapter -> security checks -> infrastructure plan -> policy checks -> # adapter -> security checks -> infrastructure plan -> policy checks ->
# confidence -> evidence event -> apply). Output is streamed to stdout. # confidence -> evidence event -> apply). Output is streamed to stdout.
bash scripts/run_platform.sh contracts/static-assets.yaml bash scripts/run_platform.sh contracts/static-assets.yml
# Expected: "=== PLATFORM E2E OK ===" # Expected: "=== PLATFORM E2E OK ==="
# Or plan-only (contract -> stack -> adapter -> infrastructure plan; no # Or plan-only (contract -> stack -> adapter -> infrastructure plan; no
@@ -189,7 +189,7 @@ bash scripts/run_ci.sh
### CI/CD pipelines ### CI/CD pipelines
The CI/CD pipeline is defined by a **central pipeline contract** — a The CI/CD pipeline is defined by a **central pipeline contract** — a
declarative YAML instance (`pipelines/ci.yaml`) validated against a JSON declarative YAML instance (`pipelines/ci.yml`) validated against a JSON
Schema (`schemas/pipeline.schema.json`). Both platform-runner workflows Schema (`schemas/pipeline.schema.json`). Both platform-runner workflows
implement the same contract: implement the same contract:
@@ -212,13 +212,13 @@ bash scripts/run_ci.sh --quiet # suppress per-stage banners
### Reusable deploy workflow ### Reusable deploy workflow
The deployment pipeline is defined by a **central deployment pipeline The deployment pipeline is defined by a **central deployment pipeline
contract** (`pipelines/deploy.yaml`, validated against contract** (`pipelines/contract.yml`, validated against
`schemas/deploy-pipeline.schema.json`) and exposed to consumer repos as a `schemas/deploy-pipeline.schema.json`) and exposed to consumer repos as a
**reusable workflow**: **reusable workflow**:
- `.github/workflows/deploy.yml` — GitHub Actions (production) - `.github/workflows/deploy.yml` — GitHub Actions (production)
The workflow implements the same stages as `pipelines/deploy.yaml` The workflow implements the same stages as `pipelines/contract.yml`
(validate-contract → resolve-stack → security checks → infrastructure plan (validate-contract → resolve-stack → security checks → infrastructure plan
→ policy checks → confidence → evidence event → apply). A consumer repo → policy checks → confidence → evidence event → apply). A consumer repo
invokes the reusable workflow via a **versioned tag** (floating MAJOR + invokes the reusable workflow via a **versioned tag** (floating MAJOR +
@@ -257,7 +257,7 @@ across all modules; `static-assets` is the worked example.
|------|---------|--------| |------|---------|--------|
| `core/` | Platform code: contract resolver, confidence signal, outbox writer, environment check, environments, separation of duties, HITL/ledger designs | active | | `core/` | Platform code: contract resolver, confidence signal, outbox writer, environment check, environments, separation of duties, HITL/ledger designs | active |
| `schemas/` | JSON Schemas: stack, contract, PolicyCheckResult, pipeline contract, deploy pipeline contract (draft 2020-12) | active | | `schemas/` | JSON Schemas: stack, contract, PolicyCheckResult, pipeline contract, deploy pipeline contract (draft 2020-12) | active |
| `pipelines/` | Central pipeline contracts: `ci.yaml` (CI), `deploy.yaml` (deployment) | active | | `pipelines/` | Central pipeline contracts: `ci.yml` (CI), `contract.yml` (deployment) | active |
| `adapters/` | Angine adapters — the engine adapter (the only engine-specific code per §12) + the policy adapter | active | | `adapters/` | Angine adapters — the engine adapter (the only engine-specific code per §12) + the policy adapter | active |
| `terraform/` | State backend (S3 + DynamoDB) + platform TF (`terraform/spike/`) + bootstrap scripts (`terraform/bootstrap/`) | active | | `terraform/` | State backend (S3 + DynamoDB) + platform TF (`terraform/spike/`) + bootstrap scripts (`terraform/bootstrap/`) | active |
| `modules/` | Primitives + modules + `registry.json`. Primitives: s3, vpc, ecs-cluster, ecs-service, iam-role, alb, ecr, cloudfront, waf, rds. Modules: microservice, static-assets. Each module has a `examples/` directory with validated contract examples | active | | `modules/` | Primitives + modules + `registry.json`. Primitives: s3, vpc, ecs-cluster, ecs-service, iam-role, alb, ecr, cloudfront, waf, rds. Modules: microservice, static-assets. Each module has a `examples/` directory with validated contract examples | active |
+3 -3
View File
@@ -53,12 +53,12 @@ invoke it. The `engine: "kyverno"` enum value is present in
The `policies/` directory holds three valid Kyverno `ClusterPolicy` The `policies/` directory holds three valid Kyverno `ClusterPolicy`
manifests (documentation-only today — the platform does not run them): manifests (documentation-only today — the platform does not run them):
- `disallow-privileged-containers.yaml` — fail pods with - `disallow-privileged-containers.yml` — fail pods with
`securityContext.privileged: true`. `securityContext.privileged: true`.
- `require-resource-labels.yaml` — require `acdl:owner` and - `require-resource-labels.yml` — require `acdl:owner` and
`acdl:environment` labels on all pods (mirrors the ACDL tagging standard `acdl:environment` labels on all pods (mirrors the ACDL tagging standard
in [`schemas/tagging-standard.json`](../../schemas/tagging-standard.json)). in [`schemas/tagging-standard.json`](../../schemas/tagging-standard.json)).
- `require-image-digests.yaml` — require container images to reference a - `require-image-digests.yml` — require container images to reference a
digest (`image@sha256:...`), not a mutable tag. digest (`image@sha256:...`), not a mutable tag.
## Schema path ## Schema path
-11
View File
@@ -1,11 +0,0 @@
# ACDL sample consumer contract — microservice module (dev)
# Per-environment contract (REQ-105). Promotion = running the dev job;
# no environment field editing. Interpolation resolves against dev.json.
uses: acdl/pipelines/deploy.yaml@v1.9
module: microservice
environment: dev
inputs:
bucket_name: acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region}
region: ${env.region}
image: public.ecr.aws/docker/library/nginx:latest
port: 80
+14
View File
@@ -0,0 +1,14 @@
# ACDL sample consumer contract — microservice module (dev)
# Per-environment contract (REQ-105). Promotion = running the dev job;
# no environment field editing. Interpolation resolves against dev.json.
id: msvc
name: microservice
environment: dev
infrastructure:
microservice:
version: "1.0.0"
inputs:
bucket_name: acdl-${env.environment}-${contract.id}-${env.account_id}-${env.region}
region: ${env.region}
image: public.ecr.aws/docker/library/nginx:latest
port: 80
-11
View File
@@ -1,11 +0,0 @@
# ACDL sample consumer contract — microservice module (dr)
# Per-environment contract (REQ-105). Promotion = running the dr job;
# no environment field editing. Interpolation resolves against dr.json.
uses: acdl/pipelines/deploy.yaml@v1.9
module: microservice
environment: dr
inputs:
bucket_name: acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region}
region: ${env.region}
image: public.ecr.aws/docker/library/nginx:latest
port: 80
+14
View File
@@ -0,0 +1,14 @@
# ACDL sample consumer contract — microservice module (dr)
# Per-environment contract (REQ-105). Promotion = running the dr job;
# no environment field editing. Interpolation resolves against dr.json.
id: msvc
name: microservice
environment: dr
infrastructure:
microservice:
version: "1.0.0"
inputs:
bucket_name: acdl-${env.environment}-${contract.id}-${env.account_id}-${env.region}
region: ${env.region}
image: public.ecr.aws/docker/library/nginx:latest
port: 80
-11
View File
@@ -1,11 +0,0 @@
# ACDL sample consumer contract — microservice module (prod)
# Per-environment contract (REQ-105). Promotion = running the prod job;
# no environment field editing. Interpolation resolves against prod.json.
uses: acdl/pipelines/deploy.yaml@v1.9
module: microservice
environment: prod
inputs:
bucket_name: acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region}
region: ${env.region}
image: public.ecr.aws/docker/library/nginx:latest
port: 80
+14
View File
@@ -0,0 +1,14 @@
# ACDL sample consumer contract — microservice module (prod)
# Per-environment contract (REQ-105). Promotion = running the prod job;
# no environment field editing. Interpolation resolves against prod.json.
id: msvc
name: microservice
environment: prod
infrastructure:
microservice:
version: "1.0.0"
inputs:
bucket_name: acdl-${env.environment}-${contract.id}-${env.account_id}-${env.region}
region: ${env.region}
image: public.ecr.aws/docker/library/nginx:latest
port: 80
-11
View File
@@ -1,11 +0,0 @@
# ACDL sample consumer contract — microservice module (qa)
# Per-environment contract (REQ-105). Promotion = running the qa job;
# no environment field editing. Interpolation resolves against qa.json.
uses: acdl/pipelines/deploy.yaml@v1.9
module: microservice
environment: qa
inputs:
bucket_name: acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region}
region: ${env.region}
image: public.ecr.aws/docker/library/nginx:latest
port: 80
+14
View File
@@ -0,0 +1,14 @@
# ACDL sample consumer contract — microservice module (qa)
# Per-environment contract (REQ-105). Promotion = running the qa job;
# no environment field editing. Interpolation resolves against qa.json.
id: msvc
name: microservice
environment: qa
infrastructure:
microservice:
version: "1.0.0"
inputs:
bucket_name: acdl-${env.environment}-${contract.id}-${env.account_id}-${env.region}
region: ${env.region}
image: public.ecr.aws/docker/library/nginx:latest
port: 80
-14
View File
@@ -1,14 +0,0 @@
# ACDL sample consumer contract — microservice module (dev)
#
# Reference example for an ECS Fargate microservice deployment.
# Interpolation (D-081): bucket_name uses the naming pattern that includes
# region, aws account id, and environment:
# acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region}
uses: acdl/pipelines/deploy.yaml@v1.9
module: microservice
environment: dev
inputs:
bucket_name: acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region}
region: ${env.region}
image: public.ecr.aws/docker/library/nginx:latest
port: 80
+17
View File
@@ -0,0 +1,17 @@
# ACDL sample consumer contract — microservice module (dev)
#
# Reference example for an ECS Fargate microservice deployment.
# Interpolation (D-081): bucket_name uses the naming pattern that includes
# region, aws account id, and environment:
# acdl-${env.environment}-${contract.id}-${env.account_id}-${env.region}
id: msvc
name: microservice
environment: dev
infrastructure:
microservice:
version: "1.0.0"
inputs:
bucket_name: acdl-${env.environment}-${contract.id}-${env.account_id}-${env.region}
region: ${env.region}
image: public.ecr.aws/docker/library/nginx:latest
port: 80
-10
View File
@@ -1,10 +0,0 @@
# ACDL sample consumer contract — static-assets module (dev)
# Per-environment contract (REQ-105). The dev default
# (contracts/static-assets.yaml) remains for backwards compat; this file
# is the explicit per-env dev contract. Interpolation resolves against dev.json.
uses: acdl/pipelines/deploy.yaml@v1.9
module: static-assets
environment: dev
inputs:
bucket_name: acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region}
region: ${env.region}
+13
View File
@@ -0,0 +1,13 @@
# ACDL sample consumer contract — static-assets module (dev)
# Per-environment contract (REQ-105). The dev default
# (contracts/static-assets.yml) remains for backwards compat; this file
# is the explicit per-env dev contract. Interpolation resolves against dev.json.
id: assets
name: static-assets
environment: dev
infrastructure:
static-assets:
version: "1.0.0"
inputs:
bucket_name: acdl-${env.environment}-${contract.id}-${env.account_id}-${env.region}
region: ${env.region}
@@ -1,9 +1,12 @@
# ACDL sample consumer contract — static-assets module (dr) # ACDL sample consumer contract — static-assets module (dr)
# Per-environment contract (REQ-105). Promotion = running the dr job; # Per-environment contract (REQ-105). Promotion = running the dr job;
# no environment field editing. Interpolation resolves against dr.json. # no environment field editing. Interpolation resolves against dr.json.
uses: acdl/pipelines/deploy.yaml@v1.9 id: assets
module: static-assets name: static-assets
environment: dr environment: dr
inputs: infrastructure:
bucket_name: acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region} static-assets:
region: ${env.region} version: "1.0.0"
inputs:
bucket_name: acdl-${env.environment}-${contract.id}-${env.account_id}-${env.region}
region: ${env.region}
@@ -1,9 +1,12 @@
# ACDL sample consumer contract — static-assets module (prod) # ACDL sample consumer contract — static-assets module (prod)
# Per-environment contract (REQ-105). Promotion = running the prod job; # Per-environment contract (REQ-105). Promotion = running the prod job;
# no environment field editing. Interpolation resolves against prod.json. # no environment field editing. Interpolation resolves against prod.json.
uses: acdl/pipelines/deploy.yaml@v1.9 id: assets
module: static-assets name: static-assets
environment: prod environment: prod
inputs: infrastructure:
bucket_name: acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region} static-assets:
region: ${env.region} version: "1.0.0"
inputs:
bucket_name: acdl-${env.environment}-${contract.id}-${env.account_id}-${env.region}
region: ${env.region}
@@ -1,9 +1,12 @@
# ACDL sample consumer contract — static-assets module (qa) # ACDL sample consumer contract — static-assets module (qa)
# Per-environment contract (REQ-105). Promotion = running the qa job; # Per-environment contract (REQ-105). Promotion = running the qa job;
# no environment field editing. Interpolation resolves against qa.json. # no environment field editing. Interpolation resolves against qa.json.
uses: acdl/pipelines/deploy.yaml@v1.9 id: assets
module: static-assets name: static-assets
environment: qa environment: qa
inputs: infrastructure:
bucket_name: acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region} static-assets:
region: ${env.region} version: "1.0.0"
inputs:
bucket_name: acdl-${env.environment}-${contract.id}-${env.account_id}-${env.region}
region: ${env.region}
-23
View File
@@ -1,23 +0,0 @@
# ACDL sample consumer contract — static-assets module (dev)
#
# This is the reference example for a consumer contract. It declares:
# uses: the central ACDL deployment pipeline to reference
# module: which module to deploy (must match a registry key)
# environment: which environment to deploy to (dev = autonomous)
# inputs: module-specific inputs
#
# Validated against schemas/contract.schema.json.
# Resolved by core/contract_resolver.py to a Target Stack instance.
#
# Interpolation (D-081): ${env.<field>} + ${contract.<field>} tokens are
# expanded by the resolver from the environment onboarding JSON. The
# bucket_name below demonstrates the naming pattern that includes region,
# aws account id, and environment:
# acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region}
uses: acdl/pipelines/deploy.yaml@v1.9
module: static-assets
environment: dev
inputs:
bucket_name: acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region}
region: ${env.region}
+29
View File
@@ -0,0 +1,29 @@
# ACDL sample consumer contract — static-assets module (dev)
#
# This is the reference example for a consumer contract. It declares:
# id: short operational acronym (becomes stack.name for state, tags, evidence)
# name: full human-readable stack name (becomes stack.title for display)
# environment: which environment to deploy to (dev = autonomous)
# infrastructure: map of modules to deploy (keyed by module registry name)
# <module>:
# version: module version pin (defaults to latest published)
# inputs: module-specific inputs
#
# Validated against schemas/contract.schema.json.
# Resolved by core/contract_resolver.py to a Target Stack instance.
#
# Interpolation (D-081): ${env.<field>} + ${contract.<field>} tokens are
# expanded by the resolver from the environment onboarding JSON. The
# bucket_name below demonstrates the naming pattern that includes region,
# aws account id, and environment:
# acdl-${env.environment}-${contract.id}-${env.account_id}-${env.region}
id: assets
name: static-assets
environment: dev
infrastructure:
static-assets:
version: "1.0.0"
inputs:
bucket_name: acdl-${env.environment}-${contract.id}-${env.account_id}-${env.region}
region: ${env.region}
+210 -77
View File
@@ -5,17 +5,27 @@ The contract resolver is the bridge between the consumer's declared intent
Stack JSON instance). It: Stack JSON instance). It:
1. Loads and validates the contract against schemas/contract.schema.json. 1. Loads and validates the contract against schemas/contract.schema.json.
2. Looks up the module name in modules/registry.json. 2. For each module in the contract's `infrastructure` map:
3. If the module is an L1 primitive: builds a stack instance directly from a. Looks up the module name + version in modules/registry.json
the interface.json + contract inputs. (version defaults to the latest non-deprecated entry when omitted).
4. If the module is an L2 composition: loads the composition.json, expands b. If the module is an L1 primitive: builds a stack fragment from
children to stack resources, resolves wires to ref: expressions, and the interface.json + module inputs.
emits the full stack instance. c. If the module is an L2 composition: loads the composition.json,
expands children to stack resources, resolves wires to ref:
expressions, and emits the fragment.
3. Merges all module fragments into a single Target Stack instance:
- stack.name = contract.id (the short operational acronym)
- stack.title = contract.name (the full human-readable name)
- When the contract has one module: resource IDs are unprefixed
(backward-compatible with existing stack consumers).
- When the contract has multiple modules: resource IDs are prefixed
with the module name (e.g. `microservice-vpc`) to avoid collisions,
and all ref:/parent references are rewritten to match.
The output is a JSON instance valid against schemas/stack.schema.json, The output is a JSON instance valid against schemas/stack.schema.json,
ready for the Terraform adapter to compile. ready for the Terraform adapter to compile.
CLI: contract_resolver.py <contract.yaml> <out.json> CLI: contract_resolver.py <contract.yml> <out.json>
""" """
import json import json
@@ -150,68 +160,77 @@ def _resolve_wire_value(wire, contract_inputs, child_outputs):
return None return None
def resolve_l1(contract, registry, repo_root): def _latest_version(registry, module_name):
"""Resolve a contract referencing an L1 primitive to a stack instance.""" """Return the latest non-deprecated version string for a module.
module_name = contract["module"]
module_ref = f"{module_name}@1.0.0" Falls back to the highest version even if all are deprecated.
inputs = contract.get("inputs", {}) """
environment = contract.get("environment", "dev") versions = registry[module_name]
non_deprecated = [(v, e) for v, e in versions.items()
if not e.get("deprecated", False)]
if not non_deprecated:
non_deprecated = list(versions.items())
non_deprecated.sort(key=lambda x: [int(p) for p in x[0].split(".")],
reverse=True)
return non_deprecated[0][0]
def _resolve_l1(module_name, version, inputs, registry, repo_root):
"""Resolve a single L1 primitive module to a stack-fragment (resources list)."""
module_ref = f"{module_name}@{version}"
# Load the interface # Load the interface
entry = registry[module_name]["1.0.0"] entry = registry[module_name][version]
iface_path = os.path.join(repo_root, entry["interface"]) iface_path = os.path.join(repo_root, entry["interface"])
iface = _load_json(iface_path) iface = _load_json(iface_path)
# Build the stack instance # Build the resource
stack_instance = { resource = {
"version": "1.0.0", "id": iface.get("type", module_name).split(":")[-1]
"stack": { if ":" in iface.get("type", "") else module_name,
"name": module_name, "type": iface["type"],
"kind": "l1", "module": module_ref,
"depth": 1, "inputs": dict(inputs),
"outputs": {
out_name: {"type": out_spec.get("type", "string")}
for out_name, out_spec in iface.get("outputs", {}).items()
}, },
"resources": [
{
"id": iface.get("type", module_name).split(":")[-1]
if ":" in iface.get("type", "") else module_name,
"type": iface["type"],
"module": module_ref,
"inputs": dict(inputs),
"outputs": {
out_name: {"type": out_spec.get("type", "string")}
for out_name, out_spec in iface.get("outputs", {}).items()
},
}
],
} }
# Add NFRs if present in the interface # Add NFRs if present in the interface
nfrs = iface.get("nfrs", {}) nfrs = iface.get("nfrs", {})
if nfrs: if nfrs:
stack_instance["resources"][0]["nfrs"] = nfrs resource["nfrs"] = nfrs
return stack_instance return {
"kind": "l1",
"depth": 1,
"resources": [resource],
"features": {},
"outputs": {},
}
def resolve_l2(contract, registry, repo_root): def _resolve_l2(module_name, version, inputs, registry, repo_root):
"""Resolve a contract referencing an L2 composition to a stack instance.""" """Resolve a single L2 composition module to a stack-fragment.
module_name = contract["module"]
inputs = contract.get("inputs", {})
Returns a dict with: kind, depth, resources, features, outputs.
The caller is responsible for merging fragments and setting stack.name/title.
"""
# Load the composition # Load the composition
entry = registry[module_name]["1.0.0"] entry = registry[module_name][version]
comp_path = os.path.join(repo_root, entry["interface"]) comp_path = os.path.join(repo_root, entry["interface"])
composition = _load_json(comp_path) composition = _load_json(comp_path)
# Track child outputs for wire resolution # Track child outputs for wire resolution
# child_outputs[childId] = {outputName: resourceId} # child_outputs[childId] = {outputName -> resourceId}
# For single-resource L1s, resourceId == childId # For single-resource L1s, resourceId == childId
# For multi-resource L1s, resourceId is the expanded sub-resource id # For multi-resource L1s, resourceId is the expanded sub-resource id
child_outputs = {} child_outputs = {}
# child_input_map[childId] = {inputName: sub_resource_id} for multi-resource L1s # child_input_map[childId] = {inputName -> sub_resource_id} for multi-resource L1s
# so a wire targeting <childId>.inputs.<name> routes to the sub-resource # so a wire targeting <childId>.inputs.<name> routes to the sub-resource
# that actually declares that input (P1-1 — desired_count aws:ecs:service, # that actually declares that input (P1-1 — desired_count -> aws:ecs:service,
# family aws:ecs:task_definition). # family -> aws:ecs:task_definition).
child_input_map = {} child_input_map = {}
resources = [] resources = []
@@ -220,9 +239,10 @@ def resolve_l2(contract, registry, repo_root):
child_id = child["id"] child_id = child["id"]
child_module = child["module"] child_module = child["module"]
child_name = child_module.split("@")[0] child_name = child_module.split("@")[0]
child_version = child_module.split("@")[1] if "@" in child_module else "1.0.0"
# Load the child's interface to get type and outputs # Load the child's interface to get type and outputs
child_entry = registry[child_name]["1.0.0"] child_entry = registry[child_name][child_version]
child_iface_path = os.path.join(repo_root, child_entry["interface"]) child_iface_path = os.path.join(repo_root, child_entry["interface"])
child_iface = _load_json(child_iface_path) child_iface = _load_json(child_iface_path)
@@ -309,20 +329,10 @@ def resolve_l2(contract, registry, repo_root):
res["inputs"][input_name] = value res["inputs"][input_name] = value
break break
# Build the stack instance
stack_instance = {
"version": "1.0.0",
"stack": {
"name": module_name,
"kind": "l2",
"depth": composition.get("depth", 1),
},
"resources": resources,
}
# REQ-87: Propagate deletion_protection feature flag from contract inputs # REQ-87: Propagate deletion_protection feature flag from contract inputs
# to all children's NFRs. When inputs.deletion_protection is false, # to all children's NFRs. When inputs.deletion_protection is false,
# all resources get deletion_protection=false (used by decommission). # all resources get deletion_protection=false (used by decommission).
features = {}
deletion_protection_input = inputs.get("deletion_protection", True) deletion_protection_input = inputs.get("deletion_protection", True)
if deletion_protection_input is not True: if deletion_protection_input is not True:
for res in resources: for res in resources:
@@ -331,9 +341,7 @@ def resolve_l2(contract, registry, repo_root):
res["nfrs"]["deletion_protection"] = deletion_protection_input res["nfrs"]["deletion_protection"] = deletion_protection_input
# Also record the feature flag on the stack object for introspection. # Also record the feature flag on the stack object for introspection.
if "deletion_protection" in inputs: if "deletion_protection" in inputs:
stack_instance["stack"]["features"] = { features["deletion_protection"] = deletion_protection_input
"deletion_protection": deletion_protection_input
}
# P1-7: Process the composition's outputs[] array to build stack.outputs. # P1-7: Process the composition's outputs[] array to build stack.outputs.
# Each output wire: {"from": "<childId>.outputs.<name>", "to": "stack.outputs.<outName>"} # Each output wire: {"from": "<childId>.outputs.<name>", "to": "stack.outputs.<outName>"}
@@ -363,10 +371,55 @@ def resolve_l2(contract, registry, repo_root):
"from": src_resource_id, "from": src_resource_id,
"output": src_output, "output": src_output,
} }
if stack_outputs:
stack_instance["outputs"] = stack_outputs
return stack_instance return {
"kind": "l2",
"depth": composition.get("depth", 1),
"resources": resources,
"features": features,
"outputs": stack_outputs,
}
def _namespace_resources(resources, module_name):
"""Prefix all resource IDs with the module name for multi-module contracts.
Rewrites resource 'id', 'parent', and ref: expressions in inputs/outputs
so cross-references stay consistent within the module fragment.
"""
prefix = f"{module_name}-"
# Build the old->new id mapping
id_map = {res["id"]: f"{prefix}{res['id']}" for res in resources}
def _rewrite_ref(val):
"""Recursively rewrite ref:<id>.<out> and parent:<id> strings."""
if isinstance(val, str):
if val.startswith("ref:"):
# ref:<resourceId>.<outputName>
rest = val[4:]
if "." in rest:
rid, outname = rest.split(".", 1)
if rid in id_map:
return f"ref:{id_map[rid]}.{outname}"
return val
return val
if isinstance(val, dict):
return {k: _rewrite_ref(v) for k, v in val.items()}
if isinstance(val, list):
return [_rewrite_ref(v) for v in val]
return val
for res in resources:
res["id"] = id_map[res["id"]]
# Rewrite parent
if "parent" in res and res["parent"] in id_map:
res["parent"] = id_map[res["parent"]]
# Rewrite all ref: expressions in inputs and outputs
res["inputs"] = _rewrite_ref(res.get("inputs", {}))
if "outputs" in res:
res["outputs"] = _rewrite_ref(res["outputs"])
return resources, id_map
def decommission_transform(stack_instance): def decommission_transform(stack_instance):
@@ -432,24 +485,105 @@ def resolve(contract_path, repo_root=None, environment_override=None):
# reference the environment by ${env.environment}). # reference the environment by ${env.environment}).
env["environment"] = env.get("name", env_name) env["environment"] = env.get("name", env_name)
context = {"env": env, "contract": contract} context = {"env": env, "contract": contract}
contract["inputs"] = _expand_vars(contract.get("inputs", {}), context)
# Expand interpolation tokens in each module's inputs
infrastructure = contract.get("infrastructure", {})
for module_name, module_entry in infrastructure.items():
module_entry["inputs"] = _expand_vars(
module_entry.get("inputs", {}), context)
# Load registry # Load registry
registry = _load_json(os.path.join(repo_root, "modules", "registry.json")) registry = _load_json(os.path.join(repo_root, "modules", "registry.json"))
module_name = contract["module"] # Validate every module exists in the registry, then resolve each
if module_name not in registry: module_names = list(infrastructure.keys())
raise ValueError(f"module '{module_name}' not found in registry") fragments = []
for module_name in module_names:
if module_name not in registry:
raise ValueError(f"module '{module_name}' not found in registry")
module_entry = infrastructure[module_name]
# Default version to latest non-deprecated
version = module_entry.get("version")
if version is None:
version = _latest_version(registry, module_name)
elif version not in registry[module_name]:
raise ValueError(
f"module '{module_name}' version '{version}' not found in registry")
module_inputs = module_entry.get("inputs", {})
# Determine if L1 or L2 # Determine if L1 or L2
entry = registry[module_name]["1.0.0"] entry = registry[module_name][version]
interface_path = entry["interface"] interface_path = entry["interface"]
is_l2 = "l2" in interface_path or "composition" in interface_path is_l2 = "l2" in interface_path or "composition" in interface_path
if is_l2: if is_l2:
stack_instance = resolve_l2(contract, registry, repo_root) fragment = _resolve_l2(module_name, version, module_inputs,
registry, repo_root)
else:
fragment = _resolve_l1(module_name, version, module_inputs,
registry, repo_root)
fragments.append((module_name, fragment))
# Merge fragments into a single stack instance
all_resources = []
max_depth = 1
any_l2 = False
merged_features = {}
merged_outputs = {}
multi_module = len(fragments) > 1
for module_name, fragment in fragments:
if fragment["kind"] == "l2":
any_l2 = True
max_depth = max(max_depth, fragment["depth"])
merged_features.update(fragment.get("features", {}))
if multi_module:
# Namespace resource IDs to avoid cross-module collisions
namespaced, id_map = _namespace_resources(
fragment["resources"], module_name)
# Namespace the fragment's stack outputs (from refs)
for out_name, out_spec in fragment.get("outputs", {}).items():
src_id = out_spec.get("from", "")
if src_id in id_map:
out_spec["from"] = id_map[src_id]
merged_outputs[f"{module_name}-{out_name}"] = out_spec
all_resources.extend(namespaced)
else:
# Single module: keep IDs as-is (backward compatible)
merged_outputs.update(fragment.get("outputs", {}))
all_resources.extend(fragment["resources"])
# Determine stack kind: L2 if any module is L2 or if multi-module
if multi_module:
kind = "l2"
elif any_l2:
kind = "l2"
else: else:
stack_instance = resolve_l1(contract, registry, repo_root) kind = "l1"
stack_instance = {
"version": "1.0.0",
"stack": {
"name": contract["id"],
"kind": kind,
"depth": max_depth,
},
"resources": all_resources,
}
# Add the human-readable title
if contract.get("name"):
stack_instance["stack"]["title"] = contract["name"]
# Add features if any were set
if merged_features:
stack_instance["stack"]["features"] = merged_features
# Add stack-level outputs
if merged_outputs:
stack_instance["outputs"] = merged_outputs
# Validate against stack schema # Validate against stack schema
stack_schema = _load_json(os.path.join(repo_root, "schemas", "stack.schema.json")) stack_schema = _load_json(os.path.join(repo_root, "schemas", "stack.schema.json"))
@@ -460,7 +594,7 @@ def resolve(contract_path, repo_root=None, environment_override=None):
if __name__ == "__main__": if __name__ == "__main__":
if len(sys.argv) < 3: if len(sys.argv) < 3:
print("usage: contract_resolver.py <contract.yaml> <out.json> [--environment <name>]", file=sys.stderr) print("usage: contract_resolver.py <contract.yml> <out.json> [--environment <name>]", file=sys.stderr)
sys.exit(2) sys.exit(2)
contract_path = sys.argv[1] contract_path = sys.argv[1]
out_path = sys.argv[2] out_path = sys.argv[2]
@@ -474,5 +608,4 @@ if __name__ == "__main__":
env_override = os.environ["ACDL_ENVIRONMENT_OVERRIDE"] env_override = os.environ["ACDL_ENVIRONMENT_OVERRIDE"]
result = resolve(contract_path, environment_override=env_override) result = resolve(contract_path, environment_override=env_override)
with open(out_path, "w") as fh: with open(out_path, "w") as fh:
json.dump(result, fh, indent=2) json.dump(result, fh, indent=2)
print(f"resolver: resolved {contract_path} -> {out_path}", file=sys.stderr)
+1 -1
View File
@@ -488,7 +488,7 @@ def run_local_e2e(contract_path: str, repo_root: Optional[Path] = None) -> Dict[
if __name__ == "__main__": if __name__ == "__main__":
contract = sys.argv[1] if len(sys.argv) > 1 else "contracts/microservice.yaml" contract = sys.argv[1] if len(sys.argv) > 1 else "contracts/microservice.yml"
os.environ["ACDL_LOCAL_TIER"] = "1" os.environ["ACDL_LOCAL_TIER"] = "1"
result = run_local_e2e(contract) result = run_local_e2e(contract)
print(json.dumps(result, indent=2)) print(json.dumps(result, indent=2))
+8 -8
View File
@@ -120,7 +120,7 @@ def _check_contract_schema_validation() -> Tuple[Status, str]:
"import json, yaml, jsonschema; " "import json, yaml, jsonschema; "
"s=json.load(open('schemas/contract.schema.json')); " "s=json.load(open('schemas/contract.schema.json')); "
"[jsonschema.validate(yaml.safe_load(open(f)), s) " "[jsonschema.validate(yaml.safe_load(open(f)), s) "
" for f in ['contracts/static-assets.yaml','contracts/microservice.yaml']]; " " for f in ['contracts/static-assets.yml','contracts/microservice.yml']]; "
"print('2 sample contracts validate')", "print('2 sample contracts validate')",
]) ])
@@ -144,7 +144,7 @@ def _check_resolver_static_assets() -> Tuple[Status, str]:
try: try:
return _check_subprocess([ return _check_subprocess([
"python3", "core/contract_resolver.py", "python3", "core/contract_resolver.py",
"contracts/static-assets.yaml", out, "contracts/static-assets.yml", out,
]) ])
finally: finally:
try: try:
@@ -160,7 +160,7 @@ def _check_resolver_microservice() -> Tuple[Status, str]:
try: try:
return _check_subprocess([ return _check_subprocess([
"python3", "core/contract_resolver.py", "python3", "core/contract_resolver.py",
"contracts/microservice.yaml", out, "contracts/microservice.yml", out,
]) ])
finally: finally:
try: try:
@@ -177,7 +177,7 @@ def _check_adapter_emits_terraform() -> Tuple[Status, str]:
os.makedirs(tf_dir, exist_ok=True) os.makedirs(tf_dir, exist_ok=True)
rc, out, err = _run_subprocess([ rc, out, err = _run_subprocess([
"python3", "core/contract_resolver.py", "python3", "core/contract_resolver.py",
"contracts/static-assets.yaml", stack_path, "contracts/static-assets.yml", stack_path,
]) ])
if rc != 0: if rc != 0:
return "Broken", f"resolver failed: {err.strip()[-200:]}" return "Broken", f"resolver failed: {err.strip()[-200:]}"
@@ -276,7 +276,7 @@ def _check_local_e2e_microservice() -> Tuple[Status, str]:
This is the local-tier half of the headline E2E; the live-AWS half This is the local-tier half of the headline E2E; the live-AWS half
lands in Phase 54 (D-093).""" lands in Phase 54 (D-093)."""
return _check_subprocess( return _check_subprocess(
["python3", "core/local_emulators.py", "contracts/microservice.yaml"], ["python3", "core/local_emulators.py", "contracts/microservice.yml"],
timeout=60, timeout=60,
) )
@@ -284,7 +284,7 @@ def _check_local_e2e_microservice() -> Tuple[Status, str]:
def _check_local_e2e_static_assets() -> Tuple[Status, str]: def _check_local_e2e_static_assets() -> Tuple[Status, str]:
"""CAP-012: local E2E on the static-assets stack (no ECS service).""" """CAP-012: local E2E on the static-assets stack (no ECS service)."""
return _check_subprocess( return _check_subprocess(
["python3", "core/local_emulators.py", "contracts/static-assets.yaml"], ["python3", "core/local_emulators.py", "contracts/static-assets.yml"],
timeout=60, timeout=60,
) )
@@ -324,7 +324,7 @@ def _check_live_terraform_plan_microservice() -> Tuple[Status, str]:
os.makedirs(tf_dir, exist_ok=True) os.makedirs(tf_dir, exist_ok=True)
rc, out, err = _run_subprocess([ rc, out, err = _run_subprocess([
"python3", "core/contract_resolver.py", "python3", "core/contract_resolver.py",
"contracts/microservice.yaml", stack_path, "contracts/microservice.yml", stack_path,
]) ])
if rc != 0: if rc != 0:
return "Broken", f"resolver failed: {err.strip()[-200:]}" return "Broken", f"resolver failed: {err.strip()[-200:]}"
@@ -364,7 +364,7 @@ def _check_live_terraform_plan_static_assets() -> Tuple[Status, str]:
os.makedirs(tf_dir, exist_ok=True) os.makedirs(tf_dir, exist_ok=True)
rc, out, err = _run_subprocess([ rc, out, err = _run_subprocess([
"python3", "core/contract_resolver.py", "python3", "core/contract_resolver.py",
"contracts/static-assets.yaml", stack_path, "contracts/static-assets.yml", stack_path,
]) ])
if rc != 0: if rc != 0:
return "Broken", f"resolver failed: {err.strip()[-200:]}" return "Broken", f"resolver failed: {err.strip()[-200:]}"
+60 -42
View File
@@ -7,10 +7,10 @@ step applies to `microservice` and any future module.
## The model ## The model
Consumers have their own repos and consume ACDL by referencing `uses:` the Consumers have their own repos and consume ACDL by writing a contract
central pipeline definitions. The consumer declares a **contract** (which that declares infrastructure (one or more modules), an environment, and inputs. The consumer declares a **contract** (which infrastructure, which
module, which environment, which inputs); the ACDL platform owns the environment, which inputs); the ACDL platform owns the pipelines, modules,
pipelines, modules, engine adapter, and evidence stream. engine adapter, and evidence stream.
You do not write infrastructure modules, workflow YAML, or adapter code. You do not write infrastructure modules, workflow YAML, or adapter code.
You write a contract YAML file and the platform does the rest. Your You write a contract YAML file and the platform does the rest. Your
@@ -27,13 +27,13 @@ flowchart LR
## Versioning the `uses:` reference ## Versioning the `uses:` reference
The central deployment pipeline is **always versioned with floating MAJOR The central deployment pipeline is **always versioned with floating MAJOR
and MINOR tags** (e.g. `acdl/pipelines/deploy.yaml@v1.9`). Version and MINOR tags** (e.g. `acdl/pipelines/contract.yml@v1.9`). Version
constraints cannot be expressed inside the contract, so the tag in constraints cannot be expressed inside the contract, so the tag in
`uses:` is the only immutability lever a consumer has. See `uses:` is the only immutability lever a consumer has. See
[Versioning](pipeline/versioning) for the full rationale. [Versioning](pipeline/versioning) for the full rationale.
**Unversioned references are discouraged.** Do not use `@main` or a bare **Unversioned references are discouraged.** Do not use `@main` or a bare
`acdl/pipelines/deploy.yaml`. `acdl/pipelines/contract.yml`.
## Prerequisites ## Prerequisites
@@ -53,7 +53,7 @@ platform-managed. See [Environments](environments/).
## Step 1 — Create a consumer repo ## Step 1 — Create a consumer repo
Create a repository for your application. The top level holds your app Create a repository for your application. The top level holds your app
code; your contract lives at `.acdl/contract.yaml`. Example for a static code; your contract lives at `.acdl/contract.yml`. Example for a static
site: site:
``` ```
@@ -83,53 +83,64 @@ my-microservice/
``` ```
Your app code lives at the top level. Your contract lives at Your app code lives at the top level. Your contract lives at
`.acdl/contract.yaml` regardless of the module you deploy. Your CI `.acdl/contract.yml` regardless of the module you deploy. Your CI
definition lives at `.github/workflows/deploy.yml`. definition lives at `.github/workflows/deploy.yml`.
## Step 2 — Reference the central pipeline ## Step 2 — Reference the central pipeline
In your contract YAML, declare `uses:` pointing at the central ACDL In your CI workflow (`.github/workflows/deploy.yml`), reference the central
deployment pipeline with a **versioned tag** (floating MAJOR + MINOR): ACDL deployment workflow with a **versioned tag** (floating MAJOR + MINOR):
```yaml ```yaml
uses: acdl/pipelines/deploy.yaml@v1.9 jobs:
deploy:
uses: acdl/.github/workflows/deploy.yml@v1.9
with:
contract: .acdl/contract.yml
environment: dev
``` ```
This tells the platform to run the standard deployment pipeline: The versioned tag is the only immutability lever — the consumer's CI workflow
validate-contract → resolve-stack → security checks → infrastructure plan → pins the platform version. The contract itself no longer carries a `uses:`
policy checks → confidence → evidence event → apply. field; the version pin lives in the CI workflow reference.
## Step 3 — Define the contract ## Step 3 — Define the contract
Write `.acdl/contract.yaml`. The `static-assets` example: Write `.acdl/contract.yml`. The `static-assets` example:
```yaml ```yaml
uses: acdl/pipelines/deploy.yaml@v1.9
module: static-assets
environment: dev environment: dev
inputs: id: assets
bucket_name: my-static-site-assets infrastructure:
region: us-east-1 static-assets:
inputs:
bucket_name: my-static-site-assets
region: us-east-1
version: 1.0.0
name: static-assets
``` ```
A `microservice` example: A `microservice` example:
```yaml ```yaml
uses: acdl/pipelines/deploy.yaml@v1.9
module: microservice
environment: dev environment: dev
inputs: id: msvc
image: my-registry/my-microservice:latest infrastructure:
port: 8080 microservice:
env: inputs:
LOG_LEVEL: info env:
LOG_LEVEL: info
image: my-registry/my-microservice:latest
port: 8080
version: 1.0.0
name: microservice
``` ```
### Contract fields ### Contract fields
| Field | Type | Required | Description | | 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.9`). Bare or `@main` references are discouraged. See [Versioning](pipeline/versioning). | | `uses` | string | yes | Reference to the central deployment pipeline, **versioned** with a floating MAJOR+MINOR tag (e.g. `acdl/pipelines/contract.yml@v1.9`). Bare or `@main` references are discouraged. See [Versioning](pipeline/versioning). |
| `module` | string | yes | Module name from the registry — any primitive or module (e.g. `static-assets`, `microservice`, `s3`). See the [module catalog](modules/). | | `module` | string | yes | Module name from the registry — any primitive or module (e.g. `static-assets`, `microservice`, `s3`). See the [module catalog](modules/). |
| `environment` | string | yes | The platform-managed environment to deploy to (e.g. `dev`). See [Environments](environments/). | | `environment` | string | yes | The platform-managed environment to deploy to (e.g. `dev`). See [Environments](environments/). |
| `inputs` | object | yes | Module-specific inputs (see the module's README). | | `inputs` | object | yes | Module-specific inputs (see the module's README). |
@@ -168,7 +179,7 @@ jobs:
deploy: deploy:
uses: acdl/.github/workflows/deploy.yml@v1.9 uses: acdl/.github/workflows/deploy.yml@v1.9
with: with:
contract: .acdl/contract.yaml contract: .acdl/contract.yml
``` ```
That is the entire consumer-side workflow. When you push to `main`: That is the entire consumer-side workflow. When you push to `main`:
@@ -181,7 +192,7 @@ That is the entire consumer-side workflow. When you push to `main`:
never clone the platform repo yourself. never clone the platform repo yourself.
4. The runner installs the runtime dependencies the platform requires. 4. The runner installs the runtime dependencies the platform requires.
5. The runner invokes `scripts/run_platform.sh` against your 5. The runner invokes `scripts/run_platform.sh` against your
`.acdl/contract.yaml`. `.acdl/contract.yml`.
You see the streamed output (infrastructure plan, policy-check results, You see the streamed output (infrastructure plan, policy-check results,
confidence signal) in your run logs. The `--check-only` and `--plan-only` confidence signal) in your run logs. The `--check-only` and `--plan-only`
@@ -202,7 +213,7 @@ static key in `.env.secrets` (gitignored) is rotated **out of band by you**
locally-held copies. locally-held copies.
```bash ```bash
bash scripts/run_platform.sh --check-only path/to/your/.acdl/contract.yaml bash scripts/run_platform.sh --check-only path/to/your/.acdl/contract.yml
``` ```
## Step 5 — What the pipeline does ## Step 5 — What the pipeline does
@@ -278,11 +289,16 @@ push your container image to the ECR repo the platform created.
## Step 8 — Promote to qa / prod ## Step 8 — Promote to qa / prod
Change `environment` in your contract (keeping the same versioned `uses:`): Change `environment` in your contract (the infrastructure stays the same):
```yaml ```yaml
uses: acdl/pipelines/deploy.yaml@v1.9 id: assets
name: static-assets
environment: qa # QA attestation + confidence >= 0.75 environment: qa # QA attestation + confidence >= 0.75
infrastructure:
static-assets:
version: "1.0.0"
inputs: { ... }
``` ```
Higher environments require human attestation (a platform-runner deployment Higher environments require human attestation (a platform-runner deployment
@@ -305,7 +321,7 @@ per-module extension points. Common examples:
| Resource | Path | Description | | Resource | Path | Description |
|----------|------|-------------| |----------|------|-------------|
| Central deployment pipeline contract | `pipelines/deploy.yaml` | The pipeline stages your contract references. | | Central deployment pipeline contract | `pipelines/contract.yml` | The pipeline stages your contract references. |
| Reusable deploy workflow | `.github/workflows/deploy.yml` | The workflow your repo invokes via `uses:`. | | 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. | | Contract schema | `schemas/contract.schema.json` | JSON Schema for consumer contracts. |
| Stack schema | `schemas/stack.schema.json` | JSON Schema for the resolved stack instance. | | Stack schema | `schemas/stack.schema.json` | JSON Schema for the resolved stack instance. |
@@ -339,7 +355,7 @@ destruction:
```yaml ```yaml
uses: acdl/.github/workflows/deploy.yml@v1.8 uses: acdl/.github/workflows/deploy.yml@v1.8
with: with:
contract: .acdl/contract.yaml contract: .acdl/contract.yml
mode: decommission mode: decommission
changeRequestId: "CHG0678912" changeRequestId: "CHG0678912"
``` ```
@@ -393,13 +409,15 @@ contract per environment (e.g. `.acdl/static-assets.dev.yaml`,
name and uses interpolation so env-specific values differ automatically: name and uses interpolation so env-specific values differ automatically:
```yaml ```yaml
# .acdl/static-assets.qa.yaml
uses: acdl/pipelines/deploy.yaml@v1.9
module: static-assets
environment: qa environment: qa
inputs: id: assets
bucket_name: acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region} infrastructure:
region: ${env.region} static-assets:
inputs:
bucket_name: acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region}
region: ${env.region}
version: 1.0.0
name: static-assets
``` ```
**Shape 2 — single contract + `environment` workflow input:** the **Shape 2 — single contract + `environment` workflow input:** the
@@ -421,7 +439,7 @@ jobs:
uses: acdl/.github/workflows/deploy.yml@v1.9 uses: acdl/.github/workflows/deploy.yml@v1.9
with: with:
environment: qa environment: qa
contract: .acdl/contract.yaml contract: .acdl/contract.yml
``` ```
### One job per environment ### One job per environment
+61 -28
View File
@@ -1,44 +1,57 @@
# Contracts # Contracts
A consumer declares intent in a **contract** — a small YAML file that A consumer declares intent in a **contract** — a small YAML file that
references the central deploy pipeline, names a module, selects an names infrastructure (one or more modules), selects an environment, and
environment, and supplies module-specific inputs. The platform validates, supplies module-specific inputs. The platform validates, resolves, and
resolves, and deploys it. deploys it.
## The contract file ## The contract file
A consumer repo keeps its contract at `.acdl/contract.yaml`. A minimal A consumer repo keeps its contract at `.acdl/contract.yml`. A minimal
example (the `static-assets` module): example (the `static-assets` module):
```yaml ```yaml
uses: acdl/pipelines/deploy.yaml@v1.6 id: assets
module: static-assets name: static-assets
environment: dev environment: dev
inputs: infrastructure:
bucket_name: my-static-site-assets static-assets:
region: us-east-1 version: "1.0.0"
inputs:
bucket_name: my-static-site-assets
region: us-east-1
``` ```
A `microservice` example: A `microservice` example:
```yaml ```yaml
uses: acdl/pipelines/deploy.yaml@v1.6 id: msvc
module: microservice name: microservice
environment: dev environment: dev
inputs: infrastructure:
image: my-registry/my-microservice:latest microservice:
port: 8080 version: "1.0.0"
env: inputs:
LOG_LEVEL: info image: my-registry/my-microservice:latest
port: 8080
env:
LOG_LEVEL: info
``` ```
## Fields ## Fields
| Field | Type | Required | Description | | Field | Type | Required | Description |
|-------|------|----------|-------------| |-------|------|----------|-------------|
| `uses` | string | yes | Reference to the central deploy pipeline, **versioned** with a floating MAJOR+MINOR tag (e.g. `acdl/pipelines/deploy.yaml@v1.6`). Bare or `@main` references are discouraged. See [Versioning](../pipeline/versioning). | | `id` | string | yes | Short operational acronym (3-6 chars, `^[a-z][a-z0-9-]{2,5}$`). Becomes the stack name used for the Terraform state key, ECS service name, outbox event identity, and resource naming prefix. |
| `module` | string | yes | Module name from the registry — any primitive or module (e.g. `static-assets`, `microservice`, `s3`). See the [module catalog](../modules/). | | `name` | string | yes | Full human-readable stack name (min 3 chars). Becomes the stack title used for display in PR comments, evidence records, and leadership dashboards. |
| `environment` | string | yes | The platform-managed environment to deploy to (e.g. `dev`). See [Environments](../environments/). | | `environment` | string | yes | The platform-managed environment to deploy to (`dev`/`qa`/`prod`/`dr`). See [Environments](../environments/). |
| `infrastructure` | object | yes | Map of modules to deploy, keyed by module registry name. Each entry has an optional `version` (defaults to latest published) and required `inputs`. One entry = single-module deploy; N entries = multi-module manifest deployed in one pipeline run. |
### Infrastructure entry fields
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `version` | string | no | Module version pin (semver `X.Y.Z`). Omitted = latest non-deprecated version from the registry. |
| `inputs` | object | yes | Module-specific inputs (see the module's README). | | `inputs` | object | yes | Module-specific inputs (see the module's README). |
## Validation ## Validation
@@ -52,19 +65,39 @@ validate-contract stage with a clear error.
Two reference examples exist in `contracts/`: Two reference examples exist in `contracts/`:
- [`contracts/static-assets.yaml`](https://github.com/acdl/acdl/blob/main/contracts/static-assets.yaml) - [`contracts/static-assets.yml`](https://github.com/acdl/acdl/blob/main/contracts/static-assets.yml)
— the `static-assets` module (uses `@v1.6`). — the `static-assets` module.
- [`contracts/microservice.yaml`](https://github.com/acdl/acdl/blob/main/contracts/microservice.yaml) - [`contracts/microservice.yml`](https://github.com/acdl/acdl/blob/main/contracts/microservice.yml)
— the `microservice` module (uses `@v1.6`). — the `microservice` module.
Additionally, every module has a `modules/<name>/examples/` directory with Additionally, every module has a `modules/<name>/examples/` directory with
validated example contracts (`simple.yaml` + `complex.yaml` + variation validated example contracts (`simple.yml` + `complex.yml` + variation
files). See the [module catalog](../modules/) for the full list. files). See the [module catalog](../modules/) for the full list.
## Multiple modules per contract
A contract may declare multiple modules under the `infrastructure` map.
All modules deploy to the same `environment` in one pipeline run. Resource
IDs are namespaced with the module name to avoid collisions (e.g.
`microservice-vpc`, `static-assets-s3`).
```yaml
id: app
name: pricing-service-api
environment: dev
infrastructure:
microservice:
version: "1.0.0"
inputs: { ... }
static-assets:
version: "1.0.0"
inputs: { ... }
```
## Multiple contracts ## Multiple contracts
A consumer repo may contain more than one contract (e.g. one per service or A consumer repo may also contain more than one contract file (e.g. one per
one per environment). Each contract is a separate deployment; each is environment). Each contract is a separate deployment; each is referenced by a
referenced by a CI definition in `.github/workflows/` that invokes the CI definition in `.github/workflows/` that invokes the central reusable
central reusable workflow with the contract path. See the workflow with the contract path. See the
[Consumer Guide](../consumer-guide/) for the multi-contract pattern. [Consumer Guide](../consumer-guide/) for the multi-contract pattern.
+1 -1
View File
@@ -16,7 +16,7 @@ There are two kinds of repository in the ACDL model:
and the reusable workflow files. Platform engineers work here. A consumer and the reusable workflow files. Platform engineers work here. A consumer
never clones it. never clones it.
- **Consumer repo (yours).** A consumer repo contains only its application - **Consumer repo (yours).** A consumer repo contains only its application
code, one or more contracts (`.acdl/contract.yaml`), and one or more CI code, one or more contracts (`.acdl/contract.yml`), and one or more CI
definitions (a thin `.github/workflows/deploy.yml` that `uses:` the central definitions (a thin `.github/workflows/deploy.yml` that `uses:` the central
reusable workflow, pointing at the appropriate environment + contract). reusable workflow, pointing at the appropriate environment + contract).
The consumer does not write infrastructure modules, workflow YAML, or The consumer does not write infrastructure modules, workflow YAML, or
+2 -2
View File
@@ -6,7 +6,7 @@ are the single source of truth for the workflow files.
## CI pipeline ## CI pipeline
The CI pipeline runs on every push and pull request to `main`. It is defined The CI pipeline runs on every push and pull request to `main`. It is defined
by [`pipelines/ci.yaml`](https://github.com/acdl/acdl/blob/main/pipelines/ci.yaml), by [`pipelines/ci.yml`](https://github.com/acdl/acdl/blob/main/pipelines/ci.yml),
validated against validated against
[`schemas/pipeline.schema.json`](https://github.com/acdl/acdl/blob/main/schemas/pipeline.schema.json). [`schemas/pipeline.schema.json`](https://github.com/acdl/acdl/blob/main/schemas/pipeline.schema.json).
Both platform-runner workflow files implement the same contract and are Both platform-runner workflow files implement the same contract and are
@@ -31,7 +31,7 @@ bash scripts/run_ci.sh --quiet # suppress per-stage banners
## Deployment pipeline ## Deployment pipeline
The deployment pipeline runs when a consumer submits a contract. It is The deployment pipeline runs when a consumer submits a contract. It is
defined by [`pipelines/deploy.yaml`](https://github.com/acdl/acdl/blob/main/pipelines/deploy.yaml), defined by [`pipelines/contract.yml`](https://github.com/acdl/acdl/blob/main/pipelines/contract.yml),
validated against validated against
[`schemas/deploy-pipeline.schema.json`](https://github.com/acdl/acdl/blob/main/schemas/deploy-pipeline.schema.json). [`schemas/deploy-pipeline.schema.json`](https://github.com/acdl/acdl/blob/main/schemas/deploy-pipeline.schema.json).
It is exposed to consumer repos as a **reusable workflow**: It is exposed to consumer repos as a **reusable workflow**:
+12 -7
View File
@@ -18,21 +18,26 @@ primitives by `name@semver`; the resolver picks the highest compatible.
Module versions are tracked in Module versions are tracked in
[`registry.json`](https://github.com/acdl/acdl/blob/main/modules/registry.json). [`registry.json`](https://github.com/acdl/acdl/blob/main/modules/registry.json).
## Deploy-pipeline versioning (the `uses:` tag) ## Deploy-pipeline versioning (the CI workflow `uses:` tag)
The central deploy pipeline is referenced by a **floating MAJOR + MINOR The central deploy pipeline is referenced by a **floating MAJOR + MINOR
tag** in a consumer's contract and CI definition: tag** in a consumer's CI workflow definition:
```yaml ```yaml
uses: acdl/pipelines/deploy.yaml@v1.6 jobs:
deploy:
uses: acdl/.github/workflows/deploy.yml@v1.6
with:
contract: .acdl/contract.yml
``` ```
Version constraints cannot be expressed inside the contract, so the tag in The version pin lives in the CI workflow reference (not in the contract
`uses:` is the only immutability lever a consumer has. itself — the contract no longer carries a `uses:` field). The CI workflow
`uses:` tag is the only immutability lever a consumer has.
**Unversioned references are discouraged.** Do not use `@main` or a bare **Unversioned references are discouraged.** Do not use `@main` or a bare
`acdl/pipelines/deploy.yaml``main` is constantly updated and can cause `acdl/.github/workflows/deploy.yml``main` is constantly updated and can
unexpected failures. Pinning to a MAJOR+MINOR tag means: cause unexpected failures. Pinning to a MAJOR+MINOR tag means:
- **Immutability** — the pipeline behavior you tested is the behavior you - **Immutability** — the pipeline behavior you tested is the behavior you
get. Patch fixes flow within the tag; breaking changes land under the get. Patch fixes flow within the tag; breaking changes land under the
+14 -14
View File
@@ -46,8 +46,8 @@ Every L1 primitive MUST contain, at minimum:
| `interface.json` | Angine-agnostic declaration: inputs, outputs, NFRs, optional multi-resource graph. | | `interface.json` | Angine-agnostic declaration: inputs, outputs, NFRs, optional multi-resource graph. |
| `instance.json` | A concrete instance used as the adapter regression baseline. | | `instance.json` | A concrete instance used as the adapter regression baseline. |
| `README.md` | Plain-language documentation following `README-TEMPLATE.md` (see §7). | | `README.md` | Plain-language documentation following `README-TEMPLATE.md` (see §7). |
| `examples/simple.yaml` | A minimal contract that uses the primitive with required inputs only. | | `examples/simple.yml` | A minimal contract that uses the primitive with required inputs only. |
| `examples/complex.yaml` | A contract that exercises optional inputs, NFRs, and (if applicable) the multi-resource graph. | | `examples/complex.yml` | A contract that exercises optional inputs, NFRs, and (if applicable) the multi-resource graph. |
Directory layout: Directory layout:
@@ -57,8 +57,8 @@ modules/l1/<name>/
instance.json instance.json
README.md README.md
examples/ examples/
simple.yaml simple.yml
complex.yaml complex.yml
``` ```
### 2.2 interface.json schema ### 2.2 interface.json schema
@@ -225,8 +225,8 @@ asset site behind CloudFront + WAF). It is declared by a
|------|---------| |------|---------|
| `composition.json` | The composition tree: children, wires, outputs, optional features. | | `composition.json` | The composition tree: children, wires, outputs, optional features. |
| `README.md` | Plain-language documentation following `README-TEMPLATE.md` (see §7). | | `README.md` | Plain-language documentation following `README-TEMPLATE.md` (see §7). |
| `examples/simple.yaml` | A minimal contract that uses the module with required inputs only. | | `examples/simple.yml` | A minimal contract that uses the module with required inputs only. |
| `examples/complex.yaml` | A contract that exercises optional inputs and feature flags. | | `examples/complex.yml` | A contract that exercises optional inputs and feature flags. |
Directory layout: Directory layout:
@@ -235,8 +235,8 @@ modules/l2/<name>/
composition.json composition.json
README.md README.md
examples/ examples/
simple.yaml simple.yml
complex.yaml complex.yml
``` ```
There is no `instance.json` for an L2 module — the L2 is deployed by There is no `instance.json` for an L2 module — the L2 is deployed by
@@ -433,8 +433,8 @@ Every module README MUST follow the structure of
8. `## Compliance extension points` — resources or behaviors that could 8. `## Compliance extension points` — resources or behaviors that could
be added for the future compliance milestone (GDPR, SOX, SOC2, be added for the future compliance milestone (GDPR, SOX, SOC2,
DORA). Not implemented yet; listed so the redesign can plan for them. DORA). Not implemented yet; listed so the redesign can plan for them.
9. `## Examples` — links to `examples/simple.yaml` and 9. `## Examples` — links to `examples/simple.yml` and
`examples/complex.yaml` with a one-line description of each. `examples/complex.yml` with a one-line description of each.
10. `## Versioning` — the module's semver policy: interface MAJOR, 10. `## Versioning` — the module's semver policy: interface MAJOR,
behavior MINOR, lifecycle PATCH. MAJOR bumps require a new behavior MINOR, lifecycle PATCH. MAJOR bumps require a new
`registry.json` entry (immutable publication); old entries enter a `registry.json` entry (immutable publication); old entries enter a
@@ -514,12 +514,12 @@ must be checked before the module is registered and published.
- [ ] All required files present: - [ ] All required files present:
- L1: `interface.json`, `instance.json`, `README.md`, - L1: `interface.json`, `instance.json`, `README.md`,
`examples/simple.yaml`, `examples/complex.yaml`. `examples/simple.yml`, `examples/complex.yml`.
- L2: `composition.json`, `README.md`, `examples/simple.yaml`, - L2: `composition.json`, `README.md`, `examples/simple.yml`,
`examples/complex.yaml` (no `instance.json`). `examples/complex.yml` (no `instance.json`).
- [ ] `interface.json` (L1) / `composition.json` (L2) validates against - [ ] `interface.json` (L1) / `composition.json` (L2) validates against
`schemas/stack.schema.json`. `schemas/stack.schema.json`.
- [ ] `examples/simple.yaml` and `examples/complex.yaml` validate - [ ] `examples/simple.yml` and `examples/complex.yml` validate
against `schemas/contract.schema.json`. against `schemas/contract.schema.json`.
- [ ] Module registered in `modules/registry.json` at its semver with a - [ ] Module registered in `modules/registry.json` at its semver with a
full ISO 8601 `published_at` and `deprecated: false`. full ISO 8601 `published_at` and `deprecated: false`.
+26 -21
View File
@@ -73,37 +73,42 @@ pipeline validates them against `schemas/contract.schema.json`.
A minimal deployment: A minimal deployment:
[`examples/simple.yaml`](examples/simple.yaml) [`examples/simple.yml`](examples/simple.yml)
```yaml ```yaml
uses: acdl/pipelines/deploy.yaml@v1.6
module: alb
environment: dev environment: dev
inputs: id: alb
name: my-alb infrastructure:
subnets: subnet-aaa,subnet-bbb alb:
security_group: sg-xxx inputs:
port: 80 name: my-alb
protocol: HTTP port: 80
region: us-east-1 protocol: HTTP
region: us-east-1
security_group: sg-xxx
subnets: subnet-aaa,subnet-bbb
version: 1.0.0
name: alb-loadbalancer
``` ```
### Complex ### Complex
A production deployment with optional inputs: A production deployment with optional inputs:
[`examples/complex.yaml`](examples/complex.yaml) [`examples/complex.yml`](examples/complex.yml)
```yaml ```yaml
# Complex ALB with HTTPS + ACM cert (requires a consumer-supplied domain)
uses: acdl/pipelines/deploy.yaml@v1.6
module: alb
environment: dev environment: dev
inputs: id: alb
name: my-production-alb infrastructure:
subnets: subnet-aaa,subnet-bbb alb:
security_group: sg-xxx inputs:
port: 443 name: my-production-alb
protocol: HTTPS port: 443
region: us-east-1 protocol: HTTPS
region: us-east-1
security_group: sg-xxx
subnets: subnet-aaa,subnet-bbb
version: 1.0.0
name: alb-loadbalancer
``` ```
## Versioning ## Versioning
-11
View File
@@ -1,11 +0,0 @@
# Complex ALB with HTTPS + ACM cert (requires a consumer-supplied domain)
uses: acdl/pipelines/deploy.yaml@v1.6
module: alb
environment: dev
inputs:
name: my-production-alb
subnets: subnet-aaa,subnet-bbb
security_group: sg-xxx
port: 443
protocol: HTTPS
region: us-east-1
+14
View File
@@ -0,0 +1,14 @@
# Complex ALB with HTTPS + ACM cert (requires a consumer-supplied domain)
environment: dev
id: alb
infrastructure:
alb:
inputs:
name: my-production-alb
port: 443
protocol: HTTPS
region: us-east-1
security_group: sg-xxx
subnets: subnet-aaa,subnet-bbb
version: 1.0.0
name: alb-loadbalancer
-10
View File
@@ -1,10 +0,0 @@
uses: acdl/pipelines/deploy.yaml@v1.6
module: alb
environment: dev
inputs:
name: my-alb
subnets: subnet-aaa,subnet-bbb
security_group: sg-xxx
port: 80
protocol: HTTP
region: us-east-1
+13
View File
@@ -0,0 +1,13 @@
environment: dev
id: alb
infrastructure:
alb:
inputs:
name: my-alb
port: 80
protocol: HTTP
region: us-east-1
security_group: sg-xxx
subnets: subnet-aaa,subnet-bbb
version: 1.0.0
name: alb-loadbalancer
+23 -19
View File
@@ -80,35 +80,39 @@ pipeline validates them against `schemas/contract.schema.json`.
A minimal deployment: A minimal deployment:
[`examples/simple.yaml`](examples/simple.yaml) [`examples/simple.yml`](examples/simple.yml)
```yaml ```yaml
# Simple CloudFront distribution (S3 origin, no WAF)
uses: acdl/pipelines/deploy.yaml@v1.6
module: cloudfront
environment: dev environment: dev
inputs: id: cdn
bucket_regional_domain_name: my-bucket.s3.us-east-1.amazonaws.com infrastructure:
region: us-east-1 cloudfront:
inputs:
bucket_regional_domain_name: my-bucket.s3.us-east-1.amazonaws.com
region: us-east-1
version: 1.0.0
name: cloudfront
``` ```
### Complex ### Complex
A production deployment with optional inputs: A production deployment with optional inputs:
[`examples/complex.yaml`](examples/complex.yaml) [`examples/complex.yml`](examples/complex.yml)
```yaml ```yaml
# Complex CloudFront with WAF + custom TTL + viewer protocol redirect
uses: acdl/pipelines/deploy.yaml@v1.6
module: cloudfront
environment: dev environment: dev
inputs: id: cdn
bucket_regional_domain_name: my-bucket.s3.us-east-1.amazonaws.com infrastructure:
price_class: PriceClass_100 cloudfront:
viewer_protocol_policy: redirect-to-https inputs:
default_ttl: 3600 bucket_regional_domain_name: my-bucket.s3.us-east-1.amazonaws.com
max_ttl: 86400 default_ttl: 3600
waf_web_acl_arn: arn:aws:wafv2:us-east-1:000000000000:webacl/my-waf max_ttl: 86400
region: us-east-1 price_class: PriceClass_100
region: us-east-1
viewer_protocol_policy: redirect-to-https
waf_web_acl_arn: arn:aws:wafv2:us-east-1:000000000000:webacl/my-waf
version: 1.0.0
name: cloudfront
``` ```
## Versioning ## Versioning
@@ -1,12 +0,0 @@
# Complex CloudFront with WAF + custom TTL + viewer protocol redirect
uses: acdl/pipelines/deploy.yaml@v1.6
module: cloudfront
environment: dev
inputs:
bucket_regional_domain_name: my-bucket.s3.us-east-1.amazonaws.com
price_class: PriceClass_100
viewer_protocol_policy: redirect-to-https
default_ttl: 3600
max_ttl: 86400
waf_web_acl_arn: arn:aws:wafv2:us-east-1:000000000000:webacl/my-waf
region: us-east-1
@@ -0,0 +1,15 @@
# Complex CloudFront with WAF + custom TTL + viewer protocol redirect
environment: dev
id: cdn
infrastructure:
cloudfront:
inputs:
bucket_regional_domain_name: my-bucket.s3.us-east-1.amazonaws.com
default_ttl: 3600
max_ttl: 86400
price_class: PriceClass_100
region: us-east-1
viewer_protocol_policy: redirect-to-https
waf_web_acl_arn: arn:aws:wafv2:us-east-1:000000000000:webacl/my-waf
version: 1.0.0
name: cloudfront
@@ -1,7 +0,0 @@
# Simple CloudFront distribution (S3 origin, no WAF)
uses: acdl/pipelines/deploy.yaml@v1.6
module: cloudfront
environment: dev
inputs:
bucket_regional_domain_name: my-bucket.s3.us-east-1.amazonaws.com
region: us-east-1
+10
View File
@@ -0,0 +1,10 @@
# Simple CloudFront distribution (S3 origin, no WAF)
environment: dev
id: cdn
infrastructure:
cloudfront:
inputs:
bucket_regional_domain_name: my-bucket.s3.us-east-1.amazonaws.com
region: us-east-1
version: 1.0.0
name: cloudfront
+18 -13
View File
@@ -60,29 +60,34 @@ pipeline validates them against `schemas/contract.schema.json`.
A minimal deployment: A minimal deployment:
[`examples/simple.yaml`](examples/simple.yaml) [`examples/simple.yml`](examples/simple.yml)
```yaml ```yaml
uses: acdl/pipelines/deploy.yaml@v1.6
module: ecr
environment: dev environment: dev
inputs: id: ecr
name: my-repo infrastructure:
region: us-east-1 ecr:
inputs:
name: my-repo
region: us-east-1
version: 1.0.0
name: ecr-repo
``` ```
### Complex ### Complex
A production deployment with optional inputs: A production deployment with optional inputs:
[`examples/complex.yaml`](examples/complex.yaml) [`examples/complex.yml`](examples/complex.yml)
```yaml ```yaml
# Complex ECR with lifecycle policy + image scanning
uses: acdl/pipelines/deploy.yaml@v1.6
module: ecr
environment: dev environment: dev
inputs: id: ecr
name: my-production-repo infrastructure:
region: us-east-1 ecr:
inputs:
name: my-production-repo
region: us-east-1
version: 1.0.0
name: ecr-repo
``` ```
## Versioning ## Versioning
-7
View File
@@ -1,7 +0,0 @@
# Complex ECR with lifecycle policy + image scanning
uses: acdl/pipelines/deploy.yaml@v1.6
module: ecr
environment: dev
inputs:
name: my-production-repo
region: us-east-1
+10
View File
@@ -0,0 +1,10 @@
# Complex ECR with lifecycle policy + image scanning
environment: dev
id: ecr
infrastructure:
ecr:
inputs:
name: my-production-repo
region: us-east-1
version: 1.0.0
name: ecr-repo
-6
View File
@@ -1,6 +0,0 @@
uses: acdl/pipelines/deploy.yaml@v1.6
module: ecr
environment: dev
inputs:
name: my-repo
region: us-east-1
+9
View File
@@ -0,0 +1,9 @@
environment: dev
id: ecr
infrastructure:
ecr:
inputs:
name: my-repo
region: us-east-1
version: 1.0.0
name: ecr-repo
+18 -13
View File
@@ -58,29 +58,34 @@ pipeline validates them against `schemas/contract.schema.json`.
A minimal deployment: A minimal deployment:
[`examples/simple.yaml`](examples/simple.yaml) [`examples/simple.yml`](examples/simple.yml)
```yaml ```yaml
uses: acdl/pipelines/deploy.yaml@v1.6
module: ecs-cluster
environment: dev environment: dev
inputs: id: clus
name: my-cluster infrastructure:
region: us-east-1 ecs-cluster:
inputs:
name: my-cluster
region: us-east-1
version: 1.0.0
name: ecs-cluster
``` ```
### Complex ### Complex
A production deployment with optional inputs: A production deployment with optional inputs:
[`examples/complex.yaml`](examples/complex.yaml) [`examples/complex.yml`](examples/complex.yml)
```yaml ```yaml
# Complex ECS cluster with container insights
uses: acdl/pipelines/deploy.yaml@v1.6
module: ecs-cluster
environment: dev environment: dev
inputs: id: clus
name: my-production-cluster infrastructure:
region: us-east-1 ecs-cluster:
inputs:
name: my-production-cluster
region: us-east-1
version: 1.0.0
name: ecs-cluster
``` ```
## Versioning ## Versioning
@@ -1,7 +0,0 @@
# Complex ECS cluster with container insights
uses: acdl/pipelines/deploy.yaml@v1.6
module: ecs-cluster
environment: dev
inputs:
name: my-production-cluster
region: us-east-1
@@ -0,0 +1,10 @@
# Complex ECS cluster with container insights
environment: dev
id: clus
infrastructure:
ecs-cluster:
inputs:
name: my-production-cluster
region: us-east-1
version: 1.0.0
name: ecs cluster
@@ -1,6 +0,0 @@
uses: acdl/pipelines/deploy.yaml@v1.6
module: ecs-cluster
environment: dev
inputs:
name: my-cluster
region: us-east-1
@@ -0,0 +1,9 @@
environment: dev
id: clus
infrastructure:
ecs-cluster:
inputs:
name: my-cluster
region: us-east-1
version: 1.0.0
name: ecs cluster
+25 -20
View File
@@ -80,36 +80,41 @@ pipeline validates them against `schemas/contract.schema.json`.
A minimal deployment: A minimal deployment:
[`examples/simple.yaml`](examples/simple.yaml) [`examples/simple.yml`](examples/simple.yml)
```yaml ```yaml
uses: acdl/pipelines/deploy.yaml@v1.6
module: ecs-service
environment: dev environment: dev
inputs: id: svc
name: my-service infrastructure:
region: us-east-1 ecs-service:
image: public.ecr.aws/docker/library/nginx:latest inputs:
port: 80 image: public.ecr.aws/docker/library/nginx:latest
name: my-service
port: 80
region: us-east-1
version: 1.0.0
name: ecs-service
``` ```
### Complex ### Complex
A production deployment with optional inputs: A production deployment with optional inputs:
[`examples/complex.yaml`](examples/complex.yaml) [`examples/complex.yml`](examples/complex.yml)
```yaml ```yaml
# Complex ECS service with env vars + health check
uses: acdl/pipelines/deploy.yaml@v1.6
module: ecs-service
environment: dev environment: dev
inputs: id: svc
name: my-production-service infrastructure:
region: us-east-1 ecs-service:
image: public.ecr.aws/docker/library/nginx:latest inputs:
port: 8080 env:
env: ENVIRONMENT: production
LOG_LEVEL: info LOG_LEVEL: info
ENVIRONMENT: production image: public.ecr.aws/docker/library/nginx:latest
name: my-production-service
port: 8080
region: us-east-1
version: 1.0.0
name: ecs-service
``` ```
## Versioning ## Versioning
@@ -1,12 +0,0 @@
# Complex ECS service with env vars + health check
uses: acdl/pipelines/deploy.yaml@v1.6
module: ecs-service
environment: dev
inputs:
name: my-production-service
region: us-east-1
image: public.ecr.aws/docker/library/nginx:latest
port: 8080
env:
LOG_LEVEL: info
ENVIRONMENT: production
@@ -0,0 +1,15 @@
# Complex ECS service with env vars + health check
environment: dev
id: svc
infrastructure:
ecs-service:
inputs:
env:
ENVIRONMENT: production
LOG_LEVEL: info
image: public.ecr.aws/docker/library/nginx:latest
name: my-production-service
port: 8080
region: us-east-1
version: 1.0.0
name: ecs service
@@ -1,8 +0,0 @@
uses: acdl/pipelines/deploy.yaml@v1.6
module: ecs-service
environment: dev
inputs:
name: my-service
region: us-east-1
image: public.ecr.aws/docker/library/nginx:latest
port: 80
@@ -0,0 +1,11 @@
environment: dev
id: svc
infrastructure:
ecs-service:
inputs:
image: public.ecr.aws/docker/library/nginx:latest
name: my-service
port: 80
region: us-east-1
version: 1.0.0
name: ecs service
+18 -13
View File
@@ -66,29 +66,34 @@ pipeline validates them against `schemas/contract.schema.json`.
A minimal deployment: A minimal deployment:
[`examples/simple.yaml`](examples/simple.yaml) [`examples/simple.yml`](examples/simple.yml)
```yaml ```yaml
uses: acdl/pipelines/deploy.yaml@v1.6
module: iam-role
environment: dev environment: dev
inputs: id: role
name: my-task-role infrastructure:
region: us-east-1 iam-role:
inputs:
name: my-task-role
region: us-east-1
version: 1.0.0
name: iam-role
``` ```
### Complex ### Complex
A production deployment with optional inputs: A production deployment with optional inputs:
[`examples/complex.yaml`](examples/complex.yaml) [`examples/complex.yml`](examples/complex.yml)
```yaml ```yaml
# Complex IAM role with managed policies
uses: acdl/pipelines/deploy.yaml@v1.6
module: iam-role
environment: dev environment: dev
inputs: id: role
name: my-production-task-role infrastructure:
region: us-east-1 iam-role:
inputs:
name: my-production-task-role
region: us-east-1
version: 1.0.0
name: iam-role
``` ```
## Versioning ## Versioning
@@ -1,7 +0,0 @@
# Complex IAM role with managed policies
uses: acdl/pipelines/deploy.yaml@v1.6
module: iam-role
environment: dev
inputs:
name: my-production-task-role
region: us-east-1
+10
View File
@@ -0,0 +1,10 @@
# Complex IAM role with managed policies
environment: dev
id: role
infrastructure:
iam-role:
inputs:
name: my-production-task-role
region: us-east-1
version: 1.0.0
name: iam role
-6
View File
@@ -1,6 +0,0 @@
uses: acdl/pipelines/deploy.yaml@v1.6
module: iam-role
environment: dev
inputs:
name: my-task-role
region: us-east-1
+9
View File
@@ -0,0 +1,9 @@
environment: dev
id: role
infrastructure:
iam-role:
inputs:
name: my-task-role
region: us-east-1
version: 1.0.0
name: iam role
+19 -13
View File
@@ -67,29 +67,35 @@ pipeline validates them against `schemas/contract.schema.json`.
A minimal deployment: A minimal deployment:
[`examples/simple.yaml`](examples/simple.yaml) [`examples/simple.yml`](examples/simple.yml)
```yaml ```yaml
uses: acdl/pipelines/deploy.yaml@v1.8
module: kms-key
environment: dev environment: dev
inputs: id: kms
description: "Simple CMK for testing" infrastructure:
region: us-east-1 kms-key:
inputs:
description: Simple CMK for testing
region: us-east-1
version: 1.0.0
name: kms-key
``` ```
### Complex ### Complex
A production deployment with optional inputs: A production deployment with optional inputs:
[`examples/complex.yaml`](examples/complex.yaml) [`examples/complex.yml`](examples/complex.yml)
```yaml ```yaml
uses: acdl/pipelines/deploy.yaml@v1.8
module: kms-key
environment: dev environment: dev
inputs: id: kms
description: "Production CMK with 90-day deletion window" infrastructure:
region: us-east-1 kms-key:
deletion_window_days: 90 inputs:
deletion_window_days: 90
description: Production CMK with 90-day deletion window
region: us-east-1
version: 1.0.0
name: kms-key
``` ```
## Versioning ## Versioning
-7
View File
@@ -1,7 +0,0 @@
uses: acdl/pipelines/deploy.yaml@v1.8
module: kms-key
environment: dev
inputs:
description: "Production CMK with 90-day deletion window"
region: us-east-1
deletion_window_days: 90
+10
View File
@@ -0,0 +1,10 @@
environment: dev
id: kms
infrastructure:
kms-key:
inputs:
deletion_window_days: 90
description: Production CMK with 90-day deletion window
region: us-east-1
version: 1.0.0
name: kms key
-6
View File
@@ -1,6 +0,0 @@
uses: acdl/pipelines/deploy.yaml@v1.8
module: kms-key
environment: dev
inputs:
description: "Simple CMK for testing"
region: us-east-1
+9
View File
@@ -0,0 +1,9 @@
environment: dev
id: kms
infrastructure:
kms-key:
inputs:
description: Simple CMK for testing
region: us-east-1
version: 1.0.0
name: kms key
+45 -39
View File
@@ -95,42 +95,46 @@ pipeline validates them against `schemas/contract.schema.json`.
A minimal deployment: A minimal deployment:
[`examples/simple.yaml`](examples/simple.yaml) [`examples/simple.yml`](examples/simple.yml)
```yaml ```yaml
# Simple RDS postgres instance
uses: acdl/pipelines/deploy.yaml@v1.6
module: rds
environment: dev environment: dev
inputs: id: rds
engine: postgres infrastructure:
engine_version: "16.4" rds:
instance_class: db.t3.micro inputs:
allocated_storage: 20 allocated_storage: 20
db_name: my_app_db db_name: my_app_db
username: db_admin engine: postgres
region: us-east-1 engine_version: '16.4'
instance_class: db.t3.micro
region: us-east-1
username: db_admin
version: 1.0.0
name: rds-instance
``` ```
### Complex ### Complex
A production deployment with optional inputs: A production deployment with optional inputs:
[`examples/complex.yaml`](examples/complex.yaml) [`examples/complex.yml`](examples/complex.yml)
```yaml ```yaml
# Complex RDS postgres with multi-AZ + encryption
uses: acdl/pipelines/deploy.yaml@v1.6
module: rds
environment: dev environment: dev
inputs: id: rds
engine: postgres infrastructure:
engine_version: "16.4" rds:
instance_class: db.r6g.large inputs:
allocated_storage: 100 allocated_storage: 100
db_name: my_production_db db_name: my_production_db
username: db_admin engine: postgres
multi_az: true engine_version: '16.4'
storage_encrypted: true instance_class: db.r6g.large
region: us-east-1 multi_az: true
region: us-east-1
storage_encrypted: true
username: db_admin
version: 1.0.0
name: rds-instance
``` ```
### Multi-engine variation ### Multi-engine variation
@@ -140,25 +144,27 @@ the `engine_version` must match.
#### PostgreSQL #### PostgreSQL
[`examples/simple.yaml`](examples/simple.yaml) — postgres 16.4 [`examples/simple.yml`](examples/simple.yml) — postgres 16.4
#### MySQL #### MySQL
[`examples/mysql.yaml`](examples/mysql.yaml) — mysql 8.4 [`examples/mysql.yml`](examples/mysql.yml) — mysql 8.4
```yaml ```yaml
# RDS mysql variation
uses: acdl/pipelines/deploy.yaml@v1.6
module: rds
environment: dev environment: dev
inputs: id: rds
engine: mysql infrastructure:
engine_version: "8.4" rds:
instance_class: db.t3.micro inputs:
allocated_storage: 20 allocated_storage: 20
db_name: my_mysql_db db_name: my_mysql_db
username: db_admin engine: mysql
region: us-east-1 engine_version: '8.4'
instance_class: db.t3.micro
region: us-east-1
username: db_admin
version: 1.0.0
name: rds-instance
``` ```
## Versioning ## Versioning
-14
View File
@@ -1,14 +0,0 @@
# Complex RDS postgres with multi-AZ + encryption
uses: acdl/pipelines/deploy.yaml@v1.6
module: rds
environment: dev
inputs:
engine: postgres
engine_version: "16.4"
instance_class: db.r6g.large
allocated_storage: 100
db_name: my_production_db
username: db_admin
multi_az: true
storage_encrypted: true
region: us-east-1
+17
View File
@@ -0,0 +1,17 @@
# Complex RDS postgres with multi-AZ + encryption
environment: dev
id: rds
infrastructure:
rds:
inputs:
allocated_storage: 100
db_name: my_production_db
engine: postgres
engine_version: '16.4'
instance_class: db.r6g.large
multi_az: true
region: us-east-1
storage_encrypted: true
username: db_admin
version: 1.0.0
name: rds-instance
-12
View File
@@ -1,12 +0,0 @@
# RDS mysql variation
uses: acdl/pipelines/deploy.yaml@v1.6
module: rds
environment: dev
inputs:
engine: mysql
engine_version: "8.4"
instance_class: db.t3.micro
allocated_storage: 20
db_name: my_mysql_db
username: db_admin
region: us-east-1
+15
View File
@@ -0,0 +1,15 @@
# RDS mysql variation
environment: dev
id: rds
infrastructure:
rds:
inputs:
allocated_storage: 20
db_name: my_mysql_db
engine: mysql
engine_version: '8.4'
instance_class: db.t3.micro
region: us-east-1
username: db_admin
version: 1.0.0
name: rds-instance
-12
View File
@@ -1,12 +0,0 @@
# Simple RDS postgres instance
uses: acdl/pipelines/deploy.yaml@v1.6
module: rds
environment: dev
inputs:
engine: postgres
engine_version: "16.4"
instance_class: db.t3.micro
allocated_storage: 20
db_name: my_app_db
username: db_admin
region: us-east-1
+15
View File
@@ -0,0 +1,15 @@
# Simple RDS postgres instance
environment: dev
id: rds
infrastructure:
rds:
inputs:
allocated_storage: 20
db_name: my_app_db
engine: postgres
engine_version: '16.4'
instance_class: db.t3.micro
region: us-east-1
username: db_admin
version: 1.0.0
name: rds-instance
+18 -12
View File
@@ -65,28 +65,34 @@ pipeline validates them against `schemas/contract.schema.json`.
A minimal deployment: A minimal deployment:
[`examples/simple.yaml`](examples/simple.yaml) [`examples/simple.yml`](examples/simple.yml)
```yaml ```yaml
uses: acdl/pipelines/deploy.yaml@v1.6
module: s3
environment: dev environment: dev
inputs: id: s3a
bucket_name: my-simple-bucket infrastructure:
region: us-east-1 s3:
inputs:
bucket_name: my-simple-bucket
region: us-east-1
version: 1.0.0
name: s3-bucket
``` ```
### Complex ### Complex
A production deployment with optional inputs: A production deployment with optional inputs:
[`examples/complex.yaml`](examples/complex.yaml) [`examples/complex.yml`](examples/complex.yml)
```yaml ```yaml
uses: acdl/pipelines/deploy.yaml@v1.6
module: s3
environment: dev environment: dev
inputs: id: s3a
bucket_name: my-production-bucket infrastructure:
region: us-east-1 s3:
inputs:
bucket_name: my-production-bucket
region: us-east-1
version: 1.0.0
name: s3-bucket
``` ```
> **Note:** the s3 primitive's compliance extensions (Object Lock, access > **Note:** the s3 primitive's compliance extensions (Object Lock, access
-6
View File
@@ -1,6 +0,0 @@
uses: acdl/pipelines/deploy.yaml@v1.6
module: s3
environment: dev
inputs:
bucket_name: my-production-bucket
region: us-east-1
+9
View File
@@ -0,0 +1,9 @@
environment: dev
id: s3a
infrastructure:
s3:
inputs:
bucket_name: my-production-bucket
region: us-east-1
version: 1.0.0
name: s3-bucket
-6
View File
@@ -1,6 +0,0 @@
uses: acdl/pipelines/deploy.yaml@v1.6
module: s3
environment: dev
inputs:
bucket_name: my-simple-bucket
region: us-east-1
+9
View File
@@ -0,0 +1,9 @@
environment: dev
id: s3a
infrastructure:
s3:
inputs:
bucket_name: my-simple-bucket
region: us-east-1
version: 1.0.0
name: s3-bucket
+50 -44
View File
@@ -87,14 +87,17 @@ pipeline validates them against `schemas/contract.schema.json`.
A minimal deployment: A minimal deployment:
[`examples/simple.yaml`](examples/simple.yaml) [`examples/simple.yml`](examples/simple.yml)
```yaml ```yaml
uses: acdl/pipelines/deploy.yaml@v1.8
module: uptime
environment: dev environment: dev
inputs: id: up1
region: us-east-1 infrastructure:
feature_flag_enabled: true uptime:
inputs:
feature_flag_enabled: true
region: us-east-1
version: 1.0.0
name: uptime-monitor
``` ```
### Complex ### Complex
@@ -102,46 +105,49 @@ inputs:
A production deployment with monitored endpoints, static checks, and A production deployment with monitored endpoints, static checks, and
multiple alert channels: multiple alert channels:
[`examples/complex.yaml`](examples/complex.yaml) [`examples/complex.yml`](examples/complex.yml)
```yaml ```yaml
uses: acdl/pipelines/deploy.yaml@v1.8
module: uptime
environment: dev environment: dev
inputs: id: up1
region: us-east-1 infrastructure:
feature_flag_enabled: true uptime:
cpu: 512 inputs:
memory: 1024 alert_channels:
monitored_endpoints: email_addresses:
- name: "api-health" - oncall@example.com
url: "https://api.example.com/health" - sre@example.com
type: "http" github_issue_repo: acdl/acdl
interval_seconds: 30 sms_numbers:
timeout_seconds: 10 - '+1234567890'
- name: "dns-check" teams_webhook: https://hooks.example.com/teams/webhook
url: "example.com" cpu: 512
type: "dns" feature_flag_enabled: true
interval_seconds: 60 memory: 1024
timeout_seconds: 10 monitored_endpoints:
- name: "tcp-check" - interval_seconds: 30
url: "db.example.com:5432" name: api-health
type: "tcp" timeout_seconds: 10
interval_seconds: 60 type: http
timeout_seconds: 10 url: https://api.example.com/health
static_checks: - interval_seconds: 60
- name: "google" name: dns-check
url: "https://google.com" timeout_seconds: 10
type: "http" type: dns
interval_seconds: 60 url: example.com
timeout_seconds: 10 - interval_seconds: 60
alert_channels: name: tcp-check
teams_webhook: "https://hooks.example.com/teams/webhook" timeout_seconds: 10
email_addresses: type: tcp
- "oncall@example.com" url: db.example.com:5432
- "sre@example.com" region: us-east-1
sms_numbers: static_checks:
- "+1234567890" - interval_seconds: 60
github_issue_repo: "acdl/acdl" name: google
timeout_seconds: 10
type: http
url: https://google.com
version: 1.0.0
name: uptime-monitor
``` ```
## Versioning ## Versioning
-38
View File
@@ -1,38 +0,0 @@
uses: acdl/pipelines/deploy.yaml@v1.8
module: uptime
environment: dev
inputs:
region: us-east-1
feature_flag_enabled: true
cpu: 512
memory: 1024
monitored_endpoints:
- name: "api-health"
url: "https://api.example.com/health"
type: "http"
interval_seconds: 30
timeout_seconds: 10
- name: "dns-check"
url: "example.com"
type: "dns"
interval_seconds: 60
timeout_seconds: 10
- name: "tcp-check"
url: "db.example.com:5432"
type: "tcp"
interval_seconds: 60
timeout_seconds: 10
static_checks:
- name: "google"
url: "https://google.com"
type: "http"
interval_seconds: 60
timeout_seconds: 10
alert_channels:
teams_webhook: "https://hooks.example.com/teams/webhook"
email_addresses:
- "oncall@example.com"
- "sre@example.com"
sms_numbers:
- "+1234567890"
github_issue_repo: "acdl/acdl"
+41
View File
@@ -0,0 +1,41 @@
environment: dev
id: up1
infrastructure:
uptime:
inputs:
alert_channels:
email_addresses:
- oncall@example.com
- sre@example.com
github_issue_repo: acdl/acdl
sms_numbers:
- '+1234567890'
teams_webhook: https://hooks.example.com/teams/webhook
cpu: 512
feature_flag_enabled: true
memory: 1024
monitored_endpoints:
- interval_seconds: 30
name: api-health
timeout_seconds: 10
type: http
url: https://api.example.com/health
- interval_seconds: 60
name: dns-check
timeout_seconds: 10
type: dns
url: example.com
- interval_seconds: 60
name: tcp-check
timeout_seconds: 10
type: tcp
url: db.example.com:5432
region: us-east-1
static_checks:
- interval_seconds: 60
name: google
timeout_seconds: 10
type: http
url: https://google.com
version: 1.0.0
name: uptime-monitor
-6
View File
@@ -1,6 +0,0 @@
uses: acdl/pipelines/deploy.yaml@v1.8
module: uptime
environment: dev
inputs:
region: us-east-1
feature_flag_enabled: true
+9
View File
@@ -0,0 +1,9 @@
environment: dev
id: up1
infrastructure:
uptime:
inputs:
feature_flag_enabled: true
region: us-east-1
version: 1.0.0
name: uptime-monitor
+22 -17
View File
@@ -69,33 +69,38 @@ pipeline validates them against `schemas/contract.schema.json`.
A minimal deployment: A minimal deployment:
[`examples/simple.yaml`](examples/simple.yaml) [`examples/simple.yml`](examples/simple.yml)
```yaml ```yaml
uses: acdl/pipelines/deploy.yaml@v1.6
module: vpc
environment: dev environment: dev
inputs: id: vpc
cidr: 10.0.0.0/16 infrastructure:
azs: us-east-1a,us-east-1b vpc:
name: my-vpc inputs:
region: us-east-1 azs: us-east-1a,us-east-1b
cidr: 10.0.0.0/16
name: my-vpc
region: us-east-1
version: 1.0.0
name: vpc-network
``` ```
### Complex ### Complex
A production deployment with optional inputs: A production deployment with optional inputs:
[`examples/complex.yaml`](examples/complex.yaml) [`examples/complex.yml`](examples/complex.yml)
```yaml ```yaml
# Complex VPC with 3 AZs and a custom CIDR
uses: acdl/pipelines/deploy.yaml@v1.6
module: vpc
environment: dev environment: dev
inputs: id: vpc
cidr: 10.50.0.0/16 infrastructure:
azs: us-east-1a,us-east-1b,us-east-1c vpc:
name: my-production-vpc inputs:
region: us-east-1 azs: us-east-1a,us-east-1b,us-east-1c
cidr: 10.50.0.0/16
name: my-production-vpc
region: us-east-1
version: 1.0.0
name: vpc-network
``` ```
## Versioning ## Versioning
-9
View File
@@ -1,9 +0,0 @@
# Complex VPC with 3 AZs and a custom CIDR
uses: acdl/pipelines/deploy.yaml@v1.6
module: vpc
environment: dev
inputs:
cidr: 10.50.0.0/16
azs: us-east-1a,us-east-1b,us-east-1c
name: my-production-vpc
region: us-east-1
+12
View File
@@ -0,0 +1,12 @@
# Complex VPC with 3 AZs and a custom CIDR
environment: dev
id: vpc
infrastructure:
vpc:
inputs:
azs: us-east-1a,us-east-1b,us-east-1c
cidr: 10.50.0.0/16
name: my-production-vpc
region: us-east-1
version: 1.0.0
name: vpc-network
-8
View File
@@ -1,8 +0,0 @@
uses: acdl/pipelines/deploy.yaml@v1.6
module: vpc
environment: dev
inputs:
cidr: 10.0.0.0/16
azs: us-east-1a,us-east-1b
name: my-vpc
region: us-east-1
+11
View File
@@ -0,0 +1,11 @@
environment: dev
id: vpc
infrastructure:
vpc:
inputs:
azs: us-east-1a,us-east-1b
cidr: 10.0.0.0/16
name: my-vpc
region: us-east-1
version: 1.0.0
name: vpc-network
+20 -16
View File
@@ -69,32 +69,36 @@ pipeline validates them against `schemas/contract.schema.json`.
A minimal deployment: A minimal deployment:
[`examples/simple.yaml`](examples/simple.yaml) [`examples/simple.yml`](examples/simple.yml)
```yaml ```yaml
# Simple WAF with managed rules only
uses: acdl/pipelines/deploy.yaml@v1.6
module: waf
environment: dev environment: dev
inputs: id: waf
name: my-waf infrastructure:
region: us-east-1 waf:
inputs:
name: my-waf
region: us-east-1
version: 1.0.0
name: waf-firewall
``` ```
### Complex ### Complex
A production deployment with optional inputs: A production deployment with optional inputs:
[`examples/complex.yaml`](examples/complex.yaml) [`examples/complex.yml`](examples/complex.yml)
```yaml ```yaml
# Complex WAF with rate limiting + geo blocking (custom rules)
uses: acdl/pipelines/deploy.yaml@v1.6
module: waf
environment: dev environment: dev
inputs: id: waf
name: my-production-waf infrastructure:
scope: cloudfront waf:
default_action: allow inputs:
region: us-east-1 default_action: allow
name: my-production-waf
region: us-east-1
scope: cloudfront
version: 1.0.0
name: waf-firewall
``` ```
## Versioning ## Versioning
-9
View File
@@ -1,9 +0,0 @@
# Complex WAF with rate limiting + geo blocking (custom rules)
uses: acdl/pipelines/deploy.yaml@v1.6
module: waf
environment: dev
inputs:
name: my-production-waf
scope: cloudfront
default_action: allow
region: us-east-1
+12
View File
@@ -0,0 +1,12 @@
# Complex WAF with rate limiting + geo blocking (custom rules)
environment: dev
id: waf
infrastructure:
waf:
inputs:
default_action: allow
name: my-production-waf
region: us-east-1
scope: cloudfront
version: 1.0.0
name: waf-firewall
-7
View File
@@ -1,7 +0,0 @@
# Simple WAF with managed rules only
uses: acdl/pipelines/deploy.yaml@v1.6
module: waf
environment: dev
inputs:
name: my-waf
region: us-east-1
+10
View File
@@ -0,0 +1,10 @@
# Simple WAF with managed rules only
environment: dev
id: waf
infrastructure:
waf:
inputs:
name: my-waf
region: us-east-1
version: 1.0.0
name: waf-firewall
+34 -27
View File
@@ -41,13 +41,16 @@ The pattern references these primitives:
Define a contract referencing this module: Define a contract referencing this module:
```yaml ```yaml
uses: acdl/pipelines/deploy.yaml@v1.6
module: microservice
environment: dev environment: dev
inputs: id: msvc
image: 581513795199.dkr.ecr.us-east-1.amazonaws.com/acdl-microservice:latest infrastructure:
port: 8080 microservice:
region: us-east-1 inputs:
image: 581513795199.dkr.ecr.us-east-1.amazonaws.com/acdl-microservice:latest
port: 8080
region: us-east-1
version: 1.0.0
name: microservice
``` ```
## Compliance extension points ## Compliance extension points
@@ -72,37 +75,41 @@ pipeline validates them against `schemas/contract.schema.json`.
A minimal deployment (minimal Fargate, no ALB): A minimal deployment (minimal Fargate, no ALB):
[`examples/simple.yaml`](examples/simple.yaml) [`examples/simple.yml`](examples/simple.yml)
```yaml ```yaml
# Simple microservice deployment (minimal Fargate, no ALB)
uses: acdl/pipelines/deploy.yaml@v1.6
module: microservice
environment: dev environment: dev
inputs: id: msvc
bucket_name: my-microservice-demo infrastructure:
region: us-east-1 microservice:
image: public.ecr.aws/docker/library/nginx:latest inputs:
port: 80 bucket_name: my-microservice-demo
image: public.ecr.aws/docker/library/nginx:latest
port: 80
region: us-east-1
version: 1.0.0
name: microservice
``` ```
### Complex ### Complex
A production deployment with optional inputs (ALB + env vars + health check): A production deployment with optional inputs (ALB + env vars + health check):
[`examples/complex.yaml`](examples/complex.yaml) [`examples/complex.yml`](examples/complex.yml)
```yaml ```yaml
# Complex microservice with ALB + env vars + health check
uses: acdl/pipelines/deploy.yaml@v1.6
module: microservice
environment: dev environment: dev
inputs: id: msvc
bucket_name: my-production-microservice infrastructure:
region: us-east-1 microservice:
image: public.ecr.aws/docker/library/nginx:latest inputs:
port: 8080 bucket_name: my-production-microservice
env: env:
LOG_LEVEL: info ENVIRONMENT: production
ENVIRONMENT: production LOG_LEVEL: info
image: public.ecr.aws/docker/library/nginx:latest
port: 8080
region: us-east-1
version: 1.0.0
name: microservice
``` ```
## Versioning ## Versioning
@@ -1,12 +0,0 @@
# Complex microservice with ALB + env vars + health check
uses: acdl/pipelines/deploy.yaml@v1.6
module: microservice
environment: dev
inputs:
bucket_name: my-production-microservice
region: us-east-1
image: public.ecr.aws/docker/library/nginx:latest
port: 8080
env:
LOG_LEVEL: info
ENVIRONMENT: production

Some files were not shown because too many files have changed in this diff Show More