---ci--- project: acdl phase: 0 milestone: v1.28 status: grill ---/ci---
29 KiB
Nova — Requirements
Compressed. The full v1.0–v1.25 requirement history (REQ-01..REQ-309) is preserved verbatim at
.ciagent/archive/REQUIREMENTS-v1.0-v1.24.md. This file retains only the v1.25 requirement set (the immediate predecessor milestone whose policy-engine substrate is load-bearing for v1.26) + a pointer to the active v1.26 requirements, which live in the consumer subproject at.ciagent/nova-blockchain-exchange/REQUIREMENTS.md(multi-project mode perconfig.json).Earlier requirement sets (v1.0–v1.24, REQ-01..REQ-290) remain valid for the milestones they governed. They are not re-decided by v1.26. Full text in the archive snapshot + git history.
v1.25 — kyverno-json Unified Policy Engine (immediate predecessor, complete)
Feature milestone — complete.
kyverno-jsonbecomes the primary compliance / policy tool, implemented behind a swappablePolicyEngineadapter so OPA (or any other engine) can replace it one day. Tags run on the v1.24.x line (milestone v1.25 → tags v1.24.0..v1.24.5). Tagv1.24.5= the milestone release.One problem, one architectural correction:
- Fragmented policy posture. Nova's compliance rules were split across Checkov (imperative YAML + a Python custom rule for tagging), Wiz (API findings), the K8s-only Kyverno adapter (inactive for Terraform stacks — D-053), and imperative Python in
core/env_transition.py+core/regression_verify.py. There was no single declarative place where "what Nova considers compliant" lived.The correction:
kyverno-json(a Kyverno-ecosystem runtime that applies Kyverno policies to any JSON/YAML payload) becomes the unified orchestrator of compliance checks. Checkov and Wiz remain as raw-finding adapters feeding into kyverno-json meta-policies. The engine is behind aPolicyEngineprotocol so it is replaceable. The confidence signal is untouched — it already consumeslist[PolicyCheckResult]engine-agnostically.
Decisions (locked in CLARIFY, full autonomy — load-bearing for v1.26)
- D-115 (C-1):
kyverno-jsonis a runtime dependency installed viago install github.com/kyverno/kyverno-json/cmd/kj@latest(pinned in ascripts/install-kyverno-json.shhelper; the CI image installs it). Not a Python package — kyverno-json is a Go binary. TheKyvernoJsonEngine.is_configured()checkswhich kjand skips gracefully when absent (emitsSKIPPEDPCR, mirroring the Wiz adapter). - D-116 (C-2): kyverno-json PCR records carry
engine: "kyverno"(no new enum value). The existingengineenum inschemas/policy_check_result.schema.jsonalready includes"kyverno"; adding"kyverno-json"would force a schema change + checkov_adapter test regression for no semantic gain. TheruleIdprefixKJ_distinguishes kyverno-json rules from the K8s Kyverno adapter'sKYVERNO_prefix where they overlap. - D-117 (C-3): Checkov and Wiz adapters keep their current
adapt() -> list[PolicyCheckResult]signatures. They emit PCRs as today. The meta-policies inadapters/kyverno-json/policies/meta/consume the merged PCR list (checkov + wiz + kyverno-json) as their input payload, applying Nova-specific posture rules on top. No adapter signature changes. - D-118 (C-4):
NOVA_TAG_NAMING(the Checkov custom rule inadapters/terraform/policy/custom_rules/nova_tagging.py) is kept. A kyverno-json mirror policyrequire-tagging-standard.jsonis added inadapters/kyverno-json/policies/stack-ir/. The P3 meta-policytagging-rules-agree.jsonasserts the two engines agree on every resource; divergence emits anerrorPCR (defense-in-depth against rule drift). The Checkov rule stays the source of truth for Terraform-static scanning; the kyverno-json policy covers Stack IR.
Category: Policy Engine Core (feat)
- REQ-291:
core/policy_engine.pydefines aPolicyEnginePythonProtocol(PEP 544) with three members:name -> str,is_configured() -> bool, andevaluate(payload: dict | str, policy_dir: Path, contract_id: str) -> list[dict](where each dict conforms toschemas/policy_check_result.schema.json). APolicyEngineRegistrysingleton selects the active engine fromconfig.json's newpolicy.enginekey (default"kyverno-json"); raisesKeyErroron an unknown engine name. The registry exposesget_engine()andregister(name, factory). Pure stdlib, no engine imports at the protocol layer. - REQ-292:
.ciagent/config.jsongains a new top-levelpolicyobject:{"engine": "kyverno-json", "policy_root": "adapters/kyverno-json/policies"}. The registry readspolicy.engineto select the active engine andpolicy.policy_rootas the default policy directory. Backward-compatible: if thepolicykey is absent, the registry returns aNullEnginethat emits onlySKIPPEDrecords (so existing tests that don't set the key still pass).
Category: kyverno-json Engine Adapter (feat)
- REQ-293:
adapters/kyverno-json/kyverno_json_engine.pyimplementsKyvernoJsonEnginesatisfying thePolicyEngineprotocol.is_configured()returnsTruewhenwhich kjsucceeds.evaluate()writes the payload to a temp JSON file, invokeskj scan --policy <policy_dir> --payload <payload.json> -o json, parses the native result list, and translates each entry to a PCR dict (engine: "kyverno",ruleIdprefixedKJ_<policy_name>, severity mapped,resultmapped pass/fail/skip → pass/fail/skipped). Whenis_configured()is false,evaluate()returns a singleSKIPPEDPCR withruleId: "KJ_ENGINE_NOT_CONFIGURED". Native output parsing is defensive: any kyverno-json output that doesn't match the expected shape produces anerrorPCR, never an exception. - REQ-294:
adapters/kyverno-json/__init__.pyexportsKyvernoJsonEngine.adapters/kyverno-json/policies/_smoke.jsonis a single trivial policy (require-contract-id) used to validate the engine round-trip end-to-end in tests.scripts/install-kyverno-json.shrunsgo install github.com/kyverno/kyverno-json/cmd/kj@latestand printskj version; documented inadapters/kyverno-json/README.md. The CI image installs Go + kj whenpolicy.engine == "kyverno-json"; the install is cached.
Category: Contract Policies (feat)
- REQ-295:
adapters/kyverno-json/policies/contract/holds kyverno-json policies over consumer contract JSON. Four policies mirroringschemas/contract.schema.jsonconstraints:require-id-pattern.json,require-env-in-enum.json,require-infrastructure-min-1.json,forbid-unknown-fields.json. Each policy is a single KyvernoPolicyresource with onevalidate.assertrule using JMESPath against the payload root. - REQ-296:
core/contract_resolver.pyinvokes thePolicyEngineRegistry.get_engine().evaluate()with the contract dict andpolicies/contract/before resolving (early-fail on contract violations) and emits anova.policy.evaluatedmetrics event. Failures feed the confidence signal'spolicyinput asfailPCRs; the resolver does not exit — the confidence signal decides the gate (consistent with the existing--soft-failCheckov pattern).
Category: Stack-IR Policies (feat)
- REQ-297:
adapters/kyverno-json/policies/stack-ir/holds policies over the resolved Target Stack IR dict.require-tagging-standard.json(every resource carriesnova:owner+nova:environmenttags — portsnova_tagging.pyinto a declarative Kyverno policy).forbid-public-ingress.json(no resource haspublic_ingress: true).require-encryption-by-default.json(every S3 bucket + EBS volume + KMS-aliased resource carries encryption config — ports the v1.8 D-encryption-default rule). - REQ-298:
core/contract_resolver.pyinvokes the engine with the resolved Stack IR andpolicies/stack-ir/after resolving. The resulting PCRs are appended to the contract-policy PCRs and fed to the confidence signal. The resolver's existingtests/test_contract_resolver.pycontinues to pass (the policy call is additive — it does not change resolver return values or exceptions). - REQ-299:
tests/test_stack_ir_policies.py+ fixturetests/fixtures/stack_ir/— a passing IR + a failing IR. Tests run theKyvernoJsonEngineagainst realkjwhenwhich kjsucceeds, andpytest.skip("kj not installed")when absent.
Category: Plan-JSON Policies + Pipeline Wiring (feat)
- REQ-300:
adapters/kyverno-json/policies/plan-json/holds policies overterraform show -jsonoutput.forbid-plaintext-secrets.json(portsCKV_AWS_41/45/46).forbid-iam-wildcard.json(portsCKV_AWS_1/40).require-kms-reference.json(portsCKV_AWS_7/33). The CheckovRULE_MAPincheckov_adapter.pyis unchanged — these are declarative mirrors, not replacements. - REQ-301:
run_platform.shStep 5 ("runtime policy scan") gains a parallel kyverno-json pass: after Checkov/Wiz produce raw PCRs, the script runskj scanand pipes throughadapters/kyverno-json/kyverno_json_engine.pyto produce a second PCR list. Both lists are concatenated and fed to the confidence signal'spolicyinput. Whenwhich kjis false, the script logs and proceeds with the Checkov/Wiz list only (no hard failure). - REQ-302:
tests/test_plan_json_policies.py+ fixturetests/fixtures/plan_json/— a passing + failing plan JSON.tests/test_run_platform_plan_json_policies.pyassertsrun_platform.shhas the kyverno-json Step 5 block and that it concatenates PCR lists.
Category: Meta-Policies (feat)
- REQ-303:
adapters/kyverno-json/policies/meta/holds policies whose payload is the mergedlist[PolicyCheckResult]itself.block-on-any-critical.json— asserts no PCR in the list hasseverity: "critical"+result: "fail"; if any does, the meta-policy emits afailPCR withruleId: "KJ_META_BLOCK_CRITICAL"and severitycritical. This is the declarative source of truth for "critical = block"; theconfidence_signal.pyPENALTY["critical"]: Nonehard-override stays as defense-in-depth.tagging-rules-agree.json— for every resource in the Stack IR, asserts the CheckovNOVA_TAG_NAMINGresult and the kyverno-jsonKJ_REQUIRE_TAGGING_STANDARDresult agree; divergence emits anerrorPCR.tests/test_meta_policies.pycovers both.
Category: Regression-Gate Policies (feat, quality improvement from IDEATE)
- REQ-304:
adapters/kyverno-json/policies/regression/holds policies over the capability-inventory JSON frontmatter. Three policies port the imperative checks incore/regression_verify.py:cap-013-adapter-dedup.json,cap-023-metrics-collector.json,cap-024-deck-structure.json. The existingcore/regression_verify.pyis kept (it drives the CI gate); the policies are the declarative mirror that makes capability regression auditable as a policy artifact, not imperative Python. Future milestones may switch the gate to the policy version. - REQ-305:
tests/test_regression_policies.py+ fixturetests/fixtures/capability_inventory.json— a clean inventory (all caps pass) + a drifted inventory. The regression gate (pytestsuite) continues to pass; the new policy tests are additive.
Category: Documentation (docs)
- REQ-306:
adapters/README.mdgains a new row for thekyverno-jsonadapter + a new section "Policy Engine Protocol" documenting thePolicyEngineProtocol, the registry, and the swap boundary (how to add anOpaEngine).adapters/kyverno-json/README.mddocuments the engine, the install path, the policy directory layout, and the four policy categories. - REQ-307:
.ciagent/ARCHITECTURE.mdgains §12.7 "Policy Engine Registry" with the registry diagram.schemas/README.mdnotes theengine: "kyverno"value is shared by the K8s Kyverno adapter and the kyverno-json engine (distinguished byruleIdprefix).modules/STANDARDS.mdgains a "Policy authoring standard" section.docs/METRICS.mdnotes the policy engine is now swappable (Strategic Objective #2 — provable trust via a replaceable substrate, not a vendor lock-in).
Category: Tests (test)
- REQ-308:
tests/test_policy_engine.py— protocol conformance, unknown-engineKeyError,NullEnginefallback when thepolicykey is absent,KyvernoJsonEngine.is_configured()returns false whenwhich kjfails (mocked).tests/test_kyverno_json_engine.py—evaluate()returns valid PCR dicts validated againstschemas/policy_check_result.schema.json; native-output parsing is defensive (malformed →errorPCR, not exception);is_configured()==false→SKIPPEDPCR withKJ_ENGINE_NOT_CONFIGURED. - REQ-309: All new tests use
pytest.skip("kj not installed")whenwhich kjis absent, so the suite passes in environments without the binary (CI matrix: with-kj and without-kj).pyproject.toml+requirements-test.txtunchanged (kyverno-json is a Go binary, not a Python dep).
Out of Scope (v1.25)
- Removing Checkov or Wiz. Both stay as raw-finding adapters.
OpaEngineimplementation. The protocol is the swap boundary; the OPA implementation is a future milestone.- Per-module policies.
modules/<name>/policies/is documented as the future pattern inmodules/STANDARDS.mdbut not populated this milestone. - kyverno-json as a long-running service. v1.25 uses the CLI
(
kj scan); thekj serveweb-app mode is future. - Replacing the K8s Kyverno adapter. The K8s adapter
(
adapters/kyverno/) remains documentation-only (D-053).
v1.25 Traceability
| REQ | Phase | Status |
|---|---|---|
| REQ-291 | P1 | complete |
| REQ-292 | P1 | complete |
| REQ-293 | P1 | complete |
| REQ-294 | P1 | complete |
| REQ-295 | P2 | complete |
| REQ-296 | P2 | complete |
| REQ-297 | P2 | complete |
| REQ-298 | P2 | complete |
| REQ-299 | P2 | complete |
| REQ-300 | P3 | complete |
| REQ-301 | P3 | complete |
| REQ-302 | P3 | complete |
| REQ-303 | P3 | complete |
| REQ-304 | P4 | complete |
| REQ-305 | P4 | complete |
| REQ-306 | P4 | complete |
| REQ-307 | P4 | complete |
| REQ-308 | P1 | complete |
| REQ-309 | P1 | complete |
v1.26 — Live Pilot Estate Activation (active)
Feature milestone. The first real consumer estate (a stock exchange on a homegrown PoA blockchain, equities only) is activated against live AWS account
581513795199, lifting D-096. Tags run on the v1.25.x line:v1.25.0(P0) →v1.25.1..v1.25.4(P1–P4) →v1.25.5(P5 final = milestone release).Multi-project mode: the v1.26 requirements live in
.ciagent/nova-blockchain-exchange/REQUIREMENTS.md(the consumer subproject). The platform-side requirement REQ-322 (DynamoDB L1 primitive) landed in P2 of the platform repo. The 13 requirements (REQ-310..322) cover: blockchain core (REQ-310), order engine (REQ-311), settlement (REQ-312), consumer contract (REQ-313), deploy invocation (REQ-314), settlement-finality policy (REQ-315), pilot regression CAP (REQ-316), outcome backfill (REQ-317), escalation reason (REQ-318), env-JSON wiring (REQ-319), pilot-readiness policy (REQ-320), docs (REQ-321), DynamoDB L1 primitive (REQ-322).
v1.26 Traceability (live — see CHECKPOINT.json for authoritative state)
| REQ | Phase | Status |
|---|---|---|
| REQ-310 | P1 | complete (v1.25.1) |
| REQ-311 | P1 | complete (v1.25.1) |
| REQ-312 | P1 | complete (v1.25.1) |
| REQ-322 | P2 | complete (v1.25.2) |
| REQ-313 | P2 | complete (v1.25.2) |
| REQ-314 | P2 | complete (v1.25.2) |
| REQ-315 | P3 | complete (v1.25.3) |
| REQ-316 | P3 + P4 | complete (v1.25.3 — CAP-025; v1.25.4 — live-verify complete) |
| REQ-317 | P3 | complete (v1.25.3) |
| REQ-318 | P3 | complete (v1.25.3) |
| REQ-319 | P3 | complete (v1.25.3) |
| REQ-320 | P3 | complete (v1.25.3) |
| REQ-321 | P4 | complete (v1.25.4) |
Full v1.26 requirement text:
.ciagent/nova-blockchain-exchange/REQUIREMENTS.md. Active phase plan:
.ciagent/PLAN.md.
v1.28 — CLI Canonicalization + Identity Layer (active)
Feature milestone — active. The Nova CLI is installable from internal PyPI (CodeArtifact); every
core/module is reachable as anova <subcommand>; the CLI and Lambda functions share a singlecore/source tree; and Nova owns its identity layer end-to-end (Nova-idp:nova-idp-auth+nova-idp-token-vendLambdas, KMS-signed OIDC tokens, kyverno-json ABAC token vending, PAT lifecycle). No AWS-managed identity services in the path.Tags run on the v1.27.x line:
v1.27.0(P0) →v1.27.1..v1.27.N→v1.27.(N+1)(final = milestone release). Milestone branch:milestone/v1.28-cli-identity.ID re-mapping (no collisions): the source spec used
REQ-001..031,CAP-025..030,INV-63/64/65/18..21/34,D-NEW-26/37..41, and akjengine — none of which exist in this repo (CAP-025..032 and INV-1..11 are already allocated to blockchain/pilot work; the policy engine is kyverno-json, notkj). This file uses the re-mapped IDs:REQ-323..353,CAP-033..038,INV-12..17,D-226..231. The 1:1 mapping is recorded in CLARIFY.md. Decisions D-226..D-231 are authored in CLARIFY (full autonomy) — they are not pre-existing "locked inputs".
Decisions (locked in CLARIFY — full autonomy, load-bearing for v1.28)
- D-226 (Mode resolution priority): flag → env (
NOVA_CLIENT_MODE) → credential type → TTY heuristic. Invalid env values are ignored + warned, falling through to credential type. No silent fallbacks (NFR-1). - D-227 (ABAC engine = kyverno-json): the token-vend Lambda uses the
existing kyverno-json engine (INV-4 swappable) as the ABAC evaluator,
not a new
kjengine. Policy atplatform/abac/token-vend.policy. - D-228 (Argon2id in Lambda):
argon2-cffiwith bundled wheels; if the C extension fails to load, fall back to the pure-Python implementation; if both fail, document the Fargate migration path. - D-229 (PAT revocation SLO): strongly-consistent DynamoDB read on every token-vend request; revocation takes effect within 60s P95 (NFR-4).
- D-230 (JWKS endpoint): Lambda function URL behind a custom domain; rate limiting at the DNS/CDN layer. API Gateway migration deferred to v1.19+ if throttling requirements grow.
- D-231 (ABAC policy ownership + versioning): Platform Security owns
platform/abac/token-vend.policy; changes require PR review; the policy version (git SHA) is recorded in every token-vend audit event.
P1 — CLI Substrate
REQ-323 — CodeArtifact wheel + Lambda layer pipeline
Journeys: J3. Priority: High.
AC: Given a merge to main affecting core/, when CI runs, then both
the wheel and the Lambda layer are published to CodeArtifact with
identical version strings; if either fails, the merge is rejected.
REQ-324 — CLI subcommand per core/ module
Journeys: J3. Priority: High.
AC: (1) Every module in core/ has a corresponding nova/<module>.py
subcommand. (2) Subcommand files are ≤ 50 lines and contain no business
logic — they delegate to core/. (3) CAP-034 verifies delegation by AST
scan.
REQ-325 — nova init scaffolds project
Journeys: J2. Priority: High.
AC: Given a directory with no .nova/, when Dev runs nova init,
then .nova/, .nova/contract.yml.attestations/, and .gitignore
(excluding secrets) are created.
REQ-326 — nova cli-action published
Journeys: J3. Priority: High. AC: (1) Action is available on both GitHub and Gitea marketplaces. (2) Integration test verifies byte-identical behavior on both platforms. (3) Python 3.12 is pinned.
REQ-327 — mode_resolver.py priority
Journeys: J2, J3. Priority: High.
AC: (1) Explicit --mode=agent|interactive flag always wins.
(2) Otherwise NOVA_CLIENT_MODE env var. (3) Otherwise credential type
default. (4) Otherwise TTY heuristic. (5) Property tests cover all four
levels. (6) INV-13 (mode determinism) enforced at PR time.
REQ-328 — Audit emission with mode + selection_reason
Journeys: J3. Priority: High.
AC: Given any CLI invocation, when the CLI runs, then the emitted
cli.invocation audit event contains mode, selection_reason,
credential_type, command, and args. INV-12 (mode observability)
enforced.
P2 — Lambda Packaging + Identity Layer
REQ-329 — Dual-use Lambda/CLI import
Journeys: J2. Priority: High.
AC: Given core/lambda/contract_ingestor.py, when imported from the
Lambda handler, then it executes the Lambda path; when imported from the
CLI, then it executes the local path; and the two paths share ≥ 80% of
their code.
REQ-330 — Local env synthesizer
Journeys: J2. Priority: High.
AC: Given a contract and a --local flag, when nova apply --local
runs, then a local env is synthesized via core/env.py:get_env() without
provisioning cloud resources.
REQ-331 — Attestations directory scaffolded
Journeys: J2. Priority: High.
AC: Given nova init ran, when Dev lists
.nova/contract.yml.attestations/, then the directory exists and is empty.
REQ-332 — JWS signing key from PAT
Journeys: J2. Priority: High.
AC: Given a PAT, when Dev runs nova apply --local --sign-local-review,
then a JWS attestation is produced; the JWS is HMAC-SHA256 with a key
derived from the PAT via HKDF-SHA256(PAT_bytes, salt='nova-local-attestation', info='jws-signing-key') → 32-byte symmetric key (C-5.2 grill fix). The
verification key is derived from the PAT via the same KDF (the PAT is
the shared secret). INV-14..17 (attestation invariants) enforced.
REQ-333 — nova-idp-auth Lambda
Journeys: J1, J2. Priority: High. AC: (1) Lambda exposes sign-up, sign-in, and session creation endpoints. (2) Passwords are hashed with Argon2id. (3) Sessions are stored in DynamoDB. (4) CAP-036 verifies end-to-end auth flow.
REQ-334 — Argon2id password hashing
Journeys: J1, J2. Priority: High. AC: Given a sign-up request, when the user record is persisted, then the password is stored as an Argon2id hash; raw passwords never appear in logs, traces, environment variables, or DynamoDB records.
REQ-335 — DynamoDB tables for identity
Journeys: J1. Priority: High.
AC: (1) Tables exist: nova-users, nova-sessions,
nova-password-resets. (2) Tables are provisioned by nova idp setup.
(3) Point-in-time recovery is enabled on each.
REQ-336 — nova-idp-token-vend Lambda
Journeys: J1, J2, J4. Priority: High.
AC: (1) Lambda accepts a PAT (or session token) and returns a
KMS-signed OIDC token. (2) Token claims include sub, aud, iss,
exp, and role claims. (3) ABAC policy is evaluated before signing.
REQ-337 — KMS-signed OIDC tokens
Journeys: J1, J4. Priority: High. AC: (1) Signing key is a KMS asymmetric key (RSA or ECDSA). (2) Token signature is verifiable via the JWKS endpoint. (3) KMS round-trip test passes. CAP-037 verifies.
REQ-338 — JWKS endpoint as Lambda function URL
Journeys: J1, J4. Priority: High.
AC: Given the identity stack is deployed, when a client GETs the JWKS
URL, then the public key(s) for token verification are returned with
Content-Type: application/json.
REQ-339 — kyverno-json ABAC policy file
Journeys: J1, J4. Priority: High.
AC: (1) Policy at platform/abac/token-vend.policy. (2) Policy inputs
include subject, requested claims, target resource, and environment.
(3) kyverno-json evaluate returns allow/deny; the decision is emitted to
the audit stream.
REQ-340 — nova idp setup walks admin
Journeys: J1. Priority: High.
AC: (1) Command supports --check, --apply, and --verify modes.
(2) --check reports missing prerequisites and the required IAM policy.
(3) --apply generates a CloudFormation template and requires explicit
approval. (4) --verify runs the KMS round-trip test.
REQ-341 — CloudFormation template for review
Journeys: J1. Priority: High.
AC: Given nova idp setup --apply, when the template is generated,
then the template is presented for review; resources are not created until
the operator approves; --dry-run shows the resource list without writing.
REQ-342 — PAT issuance via portal
Journeys: J4. Priority: High.
AC: (1) PAT is a signed JWT. (2) PAT hash is stored in DynamoDB.
(3) PAT includes a unique jti and an expiry claim. (4) Revocation marks
the jti as revoked.
REQ-343 — PAT hashes in DynamoDB
Journeys: J4. Priority: High.
AC: (1) Only the hash (not the raw PAT) is stored. (2) Table supports
lookup-by-hash and lookup-by-jti. (3) Revoked PATs are retained for
audit, not deleted.
REQ-344 — nova auth commands
Journeys: J2, J4. Priority: High.
AC: (1) nova auth login exchanges session → OIDC token, stores
locally. (2) nova auth revoke --pat <id> marks a PAT revoked.
(3) nova auth status shows current credential, mode, and
selection_reason. (4) All commands emit audit events.
P3 — Documentation
REQ-345 — Operator guide for nova idp setup
Priority: High.
AC: Guide published covering --check, --apply, --verify,
prerequisite IAM policy, and the CloudFormation review flow.
REQ-346 — Developer guide for nova auth login
Priority: High. AC: Guide published covering signup, signin, login, mode resolution, and credential-type behavior at a TTY vs. piped stdout.
REQ-347 — Identity-layer threat model
Priority: High. AC: Threat model published covering Argon2id storage, KMS signing, JWKS exposure, PAT revocation SLO, ABAC token vending, and the no-AWS- managed-identity constraint (NFR-5).
P4 — Integration Testing
REQ-348 — E2E integration test
Priority: High. AC: Given a deployed Nova-idp, when the test runs, then sign-up → sign-in → token-vend → apply → audit completes successfully; the audit event chain is verifiable.
REQ-349 — Property tests for mode_resolver
Priority: High. AC: (1) Property tests cover all four priority levels. (2) Edge cases: TTY but piped stdout, missing credential, conflicting flag/env, invalid env value. (3) INV-13 enforced via test.
REQ-350 — KMS round-trip test
Priority: High. AC: Given a token signed by the token-vend Lambda, when the test fetches the JWKS and verifies the signature, then verification succeeds.
REQ-351 — PAT revocation SLO test
Priority: High. AC: Issue PAT → use to vend token → revoke → assert denial within 60s P95. Test passes in CI.
P5 — Capability Gate
REQ-352 — CAP-033..038 gate rules wired into CI
Priority: High.
AC: (1) CAP-033 (CLI subcommand surface exists): nova --help lists a
subcommand for every core/ module. (2) CAP-034 (subcommand delegates to
core/): every nova/<module>.py ≤ 50 lines, no business logic, AST
scan. (3) CAP-035 (layer matches wheel): Lambda layer ARN version matches
the nova-cli wheel version. (4) CAP-036 (Nova-idp auth flow works): E2E
test (REQ-348) passes. (5) CAP-037 (token-vend signs via KMS): KMS
round-trip (REQ-350) passes. (6) CAP-038 (PAT issuance + revocation):
REQ-351 passes. Failure of any → merge blocked.
REQ-353 — Capability gate GREEN for v1.28 release
Priority: High. AC: CAP-001..CAP-032 remain Verified; CAP-033..CAP-038 are Verified. All v1.28 release-gate criteria in PLAN.md §6 met.
v1.28 Invariants (new — INV-12..INV-17)
- INV-12 (Mode observability): Every CLI invocation emits a
cli.invocationaudit event containingmode,selection_reason,credential_type,command, andargs. - INV-13 (Mode resolution determinism): Resolution priority is
flag → env (
NOVA_CLIENT_MODE) → credential type → TTY. No silent fallbacks. Deviations rejected at PR time. - INV-14 (Credential type encodes role):
developer_pat/nova_oidc_token+ TTY present →interactive; TTY absent →agent. - INV-15 (No AWS-managed identity in path): Nova-idp MUST NOT depend on Cognito, IAM Identity Center, or any AWS-managed identity service.
- INV-16 (Password storage): Passwords hashed with Argon2id; raw passwords never in logs/traces/env/DynamoDB.
- INV-17 (ABAC discipline): The token-vend Lambda evaluates the kyverno-json ABAC policy before signing; allow/deny + policy inputs emitted to the audit stream.
v1.28 Traceability (live — see CHECKPOINT.json for authoritative state)
| 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 |