- Dork schema with Validate() mirroring provider YAML pattern - go:embed loader tolerating empty definitions tree - Registry with List/Get/Stats/ListBySource/ListByCategory - Executor interface + Runner dispatch + ErrSourceNotImplemented - Placeholder definitions/.gitkeep and repo-root dorks/.gitkeep - Full unit test coverage for registry, validation, and runner dispatch
191 lines
4.7 KiB
Go
191 lines
4.7 KiB
Go
package dorks_test
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/salvacybersec/keyhunter/pkg/dorks"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func fixture() []dorks.Dork {
|
|
return []dorks.Dork{
|
|
{
|
|
ID: "openai-github-envfile",
|
|
Name: "OpenAI API Key in .env files",
|
|
Source: "github",
|
|
Category: "frontier",
|
|
Query: "sk-proj- extension:env",
|
|
Description: "Finds OpenAI project keys exposed in committed .env files",
|
|
Tags: []string{"openai", "env", "tier1"},
|
|
},
|
|
{
|
|
ID: "anthropic-github-env",
|
|
Name: "Anthropic Key in .env",
|
|
Source: "github",
|
|
Category: "frontier",
|
|
Query: "sk-ant-api03- extension:env",
|
|
},
|
|
{
|
|
ID: "shodan-openai-banner",
|
|
Name: "OpenAI banner on Shodan",
|
|
Source: "shodan",
|
|
Category: "infrastructure",
|
|
Query: "product:openai",
|
|
},
|
|
}
|
|
}
|
|
|
|
func TestRegistry_LoadsAndIndexesDorks(t *testing.T) {
|
|
r := dorks.NewRegistryFromDorks(fixture())
|
|
require.NotNil(t, r)
|
|
assert.Len(t, r.List(), 3)
|
|
}
|
|
|
|
func TestRegistry_Get(t *testing.T) {
|
|
r := dorks.NewRegistryFromDorks(fixture())
|
|
|
|
d, ok := r.Get("openai-github-envfile")
|
|
require.True(t, ok)
|
|
assert.Equal(t, "github", d.Source)
|
|
assert.Equal(t, "frontier", d.Category)
|
|
assert.Equal(t, "sk-proj- extension:env", d.Query)
|
|
|
|
_, ok = r.Get("does-not-exist")
|
|
assert.False(t, ok)
|
|
}
|
|
|
|
func TestRegistry_ListBySource(t *testing.T) {
|
|
r := dorks.NewRegistryFromDorks(fixture())
|
|
|
|
gh := r.ListBySource("github")
|
|
assert.Len(t, gh, 2)
|
|
for _, d := range gh {
|
|
assert.Equal(t, "github", d.Source)
|
|
}
|
|
|
|
shodan := r.ListBySource("shodan")
|
|
assert.Len(t, shodan, 1)
|
|
|
|
assert.Empty(t, r.ListBySource("fofa"))
|
|
}
|
|
|
|
func TestRegistry_ListByCategory(t *testing.T) {
|
|
r := dorks.NewRegistryFromDorks(fixture())
|
|
|
|
frontier := r.ListByCategory("frontier")
|
|
assert.Len(t, frontier, 2)
|
|
for _, d := range frontier {
|
|
assert.Equal(t, "frontier", d.Category)
|
|
}
|
|
|
|
infra := r.ListByCategory("infrastructure")
|
|
assert.Len(t, infra, 1)
|
|
|
|
assert.Empty(t, r.ListByCategory("emerging"))
|
|
}
|
|
|
|
func TestRegistry_Stats(t *testing.T) {
|
|
r := dorks.NewRegistryFromDorks(fixture())
|
|
|
|
s := r.Stats()
|
|
assert.Equal(t, 3, s.Total)
|
|
assert.Equal(t, 2, s.BySource["github"])
|
|
assert.Equal(t, 1, s.BySource["shodan"])
|
|
assert.Equal(t, 2, s.ByCategory["frontier"])
|
|
assert.Equal(t, 1, s.ByCategory["infrastructure"])
|
|
}
|
|
|
|
func TestNewRegistry_EmptyDefinitionsTreeOK(t *testing.T) {
|
|
// The embedded definitions tree contains only .gitkeep in this plan.
|
|
// NewRegistry must tolerate that and return an empty but usable Registry.
|
|
r, err := dorks.NewRegistry()
|
|
require.NoError(t, err)
|
|
require.NotNil(t, r)
|
|
assert.GreaterOrEqual(t, len(r.List()), 0)
|
|
}
|
|
|
|
func TestDork_Validate(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
dork dorks.Dork
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "valid",
|
|
dork: dorks.Dork{ID: "x", Source: "github", Query: "foo"},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "missing id",
|
|
dork: dorks.Dork{Source: "github", Query: "foo"},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "missing source",
|
|
dork: dorks.Dork{ID: "x", Query: "foo"},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "missing query",
|
|
dork: dorks.Dork{ID: "x", Source: "github"},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "unknown source",
|
|
dork: dorks.Dork{ID: "x", Source: "reddit", Query: "foo"},
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
err := tc.dork.Validate()
|
|
if tc.wantErr {
|
|
assert.Error(t, err)
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRunner_UnknownSourceReturnsErrSourceNotImplemented(t *testing.T) {
|
|
runner := dorks.NewRunner()
|
|
d := dorks.Dork{ID: "x", Source: "shodan", Category: "infrastructure", Query: "product:openai"}
|
|
|
|
_, err := runner.Run(context.Background(), d, 10)
|
|
require.Error(t, err)
|
|
assert.True(t, errors.Is(err, dorks.ErrSourceNotImplemented))
|
|
}
|
|
|
|
// stubExecutor is a test-only Executor that records invocations.
|
|
type stubExecutor struct {
|
|
source string
|
|
calls int
|
|
}
|
|
|
|
func (s *stubExecutor) Source() string { return s.source }
|
|
func (s *stubExecutor) Execute(_ context.Context, d dorks.Dork, _ int) ([]dorks.Match, error) {
|
|
s.calls++
|
|
return []dorks.Match{{DorkID: d.ID, Source: s.source, Snippet: "hit"}}, nil
|
|
}
|
|
|
|
func TestRunner_RegisterAndDispatch(t *testing.T) {
|
|
runner := dorks.NewRunner()
|
|
stub := &stubExecutor{source: "github"}
|
|
runner.Register(stub)
|
|
|
|
got, ok := runner.Executor("github")
|
|
require.True(t, ok)
|
|
assert.Equal(t, "github", got.Source())
|
|
|
|
d := dorks.Dork{ID: "t1", Source: "github", Query: "sk-"}
|
|
matches, err := runner.Run(context.Background(), d, 5)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 1, stub.calls)
|
|
require.Len(t, matches, 1)
|
|
assert.Equal(t, "t1", matches[0].DorkID)
|
|
}
|