From 136ec6abf3ee648c4b4905cfb83b4cd79e2198ed Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Thu, 23 Jul 2026 04:15:41 +0000 Subject: [PATCH] docs(init): validate v1.9 specification ---ci--- project: acdl phase: 0 milestone: v1.9 status: specify ---/ci--- v1.9 scope (user-directed, 2026-07-23): - Design doc refresh (hitl_matrix_design.md + audit_ledger_design.md) - Contract interpolation (${env.} + ${contract.}) - Per-environment CI jobs (no environment field editing for promotion) - Stub implementation (SoD, HITL gates, attestation matrix, Wiz, Kyverno) - P1-1 adapter parameterization remediation Requirements REQ-100..REQ-111 added to REQUIREMENTS.md. PROJECT.md v1.9 objective + phase table (39-43) appended. config.json milestone bumped to v1.9 (active). --- .ciagent/PROJECT.md | 68 ++++++++++++++++++++++++++++++++++++++++ .ciagent/REQUIREMENTS.md | 32 +++++++++++++++++++ .ciagent/config.json | 4 +-- 3 files changed, 102 insertions(+), 2 deletions(-) diff --git a/.ciagent/PROJECT.md b/.ciagent/PROJECT.md index 1b92a68..896753e 100644 --- a/.ciagent/PROJECT.md +++ b/.ciagent/PROJECT.md @@ -296,6 +296,74 @@ and test each. Milestone COMPLETE gate: review → ship `v1.8.0` (feature milestone, next minor per run.md — v1.7 shipped `v1.7.0`) → audit. +## Objective for Milestone v1.9 (active) + +Production-grade progression: contract interpolation, per-environment +promotion without field editing, stub implementation, and P1-1 +remediation. The v1.8 milestone shipped encryption/deletion-protection by +default, uptime, decommission, and engineering standards but left four +gaps that v1.9 closes (user-directed, 2026-07-23): + +1. **Design doc refresh.** `core/hitl_matrix_design.md` and + `core/audit_ledger_design.md` are stale — both still describe the + v1.1 spike scope ("dev-only; HITL not exercised"; "spike scope = + hash chain + outbox write; Object Lock + JWS are v1.2"). v1.9 brings + them up to date with the shipped v1.8 platform and the v1.9 wiring. +2. **Contract interpolation (variable expansion).** Contracts cannot + reference environment onboarding values today — bucket names, account + IDs, regions are hardcoded literals. v1.9 adds `${env.}` and + `${contract.}` expansion in the resolver, sourced from the + environment onboarding JSON. Naming patterns like + `acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region}` + become expressible. The S3 bucket naming-pattern requirement is the + binding example. +3. **Per-environment CI jobs (no field editing for promotion).** Today a + promotion dev → qa requires editing the `environment:` field in the + contract YAML. v1.9 ships a hybrid model: (a) per-environment contract + files (`.acdl/static-assets.dev.yaml`, `...qa.yaml`, etc.) and (b) an + `environment` `workflow_call` input on the reusable deploy workflow + that overrides the contract's environment at load time. There is one + CI job per environment, each pointing at its respective contract (or + the same contract + the env input). Promotion = running the matching + job; no field editing. +4. **Stub implementation.** Identify and implement the stubbed + functionality: `separation_of_duties.route_halt_artifact` (logs only → + real SNS + outbox event); HITL qa/prod/dr pre-execution attestation + gates (only decommission SRE gates are wired today); the full + 8-concern attestation matrix (offline-testable subset implemented; + operator-supplied concerns accept signed evidence artifacts); the Wiz + adapter (stub → real API client with graceful degrade); the Kyverno + adapter (fleshed out translator, still inactive for Terraform-only + stacks). The audit-ledger S3 Object Lock + JWS + async worker + DLQ + + daily checkpoints build-out is **deferred** to a future milestone + (D-076) — it requires non-offline-testable AWS infra (Object Lock + bucket, KMS signing key, SQS DLQ, Lambda worker). +5. **Post-hoc requirement from previous milestones.** P1-1 from the v1.2 + review (adapter ECS/ALB/VPC hardcoded defaults — `desired_count = 1`, + `launch_type = "FARGATE"`, `target_type = "ip"`, + `load_balancer_type = "application"`, `family = "app"`, `Name = ...` + — should be parameterized via the L1 interfaces, deferred to v1.3, + never implemented) is closed. The adapter becomes a thin translator; + the defaults move into `interface.json` inputs. + +The milestone also reconstructs `.ciagent/REVIEW.md`, which still holds +v1.2 review content (v1.3–v1.8 reviews were not persisted). The v1.9 +review overwrites it with current milestone content; a note records the +historical gap (no git-history rewrite). + +## Milestone v1.9 Phases + +| Phase | Name | Goal | +|-------|------|------| +| 39 | design-doc-refresh-and-p1-1-parameterization | Refresh `hitl_matrix_design.md` + `audit_ledger_design.md` to current. Move adapter ECS/ALB/VPC hardcoded defaults into L1 `interface.json` inputs (P1-1 closure). | +| 40 | contract-interpolation | `${env.}` + `${contract.}` resolver expansion from environment onboarding JSON. Environment JSON schema. Sample contracts use naming patterns (region + account id + environment). | +| 41 | per-environment-ci-jobs | Per-env contract files + `environment` workflow_call input on the deploy workflow. 1 CI job per environment (dev/qa/prod/dr), each pointing at its respective contract. HITL attestation gate structure wired (qa/prod/dr). | +| 42 | stub-implementation | `route_halt_artifact` real (SNS + outbox). HITL qa/prod/dr attestation gates. 8-concern attestation matrix (offline-testable subset). Wiz real client. Kyverno translator fleshed out. | +| 43 | verify-review-audit-complete | 4-layer verify. Multi-persona review. Audit. Complete v1.9 (tag `v1.9.0`, floating tags, `uses:` bump `@v1.6` → `@v1.9`). | + +Milestone COMPLETE gate: review → ship `v1.9.0` (feature milestone, next +minor per run.md — v1.8 shipped `v1.8.0`) → audit. + ## Requirements ### v1.0 (Prior milestone — the demo) diff --git a/.ciagent/REQUIREMENTS.md b/.ciagent/REQUIREMENTS.md index 2898181..bc90596 100644 --- a/.ciagent/REQUIREMENTS.md +++ b/.ciagent/REQUIREMENTS.md @@ -240,6 +240,38 @@ | Adversarial tamper-proofing of evidence | Hash chain is demonstrative; not cryptographically secure against a determined attacker. | | Multi-tenant isolation | Out of demo scope. | +## v1.9 (Active — design doc refresh + contract interpolation + per-env CI jobs + stub implementation + P1-1 remediation) + +### Category: Design Doc Refresh +- **REQ-100:** `core/hitl_matrix_design.md` is up to date: the "dev-only spike" framing is replaced with the v1.9 wired-gates reality (qa/prod/dr `workflow_dispatch` approval gates + CODEOWNERS routing + outbox-based SoD); the 8-concern attestation matrix is marked implemented (offline-testable subset) with operator-supplied concerns noted; the spike-scope note is updated. No stale "v1.2 wires the gates" language remains. +- **REQ-101:** `core/audit_ledger_design.md` is up to date: the hash-chain + DynamoDB-outbox path is marked shipped + production (since v1.8); the S3 Object Lock + JWS + async worker + DLQ + daily checkpoints build-out is clearly labeled "Deferred to a future milestone" (D-076); the RPO/RTO table reflects the v1.9 state. + +### Category: P1-1 Remediation +- **REQ-102:** The adapter (`adapters/terraform/adapter.py`) contains no resource-type-specific hardcoded defaults for ECS/ALB/VPC resources — `desired_count`, `launch_type`, `target_type`, `load_balancer_type`, `family`, and `Name` tag values are read from L1 `interface.json` inputs (with defaults declared in the interface). The adapter is a thin translator. An L1 with an overridden `desired_count: 3` emits `desired_count = 3`; the default emits `desired_count = 1` via the interface default, not an adapter hardcode (P1-1 closed). + +### Category: Contract Interpolation +- **REQ-103:** The contract resolver (`core/contract_resolver.py`) expands `${env.}` and `${contract.}` tokens in contract string values (including dotted paths like `${env.state_backend.bucket}`) after schema validation and before IR resolution. The `env` context is the loaded `core/environments/.json`; the `contract` context is the contract dict. Unresolved tokens raise `ValueError` (fail loud). Sample contracts use naming patterns that include region, account id, and environment (e.g. `acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region}`). +- **REQ-104:** An environment JSON schema `schemas/environment.schema.json` (draft 2020-12) defines the environment file shape (`name`, `account_id`, `region`, `state_backend`, `network`, `runner_role_arn`, `autonomy`, `confidence_threshold`). `core/environments/dev.json` validates against it. `qa.json`, `prod.json`, `dr.json` placeholder bindings exist (autonomy `attested`, thresholds 0.75/0.90/0.95). + +### Category: Per-Environment CI Jobs +- **REQ-105:** Per-environment contract files exist for each sample module (`contracts/static-assets.{dev,qa,prod,dr}.yaml` and `contracts/microservice.{dev,qa,prod,dr}.yaml`), each setting `environment:` to its own name and using interpolation for env-specific values. The existing `contracts/static-assets.yaml` + `contracts/microservice.yaml` remain as the dev default for backwards compatibility. +- **REQ-106:** The reusable deploy workflow (`.github/workflows/deploy.yml` + `.gitea/workflows/deploy.yml`, byte-identical) declares an `environment` `workflow_call` input (enum dev/qa/prod/dr, default empty). When non-empty, `scripts/run_platform.sh --environment ` overrides the contract's `environment` field at load time (before interpolation). A consumer repo's caller workflow has one job per environment, each pointing at its respective contract (or the same contract + the env input). Promotion = running the matching job; no `environment:` field editing. `docs/CONSUMER_GUIDE.md` documents the per-env caller workflow pattern. + +### Category: Stub Implementation +- **REQ-107:** `core/separation_of_duties.py` `route_halt_artifact` is a real implementation: publishes to an SNS topic `acdl-sod-halt` (ARN from `ACDL_SOD_HALT_TOPIC_ARN`); when unset, falls back to a structured stderr emission + a `SEPARATION_OF_DUTIES_VIOLATION` event write to the DynamoDB outbox via `outbox_writer.write_event`. No silent print-only stub. The SNS topic is defined in `terraform/platform/main.tf`. +- **REQ-108:** HITL qa/prod/dr pre-execution attestation gates are wired via `core/hitl_gates.py` (`attest(contract_id, env, approver, evidence)`). The gate records the approver (`gitea.actor` / `github.actor`) to the outbox (`approver_qa` / `approver_prod` / `approver_dr` attributes per `audit_ledger_design.md`), runs the separation-of-duties check on prod, and returns `(ok, reason)`. `scripts/run_platform.sh` calls `hitl_gates.attest` before apply for qa/prod/dr (dev skips). The workflow's `workflow_dispatch` approval input is the trigger. +- **REQ-109:** The full 8-concern attestation matrix from `hitl_matrix_design.md` §10.4 is implemented in `core/attestation_matrix.py`. Offline-testable concerns (contract NFRs, schema validity, policy pass) run for real; operator-supplied concerns (k6 load test, DR drill, FinOps forecast) accept an uploaded signed evidence artifact validated for freshness + schema, failing loud if missing/expired for prod/dr. `hitl_gates.attest` invokes the matrix for the target env and blocks on any failing concern. +- **REQ-110:** The Wiz adapter (`adapters/wiz/wiz_adapter.py`) is a real API client: a `WizClient` queries the Wiz GraphQL API (`WIZ_API_TOKEN` + `WIZ_API_URL`) and translates issues → `PolicyCheckResult` records. It degrades gracefully (existing `WIZ_NOT_CONFIGURED` SKIPPED record) when env unset. Offline tests use a recorded GraphQL fixture. +- **REQ-111:** The Kyverno adapter (`adapters/kyverno/kyverno_adapter.py`) translator is fleshed out: full `PolicyReport` → `PolicyCheckResult` mapping with severity + skip handling. It remains inactive for Terraform-only stacks (guard preserved); a `--kube-version` stub is added for future GitOps. Sample policies already exist. + +## Out of Scope (v1.9) + +| Feature | Reason | +|---------|--------| +| S3 Object Lock + JWS + async worker + DLQ + daily checkpoints (audit ledger build-out) | Requires non-offline-testable AWS infra (Object Lock bucket, KMS signing key, SQS DLQ, Lambda worker). Deferred to a future milestone (D-076). The hash-chain + DynamoDB-outbox path remains the v1.9 production audit record. | +| Live k6/Gatling load test execution, live DR drill, live FinOps forecast | Operator-supplied evidence artifacts (signed blobs) are accepted + validated; the platform does not run these inline. | +| Self-service environment provisioning | Adding an environment remains a platform-team action (per `core/environments/README.md`). v1.9 adds the env files + schema, not self-service provisioning. | + ## Traceability ### v1.0 (prior — demo) diff --git a/.ciagent/config.json b/.ciagent/config.json index c54ba03..5c4cc97 100644 --- a/.ciagent/config.json +++ b/.ciagent/config.json @@ -4,8 +4,8 @@ { "slug": "acdl", "name": "Agentic Cloud Delivery Platform", - "milestone": "v1.8", - "status": "complete" + "milestone": "v1.9", + "status": "active" } ], "active_project": "acdl",