docs(init): validate specification — v1.28 CLI Canonicalization + Identity Layer
---ci--- project: acdl phase: 0 milestone: v1.28 status: specify ---/ci---
This commit is contained in:
+300
-1
@@ -299,4 +299,303 @@
|
||||
|
||||
Full v1.26 requirement text:
|
||||
`.ciagent/nova-blockchain-exchange/REQUIREMENTS.md`. Active phase plan:
|
||||
`.ciagent/PLAN.md`.
|
||||
`.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 a
|
||||
> `nova <subcommand>`; the CLI and Lambda functions share a single
|
||||
> `core/` source tree; and Nova owns its identity layer end-to-end
|
||||
> (Nova-idp: `nova-idp-auth` + `nova-idp-token-vend` Lambdas, 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 a `kj`
|
||||
> engine — 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, not `kj`). 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 `kj` engine. Policy at `platform/abac/token-vend.policy`.
|
||||
- **D-228 (Argon2id in Lambda):** `argon2-cffi` with 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 public key is derivable from the
|
||||
PAT and the JWS verifies. 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.invocation` audit event containing `mode`, `selection_reason`,
|
||||
`credential_type`, `command`, and `args`.
|
||||
- **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 | P2 | planned |
|
||||
| REQ-334 | P2 | planned |
|
||||
| REQ-335 | P2 | planned |
|
||||
| REQ-336 | P2 | planned |
|
||||
| REQ-337 | P2 | planned |
|
||||
| REQ-338 | P2 | planned |
|
||||
| REQ-339 | P2 | planned |
|
||||
| REQ-340 | P2 | planned |
|
||||
| REQ-341 | P2 | planned |
|
||||
| REQ-342 | P2 | planned |
|
||||
| REQ-343 | P2 | planned |
|
||||
| REQ-344 | P2 | planned |
|
||||
| REQ-345 | P3 | planned |
|
||||
| REQ-346 | P3 | planned |
|
||||
| REQ-347 | P3 | planned |
|
||||
| REQ-348 | P4 | planned |
|
||||
| REQ-349 | P4 | planned |
|
||||
| REQ-350 | P4 | planned |
|
||||
| REQ-351 | P4 | planned |
|
||||
| REQ-352 | P5 | planned |
|
||||
| REQ-353 | P5 | planned |
|
||||
Reference in New Issue
Block a user