--- phase: 13-osint_package_registries_container_iac plan: 04 type: execute wave: 2 depends_on: - "13-01" - "13-02" - "13-03" files_modified: - pkg/recon/sources/register.go - pkg/recon/sources/register_test.go - pkg/recon/sources/integration_test.go - cmd/recon.go autonomous: true requirements: - RECON-PKG-01 - RECON-PKG-02 - RECON-PKG-03 - RECON-INFRA-01 - RECON-INFRA-02 - RECON-INFRA-03 - RECON-INFRA-04 must_haves: truths: - "RegisterAll registers all 12 new Phase 13 sources (40 total) on the engine" - "All 40 sources appear in engine.List() sorted alphabetically" - "Integration test runs SweepAll across all 40 sources with httptest fixtures and gets at least one finding per SourceType" - "cmd/recon.go wires any new SourcesConfig fields needed for Phase 13 sources" artifacts: - path: "pkg/recon/sources/register.go" provides: "Updated RegisterAll with 12 new Phase 13 source registrations" contains: "NpmSource" - path: "pkg/recon/sources/register_test.go" provides: "Updated test asserting 40 sources registered" contains: "40" - path: "pkg/recon/sources/integration_test.go" provides: "Updated integration test with httptest mux handlers for all 12 new sources" contains: "recon:npm" key_links: - from: "pkg/recon/sources/register.go" to: "pkg/recon/sources/npm.go" via: "engine.Register call" pattern: "NpmSource" - from: "pkg/recon/sources/register.go" to: "pkg/recon/sources/dockerhub.go" via: "engine.Register call" pattern: "DockerHubSource" - from: "pkg/recon/sources/integration_test.go" to: "all 12 new sources" via: "httptest mux handlers" pattern: "recon:(npm|pypi|crates|rubygems|maven|nuget|goproxy|packagist|dockerhub|k8s|terraform|helm)" --- Wire all 12 Phase 13 sources into RegisterAll, update register_test.go to assert 40 total sources, and extend the integration test with httptest handlers for all new sources. Purpose: Connects the individually-implemented sources into the recon engine so `keyhunter recon` discovers and runs them. Integration test proves end-to-end SweepAll works across all 40 sources. Output: Updated register.go, register_test.go, integration_test.go, cmd/recon.go @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @pkg/recon/sources/register.go @pkg/recon/sources/register_test.go @pkg/recon/sources/integration_test.go @cmd/recon.go @.planning/phases/13-osint_package_registries_container_iac/13-01-SUMMARY.md @.planning/phases/13-osint_package_registries_container_iac/13-02-SUMMARY.md @.planning/phases/13-osint_package_registries_container_iac/13-03-SUMMARY.md From pkg/recon/sources/register.go (current): ```go type SourcesConfig struct { GitHubToken string // ... existing fields ... Registry *providers.Registry Limiters *recon.LimiterRegistry } func RegisterAll(engine *recon.Engine, cfg SourcesConfig) { ... } ``` From pkg/recon/engine.go: ```go func (e *Engine) Register(src ReconSource) func (e *Engine) List() []string // sorted source names ``` New sources created by Plans 13-01..03 (all credentialless, struct-literal style): - NpmSource{BaseURL, Registry, Limiters, Client} - PyPISource{BaseURL, Registry, Limiters, Client} - CratesIOSource{BaseURL, Registry, Limiters, Client} - RubyGemsSource{BaseURL, Registry, Limiters, Client} - MavenSource{BaseURL, Registry, Limiters, Client} - NuGetSource{BaseURL, Registry, Limiters, Client} - GoProxySource{BaseURL, Registry, Limiters, Client} - PackagistSource{BaseURL, Registry, Limiters, Client} - DockerHubSource{BaseURL, Registry, Limiters, Client} - KubernetesSource{BaseURL, Registry, Limiters, Client} - TerraformSource{BaseURL, Registry, Limiters, Client} - HelmSource{BaseURL, Registry, Limiters, Client} Task 1: Wire Phase 13 sources into RegisterAll and update register_test pkg/recon/sources/register.go, pkg/recon/sources/register_test.go **register.go updates:** 1. Add a `// Phase 13: Package registry sources (credentialless).` comment block after the Phase 12 cloud storage block 2. Register all 8 package registry sources as struct literals (no New* constructors needed since they're credentialless): ```go engine.Register(&NpmSource{Registry: reg, Limiters: lim}) engine.Register(&PyPISource{Registry: reg, Limiters: lim}) engine.Register(&CratesIOSource{Registry: reg, Limiters: lim}) engine.Register(&RubyGemsSource{Registry: reg, Limiters: lim}) engine.Register(&MavenSource{Registry: reg, Limiters: lim}) engine.Register(&NuGetSource{Registry: reg, Limiters: lim}) engine.Register(&GoProxySource{Registry: reg, Limiters: lim}) engine.Register(&PackagistSource{Registry: reg, Limiters: lim}) ``` 3. Add a `// Phase 13: Container & IaC sources (credentialless).` comment block 4. Register all 4 infra sources: ```go engine.Register(&DockerHubSource{Registry: reg, Limiters: lim}) engine.Register(&KubernetesSource{Registry: reg, Limiters: lim}) engine.Register(&TerraformSource{Registry: reg, Limiters: lim}) engine.Register(&HelmSource{Registry: reg, Limiters: lim}) ``` 5. Update the RegisterAll doc comment: change "28 sources total" to "40 sources total" and mention Phase 13 6. No new SourcesConfig fields needed — all Phase 13 sources are credentialless **register_test.go updates:** 1. Rename `TestRegisterAll_WiresAllTwentyEightSources` to `TestRegisterAll_WiresAllFortySources` 2. Update `want` slice to include all 12 new names in alphabetical order: "crates", "dockerhub", "goproxy", "helm", "k8s", "maven", "npm", "nuget", "packagist", "pypi", "rubygems", "terraform" merged into existing list 3. Update `TestRegisterAll_MissingCredsStillRegistered` count from 28 to 40 4. The full sorted list should be: azureblob, binaryedge, bing, bitbucket, brave, censys, codeberg, codesandbox, crates, dockerhub, dospaces, duckduckgo, fofa, gcs, gist, gistpaste, github, gitlab, google, goproxy, helm, huggingface, k8s, kaggle, maven, netlas, npm, nuget, packagist, pastebin, pastesites, pypi, replit, rubygems, s3, sandboxes, shodan, spaces, terraform, yandex, zoomeye Wait — that's 41. Let me recount existing: azureblob, binaryedge, bing, bitbucket, brave, censys, codeberg, codesandbox, duckduckgo, fofa, gcs, gist, gistpaste, github, gitlab, google, huggingface, kaggle, netlas, pastebin, pastesites, replit, s3, sandboxes, shodan, spaces, yandex, zoomeye = 28. Add 12 new: crates, dockerhub, goproxy, helm, k8s, maven, npm, nuget, packagist, pypi, rubygems, terraform = 12. But wait — check if dospaces is already in the list. Looking at register.go: DOSpacesScanner is registered. Check its Name(). Need to verify. Read the current want list from register_test.go to be precise. It has 28 entries already listed. Add the 12 new ones merged alphabetically. Total = 40. cd /home/salva/Documents/apikey && go test ./pkg/recon/sources/ -run "TestRegisterAll" -v -count=1 RegisterAll registers all 40 sources. TestRegisterAll_WiresAllFortySources passes with complete sorted name list. Missing creds test asserts 40. Task 2: Extend integration test with Phase 13 httptest handlers pkg/recon/sources/integration_test.go, cmd/recon.go **integration_test.go updates:** 1. Add httptest mux handlers for all 12 new sources. Each handler serves canned JSON/HTML fixture matching the API format that source expects: **npm** — `mux.HandleFunc("/npm/-/v1/search", ...)` returning `{"objects": [{"package": {"name": "leak-pkg", "links": {"npm": "https://npmjs.com/package/leak-pkg"}}}]}` **pypi** — `mux.HandleFunc("/pypi/search/", ...)` returning HTML with `` links **crates** — `mux.HandleFunc("/crates/api/v1/crates", ...)` returning `{"crates": [{"name": "leaked-crate"}]}` **rubygems** — `mux.HandleFunc("/rubygems/api/v1/search.json", ...)` returning `[{"name": "leaked-gem", "project_uri": "https://rubygems.org/gems/leaked-gem"}]` **maven** — `mux.HandleFunc("/maven/solrsearch/select", ...)` returning `{"response": {"docs": [{"g": "com.leak", "a": "sdk", "latestVersion": "1.0"}]}}` **nuget** — `mux.HandleFunc("/nuget/query", ...)` returning `{"data": [{"id": "LeakedPkg", "version": "1.0"}]}` **goproxy** — `mux.HandleFunc("/goproxy/search", ...)` returning HTML with `` links **packagist** — `mux.HandleFunc("/packagist/search.json", ...)` returning `{"results": [{"name": "vendor/leaked", "url": "https://packagist.org/packages/vendor/leaked"}]}` **dockerhub** — `mux.HandleFunc("/dockerhub/v2/search/repositories/", ...)` returning `{"results": [{"repo_name": "user/leaked-image"}]}` **k8s** — `mux.HandleFunc("/k8s/api/v1/packages/search", ...)` returning `{"packages": [{"name": "leaked-operator", "repository": {"name": "bitnami", "kind": 6}}]}` **terraform** — `mux.HandleFunc("/terraform/v1/modules", ...)` returning `{"modules": [{"namespace": "hashicorp", "name": "leaked", "provider": "aws"}]}` **helm** — `mux.HandleFunc("/helm/api/v1/packages/search", ...)` returning `{"packages": [{"name": "leaked-chart", "repository": {"name": "bitnami", "kind": 0}}]}` NOTE: The mux path prefixes (e.g., `/npm/`, `/pypi/`) are conventions to route in a single httptest server. Each source constructor in the test sets BaseURL to `srv.URL + "/npm"`, `srv.URL + "/pypi"`, etc. 2. Register each new source with BaseURL pointing at `srv.URL + "/{prefix}"`: ```go engine.Register(&NpmSource{BaseURL: srv.URL + "/npm", Registry: reg, Limiters: lim, Client: NewClient()}) // ... same for all 12 ``` 3. Update the expected SourceType set to include all 12 new types: "recon:npm", "recon:pypi", "recon:crates", "recon:rubygems", "recon:maven", "recon:nuget", "recon:goproxy", "recon:packagist", "recon:dockerhub", "recon:k8s", "recon:terraform", "recon:helm" 4. Update the test name/comment from "28 sources" to "40 sources" **cmd/recon.go updates:** - No new SourcesConfig fields needed since all Phase 13 sources are credentialless - Verify the existing cmd/recon.go RegisterAll call passes through correctly — no changes expected but confirm no compilation errors cd /home/salva/Documents/apikey && go test ./pkg/recon/sources/ -run "TestIntegration_AllSources" -v -count=1 -timeout=60s Integration test passes with all 40 sources producing at least one finding each via httptest. Full package compiles clean. Full test suite passes: ```bash go test ./pkg/recon/sources/ -v -count=1 -timeout=120s go vet ./pkg/recon/sources/ go build ./cmd/... ``` - RegisterAll registers 40 sources (28 existing + 12 new) - register_test.go asserts exact 40-name sorted list - Integration test exercises all 40 sources via httptest - cmd/recon.go compiles with updated register.go - `go test ./pkg/recon/sources/ -count=1` all green After completion, create `.planning/phases/13-osint_package_registries_container_iac/13-04-SUMMARY.md`