test(01-02): add failing tests for provider schema validation and registry
This commit is contained in:
8
cmd/root.go
Normal file
8
cmd/root.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
// Execute is a stub. The real command tree is built in Plan 05.
|
||||||
|
func Execute() {
|
||||||
|
_ = os.Args
|
||||||
|
}
|
||||||
13
go.mod
Normal file
13
go.mod
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
module github.com/salvacybersec/keyhunter
|
||||||
|
|
||||||
|
go 1.26.1
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/stretchr/testify v1.11.1
|
||||||
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
)
|
||||||
10
go.sum
Normal file
10
go.sum
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
7
main.go
Normal file
7
main.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/salvacybersec/keyhunter/cmd"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmd.Execute()
|
||||||
|
}
|
||||||
23
pkg/engine/scanner_test.go
Normal file
23
pkg/engine/scanner_test.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package engine_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestShannonEntropy verifies the entropy function returns expected values.
|
||||||
|
// Stub: will be implemented when entropy.go exists (Plan 04).
|
||||||
|
func TestShannonEntropy(t *testing.T) {
|
||||||
|
t.Skip("stub — implement after entropy.go exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestKeywordPreFilter verifies Aho-Corasick pre-filter rejects files without keywords.
|
||||||
|
// Stub: will be implemented when filter.go exists (Plan 04).
|
||||||
|
func TestKeywordPreFilter(t *testing.T) {
|
||||||
|
t.Skip("stub — implement after filter.go exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestScannerPipeline verifies end-to-end scan of testdata returns expected findings.
|
||||||
|
// Stub: will be implemented when engine.go exists (Plan 04).
|
||||||
|
func TestScannerPipeline(t *testing.T) {
|
||||||
|
t.Skip("stub — implement after engine.go exists")
|
||||||
|
}
|
||||||
58
pkg/providers/registry_test.go
Normal file
58
pkg/providers/registry_test.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package providers_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/salvacybersec/keyhunter/pkg/providers"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRegistryLoad(t *testing.T) {
|
||||||
|
reg, err := providers.NewRegistry()
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.GreaterOrEqual(t, len(reg.List()), 3, "expected at least 3 providers")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRegistryGet(t *testing.T) {
|
||||||
|
reg, err := providers.NewRegistry()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
p, ok := reg.Get("openai")
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.Equal(t, "openai", p.Name)
|
||||||
|
assert.Equal(t, 1, p.Tier)
|
||||||
|
|
||||||
|
_, notOk := reg.Get("nonexistent-provider")
|
||||||
|
assert.False(t, notOk)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRegistryStats(t *testing.T) {
|
||||||
|
reg, err := providers.NewRegistry()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
stats := reg.Stats()
|
||||||
|
assert.GreaterOrEqual(t, stats.Total, 3)
|
||||||
|
assert.GreaterOrEqual(t, stats.ByTier[1], 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAhoCorasickBuild(t *testing.T) {
|
||||||
|
reg, err := providers.NewRegistry()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
ac := reg.AC()
|
||||||
|
matches := ac.FindAll("export OPENAI_API_KEY=sk-proj-abc")
|
||||||
|
assert.NotEmpty(t, matches)
|
||||||
|
|
||||||
|
noMatches := ac.FindAll("hello world nothing here")
|
||||||
|
assert.Empty(t, noMatches)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProviderSchemaValidation(t *testing.T) {
|
||||||
|
invalid := []byte("format_version: 0\nname: invalid\nlast_verified: \"\"\n")
|
||||||
|
var p providers.Provider
|
||||||
|
err := yaml.Unmarshal(invalid, &p)
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "format_version")
|
||||||
|
}
|
||||||
23
pkg/storage/db_test.go
Normal file
23
pkg/storage/db_test.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package storage_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestDBOpen verifies SQLite database opens and creates schema.
|
||||||
|
// Stub: will be implemented when db.go exists (Plan 03).
|
||||||
|
func TestDBOpen(t *testing.T) {
|
||||||
|
t.Skip("stub — implement after db.go exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestEncryptDecryptRoundtrip verifies AES-256-GCM encrypt/decrypt roundtrip.
|
||||||
|
// Stub: will be implemented when encrypt.go exists (Plan 03).
|
||||||
|
func TestEncryptDecryptRoundtrip(t *testing.T) {
|
||||||
|
t.Skip("stub — implement after encrypt.go exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestArgon2KeyDerivation verifies Argon2id produces 32-byte key deterministically.
|
||||||
|
// Stub: will be implemented when crypto.go exists (Plan 03).
|
||||||
|
func TestArgon2KeyDerivation(t *testing.T) {
|
||||||
|
t.Skip("stub — implement after crypto.go exists")
|
||||||
|
}
|
||||||
2
testdata/samples/anthropic_key.txt
vendored
Normal file
2
testdata/samples/anthropic_key.txt
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Test file: synthetic Anthropic key pattern
|
||||||
|
export ANTHROPIC_API_KEY="sk-ant-api03-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxy01234567890-ABCDE"
|
||||||
3
testdata/samples/multiple_keys.txt
vendored
Normal file
3
testdata/samples/multiple_keys.txt
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Multiple providers in one file
|
||||||
|
OPENAI_API_KEY=sk-proj-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr5678
|
||||||
|
ANTHROPIC_API_KEY=sk-ant-api03-XYZabcdefghijklmnopqrstuvwxyz01234567890ABCDEFGH-XYZAB
|
||||||
3
testdata/samples/no_keys.txt
vendored
Normal file
3
testdata/samples/no_keys.txt
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# This file contains no API keys
|
||||||
|
# Used to verify false-positive rate is zero for clean files
|
||||||
|
Hello world
|
||||||
2
testdata/samples/openai_key.txt
vendored
Normal file
2
testdata/samples/openai_key.txt
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Test file: synthetic OpenAI key pattern
|
||||||
|
OPENAI_API_KEY=sk-proj-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr1234
|
||||||
Reference in New Issue
Block a user