From 7ba2a94fb68da2c4be50986cdc40f117190e8ad0 Mon Sep 17 00:00:00 2001 From: salvacybersec Date: Sun, 5 Apr 2026 16:00:42 +0300 Subject: [PATCH] docs(06): output formats and key management context --- .../phases/06-output-reporting/06-CONTEXT.md | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 .planning/phases/06-output-reporting/06-CONTEXT.md diff --git a/.planning/phases/06-output-reporting/06-CONTEXT.md b/.planning/phases/06-output-reporting/06-CONTEXT.md new file mode 100644 index 0000000..39243e7 --- /dev/null +++ b/.planning/phases/06-output-reporting/06-CONTEXT.md @@ -0,0 +1,99 @@ +# Phase 6: Output, Reporting & Key Management - Context + +**Gathered:** 2026-04-05 +**Status:** Ready for planning +**Mode:** Auto-generated + + +## Phase Boundary + +Two related capabilities: +1. **Scan output formats**: table (default, colored, masked), JSON, SARIF 2.1.0, CSV. `--unmask` reveals full keys. Proper exit codes for CI/CD. +2. **Key management commands**: `keyhunter keys list/show/export/copy/delete` for lifecycle operations on stored keys. + + + + +## Implementation Decisions + +### Output Formats (OUT-01..06) +- **Extend pkg/output/** with: `json.go`, `sarif.go`, `csv.go`, keeping `table.go` from Phase 1/5 +- **Format registry**: `output.Formatter` interface with `Format(findings []Finding, w io.Writer) error` +- **Selection**: `--output=table|json|sarif|csv` flag on scan command (default: table) +- **Masking**: `MaskKey()` is default; `--unmask` passes a flag down to the formatter +- **Colors**: lipgloss for table format only (already in use), strip colors when stdout isn't a TTY (detect via `isatty`) + +### Exit Codes (OUT-06) +- **0**: no findings +- **1**: findings detected +- **2**: scan error +- Set via `os.Exit(code)` at end of scan command. Use `cobra.Command.SilenceUsage = true` on error to avoid duplicate usage message. + +### SARIF 2.1.0 +- **Implementation**: custom structs (no library per CLAUDE.md — ~200 lines). schema at https://docs.oasis-open.org/sarif/sarif/v2.1.0/ +- **Fields**: `$schema`, `version: "2.1.0"`, `runs[].tool.driver.{name, version, rules[]}`, `runs[].results[]` with `ruleId, level, message, locations[{physicalLocation.{artifactLocation.uri, region.{startLine, startColumn, endLine, endColumn}}}]` +- **Rule**: one rule per provider (ruleId = provider name) +- **Level mapping**: confidence high → error, medium → warning, low → note + +### Key Management (KEYS-01..06) +- **New command tree**: `keyhunter keys ` in cmd/keys.go (replace existing stub) + - `list` — table of all stored findings, masked by default, `--unmask` for full, `--provider=openai` filter, `--verified` filter + - `show ` — full detail for one finding (unmasked), including verify metadata + - `export --format=json|csv [--output=file]` — dump findings to file/stdout + - `copy ` — copy plaintext key to clipboard via atotto/clipboard (already imported) + - `delete ` — remove from findings table, with `--yes` to skip confirm +- **ID**: use SQLite rowid (integer). Display in list output. + +### Findings DB Query Layer +- New `pkg/storage/queries.go` — `ListFindings(filters Filters) ([]Finding, error)`, `GetFinding(id int) (*Finding, error)`, `DeleteFinding(id int) error` +- Filter struct: `Provider string, Verified *bool, Since time.Time` +- Pagination: `Limit, Offset` fields (default unlimited for v1) + +### Output Package Layout +``` +pkg/output/ + formatter.go — Formatter interface + Registry + table.go — existing, refactor to implement Formatter + json.go — NEW — JSON output (uses encoding/json) + sarif.go — NEW — SARIF 2.1.0 output + csv.go — NEW — CSV output (uses encoding/csv) + colors.go — NEW — isatty detection, color stripping +``` + + + + +## Existing Code Insights + +### Reusable Assets +- pkg/output/table.go — existing, extend to Formatter interface +- pkg/storage/findings.go — existing CRUD +- pkg/engine/finding.go — extended with verify fields in Phase 5 +- pkg/engine/finding.go MaskKey() — already defined +- cmd/stubs.go — `keys` is currently a stub, replace with real command tree + +### Dependencies to add +- `github.com/mattn/go-isatty` — for TTY detection + + + + +## Specific Ideas + +- JSON output should include full Finding struct (all fields) +- CSV header row: id,provider,confidence,key_masked,source,line,detected_at,verified,verify_status +- SARIF should include the scan binary version (extract from cmd/root.go version constant) +- Keys export to file should use atomic write (write to temp then rename) +- Delete should show confirmation: "Delete finding #42 (openai, sk-proj-***abc)? [y/N]" + + + + +## Deferred Ideas + +- Per-finding tags/labels — not in scope +- Bulk operations (delete all from provider X) — add a --provider filter, but no bulk delete +- Export to cloud storage (S3, GCS) — out of scope +- HTML report format — defer to dashboard phase + +