feat(07-01): Importer interface and TruffleHog v3 JSON adapter

- pkg/importer/importer.go: shared Importer interface (Name, Import)
- pkg/importer/trufflehog.go: TruffleHogImporter with v3 JSON decoding,
  detector-name normalization (OpenAI/GithubV2/AWS -> canonical ids),
  SourceMetadata path+line extraction for Git/Filesystem/Github
- pkg/importer/testdata/trufflehog-sample.json: 3-record fixture
- pkg/importer/trufflehog_test.go: Name, Import, NormalizeName, EmptyArray,
  InvalidJSON tests -- all passing
This commit is contained in:
salvacybersec
2026-04-05 23:55:24 +03:00
parent 6a3d5b0cb7
commit 46eec328d2
4 changed files with 383 additions and 0 deletions

View File

@@ -0,0 +1,128 @@
package importer
import (
"os"
"strings"
"testing"
)
func TestTruffleHogImporter_Name(t *testing.T) {
var imp TruffleHogImporter
if got := imp.Name(); got != "trufflehog" {
t.Fatalf("Name() = %q, want %q", got, "trufflehog")
}
}
func TestTruffleHogImporter_Import(t *testing.T) {
f, err := os.Open("testdata/trufflehog-sample.json")
if err != nil {
t.Fatalf("open fixture: %v", err)
}
defer f.Close()
var imp TruffleHogImporter
findings, err := imp.Import(f)
if err != nil {
t.Fatalf("Import returned error: %v", err)
}
if len(findings) != 3 {
t.Fatalf("expected 3 findings, got %d", len(findings))
}
// Record 1: OpenAI / Git / verified.
f0 := findings[0]
if f0.ProviderName != "openai" {
t.Errorf("findings[0].ProviderName = %q, want openai", f0.ProviderName)
}
if f0.Confidence != "high" {
t.Errorf("findings[0].Confidence = %q, want high", f0.Confidence)
}
if !f0.Verified {
t.Error("findings[0].Verified = false, want true")
}
if f0.VerifyStatus != "live" {
t.Errorf("findings[0].VerifyStatus = %q, want live", f0.VerifyStatus)
}
if f0.Source != "src/config.py" {
t.Errorf("findings[0].Source = %q, want src/config.py", f0.Source)
}
if f0.LineNumber != 42 {
t.Errorf("findings[0].LineNumber = %d, want 42", f0.LineNumber)
}
if f0.SourceType != "import:trufflehog" {
t.Errorf("findings[0].SourceType = %q, want import:trufflehog", f0.SourceType)
}
if f0.KeyValue != "sk-proj-abcdef1234567890abcdef" {
t.Errorf("findings[0].KeyValue unexpected: %q", f0.KeyValue)
}
if f0.KeyMasked == "" || f0.KeyMasked == f0.KeyValue {
t.Errorf("findings[0].KeyMasked not populated: %q", f0.KeyMasked)
}
// Record 2: AnthropicV2 / Filesystem / unverified.
f1 := findings[1]
if f1.ProviderName != "anthropic" {
t.Errorf("findings[1].ProviderName = %q, want anthropic", f1.ProviderName)
}
if f1.Confidence != "medium" {
t.Errorf("findings[1].Confidence = %q, want medium", f1.Confidence)
}
if f1.Verified {
t.Error("findings[1].Verified = true, want false")
}
if f1.VerifyStatus != "unverified" {
t.Errorf("findings[1].VerifyStatus = %q, want unverified", f1.VerifyStatus)
}
if f1.Source != "/tmp/leaked.env" {
t.Errorf("findings[1].Source = %q, want /tmp/leaked.env", f1.Source)
}
// Record 3: AWS / Github link.
f2 := findings[2]
if f2.ProviderName != "aws" {
t.Errorf("findings[2].ProviderName = %q, want aws", f2.ProviderName)
}
if !f2.Verified {
t.Error("findings[2].Verified = false, want true")
}
if f2.Source != "https://github.com/foo/bar/blob/main/a.yml" {
t.Errorf("findings[2].Source = %q, want github link", f2.Source)
}
}
func TestTruffleHogImporter_NormalizeName(t *testing.T) {
cases := []struct {
in, want string
}{
{"OpenAI", "openai"},
{"GithubV2", "github"},
{"AnthropicV2", "anthropic"},
{"AWS", "aws"},
{"GCP", "gcp"},
{"HuggingFace", "huggingface"},
{"UnknownDetector", "unknowndetector"},
}
for _, c := range cases {
if got := normalizeTruffleHogName(c.in); got != c.want {
t.Errorf("normalizeTruffleHogName(%q) = %q, want %q", c.in, got, c.want)
}
}
}
func TestTruffleHogImporter_EmptyArray(t *testing.T) {
var imp TruffleHogImporter
findings, err := imp.Import(strings.NewReader("[]"))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(findings) != 0 {
t.Fatalf("expected 0 findings, got %d", len(findings))
}
}
func TestTruffleHogImporter_InvalidJSON(t *testing.T) {
var imp TruffleHogImporter
if _, err := imp.Import(strings.NewReader("not json")); err == nil {
t.Fatal("expected error for invalid JSON, got nil")
}
}