Files
keyhunter/.planning/phases/09-osint-infrastructure/09-05-PLAN.md
2026-04-06 00:39:27 +03:00

7.0 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
09-osint-infrastructure 05 execute 2
09-01
09-02
09-03
09-04
cmd/recon.go
cmd/stubs.go
cmd/root.go
true
RECON-INFRA-08
truths artifacts key_links
`keyhunter recon full` runs Engine.SweepAll + Dedup and prints a masked findings table
`keyhunter recon list` prints the registered source names one per line
--stealth, --respect-robots (default true), --query flags exist on `recon full`
ExampleSource is registered at init() so Phase 9 ships a demonstrable pipeline
The stub reconCmd in cmd/stubs.go is removed; cmd/recon.go owns the command tree
path provides contains
cmd/recon.go reconCmd with subcommands `full` and `list`, flag wiring, source registration var reconCmd
path provides
cmd/stubs.go reconCmd stub removed; other stubs unchanged
from to via pattern
cmd/recon.go pkg/recon.Engine NewEngine + Register(ExampleSource{}) + SweepAll recon.NewEngine
from to via pattern
cmd/recon.go pkg/recon.Dedup Dedup applied to SweepAll results before printing recon.Dedup
Wire the recon package into the Cobra CLI with `keyhunter recon full` and `keyhunter recon list`. Remove the stub reconCmd from cmd/stubs.go. Register ExampleSource at init() so `recon full` produces visible output end-to-end on a fresh clone.

Purpose: Satisfies RECON-INFRA-08 "Recon full command — parallel sweep across all sources with deduplication". Completes the phase's user-facing entrypoint. Output: cmd/recon.go (new), cmd/stubs.go (stub removed), cmd/root.go (registration unchanged or updated)

<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/phases/09-osint-infrastructure/09-CONTEXT.md @cmd/stubs.go @.planning/phases/09-osint-infrastructure/09-01-SUMMARY.md @.planning/phases/09-osint-infrastructure/09-03-SUMMARY.md Task 1: Remove reconCmd stub from cmd/stubs.go cmd/stubs.go Delete the `var reconCmd = &cobra.Command{...}` block from cmd/stubs.go. Leave verifyCmd, serveCmd, scheduleCmd untouched. The real reconCmd will be declared in cmd/recon.go (Task 2).
Verify cmd/root.go still references `reconCmd` — it will resolve to the new declaration in cmd/recon.go (same package `cmd`).
cd /home/salva/Documents/apikey && ! grep -q 'var reconCmd' cmd/stubs.go cmd/stubs.go no longer declares reconCmd; file still compiles with other stubs. Task 2: Create cmd/recon.go with full and list subcommands cmd/recon.go Create cmd/recon.go declaring `var reconCmd` plus subcommands `reconFullCmd` and `reconListCmd`. Flag wiring: - `--stealth` bool, default false - `--respect-robots` bool, default true - `--query` string, default "" (empty -> sources use their own default keywords)
```go
package cmd

import (
    "context"
    "fmt"

    "github.com/salvacybersec/keyhunter/pkg/recon"
    "github.com/spf13/cobra"
)

var (
    reconStealth       bool
    reconRespectRobots bool
    reconQuery         string
)

var reconCmd = &cobra.Command{
    Use:   "recon",
    Short: "Run OSINT recon across internet sources",
    Long:  "Run OSINT recon sweeps across registered sources. Phase 9 ships with an ExampleSource stub; real sources land in Phases 10-16.",
}

var reconFullCmd = &cobra.Command{
    Use:   "full",
    Short: "Sweep all enabled sources in parallel and deduplicate findings",
    RunE: func(cmd *cobra.Command, args []string) error {
        eng := buildReconEngine()
        cfg := recon.Config{
            Stealth:       reconStealth,
            RespectRobots: reconRespectRobots,
            Query:         reconQuery,
        }
        ctx := context.Background()
        all, err := eng.SweepAll(ctx, cfg)
        if err != nil {
            return fmt.Errorf("recon sweep: %w", err)
        }
        deduped := recon.Dedup(all)
        fmt.Printf("recon: swept %d sources, %d findings (%d after dedup)\n", len(eng.List()), len(all), len(deduped))
        for _, f := range deduped {
            fmt.Printf("  [%s] %s  %s  %s\n", f.SourceType, f.ProviderName, f.KeyMasked, f.Source)
        }
        return nil
    },
}

var reconListCmd = &cobra.Command{
    Use:   "list",
    Short: "List registered recon sources",
    RunE: func(cmd *cobra.Command, args []string) error {
        eng := buildReconEngine()
        for _, name := range eng.List() {
            fmt.Println(name)
        }
        return nil
    },
}

// buildReconEngine constructs the recon Engine with all sources registered.
// Phase 9 ships ExampleSource only; Phases 10-16 will add real sources here
// (or via a registration side-effect in their packages).
func buildReconEngine() *recon.Engine {
    e := recon.NewEngine()
    e.Register(recon.ExampleSource{})
    return e
}

func init() {
    reconFullCmd.Flags().BoolVar(&reconStealth, "stealth", false, "enable UA rotation and jitter delays")
    reconFullCmd.Flags().BoolVar(&reconRespectRobots, "respect-robots", true, "respect robots.txt for web-scraping sources")
    reconFullCmd.Flags().StringVar(&reconQuery, "query", "", "override query sent to each source")
    reconCmd.AddCommand(reconFullCmd)
    reconCmd.AddCommand(reconListCmd)
}
```

Do NOT modify cmd/root.go unless `rootCmd.AddCommand(reconCmd)` is missing. (It currently exists because the stub was registered there.)
cd /home/salva/Documents/apikey && go build ./... && go run . recon list | grep -q '^example$' `keyhunter recon list` prints "example". `keyhunter recon full` prints 2 findings from ExampleSource with "recon: swept 1 sources, 2 findings (2 after dedup)". - `go build ./...` succeeds - `go run . recon list` prints `example` - `go run . recon full` prints "recon: swept 1 sources, 2 findings (2 after dedup)" and two lines with [recon:example] - `go run . recon full --stealth --query=test` runs without error

<success_criteria>

  • reconCmd owned by cmd/recon.go, stub removed from cmd/stubs.go
  • recon full and recon list subcommands work end-to-end
  • Dedup wired through the SweepAll result
  • Flags --stealth, --respect-robots (default true), --query all parse </success_criteria>
After completion, create `.planning/phases/09-osint-infrastructure/09-05-SUMMARY.md`