--- phase: 08-dork-engine plan: 06 subsystem: cli tags: [cobra, dorks, cli, sqlite, github, viper] requires: - phase: 08-dork-engine provides: "Registry, Runner, GitHubExecutor, custom_dorks storage" provides: - "keyhunter dorks list/info/export/run/add/delete command tree" - "Injectable newGitHubExecutor seam for cmd tests" - "GITHUB_TOKEN env var bound to viper.dorks.github.token" affects: [phase-09-osint, phase-10-shodan, phase-17-scheduler] tech-stack: added: [] patterns: - "Package-level executor factory var as test injection seam" - "Embedded+custom dork merge via internal dorkRow helper" - "text/tabwriter for CLI table output (no lipgloss yet for dorks)" key-files: created: - cmd/dorks.go - cmd/dorks_test.go modified: - cmd/stubs.go key-decisions: - "Flag reuse: dorks list and dorks run share dorksFilterSource/Category vars since they never run concurrently — simplifies test reset" - "initDorksDB skips encryption key derivation: dorks CLI only touches plaintext custom_dorks, not the encrypted findings table" - "dorks run wraps ErrSourceNotImplemented with friendly 'coming Phase 9-16' message instead of bare error" - "newGitHubExecutor exposed as package var (not method) so tests can swap without touching dorksRunCmd internals" patterns-established: - "Injectable executor factory: var newFooExecutor = func() Executor { ... } for mocking in cmd tests" - "resetDorksFlags helper called from setupDorksTest + between sequential rootCmd.Execute() calls" requirements-completed: [DORK-03, DORK-04] duration: ~35min completed: 2026-04-05 --- # Phase 8 Plan 06: Dorks CLI Command Tree Summary **Full Cobra command tree (list/info/export/run/add/delete) replacing the Phase-8 stub, wiring Registry + custom_dorks + GitHubExecutor through an injectable factory seam for testability.** ## Performance - **Duration:** ~35 min - **Tasks:** 2 - **Files modified:** 3 (1 created in commit 1, 1 created in commit 2, 1 edited) ## Accomplishments - Replaced cmd/stubs.go dorks stub with a six-verb subcommand tree - Merged embedded Registry dorks with user-authored custom_dorks in list + export (custom rows prefixed with `*`) - Added --source/--category filtering to both list and run - Wired dorks run to dorks.Runner with GitHub live execution, friendly ErrSourceNotImplemented messaging for other sources, and an ErrMissingAuth hint that points users at GITHUB_TOKEN - Added validation to dorks add: source must be in dorks.ValidSources, category in dorks.ValidCategories, dork id must not collide with an embedded id - Delete refuses embedded ids with a clear error - Bound GITHUB_TOKEN -> dorks.github.token via viper.BindEnv in the dorks init() - 11 end-to-end cmd tests covering every branch, passing against an in-memory SQLite temp DB ## Task Commits 1. **Task 1: list/info/export + stub removal** - `b7934ce` (feat) 2. **Task 2: run/add/delete + tests** - `c281c96` (feat) ## Files Created/Modified - `cmd/dorks.go` - Full dorks Cobra command tree, flag declarations, initDorksDB helper, newGitHubExecutor injection seam, init() wiring - `cmd/dorks_test.go` - 11 tests: list filtering, add persistence + marker, invalid source rejection, embedded id collision, embedded delete refusal, custom delete, shodan not-implemented, github missing-token hint, fake-executor run path, yaml export merge, info for both origins - `cmd/stubs.go` - Removed dorksCmd stub declaration (kept notImplemented helper and other stubs) ## Decisions Made - **Skip encryption in initDorksDB**: The dorks CLI only reads/writes `custom_dorks`, which stores plaintext metadata. Forcing users through the encryption-key derivation path that `openDBWithKey` uses would add a passphrase prompt for commands that don't need it. initDorksDB deliberately calls `storage.Open` directly. - **tabwriter over lipgloss**: Phase 8 plan lists lipgloss as a "nice to have" for the dorks table; the current pkg/output table helpers are keyed to findings, not dorks. Used stdlib text/tabwriter to keep Phase 8 self-contained. A future refactor can swap to lipgloss alongside a shared Table type. - **Package-level executor factory var**: `var newGitHubExecutor = func() dorks.Executor { ... }`. Tests swap it; production code reads it. Avoids forcing the Runner to accept a factory injection or the cmd struct to carry a builder field. - **Shared filter flag vars between list and run**: `dorksFilterSource`/`dorksFilterCategory` are reused across subcommands. Cobra runs one subcommand per invocation, so sharing is safe; `resetDorksFlags` in the test helper guarantees clean state. ## Deviations from Plan None significant. Minor adjustments made inline during implementation: 1. **[Inline adjustment] renderDork signature switched to `io.Writer`** after initial draft used a structural interface. Single-line fix before the first build. 2. **[Inline adjustment] sort key used `rows[i].Dork.Source`** not `rows[i].Source` — dorkRow wraps Dork rather than embedding it, so the field path goes through `.Dork`. Caught by `go build` on the first run and fixed immediately. Both were typo-class fixes inside Task 1, pre-commit. Neither required new infrastructure or plan changes. ## Issues Encountered None. All 11 tests passed on first run after the two trivial compile fixes above; no retries, no flakes. ## Self-Check: PASSED Files verified to exist: - `cmd/dorks.go` — FOUND - `cmd/dorks_test.go` — FOUND Commits verified in `git log`: - `b7934ce` feat(08-06): add dorks list/info/export commands — FOUND - `c281c96` feat(08-06): add dorks run/add/delete with injectable executor — FOUND Build + tests: - `go build ./...` — PASS - `go test ./cmd/... ./pkg/dorks/... ./pkg/storage/...` — PASS - `go test ./...` — PASS (entire workspace green) ## User Setup Required None for tests. For live `keyhunter dorks run --source=github ...`, users must export `GITHUB_TOKEN` with `public_repo` scope, or run `keyhunter config set dorks.github.token `. ## Next Phase Readiness - DORK-03 and DORK-04 requirements satisfied - Plan 08-07 (guardrail/E2E tests) unblocked — the CLI surface it exercises now exists - Phase 9-16 OSINT sources can plug into the dispatcher by registering executors with `dorks.Runner`; the friendly "coming Phase 9-16" message transparently disappears as each one lands --- *Phase: 08-dork-engine* *Plan: 06* *Completed: 2026-04-05*