diff --git a/.ciagent/PLAN.md b/.ciagent/PLAN.md index 6ac1645..21f7241 100644 --- a/.ciagent/PLAN.md +++ b/.ciagent/PLAN.md @@ -142,24 +142,77 @@ wiring reconciliation, + the pilot regression CAP. The Post-Pilot metrics are grounded (outcome backfill + escalation reason); the pilot- readiness + settlement-finality policies are in place. -**Project:** `acdl` (platform repo). +**Project:** `acdl` (platform repo) + `nova-blockchain-exchange` +(consumer repo — the Gitea adapter rewrites the consumer's `deploy.yml`). **Branch:** `acdl/phase/03-pilot-metrics-and-policies` (platform branch). **Personas:** backend-engineer (emitters + adapter + regression), data-engineer (DynamoDB primitive + env JSON + collector), -policy-engineer (kyverno-json policies). +policy-engineer (kyverno-json policies), lead-developer (Gitea adapter ++ deploy.yml drift + rotation workflow). -### Wave 1 — DynamoDB primitive (REQ-322) — data-engineer -- **Task 1.1** (data-engineer): `modules/l1/dynamodb/interface.json` — - stack type `aws:dynamodb:table`, inputs (table_name, region, pk, sk, - billing_mode), outputs (table_arn, table_name). -- **Task 1.2** (data-engineer): `modules/l1/dynamodb/terraform/main.tf` - — `resource "aws_dynamodb_table" "this"` (PK + optional SK, - `PAY_PER_REQUEST` default, encryption + PITR enabled per v1.8 NFR). -- **Task 1.3** (data-engineer): `modules/l1/dynamodb/README.md` + - `instance.json`. -- **Task 1.4** (data-engineer): `modules/registry.json` — `dynamodb` - entry (kind `l1`, `terraform_dir`). -- **Task 1.5** (data-engineer): `modules/README.md` — catalog index. +### Wave 0 — Gitea reusable-workflow adapter (SPEC §10 Q1, resolved by evidence) — lead-developer + blockchain-engineer +> **Highest-priority gap.** The v0.2 P3 `workflow_dispatch` (Gitea +> Actions run id=6199) failed: Gitea Actions rejects cross-repo `uses:` +> (`acdl/.github/workflows/deploy.yml@v1.25`) with `expected format +> {owner}/{repo}/.{git_platform}/workflows/{filename}@{ref}`. The +> consumer's `deploy.yml` is frozen at the v0.1 byte-identical mirror; +> the platform adapts (option c — inline checkout-then-call), not +> vice-versa. +- **Task 0.1** (lead-developer): rewrite + `nova-blockchain-exchange/.gitea/workflows/deploy.yml` + byte-identical + `.github/workflows/deploy.yml` — drop the `uses:` indirection; single + `deploy` job on `ubuntu-latest` that `actions/checkout@v4` the consumer, + `actions/checkout@v4` `acdl/acdl` @ `ref: v1.25` into `platform/`, + setup-python 3.12, install deps (jsonschema/pyyaml/boto3 + checkov), + install Terraform 1.9.*, configure AWS (static-key path: + `aws-region: ${{ secrets.AWS_DEFAULT_REGION }}`, `access-key-id` + + `secret-access-key` from `NOVA_AWS_*` secrets; no OIDC token minted), + run `bash platform/scripts/run_platform.sh $MODE_FLAG $ENV_FLAG + contract.yaml`. Preserve `on: workflow_dispatch` inputs (mode choice + default full; environment choice default "") + `permissions: {id-token: + write, contents: read}` + `secrets: inherit`. +- **Task 0.2** (blockchain-engineer): update + `nova-blockchain-exchange/tests/test_deploy_workflow_invocation.py` + + `test_deploy_gitea_invocation.py` — assert no cross-repo `uses:`, + assert `ref: v1.25`, assert `secrets: inherit`, assert + `run_platform.sh` invoked, assert `AWS_DEFAULT_REGION` wired. +- **Task 0.3** (lead-developer): `acdl/.github/workflows/deploy.yml` + stays as the GitHub Actions reference impl (the `workflow_call` + reusable workflow — used by GitHub-hosted consumers); document in + `adapters/README.md` that Gitea consumers use the inline adapter, not + the reusable `uses:`. + +### Wave 0.5 — kyverno-json substrate fix (v1.25 skip-masked bug) — backend-engineer +> The v1.25 kyverno-json engine + policies were never validated +> against the real `kj` binary (tests `pytest.skip("kj not installed")` +> when absent). With `kj` now installed (v0.0.3), 3 policy tests +> failed. Root cause: (a) `kj` v0.0.3 does not load `.json` policy +> files (only `.yaml`/`.yml`) — the engine now materializes `.yaml` +> twins at runtime; (b) the `validate` wrapper is not supported — +> `assert` goes directly under the rule; (c) the check syntax was +> inverted (`expression: expected_value`, not `key: expression`); +> (d) the engine `_translate` expected `{"results": [...]}` but `kj` +> returns a bare list with `results[].policy.metadata.name` + +> `results[].rules[].violations[]`. DONE (committed 59d837f). Also +> fixed `scripts/install-kyverno-json.sh` (the `cmd/kj@latest` path +> fails — the real binary is `kyverno-json`, symlinked as `kj`). +- **Task 0.5.1** (backend-engineer): rewrite + `adapters/kyverno-json/kyverno_json_engine.py` `_translate` for the + bare-list output format + add `_materialize_yaml_policy_dir` (DONE). +- **Task 0.5.2** (backend-engineer): remove the `validate` wrapper + + fix check syntax across all 16 existing policies (DONE). +- **Task 0.5.3** (backend-engineer): fix + `scripts/install-kyverno-json.sh` (DONE). +- **Task 0.5.4** (backend-engineer): resolve pre-existing P2 drift + uncovered by the full-suite run — dynamodb `examples/simple.yml` + + `complex.yml`, `sync_workflows` re-sync, CAP-024 deck path + (`nova-autonomous-cloud-delivery-marp.md`) + slide-count bound + + `class="benefit"` div count (DONE, committed 3735330). + +### Wave 1 — DynamoDB primitive (REQ-322) — data-engineer — verify-only (done in P2 W0) +- **Task 1.1** (data-engineer): verify `modules/l1/dynamodb/` resolves + + emits valid Terraform via `tests/test_adapter.py` (the primitive + shipped in P2 W0; this wave is a re-verify, not re-authoring). ### Wave 2 — metric grounding (REQ-317, REQ-318) — backend-engineer + data-engineer — parallel - **Task 2.1** (backend-engineer): `core/metrics/outcome_backfill.py` — @@ -204,26 +257,73 @@ policy-engineer (kyverno-json policies). — kyverno-json policy over env JSON (asserts `account_id != "000000000000"`). - **Task 4.3** (policy-engineer): `tests/test_settlement_finality_policy.py` - — passing + failing fixtures; skip when `kj` absent. + — passing + failing fixtures; **runs against real `kj`** (not skipped + — `kj` is installed via `scripts/install-kyverno-json.sh`). - **Task 4.4** (policy-engineer): `tests/test_pilot_readiness_policy.py` - — passing (real account) + failing (placeholder) fixtures; skip when - `kj` absent. + — passing (real account) + failing (placeholder) fixtures; **runs + against real `kj`** (not skipped). ### Wave 5 — regression CAP (REQ-316) — backend-engineer - **Task 5.1** (backend-engineer): `core/regression_verify.py` — CAP-025 (live-pilot-apply): the round-trip assertion. - **Task 5.2** (backend-engineer): `tests/test_regression_pilot.py`. +### Wave 6 — deploy.yml drift fixes (SPEC §5.1/§5.2) — lead-developer + backend-engineer +> The platform reference `workflows-src/deploy.yml` (synced to +> `.github`+`.gitea`) has three drifts vs the SPEC: (a) `aws-region` +> hardcoded `us-east-1` (SPEC wants `NOVA_AWS_REGION`/`AWS_DEFAULT_REGION` +> from secret); (b) platform checkout `ref: v1.9` (SPEC wants `v1.25`); +> (c) the local `scripts/run_platform.sh` fallback exports raw +> `NOVA_AWS_*` names into shell env (SPEC §5.2 constraint: consume as +> workflow secrets, not shell env — `blocked_env_vars`). +- **Task 6.1** (lead-developer): `workflows-src/deploy.yml` — + `aws-region: ${{ secrets.AWS_DEFAULT_REGION || 'us-east-1' }}`; + platform checkout `ref: v1.25`; re-sync to `.github`+`.gitea`. +- **Task 6.2** (backend-engineer): `scripts/run_platform.sh` — source + `AWS_DEFAULT_REGION` from `.env.secrets` for the local fallback (not + raw `NOVA_AWS_*`); the CI path already consumes secrets via the + `configure-aws-credentials` action. +- **Task 6.3** (backend-engineer): `tests/test_deploy_workflow_env_input.py` + — assert `AWS_DEFAULT_REGION` wired + `ref: v1.25` + no raw + `NOVA_AWS_*` in shell env. + +### Wave 7 — secret rotation scheduled workflow (SPEC §5.9) — lead-developer +> SPEC §5.9: "the rotation mechanism must *exist* (not have run)." +> A platform-managed scheduled workflow wraps the existing +> `scripts/rotate_spike_key.sh` (manual today) on a daily cron. +- **Task 7.1** (lead-developer): `workflows-src/rotate-aws-key.yml` — + `on: { schedule: [{cron: "0 0 * * *"}], workflow_dispatch:}`, + single job that checks out the platform repo + runs + `bash scripts/rotate_spike_key.sh` with `NOVA_AWS_*` bootstrap + secrets; sync to `.github`+`.gitea`. +- **Task 7.2** (lead-developer): verify `scripts/rotate_spike_key.sh` + is idempotent (deactivates old key only after the new key propagates + to the Gitea Actions secret store). +- **Task 7.3** (lead-developer): `tests/test_rotate_key_workflow.py` — + structural test (the workflow file declares `schedule` + invokes + `rotate_spike_key.sh`); document in `.ciagent/ARCHITECTURE.md` §12.8 + that the mechanism exists (v0.2 scope: exists-not-ran per SPEC §5.9). + **Must-haves (verify before ship):** -- `pytest tests/` in the platform repo passes (170 existing + new tests). -- The DynamoDB primitive resolves + emits valid Terraform. -- The outcome backfill updates `fact_decision.outcome` (not `pending`). -- The `escalation_reason` field is emitted on `block` band. -- The adapter reads `env.state_backend.bucket` from the env JSON. +- `pytest tests/` in the platform repo passes (the 170 baseline held + inaccurately — the real P2 baseline had 7 pre-existing failures + uncovered by W0.5; all now fixed). Full suite green. +- `pytest tests/` in the consumer repo passes (deploy invocation tests + updated for the inline adapter). +- The kyverno-json substrate works against real `kj` (W0.5 — DONE). +- The Gitea adapter: consumer `deploy.yml` has no cross-repo `uses:`; + inline checkout `acdl@v1.25` + `run_platform.sh` (W0). +- The DynamoDB primitive resolves + emits valid Terraform (W1 verify). +- The outcome backfill updates `fact_decision.outcome` (not `pending`) + (W2). +- The `escalation_reason` field is emitted on `block` band (W2). +- The adapter reads `env.state_backend.bucket` from the env JSON (W3). - The 2 new kyverno-json policies pass on valid fixtures + fail on - invalid fixtures (skip when `kj` absent). -- CAP-025 is in the regression gate. -- No existing tests regress (170 baseline holds). + invalid fixtures, against real `kj` (W4 — not skipped). +- CAP-025 is in the regression gate (W5). +- The deploy.yml drifts fixed: `AWS_DEFAULT_REGION` wired, `ref: + v1.25`, no raw `NOVA_AWS_*` in shell env (W6). +- The rotation scheduled workflow exists (W7). **Ship:** tag `v1.25.3`, merge `phase/03` → milestone, Gitea release. Delete `phase/03`.