Commit Graph

325 Commits

Author SHA1 Message Date
salvacybersec
5292502000 docs(06-01): complete formatter interface + TableFormatter plan 2026-04-05 23:29:13 +03:00
salvacybersec
8e4db5db09 feat(06-01): refactor table output into TableFormatter
- TableFormatter implements Formatter interface, registered as "table"
- Writes to arbitrary io.Writer instead of hardcoded os.Stdout
- Strips ANSI colors when writer is not a TTY or NO_COLOR is set
- Uses bundled tableStyles so plain/colored paths share one renderer
- PrintFindings retained as backward-compat wrapper delegating to Format
2026-04-05 23:27:53 +03:00
salvacybersec
8c37252c1b test(06-01): add failing tests for TableFormatter refactor
- Add TestTableFormatter_Empty, NoColorInBuffer, Unverified/VerifiedLayout
- Add TestTableFormatter_Masking, MetadataSorted, RegisteredUnderTable
- Keep legacy PrintFindings tests as backward-compat wrapper coverage
2026-04-05 23:27:03 +03:00
salvacybersec
291c97ed0b feat(06-01): add Formatter interface, Registry, and TTY color detection
- pkg/output/formatter.go: Formatter interface, Options, Registry with
  Register/Get/Names, ErrUnknownFormat sentinel
- pkg/output/colors.go: IsTTY + ColorsEnabled honoring NO_COLOR
- Promote github.com/mattn/go-isatty to direct dependency
- Unit tests cover registry round-trip, unknown lookup, sorted Names,
  non-TTY buffer, NO_COLOR override

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 18:41:23 +03:00
salvacybersec
ce37ee2bc5 docs(06): create phase 6 plans — output formats + key management 2026-04-05 16:10:14 +03:00
salvacybersec
7ba2a94fb6 docs(06): output formats and key management context 2026-04-05 16:00:42 +03:00
salvacybersec
0a474e70c5 docs(phase-05): complete phase execution 2026-04-05 15:59:51 +03:00
salvacybersec
8cceca164c docs(05-05): complete scan --verify integration plan 2026-04-05 15:56:23 +03:00
salvacybersec
cc9dabe5f5 feat(05-05): render VERIFY column and metadata line in output table
- When any finding has Verified=true, append a VERIFY column with colored
  glyphs: ✓ live / ✗ dead / ⚠ rate / ! err / ? unk
- Per-finding VerifyMetadata is rendered on an indented secondary line
  with deterministic (sorted) key ordering
- Backward compatible: unverified scans produce identical output to
  pre-Phase-5 runs
2026-04-05 15:54:51 +03:00
salvacybersec
edba8fb5d4 test(05-05): add failing tests for VERIFY column and metadata rendering 2026-04-05 15:54:13 +03:00
salvacybersec
6fc0abe8ae feat(05-05): wire --verify into scan pipeline with consent gate
- Add --verify-timeout (default 10s) and --verify-workers (default 10) flags
- Refactor scan loop to collect findings, verify, then persist
- Gate verification behind verify.EnsureConsent(db, stdin, stderr)
- Route findings through verify.HTTPVerifier.VerifyAll with configurable
  timeout and worker pool, back-assign Result.Status/HTTPCode/Metadata
  onto engine.Finding by provider+masked-key tuple
- Persist verify_* columns via storage.SaveFinding after verification
2026-04-05 15:53:47 +03:00
salvacybersec
d5370783d4 test(05-05): add failing test for --verify-timeout/--verify-workers flags 2026-04-05 15:52:57 +03:00
salvacybersec
c6968a4a72 docs(05-03): complete HTTPVerifier core plan
- SUMMARY.md with decisions, metrics, deviations, self-check
- STATE.md advanced, requirements VRFY-02/03/05 marked complete
- ROADMAP.md plan progress updated
2026-04-05 15:51:23 +03:00
salvacybersec
35c7759f02 feat(05-03): add VerifyAll ants worker pool for parallel verification
- VerifyAll(ctx, findings, reg, workers) returns a result channel closed
  after all findings are processed or ctx is cancelled.
