---
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