Files
trufflehog/pkg/analyzer/analyzers/dockerhub/dockerhub_test.go
Jordan Tunstill 4ec774956c preallocate bindings capacity in dockerhub and groq, with unit tests (#5213)
* preallocate bindings capacity in dockerhub and groq, with unit tests

* ran linter
2026-08-20 14:36:24 -07:00

173 lines
4.6 KiB
Go

package dockerhub
import (
_ "embed"
"encoding/json"
"testing"
"time"
"github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers"
"github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
)
//go:embed result_output.json
var expectedOutput []byte
func repo(name string) Repository {
return Repository{
ID: "user123/repo/image/" + name,
Name: name,
Type: "image",
IsPrivate: true,
StarCount: 1,
PullCount: 2,
}
}
func TestSecretInfoToAnalyzerResult(t *testing.T) {
tests := []struct {
name string
repos []Repository
wantLen int
wantNames []string
}{
{
name: "one repository produces exactly one binding",
repos: []Repository{repo("repo1")},
wantLen: 1,
wantNames: []string{"repo1"},
},
{
name: "three repositories produce exactly three bindings, not six",
repos: []Repository{repo("repo1"), repo("repo2"), repo("repo3")},
wantLen: 3,
wantNames: []string{"repo1", "repo2", "repo3"},
},
{
name: "no repositories: no bindings",
repos: nil,
wantLen: 0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
info := &SecretInfo{
Valid: true,
User: User{ID: "uuid-123", Username: "user123", Email: "[email protected]"},
Permissions: []string{"repo:admin"},
Repositories: tt.repos,
}
result := secretInfoToAnalyzerResult(info)
if result == nil {
t.Fatal("secretInfoToAnalyzerResult() returned nil")
}
if len(result.Bindings) != tt.wantLen {
t.Errorf("got %d bindings, want %d", len(result.Bindings), tt.wantLen)
}
// Mirrors the four proto min_len constraints so this test fails for
// the same reason the enterprise API does.
for i, binding := range result.Bindings {
if binding.Resource.Name == "" {
t.Errorf("binding[%d].Resource.Name is empty", i)
}
if binding.Resource.Type == "" {
t.Errorf("binding[%d].Resource.Type is empty", i)
}
if binding.Resource.FullyQualifiedName == "" {
t.Errorf("binding[%d].Resource.FullyQualifiedName is empty", i)
}
if binding.Permission.Value == "" {
t.Errorf("binding[%d].Permission.Value is empty", i)
}
}
for i, name := range tt.wantNames {
if i >= len(result.Bindings) {
break
}
if result.Bindings[i].Resource.Name != name {
t.Errorf("binding[%d].Resource.Name = %q, want %q", i, result.Bindings[i].Resource.Name, name)
}
}
})
}
}
func TestAnalyzer_Analyze(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5)
defer cancel()
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors4")
if err != nil {
t.Fatalf("could not get test secrets from GCP: %s", err)
}
username := testSecrets.MustGetField("DOCKERHUB_USERNAME")
pat := testSecrets.MustGetField("DOCKERHUB_PAT")
tests := []struct {
name string
username string
pat string
want []byte // JSON string
wantErr bool
}{
{
name: "valid dockerhub credentials",
username: username,
pat: pat,
want: expectedOutput,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
a := Analyzer{Cfg: &config.Config{}}
got, err := a.Analyze(ctx, map[string]string{"username": tt.username, "pat": tt.pat})
if (err != nil) != tt.wantErr {
t.Errorf("Analyzer.Analyze() error = %v, wantErr %v", err, tt.wantErr)
return
}
// Marshal the actual result to JSON
gotJSON, err := json.Marshal(got)
if err != nil {
t.Fatalf("could not marshal got to JSON: %s", err)
}
// Parse the expected JSON string
var wantObj analyzers.AnalyzerResult
if err := json.Unmarshal([]byte(tt.want), &wantObj); err != nil {
t.Fatalf("could not unmarshal want JSON string: %s", err)
}
// Marshal the expected result to JSON (to normalize)
wantJSON, err := json.Marshal(wantObj)
if err != nil {
t.Fatalf("could not marshal want to JSON: %s", err)
}
// Compare the JSON strings
if string(gotJSON) != string(wantJSON) {
// Pretty-print both JSON strings for easier comparison
var gotIndented, wantIndented []byte
gotIndented, err = json.MarshalIndent(got, "", " ")
if err != nil {
t.Fatalf("could not marshal got to indented JSON: %s", err)
}
wantIndented, err = json.MarshalIndent(wantObj, "", " ")
if err != nil {
t.Fatalf("could not marshal want to indented JSON: %s", err)
}
t.Errorf("Analyzer.Analyze() = %s, want %s", gotIndented, wantIndented)
}
})
}
}