- Default worker count of 10 when workers <= 0.
- Missing providers yield StatusUnknown with 'provider not found' error.
- Graceful context cancellation stops dispatch while still draining inflight.
2026-04-05 15:49:22 +03:00
salvacybersec
0be926f823 docs(05-02): complete legal disclaimer & consent prompt plan 2026-04-05 15:49:05 +03:00
salvacybersec
45ee2f8f53 test(05-03): add failing tests for VerifyAll worker pool
- TestVerifyAll_MultipleFindings: 5 findings via 3-worker pool
- TestVerifyAll_MissingProvider: unknown provider yields StatusUnknown
- TestVerifyAll_ContextCancellation: cancellation closes channel early
- Add providers.NewRegistryFromProviders test helper
2026-04-05 15:48:46 +03:00
salvacybersec
026d305026 docs(05-04): complete Tier 1 verify specs plan 2026-04-05 15:48:15 +03:00
salvacybersec
3dfe72779b feat(05-03): implement HTTPVerifier single-key verification
- HTTPVerifier with TLS 1.2+ client and configurable per-call timeout
- {{KEY}} template substitution in URL, header values, and body
- Classification via EffectiveSuccessCodes/FailureCodes/RateLimitCodes
- Retry-After header captured on rate-limit responses
- gjson-based metadata extraction for JSON responses (1 MiB cap)
- HTTPS-only enforcement; missing URL yields StatusUnknown
- Consent stub added to unblock parallel Plan 05-02 worktree (Rule 3 deviation)
2026-04-05 15:47:49 +03:00
salvacybersec
d4c140371e feat(05-02): implement EnsureConsent prompt gating --verify
- Add EnsureConsent(db, in, out) that returns (true, nil) immediately if
  verify.consent==granted, otherwise prompts once, reads a line, persists
  'granted' on 'yes' (case-insensitive), 'declined' otherwise.
- Declined is not sticky — next call re-prompts; only granted persists.
- Prompt references legal implications and directs users to 'keyhunter legal'.
2026-04-05 15:47:30 +03:00
salvacybersec
6a94ce5903 test(05-04): guardrail tests for Tier 1 verify spec completeness
- TestTier1VerifySpecs_Complete asserts 11 Tier 1 providers have HTTPS
  verify URLs and non-empty effective success codes
- TestInflection_NoVerifyEndpoint documents the intentional empty URL
- Prevents future regressions when editing provider YAMLs
2026-04-05 15:46:57 +03:00
salvacybersec
e5f72149cf test(05-02): add failing tests for EnsureConsent prompt logic 2026-04-05 15:46:41 +03:00
salvacybersec
f3ae8f0b09 feat(05-04): extend Tier 1 provider verify specs
- 12 Tier 1 providers now carry success_codes, failure_codes, rate_limit_codes
- {{KEY}} template in headers or URL (double-brace canonical form)
- metadata_paths added where provider APIs return useful metadata
- Anthropic switched to POST /v1/messages with minimal body
- Perplexity gains JSON body, content-type header
- Inflection verify URL left empty (no public endpoint)
- Dual-location sync preserved: providers/ mirrors pkg/providers/definitions/
2026-04-05 15:46:30 +03:00
salvacybersec
3ceccd98ad test(05-03): add failing tests for HTTPVerifier single-key verification
- 10 test cases covering live/dead/rate-limited/unknown/error classification
- Key substitution in header/body/URL via {{KEY}} template
- JSON metadata extraction via gjson paths
- HTTPS-only enforcement and per-call timeout
2026-04-05 15:46:15 +03:00
salvacybersec
260e342f2f feat(05-02): add LEGAL.md, embed it, and wire keyhunter legal command
- Add LEGAL.md at repo root (109 lines) covering CFAA, Computer Misuse Act,
  EU Directive 2013/40/EU, responsible use, disclosure, and disclaimer.
