add detection for updated asana personal access token (#4273)

* add detection for updated asana personal access token

* removed unnecessary checks

* add integration tests

* add verification error
This commit is contained in:
SyedAliHamad
2025-07-11 11:15:51 +05:00
committed by GitHub
parent ab136f6e9d
commit 55cfe6b18a
3 changed files with 76 additions and 26 deletions
@@ -22,7 +22,10 @@ var _ detectors.Detector = (*Scanner)(nil)
var (
client = common.SaneHttpClient()
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"asana"}) + `\b([0-9]{1,}\/[0-9]{16,}:[A-Za-z0-9]{32,})\b`)
// Updated pattern to handle both old and new token formats
// Old format: [digits]/[16+ digits]:[32+ chars]
// New format: [digits]/[16+ digits]/[16+ digits]:[32+ chars]
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"asana"}) + `\b([0-9]{1,}\/[0-9]{16,}(?:\/[0-9]{16,})?:[A-Za-z0-9]{32,})\b`)
)
// Keywords are used for efficiently pre-filtering chunks.
@@ -23,8 +23,15 @@ func TestAsanaPersonalAccessToken_FromChunk(t *testing.T) {
if err != nil {
t.Fatalf("could not get test secrets from GCP: %s", err)
}
secret := testSecrets.MustGetField("ASANA_PAT")
inactiveSecret := testSecrets.MustGetField("ASANA_PAT_INACTIVE")
testNewSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors6")
if err != nil {
t.Fatalf("could not get test secrets from GCP: %s", err)
}
oldFormatSecret := testSecrets.MustGetField("ASANA_PAT")
newFormatSecret := testNewSecrets.MustGetField("ASANA_PAT_NEW")
inactiveOldFormatSecret := testSecrets.MustGetField("ASANA_PAT_INACTIVE")
inactiveNewFormatSecret := testNewSecrets.MustGetField("ASANA_PAT_NEW_INACTIVE")
type args struct {
ctx context.Context
@@ -43,7 +50,7 @@ func TestAsanaPersonalAccessToken_FromChunk(t *testing.T) {
s: Scanner{},
args: args{
ctx: context.Background(),
data: []byte(fmt.Sprintf("You can find a asana secret %s within", secret)),
data: []byte(fmt.Sprintf("You can find a asana secret %s within", oldFormatSecret)),
verify: true,
},
want: []detectors.Result{
@@ -71,6 +78,38 @@ func TestAsanaPersonalAccessToken_FromChunk(t *testing.T) {
wantErr: false,
},
{
name: "found, verified - new format",
s: Scanner{},
args: args{
ctx: context.Background(),
data: []byte(fmt.Sprintf("You can find a asana secret %s within", newFormatSecret)),
verify: true,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_AsanaPersonalAccessToken,
Verified: true,
},
},
wantErr: false,
},
{
name: "found, unverified - new format",
s: Scanner{},
args: args{
ctx: context.Background(),
data: []byte(fmt.Sprintf("You can find a asana secret %s but unverified", inactiveNewFormatSecret)),
verify: true,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_AsanaPersonalAccessToken,
Verified: false,
},
},
wantErr: false,
},
{
name: "not found",
s: Scanner{},
args: args{
@@ -81,25 +120,25 @@ func TestAsanaPersonalAccessToken_FromChunk(t *testing.T) {
want: nil,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := Scanner{}
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
if (err != nil) != tt.wantErr {
t.Errorf("AsanaPersonalAccessToken.FromData() error = %v, wantErr %v", err, tt.wantErr)
return
}
for i := range got {
if len(got[i].Raw) == 0 {
t.Fatalf("no raw secret present: \n %+v", got[i])
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := Scanner{}
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
if (err != nil) != tt.wantErr {
t.Errorf("AsanaPersonalAccessToken.FromData() error = %v, wantErr %v", err, tt.wantErr)
return
}
got[i].Raw = nil
}
if diff := pretty.Compare(got, tt.want); diff != "" {
t.Errorf("AsanaPersonalAccessToken.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
}
})
for i := range got {
if len(got[i].Raw) == 0 {
t.Fatalf("no raw secret present: \n %+v", got[i])
}
got[i].Raw = nil
}
if diff := pretty.Compare(got, tt.want); diff != "" {
t.Errorf("AsanaPersonalAccessToken.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
}
})
}
}
}
@@ -11,8 +11,11 @@ import (
)
var (
validPattern = "asana_token: 594776654034514343561917591881414702593902454625364993/1724908107002616220416212965:Yv3DoiSFhtsgUwN3AcnXWjK8zabQHKSHBRHpuNKVjz3oCcpyDIdXRm3GL4SUDkTMFoTbRDCHe8tTBHxdtoXItn"
invalidPattern = "asana_token: 1724908107002616220416212965%594776654034514343561917591881414702593902454625364993:Yv3DoiSFhtsgUwN3AcnXWjK8zabQHKSHBRHpuNKVjz3oCcpyDIdXRm3GL4SUDkTMFoTbRDCHe8tTBHxdtoXItn-ij2gwtg/xn9vh4jvsokdfaic0bn"
// Old format token
validPatternOld = "asana_token: 594776654034514343561917591881414702593902454625364993/1724908107002616220416212965:Yv3DoiSFhtsgUwN3AcnXWjK8zabQHKSHBRHpuNKVjz3oCcpyDIdXRm3GL4SUDkTMFoTbRDCHe8tTBHxdtoXItn"
// New format token with two forward slashes
newValidPattern = "asana_token: 7/9823746598123746/8923746598123456:7f1a3c9be84d2a6c4e7d9c32bf1e7f88"
invalidPattern = "asana_token: 1724908107002616220416212965%594776654034514343561917591881414702593902454625364993:Yv3DoiSFhtsgUwN3AcnXWjK8zabQHKSHBRHpuNKVjz3oCcpyDIdXRm3GL4SUDkTMFoTbRDCHe8tTBHxdtoXItn-ij2gwtg/xn9vh4jvsokdfaic0bn"
)
func TestAsanaPersonalAccessToken_Pattern(t *testing.T) {
@@ -25,10 +28,15 @@ func TestAsanaPersonalAccessToken_Pattern(t *testing.T) {
want []string
}{
{
name: "valid pattern",
input: validPattern,
name: "valid pattern - old format",
input: validPatternOld,
want: []string{"594776654034514343561917591881414702593902454625364993/1724908107002616220416212965:Yv3DoiSFhtsgUwN3AcnXWjK8zabQHKSHBRHpuNKVjz3oCcpyDIdXRm3GL4SUDkTMFoTbRDCHe8tTBHxdtoXItn"},
},
{
name: "valid pattern - new format",
input: newValidPattern,
want: []string{"7/9823746598123746/8923746598123456:7f1a3c9be84d2a6c4e7d9c32bf1e7f88"},
},
{
name: "invalid pattern",
input: invalidPattern,