(fix) Flaky BoxOAuth detector test (#4199)

* moved Generate random Password func to utils to be used by multiple detectors test.

* fixed spelling issue

---------

Co-authored-by: Amaan Ullah <[email protected]>
This commit is contained in:
Abdul Basit
2025-06-25 14:12:22 +05:00
committed by GitHub
co-authored by Amaan Ullah
parent bda0787e98
commit 5eb357dd1c
4 changed files with 152 additions and 57 deletions
+63
View File
@@ -5,6 +5,7 @@ import (
"crypto/rand"
"io"
"math/big"
mrand "math/rand"
"strings"
)
@@ -70,3 +71,65 @@ func SliceContainsString(origTargetString string, stringSlice []string, ignoreCa
}
return false, "", 0
}
// GoFakeIt Password generator does not guarantee inclusion of characters.
// Using a custom random password generator with guaranteed inclusions (atleast) of lower, upper, numeric and special characters
func GenerateRandomPassword(lower, upper, numeric, special bool, length int) string {
if length < 1 {
return ""
}
var password []rune
var required []rune
var allowed []rune
lowerChars := []rune("abcdefghijklmnopqrstuvwxyz")
upperChars := []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
specialChars := []rune("!@#$%^&*()-_=+[]{}|;:',.<>?/")
numberChars := []rune("0123456789")
// Ensure inclusion from each requested category
if lower {
rand, _ := rand.Int(rand.Reader, big.NewInt(int64(len(lowerChars))))
ch := lowerChars[rand.Int64()]
required = append(required, ch)
allowed = append(allowed, lowerChars...)
}
if upper {
rand, _ := rand.Int(rand.Reader, big.NewInt(int64(len(upperChars))))
ch := upperChars[rand.Int64()]
required = append(required, ch)
allowed = append(allowed, upperChars...)
}
if numeric {
rand, _ := rand.Int(rand.Reader, big.NewInt(int64(len(numberChars))))
ch := numberChars[rand.Int64()]
required = append(required, ch)
allowed = append(allowed, numberChars...)
}
if special {
rand, _ := rand.Int(rand.Reader, big.NewInt(int64(len(specialChars))))
ch := specialChars[rand.Int64()]
required = append(required, ch)
allowed = append(allowed, specialChars...)
}
if len(allowed) == 0 {
return "" // No character sets enabled
}
// Fill the rest of the password
for i := 0; i < length-len(required); i++ {
rand, _ := rand.Int(rand.Reader, big.NewInt(int64(len(allowed))))
ch := allowed[rand.Int64()]
password = append(password, ch)
}
// Combine required and random characters, then shuffle
password = append(password, required...)
mrand.Shuffle(len(password), func(i, j int) {
password[i], password[j] = password[j], password[i]
})
return string(password)
}
+83
View File
@@ -5,6 +5,7 @@ import (
"reflect"
"strings"
"testing"
"unicode"
)
func TestAddItem(t *testing.T) {
@@ -194,3 +195,85 @@ func TestSliceContainsString(t *testing.T) {
}
}
}
func TestGenerateRandomPassword_Length(t *testing.T) {
pass := GenerateRandomPassword(true, true, true, true, 16)
if len(pass) != 16 {
t.Errorf("expected length 16, got %d", len(pass))
}
}
func TestGenerateRandomPassword_Empty(t *testing.T) {
pass := GenerateRandomPassword(false, false, false, false, 10)
if pass != "" {
t.Errorf("expected empty string, got %q", pass)
}
}
func TestGenerateRandomPassword_RequiredSets(t *testing.T) {
tests := []struct {
name string
lower bool
upper bool
numeric bool
special bool
}{
{"lower only", true, false, false, false},
{"upper only", false, true, false, false},
{"numeric only", false, false, true, false},
{"special only", false, false, false, true},
{"all", true, true, true, true},
{"lower+upper", true, true, false, false},
{"lower+numeric", true, false, true, false},
{"upper+special", false, true, false, true},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
pass := GenerateRandomPassword(tc.lower, tc.upper, tc.numeric, tc.special, 12)
if len(pass) != 12 {
t.Errorf("expected length 12, got %d", len(pass))
}
if tc.lower && !contains(pass, unicode.IsLower) {
t.Errorf("expected at least one lowercase letter")
}
if tc.upper && !contains(pass, unicode.IsUpper) {
t.Errorf("expected at least one uppercase letter")
}
if tc.numeric && !contains(pass, unicode.IsDigit) {
t.Errorf("expected at least one digit")
}
if tc.special && !containsSpecial(pass) {
t.Errorf("expected at least one special character")
}
})
}
}
func TestGenerateRandomPassword_ShortLength(t *testing.T) {
pass := GenerateRandomPassword(true, true, true, true, 0)
if pass != "" {
t.Errorf("expected empty string for length 0, got %q", pass)
}
}
func contains(s string, fn func(rune) bool) bool {
for _, r := range s {
if fn(r) {
return true
}
}
return false
}
func containsSpecial(s string) bool {
specials := "!@#$%^&*()-_=+[]{}|;:',.<>?/"
for _, r := range s {
for _, sr := range specials {
if r == sr {
return true
}
}
}
return false
}
+4 -4
View File
@@ -7,15 +7,15 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/brianvoe/gofakeit/v7"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
"github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick"
)
var (
clientId = gofakeit.Password(true, true, true, false, false, 32)
clientSecret = gofakeit.Password(true, true, true, false, false, 32)
invalidClientSecret = gofakeit.Password(true, true, true, true, false, 32)
clientId = common.GenerateRandomPassword(true, true, true, false, 32)
clientSecret = common.GenerateRandomPassword(true, true, true, false, 32)
invalidClientSecret = common.GenerateRandomPassword(true, true, true, true, 32)
)
func TestBoxOauth_Pattern(t *testing.T) {
+2 -53
View File
@@ -3,66 +3,15 @@ package snowflake
import (
"context"
"fmt"
"math/rand"
"testing"
"github.com/brianvoe/gofakeit/v7"
"github.com/google/go-cmp/cmp"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
"github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick"
)
// GoFakeIt Password generator does not guarantee inclusion of characters.
// Using a custom Password gennerator with guaranteed inclusions (atleast) of lower, upper and numeric characters
func generatePassword(lower, upper, numeric bool, length int) string {
if length < 1 {
return ""
}
var password []rune
var required []rune
var allowed []rune
lowerChars := []rune("abcdefghijklmnopqrstuvwxyz")
upperChars := []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
numberChars := []rune("0123456789")
// Ensure inclusion from each requested category
if lower {
ch := lowerChars[rand.Intn(len(lowerChars))]
required = append(required, ch)
allowed = append(allowed, lowerChars...)
}
if upper {
ch := upperChars[rand.Intn(len(upperChars))]
required = append(required, ch)
allowed = append(allowed, upperChars...)
}
if numeric {
ch := numberChars[rand.Intn(len(numberChars))]
required = append(required, ch)
allowed = append(allowed, numberChars...)
}
if len(allowed) == 0 {
return "" // No character sets enabled
}
// Fill the rest of the password
for i := 0; i < length-len(required); i++ {
ch := allowed[rand.Intn(len(allowed))]
password = append(password, ch)
}
// Combine required and random characters, then shuffle
password = append(password, required...)
rand.Shuffle(len(password), func(i, j int) {
password[i], password[j] = password[j], password[i]
})
return string(password)
}
func TestSnowflake_Pattern(t *testing.T) {
validAccount := "tuacoip-zt74995"
@@ -71,7 +20,7 @@ func TestSnowflake_Pattern(t *testing.T) {
validUsername := gofakeit.Username()
invalidUsername := "[email protected]" // special characters not allowed
validPassword := generatePassword(true, true, true, 10)
validPassword := common.GenerateRandomPassword(true, true, true, false, 10)
invalidPassword := "!12" // invalid length
d := Scanner{}