diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index daf9212..253c76b 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -1,18 +1,35 @@ { - "phase": 5, + "phase": 6, "stage": "complete", "milestone": "v1.28", - "phase_role": "execution", + "phase_role": "final", "attempts": 0, - "updated_at": "2026-08-19T23:45:00Z", + "updated_at": "2026-08-19T23:59:00Z", "project": "acdl", "projects": ["acdl", "nova-blockchain-exchange"], "active_milestone": "v1.28", "milestone_branch": "milestone/v1.28-cli-identity", - "phase_branch": "phase/05-docs-integration", + "phase_branch": "phase/06-final-review-ship", "tag_line": "v1.27.x", - "phase_name": "docs-integration", - "reqs_covered": ["REQ-345", "REQ-346", "REQ-347", "REQ-348", "REQ-349", "REQ-350", "REQ-351"], - "tests": {"p5_specific": 17, "total_passing": 1000, "failures": 0}, - "notes": "v1.28 P5 SHIP. docs-integration complete. Tag v1.27.5. 7 REQs covered (REQ-345..351). Operator guide (C-6.3), developer guide (C-7.3), threat model (C-6.2, C-9.2 INV audit), E2E test (REQ-348). 1000 tests passing. Next: P6 final-review-ship (milestone release)." + "phase_name": "final-review-ship", + "reqs_covered": ["REQ-323..353"], + "reqs_partial": [], + "caps_verified": ["CAP-033", "CAP-034", "CAP-035", "CAP-036", "CAP-037", "CAP-038"], + "invariants_added": ["INV-12", "INV-13", "INV-14", "INV-15", "INV-16", "INV-17"], + "decisions": ["D-226", "D-227", "D-228", "D-229", "D-230", "D-231"], + "milestone_complete": true, + "milestone_release": {"tag": "v1.27.6", "type": "feature"}, + "tests": {"total_passing": 1000, "failures": 0, "deselected": 5}, + "phases": [ + {"phase": 0, "tag": "v1.27.0", "status": "complete"}, + {"phase": 1, "tag": "v1.27.1", "status": "complete"}, + {"phase": 2, "tag": "v1.27.2", "status": "complete"}, + {"phase": 3, "tag": "v1.27.3", "status": "complete"}, + {"phase": 4, "tag": "v1.27.4", "status": "complete"}, + {"phase": 5, "tag": "v1.27.5", "status": "complete"}, + {"phase": 6, "tag": "v1.27.6", "status": "complete"} + ], + "grill": {"verdict": "PROCEED-WITH-CONDITIONS", "confidence": 0.76, "critical_resolved": 3, "tracked_resolved": 16}, + "audit": {"reconstruction": "PASS", "commit_discipline": "CLEAN", "branch_hygiene": "CLEAN", "file_discipline": "CLEAN"}, + "notes": "v1.28 COMPLETE. Feature milestone (CLI Canonicalization + Identity Layer). 7 phases (P0 + P1..P5 execution + P6 final). 31 REQs covered (REQ-323..353). 6 CAPs verified (CAP-033..038). 6 invariants added (INV-12..17). 6 decisions (D-226..231). Grill PROCEED 0.76 (3 critical + 16 tracked conditions resolved). 1000 tests passing, 0 failures. Audit: reconstruction PASS, commit/branch/file discipline CLEAN. Merged milestone/v1.28-cli-identity -> main. Tag v1.27.6 = milestone release. All milestone branches deleted." } \ No newline at end of file diff --git a/.ciagent/PROJECT.md b/.ciagent/PROJECT.md index 9a54ef3..ed35491 100644 --- a/.ciagent/PROJECT.md +++ b/.ciagent/PROJECT.md @@ -450,7 +450,7 @@ already exist). > Review: 0 P0. Audit: reconstruction PASS, file/branch/commit discipline CLEAN. > Full phase detail: `.ciagent/archive/` (v1.27 artifacts) + git history. -## v1.28 — CLI Canonicalization + Identity Layer (active) +## v1.28 — CLI Canonicalization + Identity Layer (complete, tag `v1.27.6`, merged to main 2026-08-19) > **Feature milestone — active.** The Nova CLI becomes installable from > internal PyPI (CodeArtifact), every `core/` module is reachable as a diff --git a/.ciagent/REQUIREMENTS.md b/.ciagent/REQUIREMENTS.md index ab11100..25e9803 100644 --- a/.ciagent/REQUIREMENTS.md +++ b/.ciagent/REQUIREMENTS.md @@ -301,7 +301,7 @@ Full v1.26 requirement text: `.ciagent/nova-blockchain-exchange/REQUIREMENTS.md`. Active phase plan: `.ciagent/PLAN.md`. -## v1.28 — CLI Canonicalization + Identity Layer (active) +## v1.28 — CLI Canonicalization + Identity Layer (complete, tag `v1.27.6`, merged to main 2026-08-19) > **Feature milestone — active.** The Nova CLI is installable from > internal PyPI (CodeArtifact); every `core/` module is reachable as a @@ -571,34 +571,34 @@ All v1.28 release-gate criteria in PLAN.md §6 met. | REQ | Phase | Status | |-----|-------|--------| -| REQ-323 | P1 | planned | -| REQ-324 | P1 | planned | -| REQ-325 | P1 | planned | -| REQ-326 | P1 | planned | -| REQ-327 | P1 | planned | -| REQ-328 | P1 | planned | -| REQ-329 | P2 | planned | -| REQ-330 | P2 | planned | -| REQ-331 | P2 | planned | -| REQ-332 | P2 | planned | -| REQ-333 | P3 | planned | -| REQ-334 | P3 | planned | -| REQ-335 | P3 | planned | -| REQ-336 | P4 | planned | -| REQ-337 | P4 | planned | -| REQ-338 | P4 | planned | -| REQ-339 | P4 | planned | -| REQ-340 | P4 | planned | -| REQ-341 | P4 | planned | -| REQ-342 | P4 | planned | -| REQ-343 | P4 | planned | -| REQ-344 | P4 | planned | -| REQ-345 | P5 | planned | -| REQ-346 | P5 | planned | -| REQ-347 | P5 | planned | -| REQ-348 | P5 | planned | -| REQ-349 | P5 | planned | -| REQ-350 | P5 | planned | -| REQ-351 | P5 | planned | -| REQ-352 | P6 | planned | -| REQ-353 | P6 | planned | \ No newline at end of file +| REQ-323 | P1 | complete (v1.27.1) | +| REQ-324 | P1 | complete (v1.27.1) | +| REQ-325 | P1 | complete (v1.27.1) | +| REQ-326 | P1 | complete (v1.27.1) | +| REQ-327 | P1 | complete (v1.27.1) | +| REQ-328 | P1 | complete (v1.27.1) | +| REQ-329 | P2 | complete (v1.27.2) | +| REQ-330 | P2 | complete (v1.27.2) | +| REQ-331 | P2 | complete (v1.27.2) | +| REQ-332 | P2 | complete (v1.27.2) | +| REQ-333 | P3 | complete (v1.27.3) | +| REQ-334 | P3 | complete (v1.27.3) | +| REQ-335 | P3 | complete (v1.27.3) | +| REQ-336 | P4 | complete (v1.27.4) | +| REQ-337 | P4 | complete (v1.27.4) | +| REQ-338 | P4 | complete (v1.27.4) | +| REQ-339 | P4 | complete (v1.27.4) | +| REQ-340 | P4 | complete (v1.27.4) | +| REQ-341 | P4 | complete (v1.27.4) | +| REQ-342 | P4 | complete (v1.27.4) | +| REQ-343 | P4 | complete (v1.27.4) | +| REQ-344 | P4 | complete (v1.27.4) | +| REQ-345 | P5 | complete (v1.27.5) | +| REQ-346 | P5 | complete (v1.27.5) | +| REQ-347 | P5 | complete (v1.27.5) | +| REQ-348 | P5 | complete (v1.27.5) | +| REQ-349 | P5 | complete (v1.27.5) | +| REQ-350 | P5 | complete (v1.27.5) | +| REQ-351 | P5 | complete (v1.27.5) | +| REQ-352 | P6 | complete (v1.27.6) | +| REQ-353 | P6 | complete (v1.27.6) | \ No newline at end of file diff --git a/.ciagent/ROADMAP.md b/.ciagent/ROADMAP.md index aefd463..8efc7dc 100644 --- a/.ciagent/ROADMAP.md +++ b/.ciagent/ROADMAP.md @@ -94,6 +94,32 @@ checkpoint. 3 phases (P0 pre-execution + P1 author-archive + P2 fix-stale-wire + P3 final-review-ship). No REQ-NNN (NFR). +- **v1.28:** complete (tag `v1.27.6`) — CLI Canonicalization + Identity + Layer. Feature milestone. The Nova CLI is installable from internal + PyPI (CodeArtifact); every `core/` module is reachable as a `nova + ` (15 subcommands, argparse-only, ≤50-line thin delegates, + CAP-033/034); `nova init` scaffolds `.nova/`; `nova cli-action` + composite action published to GitHub + Gitea (byte-identical, NFR-11); + `core/mode_resolver.py` (flag → env → credential type → + `sys.stdin.isatty()`, D-226); INV-12 audit emission on every + invocation. Nova owns its identity layer end-to-end (Nova-idp): + `nova-idp-auth` Lambda (sign-up/sign-in/session, Argon2id t=3 m=65536 + p=1, fail-closed D-228), `nova-idp-token-vend` Lambda (KMS-signed + OIDC tokens, ECDSA P-256 / ES256, DER→raw conversion, kyverno-json + ABAC fail-closed C-6.1), `nova-idp-jwks` Lambda (JWKS endpoint), + `nova-pats` DynamoDB (PAT lifecycle, strong-read revocation D-229, + 60s SLO), `nova auth login/revoke/status`, `nova idp setup + --check/--apply/--verify` (CloudFormation, NFR-10 explicit approval). + No AWS-managed identity (INV-15). 31 requirements (REQ-323..353), 6 + capabilities (CAP-033..038), 6 invariants (INV-12..17), 6 decisions + (D-226..231). 6 execution phases (P1 cli-substrate, P2 + lambda-packaging, P3 idp-auth, P4 token-vend-pat + idp-setup folded + C-2.1, P5 docs-integration, P6 final-review-ship). Grill: + PROCEED-WITH-CONDITIONS (0.76), 3 critical fixes (ABAC fail-closed, + JWS KDF, traceability drift) + 16 tracked conditions applied. 1000 + tests passing. Tags: `v1.27.0` (P0) → `v1.27.1..v1.27.5` (P1..P5) → + `v1.27.6` (P6 final = milestone release). + > **Full v1.0–v1.24 phase detail, wave ordering, success criteria, and > decision cross-references:** `.ciagent/archive/ROADMAP-v1.0-v1.24.md`. diff --git a/.ciagent/STATE.md b/.ciagent/STATE.md index 4c0b537..26be8ba 100644 --- a/.ciagent/STATE.md +++ b/.ciagent/STATE.md @@ -80,6 +80,29 @@ path deferred (D-126). Multi-cloud deferred. Multi-validator BFT deferred. The pilot runs `mode: full` for `dev` only (D-209); qa/prod/dr stay placeholder (D-208, blocked by the pilot-readiness policy). +- **INV-12 (Mode observability, v1.28):** Every CLI invocation emits a + `cli.invocation` audit event containing `mode`, `selection_reason`, + `credential_type`, `command`, and `args`. Operators can debug mode + selection without reproducing. +- **INV-13 (Mode resolution determinism, v1.28):** Resolution priority + is flag → env (`NOVA_CLIENT_MODE`) → credential type → + `sys.stdin.isatty()`. No silent fallbacks. Invalid env values are + ignored + warned. Deviations rejected at PR time. +- **INV-14 (Credential type encodes role, v1.28):** `developer_pat` / + `nova_oidc_token` + TTY present → `interactive`; TTY absent → `agent`. +- **INV-15 (No AWS-managed identity in path, v1.28):** Nova-idp MUST + NOT depend on Cognito, IAM Identity Center, or any AWS-managed + identity service. Greenfield constraint (no Cognito existed to + "drop"). +- **INV-16 (Password storage, v1.28):** Passwords hashed with Argon2id + (t=3, m=65536 KiB, p=1). Fail-closed on `ImportError` (D-228 amended + — no pure-Python fallback). Raw passwords never in logs/traces/env/ + DynamoDB. +- **INV-17 (ABAC discipline, v1.28):** The token-vend Lambda evaluates + the kyverno-json ABAC policy before signing. Fail-closed on `kj` + absence or evaluation error (C-6.1 — never fail open). Allow/deny + + policy inputs emitted to the audit stream. `policy_version` (git SHA, + D-231) recorded in every event. ## Domains (capability groups) @@ -248,6 +271,31 @@ | — | IAM policy baseline (`acdl-spike-runner-policy`) | v1.11 / `v1.11.0` | `terraform/bootstrap/spike_runner_policy.json`, `.ciagent/IAM_POLICY.md` | REQ-116, D-095 | live-aws | regression-tested by `tests/test_iam_policy_baseline.py`; OIDC role `acdl-act-runner-role` (CAP-022) | | — | Local emulating adapters (no AWS) | v1.10 / `v1.10.0` | `core/local_lambda_stub.py`, `scripts/run_local_e2e.sh` | D-092 | local | proves runtime behavior without live AWS | +### Domain 11 — CLI + Identity Layer (v1.28) + +| ID | Capability | Shipped | Files | Controlling | Tier | Notes | +|----|-----------|---------|-------|-------------|------|-------| +| CAP-033 | CLI subcommand surface exists | v1.28 / `v1.27.1` | `nova/cli.py`, `nova/.py` (15 subcommands) | REQ-324 | local | `nova --help` lists a subcommand for every `core/` module; argparse-only, auto-discovered | +| CAP-034 | Subcommand delegates to `core/` | v1.28 / `v1.27.1` | `nova/.py` | REQ-324 | local | ≤50 lines, ≤3 FunctionDef, all calls resolve to `core.*` imports; AST-scanned in `tests/test_cli_subcommands.py` | +| CAP-035 | Layer matches wheel | v1.28 / `v1.27.1` | `.github/workflows/publish.yml`, `.gitea/workflows/publish.yml`, SSM `/nova/layer/nova-cli/version` | REQ-323 | local | wheel + Lambda layer co-published with identical version; SSM mapping; CodeArtifact + fallback | +| CAP-036 | Nova-idp auth flow works | v1.28 / `v1.27.3` | `core/lambda/nova_idp_auth.py`, `tests/test_idp_auth.py` | REQ-333 | local | sign-up → sign-in → session E2E; Argon2id t=3 m=65536 p=1; fail-closed D-228; moto locally, real DDB in CI | +| CAP-037 | Token-vend signs via KMS | v1.28 / `v1.27.4` | `core/lambda/nova_idp_token_vend.py`, `core/kms_signing.py`, `tests/test_kms_roundtrip.py` | REQ-337 | local | ECDSA P-256 / ES256; DER→raw conversion; KMS round-trip test; mock KMS locally, real KMS in CI | +| CAP-038 | PAT issuance + revocation | v1.28 / `v1.27.4` | `core/pat_lifecycle.py`, `tests/test_pat_revocation.py` | REQ-342 | local | issue → vend → revoke → 403 within 60s P95; strong-read DDB (D-229); verified <1s locally | +| — | `nova init` scaffolds `.nova/` | v1.28 / `v1.27.1` | `nova/init.py`, `core/init_scaffold.py` | REQ-325 | local | `.nova/`, `.nova/contract.yml.attestations/`, `.gitignore` (secrets excluded) | +| — | `nova cli-action` composite action | v1.28 / `v1.27.1` | `.github/actions/nova-cli/action.yml` | REQ-326 | local | byte-identical GitHub + Gitea; Python 3.12 pinned; NFR-11 | +| — | `mode_resolver` (flag→env→cred→TTY) | v1.28 / `v1.27.1` | `core/mode_resolver.py` | REQ-327, D-226 | local | `sys.stdin.isatty()` (not stdout); hypothesis property tests | +| — | Dual-use Lambda/CLI import | v1.28 / `v1.27.2` | `core/lambda/contract_ingestor.py` | REQ-329 | local | shared `dispatch_action()`; ≥80% code share; NFR-7 | +| — | Local env synthesizer | v1.28 / `v1.27.2` | `core/env.py` (`synthesize_local_env`) | REQ-330 | local | `nova apply --local`; no cloud provisioning | +| — | JWS-from-PAT (HKDF-SHA256, HS256) | v1.28 / `v1.27.2` | `core/jws_attestation.py` | REQ-332, C-5.2 | local | symmetric; verification key derived from PAT via same KDF | +| — | JWKS endpoint (function URL) | v1.28 / `v1.27.4` | `core/lambda/nova_idp_jwks.py` | REQ-338, D-230 | local | `AuthType: NONE`; `Cache-Control: max-age=3600`; optional CloudFront/WAF | +| — | kyverno-json ABAC token-vend policy | v1.28 / `v1.27.4` | `platform/abac/token-vend.policy`, `core/abac_evaluator.py` | REQ-339, D-227 | local | fail-closed (C-6.1, 7 tests); `policy_version` git SHA (D-231) | +| — | `nova idp setup --check/--apply/--verify` | v1.28 / `v1.27.4` | `nova/idp/setup.py`, `core/lambda/nova_idp_setup.py`, `core/lambda/nova_idp_cfn.py` | REQ-340, REQ-341 | local | CloudFormation template review (NFR-10); IAM policy delta; KMS round-trip verify | +| — | `nova auth login/revoke/status` | v1.28 / `v1.27.4` | `nova/auth/{login,revoke,status}.py`, `core/auth_store.py` | REQ-344, C-7.3 | local | `~/.nova/credentials.json` 0600 stores OIDC token + metadata (NOT raw PAT) | +| — | E2E integration test | v1.28 / `v1.27.5` | `tests/test_e2e_idp.py` | REQ-348 | local | sign-up → sign-in → token-vend → apply → audit chain | +| — | Identity-layer threat model | v1.28 / `v1.27.5` | `docs/threat-model.md` | REQ-347 | local | 8 threats + C-9.2 INV-18..21 compression audit | +| — | Operator guide | v1.28 / `v1.27.5` | `docs/operator-guide-idp.md` | REQ-345 | local | `nova idp setup` + KMS rotation + layer update + PITR restore + emergency PAT revocation | +| — | Developer guide | v1.28 / `v1.27.5` | `docs/developer-guide-auth.md` | REQ-346 | local | quickstart + mode resolution + JWS KDF + service-account PATs | + ## Archive pointers - **v1.0–v1.24 capability narrative + the 2026-07-27 re-verification sweep:**