- Mirror to pkg/legal/LEGAL.md for go:embed (Go cannot traverse parents).
- Add pkg/legal package exposing Text() for the embedded markdown.
- Add cmd/legal.go registering keyhunter legal subcommand to print it.
2026-04-05 15:46:11 +03:00
salvacybersec
177888bfa8 docs(05-01): complete verification foundation plan
Wave 0 contracts for the verification engine are in place:
- VerifySpec extended with SuccessCodes/FailureCodes/RateLimitCodes/MetadataPaths/Body
- Finding extended with Verified/VerifyStatus/VerifyHTTPCode/VerifyMetadata/VerifyError
- findings table schema migrated with verify_* columns (fresh + legacy DBs)
- gjson dep wired as direct require
- VRFY-02, VRFY-03 marked complete
2026-04-05 15:44:20 +03:00
salvacybersec
aec559d2aa feat(05-01): migrate findings schema with verify_* columns
- schema.sql: new findings columns verified, verify_status, verify_http_code, verify_metadata_json
- db.go: migrateFindingsVerifyColumns runs on Open() for legacy DBs using PRAGMA table_info + ALTER TABLE
- findings.go: Finding struct gains Verified/VerifyStatus/VerifyHTTPCode/VerifyMetadata
- SaveFinding serializes verify metadata as JSON (NULL when nil)
- ListFindings round-trips all verify fields
2026-04-05 15:42:53 +03:00
salvacybersec
26544872f7 test(05-01): add failing tests for findings verify columns
- Round-trip verify fields (Verified, VerifyStatus, VerifyHTTPCode, VerifyMetadata)
- Empty verify fields persist as defaults
- Legacy DB schema migrates verify columns idempotently
2026-04-05 15:41:49 +03:00
salvacybersec
30c0e9871b feat(05-01): extend VerifySpec and Finding, add gjson dep
- VerifySpec: add SuccessCodes, FailureCodes, RateLimitCodes, MetadataPaths, Body
- Preserve legacy ValidStatus/InvalidStatus for backward compat
- Add EffectiveSuccessCodes/FailureCodes/RateLimitCodes fallback helpers
- Add ExtractMetadata helper using gjson (skeleton for Plan 05-03)
- Finding: add Verified, VerifyStatus, VerifyHTTPCode, VerifyMetadata, VerifyError
- Add github.com/tidwall/gjson v1.18.0 as direct dependency
2026-04-05 15:41:13 +03:00
salvacybersec
499f5d5025 test(05-01): add failing tests for extended VerifySpec
- New canonical fields: SuccessCodes, FailureCodes, RateLimitCodes, MetadataPaths, Body
- EffectiveSuccessCodes/FailureCodes/RateLimitCodes fallback logic
- Legacy ValidStatus/InvalidStatus still parse
2026-04-05 15:39:35 +03:00
salvacybersec
0b667566c4 docs(05): create phase 5 verification engine plans 2026-04-05 15:38:23 +03:00
salvacybersec
e65b9c981b docs(05): verification engine context 2026-04-05 15:30:11 +03:00
salvacybersec
b079ed202c docs(phase-04): complete phase execution 2026-04-05 15:29:09 +03:00
salvacybersec
c40e9f087f docs(04-05): complete scan command source wiring plan 2026-04-05 15:24:46 +03:00
salvacybersec
b151e88a29 feat(04-05): wire all Phase 4 sources through scan command
- Add --git, --url, --clipboard, --since, --max-file-size, --insecure flags
- Introduce selectSource dispatcher with sourceFlags struct
- Dispatch to Dir/File/Git/Stdin/URL/Clipboard sources based on args+flags
- Reject mutually exclusive source selectors with clear error
- Forward --exclude patterns into DirSource
- Args changed to MaximumNArgs(1) to allow --url/--clipboard without positional
2026-04-05 15:23:12 +03:00
salvacybersec
9105ca11f5 test(04-05): add failing tests for selectSource dispatcher 2026-04-05 15:21:37 +03:00
salvacybersec
66fc597399 docs(04-04): complete stdin/url/clipboard sources plan 2026-04-05 15:20:10 +03:00
salvacybersec
563d6e5ce2 docs(04-02): complete DirSource plan 2026-04-05 15:19:50 +03:00
salvacybersec
e8ba651a51 docs(04-03): complete GitSource plan 2026-04-05 15:19:15 +03:00
salvacybersec
850c3ff8e9 feat(04-04): add StdinSource, URLSource, and ClipboardSource
- StdinSource reads from an injectable io.Reader (INPUT-03)
- URLSource fetches http/https with 30s timeout, 50MB cap, scheme whitelist, and Content-Type filter (INPUT-04)
- ClipboardSource wraps atotto/clipboard with graceful fallback for missing tooling (INPUT-05)
- emitByteChunks local helper mirrors file.go windowing to stay independent of sibling wave-1 plans
- Tests cover happy path, cancellation, redirects, oversize bodies, binary content types, scheme rejection, and clipboard error paths
2026-04-05 15:18:23 +03:00
salvacybersec
6f834c9c06 feat(04-02): implement DirSource with recursive walk, glob exclusion, and mmap
- Add DirSource with filepath.WalkDir recursive traversal
- Default exclusions for .git, node_modules, vendor, *.min.js, *.map
- Binary file detection via NUL byte sniff (first 512 bytes)
- mmap reads for files >= 10MB via golang.org/x/exp/mmap
- Deterministic sorted emission order for reproducible tests
- Refactor FileSource to share emitChunks/isBinary helpers and mmap large files
2026-04-05 15:18:10 +03:00
salvacybersec
e48a7a489e feat(04-03): implement GitSource with full-history traversal
- Walks every commit across branches, tags, remote-tracking refs, and stash
- Deduplicates blob scans by OID (seenBlobs map) so identical content
  across commits/files is scanned exactly once
