Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions pkg/detectors/hashicorpvaultauth/hashicorpvaultauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,22 @@ import (

regexp "github.com/wasilibs/go-re2"

"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
)

type Scanner struct {
client *http.Client
detectors.DefaultMultiPartCredentialProvider
detectors.EndpointSetter
}

// Ensure the Scanner satisfies the interface at compile time.
var _ detectors.Detector = (*Scanner)(nil)
var _ detectors.EndpointCustomizer = (*Scanner)(nil)

var (
defaultClient = common.SaneHttpClient()
defaultClient = detectors.DetectorHttpClientWithNoLocalAddresses

roleIdPat = regexp.MustCompile(detectors.PrefixRegex([]string{"role"}) + `\b([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\b`)

Expand Down Expand Up @@ -61,15 +63,19 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
uniqueVaultUrls[url] = struct{}{}
}

// If no names or secrets found, return empty results
if len(uniqueRoleIds) == 0 || len(uniqueSecretIds) == 0 || len(uniqueVaultUrls) == 0 {
// If no roleIds or secrets found, return empty results
if len(uniqueRoleIds) == 0 || len(uniqueSecretIds) == 0 {
return results, nil
}

endpoints := make([]string, 0, len(uniqueVaultUrls))
for endpoint := range uniqueVaultUrls {
endpoints = append(endpoints, endpoint)
}
// create combination results that can be verified
for roleId := range uniqueRoleIds {
for secretId := range uniqueSecretIds {
for vaultUrl := range uniqueVaultUrls {
for _, vaultUrl := range s.Endpoints(endpoints...) {
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_HashiCorpVaultAuth,
Raw: []byte(secretId),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ func TestHashiCorpVaultAuth_FromChunk(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.s.UseCloudEndpoint(true)
tt.s.UseFoundEndpoints(true)
got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
if (err != nil) != tt.wantErr {
t.Errorf("HashiCorpVaultAuth.FromData() error = %v, wantErr %v", err, tt.wantErr)
Expand All @@ -164,6 +166,58 @@ func TestHashiCorpVaultAuth_FromChunk(t *testing.T) {
}
}

func TestHashiCorpVaultAuth_WithCustomEndpoint(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors6")
if err != nil {
t.Fatalf("could not get test secrets from GCP: %s", err)
}
roleId := testSecrets.MustGetField("HASHICORPVAULTAUTH_ROLE_ID")
secretId := testSecrets.MustGetField("HASHICORPVAULTAUTH_SECRET_ID")
vaultUrl := testSecrets.MustGetField("HASHICORPVAULTAUTH_URL")
s := Scanner{}
s.UseCloudEndpoint(true)
s.UseFoundEndpoints(true)
s.SetConfiguredEndpoints(vaultUrl)
data := fmt.Appendf(nil, "hashicorp config:\nrole_id: %s\nsecret_id: %s", roleId, secretId)

results, err := s.FromData(context.Background(), true, data)
if err != nil {
t.Fatalf("unexpected error from FromData: %v", err)
}
if len(results) == 0 {
t.Fatal("expected at least one result from FromData, got 0")
}
for _, result := range results {
endpoint, ok := result.ExtraData["URL"]
if !ok {
t.Fatalf("expected URL in ExtraData, got: %v", result.ExtraData)
}
if endpoint != vaultUrl {
t.Fatalf("expected endpoint %s, got %s", vaultUrl, endpoint)
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This loop will always run only one time. Also, do you think this loop provides value? because the cmp.Diff at the end is sufficient as it does the same job.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to remove the manual loop check. cmp.Diff is good enough

want := []detectors.Result{
{
DetectorType: detectorspb.DetectorType_HashiCorpVaultAuth,
Verified: true,
VerificationFromCache: false,
Raw: []byte(secretId),
RawV2: []byte(fmt.Sprintf("%s:%s", roleId, secretId)),
ExtraData: map[string]string{
"URL": vaultUrl,
},
StructuredData: nil,
},
}

ignoreOpts := cmpopts.IgnoreUnexported(detectors.Result{})
if diff := cmp.Diff(results, want, ignoreOpts); diff != "" {
t.Errorf("HashiCorpVaultAuth.FromData() %s diff: (-got +want)\n%s", "TestHashiCorpVaultAuth_WithCustomEndpoint", diff)
}
}

func BenchmarkFromData(benchmark *testing.B) {
ctx := context.Background()
s := Scanner{}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ func TestHashiCorpVaultAppRoleAuth_Pattern(t *testing.T) {
t.Errorf("keywords '%v' not matched by: %s", d.Keywords(), test.input)
return
}

d.UseCloudEndpoint(true)
d.UseFoundEndpoints(true)
results, err := d.FromData(context.Background(), false, []byte(test.input))
if err != nil {
t.Errorf("error = %v", err)
Expand Down
1 change: 1 addition & 0 deletions pkg/engine/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1377,6 +1377,7 @@ func TestEngineInitializesCloudProviderDetectors(t *testing.T) {
detectorspb.DetectorType_ArtifactoryAccessToken: {},
detectorspb.DetectorType_ArtifactoryReferenceToken: {},
detectorspb.DetectorType_TableauPersonalAccessToken: {},
detectorspb.DetectorType_HashiCorpVaultAuth: {},
// these do not have any cloud endpoint
}

Expand Down
Loading