docs(05-05): complete scan --verify integration plan
This commit is contained in:
@@ -44,7 +44,7 @@ Requirements for initial release. Each maps to roadmap phases.
|
|||||||
- [x] **VRFY-01**: Active key verification via lightweight API calls when --verify flag is set
|
- [x] **VRFY-01**: Active key verification via lightweight API calls when --verify flag is set
|
||||||
- [x] **VRFY-02**: Verification is opt-in only (off by default) with consent prompt on first use
|
- [x] **VRFY-02**: Verification is opt-in only (off by default) with consent prompt on first use
|
||||||
- [x] **VRFY-03**: Each provider YAML defines verify endpoint, method, headers, success/failure codes
|
- [x] **VRFY-03**: Each provider YAML defines verify endpoint, method, headers, success/failure codes
|
||||||
- [ ] **VRFY-04**: Verification extracts additional metadata (org, rate limit, permissions) when available
|
- [x] **VRFY-04**: Verification extracts additional metadata (org, rate limit, permissions) when available
|
||||||
- [x] **VRFY-05**: Configurable verification timeout (default 10s, --verify-timeout flag)
|
- [x] **VRFY-05**: Configurable verification timeout (default 10s, --verify-timeout flag)
|
||||||
- [x] **VRFY-06**: Legal disclaimer and documentation ships with verification feature
|
- [x] **VRFY-06**: Legal disclaimer and documentation ships with verification feature
|
||||||
|
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ Plans:
|
|||||||
- [x] 05-02-PLAN.md — LEGAL.md + pkg/legal embed + consent prompt + keyhunter legal command
|
- [x] 05-02-PLAN.md — LEGAL.md + pkg/legal embed + consent prompt + keyhunter legal command
|
||||||
- [x] 05-03-PLAN.md — pkg/verify HTTPVerifier: template sub, gjson metadata extraction, ants pool
|
- [x] 05-03-PLAN.md — pkg/verify HTTPVerifier: template sub, gjson metadata extraction, ants pool
|
||||||
- [x] 05-04-PLAN.md — Update 12 Tier 1 provider YAMLs with extended verify specs + guardrail test
|
- [x] 05-04-PLAN.md — Update 12 Tier 1 provider YAMLs with extended verify specs + guardrail test
|
||||||
- [ ] 05-05-PLAN.md — cmd/scan.go --verify wiring + --verify-timeout/workers flags + output verify column
|
- [x] 05-05-PLAN.md — cmd/scan.go --verify wiring + --verify-timeout/workers flags + output verify column
|
||||||
|
|
||||||
### Phase 6: Output, Reporting & Key Management
|
### Phase 6: Output, Reporting & Key Management
|
||||||
**Goal**: Users can consume scan results in any format they need and perform full lifecycle management of stored keys — listing, inspecting, exporting, copying, and deleting
|
**Goal**: Users can consume scan results in any format they need and perform full lifecycle management of stored keys — listing, inspecting, exporting, copying, and deleting
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
gsd_state_version: 1.0
|
gsd_state_version: 1.0
|
||||||
milestone: v1.0
|
milestone: v1.0
|
||||||
milestone_name: milestone
|
milestone_name: milestone
|
||||||
status: executing
|
status: verifying
|
||||||
stopped_at: Completed 05-03-PLAN.md
|
stopped_at: Completed 05-05-PLAN.md
|
||||||
last_updated: "2026-04-05T12:51:16.897Z"
|
last_updated: "2026-04-05T12:56:19.430Z"
|
||||||
last_activity: 2026-04-05
|
last_activity: 2026-04-05
|
||||||
progress:
|
progress:
|
||||||
total_phases: 18
|
total_phases: 18
|
||||||
completed_phases: 4
|
completed_phases: 5
|
||||||
total_plans: 28
|
total_plans: 28
|
||||||
completed_plans: 27
|
completed_plans: 28
|
||||||
percent: 20
|
percent: 20
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ See: .planning/PROJECT.md (updated 2026-04-04)
|
|||||||
|
|
||||||
Phase: 05 (verification-engine) — EXECUTING
|
Phase: 05 (verification-engine) — EXECUTING
|
||||||
Plan: 5 of 5
|
Plan: 5 of 5
|
||||||
Status: Ready to execute
|
Status: Phase complete — ready for verification
|
||||||
Last activity: 2026-04-05
|
Last activity: 2026-04-05
|
||||||
|
|
||||||
Progress: [██░░░░░░░░] 20%
|
Progress: [██░░░░░░░░] 20%
|
||||||
@@ -73,6 +73,7 @@ Progress: [██░░░░░░░░] 20%
|
|||||||
| Phase 05 P04 | 10m | 2 tasks | 25 files |
|
| Phase 05 P04 | 10m | 2 tasks | 25 files |
|
||||||
| Phase 05-verification-engine P02 | 7m | 2 tasks | 9 files |
|
| Phase 05-verification-engine P02 | 7m | 2 tasks | 9 files |
|
||||||
| Phase 05-verification-engine P03 | 245s | 2 tasks | 4 files |
|
| Phase 05-verification-engine P03 | 245s | 2 tasks | 4 files |
|
||||||
|
| Phase 05 P05 | 12min | 2 tasks | 5 files |
|
||||||
|
|
||||||
## Accumulated Context
|
## Accumulated Context
|
||||||
|
|
||||||
@@ -100,6 +101,7 @@ Recent decisions affecting current work:
|
|||||||
- [Phase 05-verification-engine]: LEGAL.md dual-location mirror (root + pkg/legal/) required because go:embed cannot traverse parents — mirrors Phase 1 providers pattern
|
- [Phase 05-verification-engine]: LEGAL.md dual-location mirror (root + pkg/legal/) required because go:embed cannot traverse parents — mirrors Phase 1 providers pattern
|
||||||
- [Phase 05-verification-engine]: verify.consent setting: granted is sticky across runs; declined is not — users who initially refuse can change mind without manual reset
|
- [Phase 05-verification-engine]: verify.consent setting: granted is sticky across runs; declined is not — users who initially refuse can change mind without manual reset
|
||||||
- [Phase 05-verification-engine]: Plan 05-03: HTTPVerifier classifies via YAML VerifySpec only; no per-provider branches. VerifyAll uses ants pool with per-finding Result guarantee.
|
- [Phase 05-verification-engine]: Plan 05-03: HTTPVerifier classifies via YAML VerifySpec only; no per-provider branches. VerifyAll uses ants pool with per-finding Result guarantee.
|
||||||
|
- [Phase 05]: Verification runs in batch mode after scan completes (collect -> verify -> persist) with Result->Finding back-assignment via provider+masked-key tuple
|
||||||
|
|
||||||
### Pending Todos
|
### Pending Todos
|
||||||
|
|
||||||
@@ -114,6 +116,6 @@ None yet.
|
|||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-04-05T12:51:12.569Z
|
Last session: 2026-04-05T12:56:13.570Z
|
||||||
Stopped at: Completed 05-03-PLAN.md
|
Stopped at: Completed 05-05-PLAN.md
|
||||||
Resume file: None
|
Resume file: None
|
||||||
|
|||||||
143
.planning/phases/05-verification-engine/05-05-SUMMARY.md
Normal file
143
.planning/phases/05-verification-engine/05-05-SUMMARY.md
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
---
|
||||||
|
phase: 05-verification-engine
|
||||||
|
plan: 05
|
||||||
|
subsystem: cmd
|
||||||
|
tags: [cli, verification, scan, output, consent]
|
||||||
|
one-liner: "Wire --verify into scan pipeline with consent gate, configurable timeout/workers, and VERIFY column rendering in output table."
|
||||||
|
requires:
|
||||||
|
- verify.EnsureConsent (Plan 05-02)
|
||||||
|
- verify.HTTPVerifier + VerifyAll (Plan 05-03)
|
||||||
|
- storage.Finding verify_* columns (Plan 05-01)
|
||||||
|
- engine.Finding verification fields (Plan 05-01)
|
||||||
|
provides:
|
||||||
|
- Working `keyhunter scan --verify` command end-to-end
|
||||||
|
- `--verify-timeout` and `--verify-workers` user-facing flags
|
||||||
|
- VERIFY column + metadata line in table output (backward compatible)
|
||||||
|
affects:
|
||||||
|
- cmd/scan.go RunE now collects findings, verifies, then persists
|
||||||
|
- pkg/output/table.go now renders verify column conditionally
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns:
|
||||||
|
- "Collect-then-verify-then-persist batch pattern (verification is not per-finding streaming)"
|
||||||
|
- "Provider+masked-key tuple for back-assigning Result to Finding index"
|
||||||
|
- "Conditional table columns driven by anyVerified flag for backward compat"
|
||||||
|
key-files:
|
||||||
|
created:
|
||||||
|
- cmd/scan_test.go
|
||||||
|
- pkg/output/table_test.go
|
||||||
|
- .planning/phases/05-verification-engine/05-05-SUMMARY.md
|
||||||
|
modified:
|
||||||
|
- cmd/scan.go
|
||||||
|
- pkg/output/table.go
|
||||||
|
decisions:
|
||||||
|
- "Verification runs in batch after scan completes, not streamed per-finding — matches plan requirement and keeps consent prompt off the hot path."
|
||||||
|
- "Result→Finding back-assignment via provider+KeyMasked tuple (VerifyAll preserves neither order nor identity)."
|
||||||
|
- "Scoped scan_test.go to flag-registration only (per plan escape hatch) — full RunE integration test would require stdin injection refactor that's out of scope."
|
||||||
|
- "Table column conditionally added based on anyVerified to preserve pre-Phase-5 output format exactly when --verify is not used."
|
||||||
|
- "Metadata keys rendered in sorted order for deterministic test assertions and stable display."
|
||||||
|
metrics:
|
||||||
|
duration: "~12min"
|
||||||
|
completed: "2026-04-05T12:54:59Z"
|
||||||
|
tasks: 2
|
||||||
|
commits: 4
|
||||||
|
requirements: [VRFY-01, VRFY-04, VRFY-05]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 5 Plan 05: Scan --verify Integration Summary
|
||||||
|
|
||||||
|
## Objective
|
||||||
|
|
||||||
|
Wire Plans 05-02/03/04 together into the scan command: gate `--verify` behind consent, run the HTTPVerifier over collected findings, persist verify results, and render a new VERIFY column in the output table. Add `--verify-timeout` and `--verify-workers` flags.
|
||||||
|
|
||||||
|
## What Was Built
|
||||||
|
|
||||||
|
### Task 1: Scan command wiring (cmd/scan.go)
|
||||||
|
|
||||||
|
- Added `flagVerifyTimeout time.Duration` (default 10s) and `flagVerifyWorkers int` (default 10) package-level vars.
|
||||||
|
- Registered `--verify-timeout` and `--verify-workers` flags in `init()`.
|
||||||
|
- Imported `github.com/salvacybersec/keyhunter/pkg/verify`.
|
||||||
|
- Refactored `RunE` scan loop:
|
||||||
|
1. **Collect** — drain `eng.Scan` channel into `[]engine.Finding` without persisting.
|
||||||
|
2. **Verify** — when `--verify && len(findings) > 0`, call `verify.EnsureConsent(db, os.Stdin, os.Stderr)`. If declined, print notice to stderr and skip. If granted, create `verify.NewHTTPVerifier(flagVerifyTimeout)`, call `VerifyAll(ctx, findings, reg, flagVerifyWorkers)`, and back-assign each `Result` to its `Finding` via a `provider|masked` lookup index (populating `Verified`, `VerifyStatus`, `VerifyHTTPCode`, `VerifyMetadata`, `VerifyError`).
|
||||||
|
3. **Persist** — loop over enriched findings once, build `storage.Finding` with verify_* fields, call `db.SaveFinding`.
|
||||||
|
- Output rendering unchanged at this layer (Task 2 handles the column).
|
||||||
|
|
||||||
|
### Task 2: Output table verify column (pkg/output/table.go)
|
||||||
|
|
||||||
|
- Added five lipgloss styles: `styleVerifyLive` (green), `styleVerifyDead` (red), `styleVerifyRate` (yellow), `styleVerifyErr` (red), `styleVerifyUnk` (gray).
|
||||||
|
- `PrintFindings` now scans findings once to compute `anyVerified`.
|
||||||
|
- When `anyVerified` is true, the header gains a `VERIFY` column and each row prints `verifySymbol(f)` (✓ live / ✗ dead / ⚠ rate / ! err / ? unk). When false, the layout matches the exact pre-Phase-5 output (backward compatible — `TestPrintFindings_NoVerification_Unchanged` enforces this).
|
||||||
|
- When `len(f.VerifyMetadata) > 0`, an indented secondary line ` ↳ key: value, key: value` is rendered with keys sorted alphabetically for deterministic output.
|
||||||
|
- New `verifySymbol(f engine.Finding) string` helper maps `VerifyStatus` → colored glyph.
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
### cmd/scan_test.go (new)
|
||||||
|
|
||||||
|
- `TestScan_VerifyFlags_Registered/verify-timeout_flag_exists_with_10s_default`
|
||||||
|
- `TestScan_VerifyFlags_Registered/verify-workers_flag_exists_with_default_10`
|
||||||
|
- `TestScan_VerifyFlags_Registered/verify_flag_still_present`
|
||||||
|
|
||||||
|
All three pass. Per plan escape hatch, behavioral integration tests (declined/granted consent end-to-end) were deferred because the current `scanCmd.RunE` reads `os.Stdin` directly without injection — refactoring it to accept an injected reader would ripple outside Plan 05-05's scope. Behavior is exercised indirectly via `pkg/verify/consent_test.go` + `pkg/verify/verifier_test.go` from Wave 1.
|
||||||
|
|
||||||
|
### pkg/output/table_test.go (new)
|
||||||
|
|
||||||
|
- `TestPrintFindings_NoVerification_Unchanged` — asserts VERIFY header absent when no findings are verified (backward compat lock).
|
||||||
|
- `TestPrintFindings_LiveVerification_ShowsCheck` — verified live finding produces VERIFY header and "live" text in output.
|
||||||
|
- `TestPrintFindings_Metadata_Rendered` — metadata pairs render on indented line, sorted alphabetically (org before tier).
|
||||||
|
|
||||||
|
Uses `os.Pipe` + `os.Stdout` swap to capture stdout, strips ANSI escape sequences via regex before assertions. All three pass.
|
||||||
|
|
||||||
|
## Verification Results
|
||||||
|
|
||||||
|
```
|
||||||
|
$ go build ./...
|
||||||
|
(clean)
|
||||||
|
|
||||||
|
$ go test ./...
|
||||||
|
ok github.com/salvacybersec/keyhunter/cmd 0.005s
|
||||||
|
ok github.com/salvacybersec/keyhunter/pkg/engine 0.242s
|
||||||
|
ok github.com/salvacybersec/keyhunter/pkg/engine/sources (cached)
|
||||||
|
ok github.com/salvacybersec/keyhunter/pkg/legal (cached)
|
||||||
|
ok github.com/salvacybersec/keyhunter/pkg/output 0.004s
|
||||||
|
ok github.com/salvacybersec/keyhunter/pkg/providers 0.944s
|
||||||
|
ok github.com/salvacybersec/keyhunter/pkg/storage (cached)
|
||||||
|
ok github.com/salvacybersec/keyhunter/pkg/verify 0.393s
|
||||||
|
|
||||||
|
$ go run . scan --help | grep verify
|
||||||
|
--verify actively verify found keys (opt-in, Phase 5)
|
||||||
|
--verify-timeout duration per-key verification HTTP timeout (default 10s) (default 10s)
|
||||||
|
--verify-workers int parallel workers for key verification (default 10) (default 10)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Commits
|
||||||
|
|
||||||
|
| Hash | Message |
|
||||||
|
| ------- | ------------------------------------------------------------------------- |
|
||||||
|
| d537078 | test(05-05): add failing test for --verify-timeout/--verify-workers flags |
|
||||||
|
| 6fc0abe | feat(05-05): wire --verify into scan pipeline with consent gate |
|
||||||
|
| edba8fb | test(05-05): add failing tests for VERIFY column and metadata rendering |
|
||||||
|
| cc9dabe | feat(05-05): render VERIFY column and metadata line in output table |
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
None — plan executed as written. Test scope was explicitly scoped down to flag-registration per the plan's own escape hatch ("Prefer the lightweight flag-registration test to avoid pulling the full scan path into tests").
|
||||||
|
|
||||||
|
## Success Criteria Check
|
||||||
|
|
||||||
|
- [x] VRFY-01: consent prompt gates --verify on first use (via `verify.EnsureConsent` call before verifier)
|
||||||
|
- [x] VRFY-04: metadata displayed under finding when extracted (indented `↳` line)
|
||||||
|
- [x] VRFY-05: `--verify-timeout` and `--verify-workers` flags work (threaded through `NewHTTPVerifier` + `VerifyAll` workers arg)
|
||||||
|
- [x] Unverified scans unchanged from Phase 4 behavior (backward-compat test enforces identical header format)
|
||||||
|
- [x] `go build ./...` clean
|
||||||
|
- [x] `go test ./... -v` green across all modified packages
|
||||||
|
- [x] `go run . scan --help` shows `--verify`, `--verify-timeout`, `--verify-workers`
|
||||||
|
|
||||||
|
## Known Stubs
|
||||||
|
|
||||||
|
None. All wiring is live; no placeholders in the verified code paths.
|
||||||
|
|
||||||
|
## Self-Check: PASSED
|
||||||
|
|
||||||
|
All 5 key files exist on disk. All 4 commit hashes are present in git history.
|
||||||
Reference in New Issue
Block a user