5.3 KiB
5.3 KiB
phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, requirements-completed, duration, completed
| phase | plan | subsystem | tags | requires | provides | affects | tech-stack | key-files | key-decisions | requirements-completed | duration | completed | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 06-output-reporting | 06 | cli |
|
|
|
|
|
|
|
|
3min | 2026-04-05 |
Phase 06 Plan 06: Scan Output Wiring and Exit Codes Summary
Scan command now dispatches --output=table|json|sarif|csv through the formatter registry and honors the OUT-06 exit-code contract (0 clean, 1 findings, 2 error) for CI/CD consumers.
Performance
- Duration: ~3 min
- Tasks: 2
- Files modified: 2 (cmd/scan.go, cmd/root.go)
- Files created: 1 (cmd/scan_output_test.go)
Accomplishments
- Replaced inline
jsonFindingswitch in scan RunE with a single call tooutput.Get(flagOutput)→Formatter.Format(...), unlocking SARIF and CSV for scan output. - Extracted the dispatch into
renderScanOutput(findings, name, unmask, w io.Writer)so the logic can be unit-tested without booting the full scanner/DB/consent pipeline. - Implemented OUT-06 exit-code contract:
0: scan returns cleanly, no findings1:os.Exit(1)at the tail of scan RunE whenlen(findings) > 02: rootExecute()now maps any non-nilrootCmd.Execute()error toos.Exit(2)(was 1)
- Added
versionpackage var +versionString()helper so SARIFtool.driver.versionis populated and overridable via-ldflags "-X github.com/salvacybersec/keyhunter/cmd.version=...". - Updated
--outputhelp text to list all four formats. - Four-test coverage in
cmd/scan_output_test.go:TestScanOutput_FormatNamesIncludeAll— registry wiring guardTestRenderScanOutput_UnknownReturnsError—errors.Is(err, output.ErrUnknownFormat)+ "valid:" substringTestRenderScanOutput_JSONSucceeds— valid[]JSON for empty findingsTestRenderScanOutput_TableEmpty— "No API keys found" sentinel
Verification
go build ./...— cleango vet ./cmd/...— cleango test ./... -count=1— all packages green (cmd, engine, engine/sources, legal, output, providers, storage, verify)go test ./cmd/... -run "TestScanOutput|TestRenderScanOutput" -count=1— 4/4 pass
Commits
| Task | Type | Hash | Message |
|---|---|---|---|
| 1 | feat | c9114e4 |
wire scan --output to formatter registry and exit-code contract |
| 2 | test | cdf3c8a |
cover scan output dispatch and unknown-format error |
Deviations from Plan
None — plan executed exactly as written. The renderScanOutput helper called out as optional in Task 2 was added during Task 1 (the plan explicitly permitted this consolidation in Task 2 step 1).
Files Touched
Modified:
cmd/scan.go— removed inlinejsonFindingstruct +encoding/jsonimport; addedio/stringsimports; replaced output switch withrenderScanOutputhelper; introducedversionvar +versionString(); updated flag help text.cmd/root.go—Execute()now exits with code 2 (was 1) on non-nilrootCmd.Execute()error, with a comment documenting the OUT-06 exit-code contract.
Created:
cmd/scan_output_test.go— four tests covering registration, unknown-format error, JSON dispatch, table dispatch.
Known Stubs
None. All four registered formatters (table, json, csv, sarif) are fully wired and exercised by tests.
Self-Check: PASSED
- cmd/scan.go contains
output.Get(name)— verified (in renderScanOutput) - cmd/scan.go contains
output.Options{— verified - cmd/scan.go no longer contains
jsonFinding— verified - cmd/root.go contains
os.Exit(2)— verified - cmd/scan_output_test.go exists with four tests — verified
- Task 1 commit
c9114e4present in git log — verified - Task 2 commit
cdf3c8apresent in git log — verified