Files
trufflehog/pkg/detectors/tableau/tableau_test.go
SyedAliHamadandAmaan Ullah 05e2328da2 [Detector]-Detector for tableau personal access token (#4261)
* add detector for tableau personal access token

* add test for tableau detector

* removed unnecessary checks

* add cloud endpoint for tableau

* cleanup: simplify map copying with maps.Copy

* resolve comments

* added correct detector type for tableau

* updated tableau PAT key and corrected integration tests

* resolved comments

* updated test cases

* resolved comments

* fixed integration tests

* removed redundant validation

* resolved false positive issue

* updated regex for pat-name

* resolved comments

* update regex for better token name extraction

* simplify prefix regex  for tableau pat name

* merged main into origin/detector/tableau-personal-access-token

---------

Co-authored-by: Amaan Ullah <[email protected]>
2025-07-28 21:42:58 +05:00

145 lines
5.0 KiB
Go

package tableau
import (
"context"
"fmt"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
"github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick"
)
var (
validPATName = "test-token-6"
validPATSecret = "YMqNfVWiTSa0QgpoJ9GpCw==:KTamjuKrXF5gVETjIJafBBvP8Ctj5aJ3"
invalidPATSecret = "invalid-secret-format"
// Tableau Online endpoints for testing
validTableauURL = "prod-ansouthgest-a.online.tableau.com"
valid2ndTableauURL = "prod.online.tableau.com"
invalidTableauURL = "prod.tabeau.com"
)
func TestTableau_Pattern(t *testing.T) {
d := Scanner{}
d.UseFoundEndpoints(true) // Enable found endpoints for tests
ahoCorasickCore := ahocorasick.NewAhoCorasickCore([]detectors.Detector{d})
tests := []struct {
name string
input string
want []string
description string
}{
{
name: "tableau_prefix_with_token_name",
input: fmt.Sprintf("token=%s\nsecret=%s\nserver=%s", validPATName, validPATSecret, validTableauURL),
want: []string{fmt.Sprintf("%s:%s:%s", validPATName, validPATSecret, validTableauURL)},
description: "Tests tableau prefix directly followed by token name",
},
{
name: "pat_prefix_with_name",
input: fmt.Sprintf("pat %s\n%s\nurl=%s", validPATName, validPATSecret, validTableauURL),
want: []string{fmt.Sprintf("%s:%s:%s", validPATName, validPATSecret, validTableauURL)},
description: "Tests pat prefix triggering detection",
},
{
name: "name_prefix_with_token",
input: fmt.Sprintf("name %s\n%s\nurl=%s", validPATName, validPATSecret, validTableauURL),
want: []string{fmt.Sprintf("%s:%s:%s", validPATName, validPATSecret, validTableauURL)},
description: "Tests name prefix triggering detection",
},
{
name: "single_token_multiple_urls",
input: fmt.Sprintf("token %s\n%s\nserver1=%s\nserver2=%s", validPATName, validPATSecret, validTableauURL, valid2ndTableauURL),
want: []string{
fmt.Sprintf("%s:%s:%s", validPATName, validPATSecret, validTableauURL),
fmt.Sprintf("%s:%s:%s", validPATName, validPATSecret, valid2ndTableauURL),
},
description: "Tests single token with multiple URLs",
},
{
name: "invalid_secret_format",
input: fmt.Sprintf("tableau %s\n%s\nserver=%s", validPATName, invalidPATSecret, validTableauURL),
want: []string{},
description: "Tests that invalid secret format is not detected",
},
{
name: "invalid_tableau_url",
input: fmt.Sprintf("tableau %s\n%s\nserver=%s", validPATName, validPATSecret, invalidTableauURL),
want: []string{},
description: "Tests that invalid Tableau URL is not detected when useFoundEndpoints is true",
},
{
name: "missing_token_name",
input: fmt.Sprintf("\n%s\nserver=%s", validPATSecret, validTableauURL),
want: []string{},
description: "Tests that missing token name produces no results",
},
{
name: "missing_secret",
input: fmt.Sprintf("tableau %s\nserver=%s", validPATName, validTableauURL),
want: []string{},
description: "Tests that missing secret produces no results",
},
{
name: "no_tableau_keywords",
input: "username=test\npassword=secret123\nhost=example.com",
want: []string{},
description: "Tests that non-Tableau config produces no results",
},
{
name: "token_name_with_whitespace",
input: fmt.Sprintf("name %s\n%s\nserver=%s", validPATName, validPATSecret, validTableauURL),
want: []string{fmt.Sprintf("%s:%s:%s", validPATName, validPATSecret, validTableauURL)},
description: "Tests token name with extra whitespace",
},
{
name: "pat_with_single_quotes",
input: fmt.Sprintf("pat '%s'\n%s\nserver=%s", validPATName, validPATSecret, validTableauURL),
want: []string{fmt.Sprintf("%s:%s:%s", validPATName, validPATSecret, validTableauURL)},
description: "Tests token name with single quotes",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
matchedDetectors := ahoCorasickCore.FindDetectorMatches([]byte(test.input))
if len(test.want) > 0 {
if len(matchedDetectors) == 0 {
t.Errorf("keywords '%v' not matched in input: %s", d.Keywords(), test.input)
return
}
}
if len(matchedDetectors) == 0 && len(test.want) == 0 {
return
}
results, err := d.FromData(context.Background(), false, []byte(test.input))
if err != nil {
t.Errorf("FromData error: %v", err)
return
}
if len(results) != len(test.want) {
t.Errorf("expected %d results, got %d", len(test.want), len(results))
return
}
actual := make(map[string]struct{}, len(results))
for _, r := range results {
actual[string(r.RawV2)] = struct{}{}
}
expected := make(map[string]struct{}, len(test.want))
for _, v := range test.want {
expected[v] = struct{}{}
}
if diff := cmp.Diff(expected, actual); diff != "" {
t.Errorf("%s diff: (-want +got)\n%s", test.name, diff)
}
})
}
}