diff --git a/docs/implplan/SPRINT_3500_0004_0001_cli_verbs.md b/docs/implplan/SPRINT_3500_0004_0001_cli_verbs.md new file mode 100644 index 000000000..7684c47b8 --- /dev/null +++ b/docs/implplan/SPRINT_3500_0004_0001_cli_verbs.md @@ -0,0 +1,239 @@ +# SPRINT_3500_0004_0001: CLI Verbs + Offline Bundles + +**Epic**: Deeper Moat Beyond Reachability +**Sprint**: 1 of 4 (CLI & UI phase) +**Duration**: 2 weeks +**Working Directory**: `src/Cli/StellaOps.Cli/` +**Owner**: CLI Team + +--- + +## Sprint Goal + +Implement CLI verbs for score proofs, reachability, and unknowns management: + +1. `stella score replay --scan ` — Replay a score computation +2. `stella scan graph --lang dotnet|java --sln ` — Extract call graph +3. `stella unknowns list --band HOT` — List unknowns by band +4. Complete `stella proof verify --bundle ` implementation +5. Offline bundle extensions for reachability + +**Success Criteria**: +- [ ] All CLI verbs implemented and functional +- [ ] JSON and text output formats supported +- [ ] Offline mode works without backend connectivity +- [ ] Unit tests achieve ≥85% coverage +- [ ] CLI help text is comprehensive + +--- + +## Dependencies & Concurrency + +- **Upstream**: SPRINT_3500_0002_0003 (Proof Replay API) — DONE +- **Upstream**: SPRINT_3500_0003_0003 (Graph Attestations) — DONE +- **Parallel with**: SPRINT_3500_0004_0002 (UI Components) + +--- + +## Documentation Prerequisites + +- `docs/09_API_CLI_REFERENCE.md` — CLI documentation +- `docs/24_OFFLINE_KIT.md` — Offline bundle format +- `src/Cli/StellaOps.Cli/AGENTS.md` — CLI working agreements + +--- + +## Existing Infrastructure + +The CLI already has: +- `stella proof verify` — Stub implementation in `ProofCommandGroup.cs` +- `stella reachability explain` — Full implementation in `CommandFactory.cs` +- `stella graph verify` — Graph DSSE verification +- Backend client infrastructure in `BackendOperationsClient.cs` + +**Gaps to fill**: +1. `stella score replay` — New command +2. `stella scan graph` — New command +3. `stella unknowns list` — New command +4. Complete `proof verify` implementation + +--- + +## Tasks + +### T1: Score Replay Command + +**Assignee**: CLI Engineer +**Story Points**: 3 +**Status**: TODO + +**Description**: +Add `stella score replay --scan ` command to replay score computation. + +**Acceptance Criteria**: +- [ ] Accepts scan ID as argument +- [ ] Calls `/api/v1/scanner/scans/{id}/score/replay` endpoint +- [ ] Returns proof bundle with root hash +- [ ] Supports `--output json|text` format +- [ ] Shows verification status + +**Implementation**: +- Add to `CommandFactory.cs` under score command group +- Use `BackendOperationsClient` for API calls + +--- + +### T2: Scan Graph Command + +**Assignee**: CLI Engineer +**Story Points**: 5 +**Status**: TODO + +**Description**: +Add `stella scan graph` command to extract call graphs locally. + +**Acceptance Criteria**: +- [ ] `--lang dotnet|java|node|python|go` language selection +- [ ] `--sln ` or `--target ` for source path +- [ ] `--output ` for call graph output +- [ ] `--upload` flag to submit to backend +- [ ] Deterministic output (stable ordering) + +**Implementation**: +- Invoke language-specific extractors from `StellaOps.Scanner.CallGraph` +- Support offline extraction without backend + +--- + +### T3: Unknowns List Command + +**Assignee**: CLI Engineer +**Story Points**: 3 +**Status**: TODO + +**Description**: +Add `stella unknowns list` command to list unknowns by band. + +**Acceptance Criteria**: +- [ ] `--band HOT|WARM|COLD` filter +- [ ] `--limit N` pagination +- [ ] `--format json|table` output +- [ ] Shows CVE, package, band, age + +**Implementation**: +- Call `/api/v1/policy/unknowns` endpoint +- Add `UnknownsCommandGroup.cs` + +--- + +### T4: Complete Proof Verify + +**Assignee**: CLI Engineer +**Story Points**: 5 +**Status**: TODO + +**Description**: +Complete the `stella proof verify --bundle ` implementation. + +**Acceptance Criteria**: +- [ ] Verifies DSSE envelope signature +- [ ] Validates Merkle proof +- [ ] Checks Rekor inclusion (unless `--offline`) +- [ ] Returns detailed verification result +- [ ] Supports `--output json|text` + +**Implementation**: +- Wire up `IVerificationPipeline` from Attestor module +- Add Rekor client for inclusion proof + +--- + +### T5: Offline Bundle Extensions + +**Assignee**: CLI Engineer +**Story Points**: 3 +**Status**: TODO + +**Description**: +Extend offline bundle format for reachability data. + +**Acceptance Criteria**: +- [ ] `/offline/reachability/` directory structure +- [ ] `/offline/corpus/` for ground-truth data +- [ ] Bundle includes call graphs and proofs +- [ ] Verification works offline + +**Implementation**: +- Extend `OfflineKitImportService` +- Add reachability bundle builder + +--- + +### T6: Unit Tests + +**Assignee**: CLI Engineer +**Story Points**: 3 +**Status**: TODO + +**Description**: +Comprehensive unit tests for new CLI commands. + +**Acceptance Criteria**: +- [ ] Score replay command tests +- [ ] Scan graph command tests +- [ ] Unknowns list command tests +- [ ] Proof verify tests +- [ ] ≥85% code coverage + +--- + +### T7: Documentation Updates + +**Assignee**: CLI Engineer +**Story Points**: 2 +**Status**: TODO + +**Description**: +Update CLI documentation with new commands. + +**Acceptance Criteria**: +- [ ] `docs/09_API_CLI_REFERENCE.md` updated +- [ ] Help text for all new commands +- [ ] Examples in documentation +- [ ] Offline usage documented + +--- + +## Delivery Tracker + +| # | Task ID | Status | Dependency | Owners | Task Definition | +|---|---------|--------|------------|--------|-----------------| +| 1 | T1 | TODO | — | CLI Team | Score Replay Command | +| 2 | T2 | TODO | — | CLI Team | Scan Graph Command | +| 3 | T3 | TODO | — | CLI Team | Unknowns List Command | +| 4 | T4 | TODO | — | CLI Team | Complete Proof Verify | +| 5 | T5 | TODO | T1, T4 | CLI Team | Offline Bundle Extensions | +| 6 | T6 | TODO | T1-T4 | CLI Team | Unit Tests | +| 7 | T7 | TODO | T1-T5 | CLI Team | Documentation Updates | + +--- + +## Execution Log + +| Date (UTC) | Update | Owner | +|------------|--------|-------| +| 2025-12-20 | Sprint file created. Analyzed existing CLI commands; identified gaps. Ready to implement. | Agent | + +--- + +## Decisions & Risks + +| Item | Type | Owner | Notes | +|------|------|-------|-------| +| Use existing BackendOperationsClient | Decision | CLI Team | Consistent API access pattern | +| Offline-first for scan graph | Decision | CLI Team | Local extraction before upload | +| JSON as default for piping | Decision | CLI Team | Machine-readable output | + +--- + +**Sprint Status**: IN PROGRESS (0/7 tasks done) diff --git a/docs/implplan/SPRINT_3500_0004_0001_cli_verbs_offline_bundles.md b/docs/implplan/SPRINT_3500_0004_0001_cli_verbs_offline_bundles.md new file mode 100644 index 000000000..3e5031057 --- /dev/null +++ b/docs/implplan/SPRINT_3500_0004_0001_cli_verbs_offline_bundles.md @@ -0,0 +1,200 @@ +# Sprint 3500.0004.0001 · CLI Verbs + Offline Bundles + +## Topic & Scope +- Implement CLI commands for score replay, proof verification, call graph analysis, reachability explanation, and unknowns management. +- Extend offline kit with reachability graphs and test corpus bundles. +- **Working directory:** `src/Cli/StellaOps.Cli.Plugins.Scanner/` and `offline-kit/`. + +## Dependencies & Concurrency +- Upstream: Sprint 3500.0002.0003 (Proof Replay + API) — DONE +- Upstream: Sprint 3500.0003.0003 (Graph Attestations + Rekor) — DONE +- Safe to parallelize with: Sprint 3500.0004.0002 (UI Components) + +## Documentation Prerequisites +- `docs/modules/cli/architecture.md` +- `docs/10_CONCELIER_CLI_QUICKSTART.md` +- `docs/api/scanner-score-proofs-api.md` +- `src/Cli/AGENTS.md` + +--- + +## Tasks + +### T1: Score Replay Command + +**Assignee**: CLI Team +**Story Points**: 3 +**Status**: TODO + +**Description**: +Implement `stella score replay --scan ` command to replay score computation. + +**Acceptance Criteria**: +- [ ] `stella score replay --scan ` triggers score replay +- [ ] `--output ` supports `json`, `table`, `yaml` +- [ ] `--verbose` shows detailed computation steps +- [ ] Returns exit code 0 on success, non-zero on failure +- [ ] Handles offline mode gracefully + +--- + +### T2: Proof Verification Command + +**Assignee**: CLI Team +**Story Points**: 3 +**Status**: TODO + +**Description**: +Implement `stella proof verify --bundle ` command to verify proof bundles. + +**Acceptance Criteria**: +- [ ] `stella proof verify --bundle ` verifies a proof bundle file +- [ ] `--scan ` fetches bundle from API then verifies +- [ ] Displays Merkle tree verification result +- [ ] Shows DSSE signature validation status +- [ ] Optionally checks Rekor transparency log + +--- + +### T3: Call Graph Command + +**Assignee**: CLI Team +**Story Points**: 5 +**Status**: TODO + +**Description**: +Implement `stella scan graph --lang --path ` for call graph extraction. + +**Acceptance Criteria**: +- [ ] `stella scan graph --lang dotnet --path ` extracts .NET call graph +- [ ] `stella scan graph --lang java --path ` extracts Java call graph +- [ ] `--output ` saves CallGraph.v1.json +- [ ] `--entrypoints` lists discovered entrypoints +- [ ] Progress indicator for large codebases + +--- + +### T4: Reachability Explain Command + +**Assignee**: CLI Team +**Story Points**: 5 +**Status**: TODO + +**Description**: +Implement `stella reachability explain --scan --cve ` for CVE reachability explanation. + +**Acceptance Criteria**: +- [ ] Shows path from entrypoint to vulnerable function +- [ ] Displays confidence score and factors +- [ ] `--format graph` renders ASCII call chain +- [ ] `--verbose` shows all intermediate nodes +- [ ] Returns actionable remediation suggestions + +--- + +### T5: Unknowns List Command + +**Assignee**: CLI Team +**Story Points**: 2 +**Status**: TODO + +**Description**: +Implement `stella unknowns list --band ` for unknowns management. + +**Acceptance Criteria**: +- [ ] Lists unknowns filtered by band +- [ ] `--scan ` filters to specific scan +- [ ] `--sort ` supports sorting by age, rank, count +- [ ] `--limit ` limits output +- [ ] Shows band transitions + +--- + +### T6: Offline Reachability Bundle + +**Assignee**: CLI Team +**Story Points**: 3 +**Status**: TODO + +**Description**: +Extend offline kit to include reachability graph bundles. + +**Acceptance Criteria**: +- [ ] `/offline/reachability/` directory structure defined +- [ ] Call graphs exportable to offline format +- [ ] Entrypoint mappings included in bundle +- [ ] Reachability computation works fully offline +- [ ] Bundle size optimization (deduplicated nodes) + +--- + +### T7: Offline Corpus Bundle + +**Assignee**: CLI Team +**Story Points**: 3 +**Status**: TODO + +**Description**: +Create test corpus bundles for offline verification. + +**Acceptance Criteria**: +- [ ] `/offline/corpus/` contains golden test cases +- [ ] Corpus covers all scoring scenarios +- [ ] SBOM + manifest + proof bundles for each case +- [ ] `stella test corpus --offline` validates corpus +- [ ] Corpus versioned with kit + +--- + +### T8: Unit Tests + +**Assignee**: CLI Team +**Story Points**: 3 +**Status**: TODO + +**Description**: +Comprehensive unit tests for all CLI commands. + +**Acceptance Criteria**: +- [ ] ≥85% code coverage for new commands +- [ ] Mock API responses for all endpoints +- [ ] Offline mode tests +- [ ] Error handling tests +- [ ] Exit code verification + +--- + +## Delivery Tracker + +| # | Task ID | Status | Dependency | Owners | Task Definition | +|---|---------|--------|------------|--------|-----------------| +| 1 | T1 | TODO | — | CLI Team | Score Replay Command | +| 2 | T2 | TODO | — | CLI Team | Proof Verification Command | +| 3 | T3 | TODO | — | CLI Team | Call Graph Command | +| 4 | T4 | TODO | T3 | CLI Team | Reachability Explain Command | +| 5 | T5 | TODO | — | CLI Team | Unknowns List Command | +| 6 | T6 | TODO | T3, T4 | CLI Team | Offline Reachability Bundle | +| 7 | T7 | TODO | T1, T2 | CLI Team | Offline Corpus Bundle | +| 8 | T8 | TODO | T1-T7 | CLI Team | Unit Tests | + +--- + +## Execution Log + +| Date (UTC) | Update | Owner | +|------------|--------|-------| +| 2025-12-20 | Sprint file created. Ready for implementation. | Agent | + +--- + +## Decisions & Risks + +| Item | Type | Owner | Notes | +|------|------|-------|-------| +| CLI framework | Decision | CLI Team | Use existing System.CommandLine infrastructure | +| Offline bundle format | Decision | CLI Team | JSON with optional compression | +| Corpus versioning | Risk | CLI Team | Must stay in sync with scoring algorithm versions | + +--- + +**Sprint Status**: TODO (0/8 tasks done) diff --git a/docs/implplan/SPRINT_3500_0004_0002_ui_components_visualization.md b/docs/implplan/SPRINT_3500_0004_0002_ui_components_visualization.md new file mode 100644 index 000000000..c23caa098 --- /dev/null +++ b/docs/implplan/SPRINT_3500_0004_0002_ui_components_visualization.md @@ -0,0 +1,202 @@ +# Sprint 3500.0004.0002 · UI Components + Visualization + +## Topic & Scope +- Implement Angular UI components for proof ledger visualization, unknowns queue management, and reachability explanation widgets. +- **Working directory:** `src/Web/StellaOps.Web/src/app/` (Angular v17). + +## Dependencies & Concurrency +- Upstream: Sprint 3500.0002.0003 (Proof Replay + API) — DONE +- Upstream: Sprint 3500.0003.0003 (Graph Attestations + Rekor) — DONE +- Safe to parallelize with: Sprint 3500.0004.0001 (CLI Verbs) + +## Documentation Prerequisites +- `docs/modules/ui/architecture.md` +- `docs/15_UI_GUIDE.md` +- `docs/accessibility.md` +- `src/Web/AGENTS.md` + +--- + +## Tasks + +### T1: Proof Ledger View Component + +**Assignee**: UI Team +**Story Points**: 5 +**Status**: TODO + +**Description**: +Create ProofLedgerViewComponent to display scan proof history with Merkle tree visualization. + +**Acceptance Criteria**: +- [ ] Displays scan manifest with all input hashes +- [ ] Shows Merkle tree structure (expandable) +- [ ] DSSE signature validation indicator +- [ ] Rekor transparency log link (if available) +- [ ] Download proof bundle button +- [ ] Responsive design (mobile-friendly) + +--- + +### T2: Unknowns Queue Component + +**Assignee**: UI Team +**Story Points**: 5 +**Status**: TODO + +**Description**: +Create UnknownsQueueComponent to manage unknown packages with band-based prioritization. + +**Acceptance Criteria**: +- [ ] Tabbed view: HOT / WARM / COLD bands +- [ ] Sort by rank, age, occurrence count +- [ ] Escalate/Resolve action buttons +- [ ] Batch selection and bulk actions +- [ ] Filter by scan, image, package type +- [ ] Real-time updates via SignalR + +--- + +### T3: Reachability Explain Widget + +**Assignee**: UI Team +**Story Points**: 8 +**Status**: TODO + +**Description**: +Create ReachabilityExplainWidget to visualize CVE reachability paths. + +**Acceptance Criteria**: +- [ ] Interactive call graph visualization (D3.js or similar) +- [ ] Path highlighting from entrypoint to vulnerable function +- [ ] Confidence score display with factor breakdown +- [ ] Zoom/pan controls +- [ ] Node details on hover/click +- [ ] Export to PNG/SVG + +--- + +### T4: Score Comparison View + +**Assignee**: UI Team +**Story Points**: 3 +**Status**: TODO + +**Description**: +Create ScoreComparisonViewComponent to diff scores between scan versions. + +**Acceptance Criteria**: +- [ ] Side-by-side score comparison +- [ ] Highlight score changes (delta) +- [ ] Show which findings changed +- [ ] VEX status impact visualization +- [ ] Time-series chart option + +--- + +### T5: Proof Replay Dashboard + +**Assignee**: UI Team +**Story Points**: 5 +**Status**: TODO + +**Description**: +Create ProofReplayDashboardComponent for score replay operations. + +**Acceptance Criteria**: +- [ ] Trigger replay from UI +- [ ] Progress indicator during replay +- [ ] Show original vs replayed score comparison +- [ ] Display any drift/discrepancies +- [ ] Export replay report + +--- + +### T6: API Integration Service + +**Assignee**: UI Team +**Story Points**: 3 +**Status**: TODO + +**Description**: +Create Angular services to integrate with new Scanner API endpoints. + +**Acceptance Criteria**: +- [ ] ManifestService for `/scans/{id}/manifest` +- [ ] ProofBundleService for `/scans/{id}/proofs` +- [ ] UnknownsService for `/unknowns/*` +- [ ] ReachabilityService for reachability endpoints +- [ ] Error handling and retry logic + +--- + +### T7: Accessibility Compliance + +**Assignee**: UI Team +**Story Points**: 3 +**Status**: TODO + +**Description**: +Ensure all new components meet WCAG 2.1 AA accessibility standards. + +**Acceptance Criteria**: +- [ ] Keyboard navigation for all interactive elements +- [ ] Screen reader compatibility (ARIA labels) +- [ ] Color contrast compliance +- [ ] Focus management +- [ ] Accessibility audit passing + +--- + +### T8: Component Tests + +**Assignee**: UI Team +**Story Points**: 3 +**Status**: TODO + +**Description**: +Comprehensive tests for all UI components using Angular testing utilities. + +**Acceptance Criteria**: +- [ ] Unit tests for all components +- [ ] Integration tests with mock API +- [ ] Snapshot tests for visual regression +- [ ] E2E tests with Playwright +- [ ] ≥80% code coverage + +--- + +## Delivery Tracker + +| # | Task ID | Status | Dependency | Owners | Task Definition | +|---|---------|--------|------------|--------|-----------------| +| 1 | T1 | TODO | — | UI Team | Proof Ledger View Component | +| 2 | T2 | TODO | — | UI Team | Unknowns Queue Component | +| 3 | T3 | TODO | — | UI Team | Reachability Explain Widget | +| 4 | T4 | TODO | T1 | UI Team | Score Comparison View | +| 5 | T5 | TODO | T1, T6 | UI Team | Proof Replay Dashboard | +| 6 | T6 | TODO | — | UI Team | API Integration Service | +| 7 | T7 | TODO | T1-T5 | UI Team | Accessibility Compliance | +| 8 | T8 | TODO | T1-T7 | UI Team | Component Tests | + +--- + +## Execution Log + +| Date (UTC) | Update | Owner | +|------------|--------|-------| +| 2025-12-20 | Sprint file created. UX wireframes available (per master sprint tracker). | Agent | + +--- + +## Decisions & Risks + +| Item | Type | Owner | Notes | +|------|------|-------|-------| +| Graph library | Decision | UI Team | Evaluate D3.js vs Cytoscape.js for call graph | +| Real-time updates | Decision | UI Team | SignalR for unknowns queue notifications | +| Large graph rendering | Risk | UI Team | May need virtualization for 10k+ node graphs | + +--- + +**Sprint Status**: TODO (0/8 tasks done) diff --git a/docs/implplan/SPRINT_3500_0004_0003_integration_tests_corpus.md b/docs/implplan/SPRINT_3500_0004_0003_integration_tests_corpus.md new file mode 100644 index 000000000..0bdc1233d --- /dev/null +++ b/docs/implplan/SPRINT_3500_0004_0003_integration_tests_corpus.md @@ -0,0 +1,205 @@ +# Sprint 3500.0004.0003 · Integration Tests + Corpus + +## Topic & Scope +- Create comprehensive integration tests covering full proof-chain and reachability workflows. +- Build golden test corpus with known-good SBOM/manifest/proof bundles. +- Add CI gates to prevent regressions. +- **Working directory:** `tests/` and `bench/`. + +## Dependencies & Concurrency +- Upstream: Sprint 3500.0004.0001 (CLI Verbs) — for corpus validation commands +- Upstream: Sprint 3500.0004.0002 (UI Components) — for E2E coverage +- Requires: All Epic A and Epic B sprints DONE + +## Documentation Prerequisites +- `docs/19_TEST_SUITE_OVERVIEW.md` +- `docs/modules/ci/architecture.md` +- `bench/README.md` +- `tests/AGENTS.md` + +--- + +## Tasks + +### T1: Proof Chain Integration Tests + +**Assignee**: QA Team +**Story Points**: 5 +**Status**: TODO + +**Description**: +End-to-end tests for the complete proof chain: scan → manifest → score → proof bundle → verify. + +**Acceptance Criteria**: +- [ ] Test scan submission creates manifest +- [ ] Test score computation produces deterministic results +- [ ] Test proof bundle generation and signing +- [ ] Test proof verification succeeds for valid bundles +- [ ] Test verification fails for tampered bundles +- [ ] Test replay produces identical scores + +--- + +### T2: Reachability Integration Tests + +**Assignee**: QA Team +**Story Points**: 5 +**Status**: TODO + +**Description**: +End-to-end tests for call graph extraction and reachability analysis. + +**Acceptance Criteria**: +- [ ] Test .NET call graph extraction +- [ ] Test Java call graph extraction +- [ ] Test entrypoint discovery +- [ ] Test reachability computation +- [ ] Test reachability explanation output +- [ ] Test graph attestation signing + +--- + +### T3: Unknowns Workflow Tests + +**Assignee**: QA Team +**Story Points**: 3 +**Status**: TODO + +**Description**: +Integration tests for unknowns lifecycle: detection → ranking → escalation → resolution. + +**Acceptance Criteria**: +- [ ] Test unknown detection during scan +- [ ] Test ranking determinism +- [ ] Test band assignment +- [ ] Test escalation triggers rescan +- [ ] Test resolution updates status +- [ ] Test band transitions + +--- + +### T4: Golden Test Corpus + +**Assignee**: QA Team +**Story Points**: 8 +**Status**: TODO + +**Description**: +Create golden test corpus with known-good artifacts for all scoring scenarios. + +**Acceptance Criteria**: +- [ ] Corpus covers all CVE severity levels +- [ ] Corpus includes VEX overrides +- [ ] Corpus has reachability scenarios +- [ ] Corpus versioned with scoring algorithm +- [ ] Each case has: SBOM, manifest, proof bundle, expected score +- [ ] Corpus documented with scenario descriptions + +--- + +### T5: Determinism Validation Suite + +**Assignee**: QA Team +**Story Points**: 5 +**Status**: TODO + +**Description**: +Tests to validate scoring determinism across runs, platforms, and time. + +**Acceptance Criteria**: +- [ ] Same input produces identical score hash +- [ ] Cross-platform determinism (Windows/Linux/macOS) +- [ ] Timestamp independence (frozen time tests) +- [ ] Parallel execution determinism +- [ ] Replay after code changes produces same result + +--- + +### T6: CI Gate Configuration + +**Assignee**: DevOps Team +**Story Points**: 3 +**Status**: TODO + +**Description**: +Configure CI to run integration tests and gate on failures. + +**Acceptance Criteria**: +- [ ] Integration tests run on PR +- [ ] Corpus validation on release branch +- [ ] Determinism tests on nightly +- [ ] Test coverage reported to dashboard +- [ ] Flaky test quarantine process + +--- + +### T7: Performance Baseline Tests + +**Assignee**: QA Team +**Story Points**: 3 +**Status**: TODO + +**Description**: +Establish performance baselines for key operations. + +**Acceptance Criteria**: +- [ ] Score computation time baseline +- [ ] Proof bundle generation baseline +- [ ] Call graph extraction baseline +- [ ] Reachability computation baseline +- [ ] Regression alerts on >20% degradation + +--- + +### T8: Air-Gap Integration Tests + +**Assignee**: QA Team +**Story Points**: 3 +**Status**: TODO + +**Description**: +Tests to verify full functionality in air-gapped environments. + +**Acceptance Criteria**: +- [ ] Offline kit installation test +- [ ] Offline scan test +- [ ] Offline score replay test +- [ ] Offline proof verification test +- [ ] No network calls during offline operation + +--- + +## Delivery Tracker + +| # | Task ID | Status | Dependency | Owners | Task Definition | +|---|---------|--------|------------|--------|-----------------| +| 1 | T1 | TODO | — | QA Team | Proof Chain Integration Tests | +| 2 | T2 | TODO | — | QA Team | Reachability Integration Tests | +| 3 | T3 | TODO | — | QA Team | Unknowns Workflow Tests | +| 4 | T4 | TODO | T1, T2, T3 | QA Team | Golden Test Corpus | +| 5 | T5 | TODO | T1 | QA Team | Determinism Validation Suite | +| 6 | T6 | TODO | T1-T5 | DevOps Team | CI Gate Configuration | +| 7 | T7 | TODO | T1, T2 | QA Team | Performance Baseline Tests | +| 8 | T8 | TODO | T4 | QA Team | Air-Gap Integration Tests | + +--- + +## Execution Log + +| Date (UTC) | Update | Owner | +|------------|--------|-------| +| 2025-12-20 | Sprint file created. | Agent | + +--- + +## Decisions & Risks + +| Item | Type | Owner | Notes | +|------|------|-------|-------| +| Corpus storage | Decision | QA Team | Store in `bench/corpus/` with LFS for large files | +| Flaky test policy | Decision | DevOps Team | Quarantine after 2 consecutive failures | +| Performance thresholds | Risk | QA Team | Need production baselines before setting thresholds | + +--- + +**Sprint Status**: TODO (0/8 tasks done) diff --git a/docs/implplan/SPRINT_3500_0004_0004_documentation_handoff.md b/docs/implplan/SPRINT_3500_0004_0004_documentation_handoff.md new file mode 100644 index 000000000..0aaa00212 --- /dev/null +++ b/docs/implplan/SPRINT_3500_0004_0004_documentation_handoff.md @@ -0,0 +1,204 @@ +# Sprint 3500.0004.0004 · Documentation + Handoff + +## Topic & Scope +- Complete all documentation for Score Proofs and Reachability features. +- Create runbooks, training materials, and API documentation. +- Prepare handoff materials for operations and support teams. +- **Working directory:** `docs/`. + +## Dependencies & Concurrency +- Upstream: All 3500.0002.x, 3500.0003.x, 3500.0004.x sprints +- Final sprint in Epic 3500; cannot start until implementation is stable + +## Documentation Prerequisites +- All existing `docs/` content +- API specifications from implementation sprints +- Test results and coverage reports + +--- + +## Tasks + +### T1: API Reference Documentation + +**Assignee**: Docs Team +**Story Points**: 5 +**Status**: TODO + +**Description**: +Complete API reference documentation for all new endpoints. + +**Acceptance Criteria**: +- [ ] Score Proofs API documented +- [ ] Reachability API documented +- [ ] Unknowns API documented +- [ ] Request/response examples for each endpoint +- [ ] Error codes and handling documented +- [ ] Rate limiting documented + +--- + +### T2: Operations Runbooks + +**Assignee**: Docs Team +**Story Points**: 5 +**Status**: TODO + +**Description**: +Create operational runbooks for Score Proofs and Reachability features. + +**Acceptance Criteria**: +- [ ] Score replay runbook +- [ ] Proof verification runbook +- [ ] Reachability troubleshooting runbook +- [ ] Unknowns queue management runbook +- [ ] Air-gap operations runbook +- [ ] Escalation procedures + +--- + +### T3: Architecture Documentation + +**Assignee**: Docs Team +**Story Points**: 3 +**Status**: TODO + +**Description**: +Update architecture documentation with new components. + +**Acceptance Criteria**: +- [ ] Update HIGH_LEVEL_ARCHITECTURE.md +- [ ] Document proof chain architecture +- [ ] Document reachability graph architecture +- [ ] Data flow diagrams +- [ ] Component interaction diagrams + +--- + +### T4: CLI Reference Guide + +**Assignee**: Docs Team +**Story Points**: 3 +**Status**: TODO + +**Description**: +Complete CLI reference documentation for new commands. + +**Acceptance Criteria**: +- [ ] `stella score` command reference +- [ ] `stella proof` command reference +- [ ] `stella scan graph` command reference +- [ ] `stella reachability` command reference +- [ ] `stella unknowns` command reference +- [ ] Examples and common use cases + +--- + +### T5: Training Materials + +**Assignee**: Docs Team +**Story Points**: 5 +**Status**: TODO + +**Description**: +Create training materials for internal and external users. + +**Acceptance Criteria**: +- [ ] Score Proofs concept guide +- [ ] Reachability analysis guide +- [ ] Unknowns management guide +- [ ] Video tutorials (scripts at minimum) +- [ ] FAQ document +- [ ] Troubleshooting guide + +--- + +### T6: Release Notes + +**Assignee**: Docs Team +**Story Points**: 2 +**Status**: TODO + +**Description**: +Prepare release notes for Score Proofs and Reachability features. + +**Acceptance Criteria**: +- [ ] Feature highlights +- [ ] Breaking changes (if any) +- [ ] Migration guide (if needed) +- [ ] Known limitations +- [ ] Upgrade instructions + +--- + +### T7: OpenAPI Specification Update + +**Assignee**: Docs Team +**Story Points**: 3 +**Status**: TODO + +**Description**: +Finalize OpenAPI specification updates for all new endpoints. + +**Acceptance Criteria**: +- [ ] All endpoints documented in OpenAPI +- [ ] Schema definitions complete +- [ ] Examples included +- [ ] Generated documentation validates +- [ ] SDK generation tested + +--- + +### T8: Handoff Checklist + +**Assignee**: Project Management +**Story Points**: 2 +**Status**: TODO + +**Description**: +Complete handoff to operations and support teams. + +**Acceptance Criteria**: +- [ ] Knowledge transfer sessions completed +- [ ] Support team trained +- [ ] Escalation paths documented +- [ ] Monitoring dashboards configured +- [ ] Alerting rules defined +- [ ] Sign-off from stakeholders + +--- + +## Delivery Tracker + +| # | Task ID | Status | Dependency | Owners | Task Definition | +|---|---------|--------|------------|--------|-----------------| +| 1 | T1 | TODO | — | Docs Team | API Reference Documentation | +| 2 | T2 | TODO | — | Docs Team | Operations Runbooks | +| 3 | T3 | TODO | — | Docs Team | Architecture Documentation | +| 4 | T4 | TODO | — | Docs Team | CLI Reference Guide | +| 5 | T5 | TODO | T1-T4 | Docs Team | Training Materials | +| 6 | T6 | TODO | T1-T5 | Docs Team | Release Notes | +| 7 | T7 | TODO | T1 | Docs Team | OpenAPI Specification Update | +| 8 | T8 | TODO | T1-T7 | Project Mgmt | Handoff Checklist | + +--- + +## Execution Log + +| Date (UTC) | Update | Owner | +|------------|--------|-------| +| 2025-12-20 | Sprint file created. | Agent | + +--- + +## Decisions & Risks + +| Item | Type | Owner | Notes | +|------|------|-------|-------| +| Documentation format | Decision | Docs Team | Markdown in docs/, with generated API docs | +| Training delivery | Decision | Docs Team | Written guides + recorded sessions | +| Handoff timing | Risk | Project Mgmt | Must complete before release | + +--- + +**Sprint Status**: TODO (0/8 tasks done) diff --git a/src/Scanner/StellaOps.Scanner.WebService/Middleware/IdempotencyMiddlewareExtensions.cs b/src/Scanner/StellaOps.Scanner.WebService/Middleware/IdempotencyMiddlewareExtensions.cs index e5b4de5a0..8b2006fec 100644 --- a/src/Scanner/StellaOps.Scanner.WebService/Middleware/IdempotencyMiddlewareExtensions.cs +++ b/src/Scanner/StellaOps.Scanner.WebService/Middleware/IdempotencyMiddlewareExtensions.cs @@ -8,8 +8,6 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using StellaOps.Scanner.Storage.Postgres; -using StellaOps.Scanner.Storage.Repositories; using StellaOps.Scanner.WebService.Options; namespace StellaOps.Scanner.WebService.Middleware; @@ -21,6 +19,7 @@ public static class IdempotencyMiddlewareExtensions { /// /// Adds idempotency services to the service collection. + /// Note: IIdempotencyKeyRepository is registered by AddScannerStorage. /// public static IServiceCollection AddIdempotency( this IServiceCollection services, @@ -32,8 +31,6 @@ public static class IdempotencyMiddlewareExtensions services.Configure( configuration.GetSection(IdempotencyOptions.SectionName)); - services.AddScoped(); - return services; } diff --git a/src/Scanner/__Libraries/StellaOps.Scanner.Storage/Extensions/ServiceCollectionExtensions.cs b/src/Scanner/__Libraries/StellaOps.Scanner.Storage/Extensions/ServiceCollectionExtensions.cs index 1d14f82a7..c53fad4c3 100644 --- a/src/Scanner/__Libraries/StellaOps.Scanner.Storage/Extensions/ServiceCollectionExtensions.cs +++ b/src/Scanner/__Libraries/StellaOps.Scanner.Storage/Extensions/ServiceCollectionExtensions.cs @@ -83,6 +83,9 @@ public static class ServiceCollectionExtensions services.AddScoped(); services.AddScoped(); + // Idempotency key storage (Sprint: SPRINT_3500_0002_0003) + services.AddScoped(); + // EPSS ingestion services services.AddSingleton(); services.AddScoped(); diff --git a/src/Scanner/__Libraries/StellaOps.Scanner.Storage/Postgres/PostgresIdempotencyKeyRepository.cs b/src/Scanner/__Libraries/StellaOps.Scanner.Storage/Postgres/PostgresIdempotencyKeyRepository.cs index 460b0a469..2866db042 100644 --- a/src/Scanner/__Libraries/StellaOps.Scanner.Storage/Postgres/PostgresIdempotencyKeyRepository.cs +++ b/src/Scanner/__Libraries/StellaOps.Scanner.Storage/Postgres/PostgresIdempotencyKeyRepository.cs @@ -5,6 +5,7 @@ // Description: PostgreSQL implementation of idempotency key repository // ----------------------------------------------------------------------------- +using Dapper; using Microsoft.Extensions.Logging; using Npgsql; using StellaOps.Scanner.Storage.Entities; @@ -17,11 +18,12 @@ namespace StellaOps.Scanner.Storage.Postgres; /// public sealed class PostgresIdempotencyKeyRepository : IIdempotencyKeyRepository { - private readonly NpgsqlDataSource _dataSource; + private readonly ScannerDataSource _dataSource; private readonly ILogger _logger; + private string SchemaName => _dataSource.SchemaName ?? ScannerDataSource.DefaultSchema; public PostgresIdempotencyKeyRepository( - NpgsqlDataSource dataSource, + ScannerDataSource dataSource, ILogger logger) { _dataSource = dataSource ?? throw new ArgumentNullException(nameof(dataSource)); @@ -35,41 +37,28 @@ public sealed class PostgresIdempotencyKeyRepository : IIdempotencyKeyRepository string endpointPath, CancellationToken cancellationToken = default) { - const string sql = """ - SELECT key_id, tenant_id, content_digest, endpoint_path, - response_status, response_body, response_headers, - created_at, expires_at - FROM scanner.idempotency_keys - WHERE tenant_id = @tenantId - AND content_digest = @contentDigest - AND endpoint_path = @endpointPath + var sql = $""" + SELECT + key_id AS KeyId, + tenant_id AS TenantId, + content_digest AS ContentDigest, + endpoint_path AS EndpointPath, + response_status AS ResponseStatus, + response_body AS ResponseBody, + response_headers AS ResponseHeaders, + created_at AS CreatedAt, + expires_at AS ExpiresAt + FROM {SchemaName}.idempotency_keys + WHERE tenant_id = @TenantId + AND content_digest = @ContentDigest + AND endpoint_path = @EndpointPath AND expires_at > now() """; - await using var conn = await _dataSource.OpenConnectionAsync(cancellationToken).ConfigureAwait(false); - await using var cmd = new NpgsqlCommand(sql, conn); - cmd.Parameters.AddWithValue("tenantId", tenantId); - cmd.Parameters.AddWithValue("contentDigest", contentDigest); - cmd.Parameters.AddWithValue("endpointPath", endpointPath); - - await using var reader = await cmd.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false); - if (!await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) - { - return null; - } - - return new IdempotencyKeyRow - { - KeyId = reader.GetGuid(0), - TenantId = reader.GetString(1), - ContentDigest = reader.GetString(2), - EndpointPath = reader.GetString(3), - ResponseStatus = reader.GetInt32(4), - ResponseBody = reader.IsDBNull(5) ? null : reader.GetString(5), - ResponseHeaders = reader.IsDBNull(6) ? null : reader.GetString(6), - CreatedAt = reader.GetDateTime(7), - ExpiresAt = reader.GetDateTime(8) - }; + await using var conn = await _dataSource.OpenSystemConnectionAsync(cancellationToken).ConfigureAwait(false); + return await conn.QuerySingleOrDefaultAsync( + new CommandDefinition(sql, new { TenantId = tenantId, ContentDigest = contentDigest, EndpointPath = endpointPath }, cancellationToken: cancellationToken)) + .ConfigureAwait(false); } /// @@ -77,15 +66,20 @@ public sealed class PostgresIdempotencyKeyRepository : IIdempotencyKeyRepository IdempotencyKeyRow key, CancellationToken cancellationToken = default) { - const string sql = """ - INSERT INTO scanner.idempotency_keys + if (key.KeyId == Guid.Empty) + { + key.KeyId = Guid.NewGuid(); + } + + var sql = $""" + INSERT INTO {SchemaName}.idempotency_keys (key_id, tenant_id, content_digest, endpoint_path, response_status, response_body, response_headers, created_at, expires_at) VALUES - (@keyId, @tenantId, @contentDigest, @endpointPath, - @responseStatus, @responseBody::jsonb, @responseHeaders::jsonb, - @createdAt, @expiresAt) + (@KeyId, @TenantId, @ContentDigest, @EndpointPath, + @ResponseStatus, @ResponseBody::jsonb, @ResponseHeaders::jsonb, + @CreatedAt, @ExpiresAt) ON CONFLICT (tenant_id, content_digest, endpoint_path) DO UPDATE SET response_status = EXCLUDED.response_status, response_body = EXCLUDED.response_body, @@ -95,26 +89,23 @@ public sealed class PostgresIdempotencyKeyRepository : IIdempotencyKeyRepository RETURNING key_id """; - await using var conn = await _dataSource.OpenConnectionAsync(cancellationToken).ConfigureAwait(false); - await using var cmd = new NpgsqlCommand(sql, conn); + await using var conn = await _dataSource.OpenSystemConnectionAsync(cancellationToken).ConfigureAwait(false); + var keyId = await conn.ExecuteScalarAsync( + new CommandDefinition(sql, new + { + key.KeyId, + key.TenantId, + key.ContentDigest, + key.EndpointPath, + key.ResponseStatus, + key.ResponseBody, + key.ResponseHeaders, + key.CreatedAt, + key.ExpiresAt + }, cancellationToken: cancellationToken)) + .ConfigureAwait(false); - if (key.KeyId == Guid.Empty) - { - key.KeyId = Guid.NewGuid(); - } - - cmd.Parameters.AddWithValue("keyId", key.KeyId); - cmd.Parameters.AddWithValue("tenantId", key.TenantId); - cmd.Parameters.AddWithValue("contentDigest", key.ContentDigest); - cmd.Parameters.AddWithValue("endpointPath", key.EndpointPath); - cmd.Parameters.AddWithValue("responseStatus", key.ResponseStatus); - cmd.Parameters.AddWithValue("responseBody", (object?)key.ResponseBody ?? DBNull.Value); - cmd.Parameters.AddWithValue("responseHeaders", (object?)key.ResponseHeaders ?? DBNull.Value); - cmd.Parameters.AddWithValue("createdAt", key.CreatedAt); - cmd.Parameters.AddWithValue("expiresAt", key.ExpiresAt); - - var keyId = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false); - key.KeyId = (Guid)keyId!; + key.KeyId = keyId; _logger.LogDebug( "Saved idempotency key {KeyId} for tenant {TenantId}, digest {ContentDigest}", @@ -126,19 +117,18 @@ public sealed class PostgresIdempotencyKeyRepository : IIdempotencyKeyRepository /// public async Task DeleteExpiredAsync(CancellationToken cancellationToken = default) { - const string sql = "SELECT scanner.cleanup_expired_idempotency_keys()"; + var sql = $"SELECT {SchemaName}.cleanup_expired_idempotency_keys()"; - await using var conn = await _dataSource.OpenConnectionAsync(cancellationToken).ConfigureAwait(false); - await using var cmd = new NpgsqlCommand(sql, conn); + await using var conn = await _dataSource.OpenSystemConnectionAsync(cancellationToken).ConfigureAwait(false); + var result = await conn.ExecuteScalarAsync( + new CommandDefinition(sql, cancellationToken: cancellationToken)) + .ConfigureAwait(false); - var result = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false); - var deletedCount = Convert.ToInt32(result); - - if (deletedCount > 0) + if (result > 0) { - _logger.LogInformation("Cleaned up {Count} expired idempotency keys", deletedCount); + _logger.LogInformation("Cleaned up {Count} expired idempotency keys", result); } - return deletedCount; + return result; } }