- Emits chunks with source format git:<short-sha>:<path>
- Honors --since filter via GitSource.Since (commit author date)
- Resolves annotated tag objects down to their commit hash
- Skips binary blobs via go-git IsBinary plus null-byte sniff
- 8 subtests cover history walk, dedup, modified-file, multi-branch,
  tag reachability, since filter, source format, missing repo
2026-04-05 15:18:05 +03:00
salvacybersec
ce6298f304 test(04-02): add failing tests for DirSource recursive walk and mmap 2026-04-05 15:16:48 +03:00
salvacybersec
842cfea268 docs(04-01): complete dependency bootstrap plan 2026-04-05 15:15:32 +03:00
salvacybersec
0f30c0d156 chore(04-01): add go-git, clipboard, and x/exp/mmap dependencies
- github.com/go-git/go-git/v5 v5.17.2 (git history traversal)
- github.com/atotto/clipboard v0.1.4 (cross-platform clipboard)
- golang.org/x/exp (mmap for large file reads)

Wave 0 dependency bootstrap for Phase 4 input sources. Modules
are recorded as indirect until Wave 1 plans import them; go.sum
contains checksums. go build ./... and go vet ./... both green.
2026-04-05 15:14:37 +03:00
salvacybersec
3d38616d80 docs(04-input-sources): create phase plan 2026-04-05 15:12:57 +03:00
salvacybersec
1bc8f02370 docs(04): phase context with source adapter decisions 2026-04-05 15:00:25 +03:00
salvacybersec
03e768782a docs: mark phases 2-3 complete in ROADMAP checkboxes 2026-04-05 14:50:48 +03:00
salvacybersec
626544e4af docs(phase-03): complete phase execution 2026-04-05 14:50:13 +03:00
salvacybersec
a639cdea02 docs(03-08): complete Tier 3-9 guardrail tests plan 2026-04-05 14:46:35 +03:00
salvacybersec
1aea496a17 test(03-08): add Tier 3-9 guardrail tests locking 108 total providers
- Add tier39_test.go with per-tier count assertions (T3=12, T4=16, T5=11, T6=15, T7=10, T8=10, T9=8)
- Lock all 82 Tier 3-9 provider names against drift via expectedTier3..expectedTier9 slices
- Assert total registry provider count == 108
- Existing TestAllPatternsCompile and TestAllProvidersHaveKeywords transitively cover Tier 3-9 regex compilation and keyword presence
- Satisfies PROV-03..PROV-09
2026-04-05 14:45:41 +03:00