Skip to content

Commit 55cfe6b

Browse files
authored
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
1 parent ab136f6 commit 55cfe6b

File tree

3 files changed

+76
-26
lines changed

3 files changed

+76
-26
lines changed

pkg/detectors/asanapersonalaccesstoken/asanapersonalaccesstoken.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ var _ detectors.Detector = (*Scanner)(nil)
2222
var (
2323
client = common.SaneHttpClient()
2424

25-
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"asana"}) + `\b([0-9]{1,}\/[0-9]{16,}:[A-Za-z0-9]{32,})\b`)
25+
// Updated pattern to handle both old and new token formats
26+
// Old format: [digits]/[16+ digits]:[32+ chars]
27+
// New format: [digits]/[16+ digits]/[16+ digits]:[32+ chars]
28+
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"asana"}) + `\b([0-9]{1,}\/[0-9]{16,}(?:\/[0-9]{16,})?:[A-Za-z0-9]{32,})\b`)
2629
)
2730

2831
// Keywords are used for efficiently pre-filtering chunks.

pkg/detectors/asanapersonalaccesstoken/asanapersonalaccesstoken_integration_test.go

Lines changed: 60 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,15 @@ func TestAsanaPersonalAccessToken_FromChunk(t *testing.T) {
2323
if err != nil {
2424
t.Fatalf("could not get test secrets from GCP: %s", err)
2525
}
26-
secret := testSecrets.MustGetField("ASANA_PAT")
27-
inactiveSecret := testSecrets.MustGetField("ASANA_PAT_INACTIVE")
26+
testNewSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors6")
27+
if err != nil {
28+
t.Fatalf("could not get test secrets from GCP: %s", err)
29+
}
30+
31+
oldFormatSecret := testSecrets.MustGetField("ASANA_PAT")
32+
newFormatSecret := testNewSecrets.MustGetField("ASANA_PAT_NEW")
33+
inactiveOldFormatSecret := testSecrets.MustGetField("ASANA_PAT_INACTIVE")
34+
inactiveNewFormatSecret := testNewSecrets.MustGetField("ASANA_PAT_NEW_INACTIVE")
2835

2936
type args struct {
3037
ctx context.Context
@@ -43,7 +50,7 @@ func TestAsanaPersonalAccessToken_FromChunk(t *testing.T) {
4350
s: Scanner{},
4451
args: args{
4552
ctx: context.Background(),
46-
data: []byte(fmt.Sprintf("You can find a asana secret %s within", secret)),
53+
data: []byte(fmt.Sprintf("You can find a asana secret %s within", oldFormatSecret)),
4754
verify: true,
4855
},
4956
want: []detectors.Result{
@@ -71,6 +78,38 @@ func TestAsanaPersonalAccessToken_FromChunk(t *testing.T) {
7178
wantErr: false,
7279
},
7380
{
81+
name: "found, verified - new format",
82+
s: Scanner{},
83+
args: args{
84+
ctx: context.Background(),
85+
data: []byte(fmt.Sprintf("You can find a asana secret %s within", newFormatSecret)),
86+
verify: true,
87+
},
88+
want: []detectors.Result{
89+
{
90+
DetectorType: detectorspb.DetectorType_AsanaPersonalAccessToken,
91+
Verified: true,
92+
},
93+
},
94+
wantErr: false,
95+
},
96+
{
97+
name: "found, unverified - new format",
98+
s: Scanner{},
99+
args: args{
100+
ctx: context.Background(),
101+
data: []byte(fmt.Sprintf("You can find a asana secret %s but unverified", inactiveNewFormatSecret)),
102+
verify: true,
103+
},
104+
want: []detectors.Result{
105+
{
106+
DetectorType: detectorspb.DetectorType_AsanaPersonalAccessToken,
107+
Verified: false,
108+
},
109+
},
110+
wantErr: false,
111+
},
112+
{
74113
name: "not found",
75114
s: Scanner{},
76115
args: args{
@@ -81,25 +120,25 @@ func TestAsanaPersonalAccessToken_FromChunk(t *testing.T) {
81120
want: nil,
82121
wantErr: false,
83122
},
84-
}
85-
for _, tt := range tests {
86-
t.Run(tt.name, func(t *testing.T) {
87-
s := Scanner{}
88-
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
89-
if (err != nil) != tt.wantErr {
90-
t.Errorf("AsanaPersonalAccessToken.FromData() error = %v, wantErr %v", err, tt.wantErr)
91-
return
92-
}
93-
for i := range got {
94-
if len(got[i].Raw) == 0 {
95-
t.Fatalf("no raw secret present: \n %+v", got[i])
123+
for _, tt := range tests {
124+
t.Run(tt.name, func(t *testing.T) {
125+
s := Scanner{}
126+
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
127+
if (err != nil) != tt.wantErr {
128+
t.Errorf("AsanaPersonalAccessToken.FromData() error = %v, wantErr %v", err, tt.wantErr)
129+
return
96130
}
97-
got[i].Raw = nil
98-
}
99-
if diff := pretty.Compare(got, tt.want); diff != "" {
100-
t.Errorf("AsanaPersonalAccessToken.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
101-
}
102-
})
131+
for i := range got {
132+
if len(got[i].Raw) == 0 {
133+
t.Fatalf("no raw secret present: \n %+v", got[i])
134+
}
135+
got[i].Raw = nil
136+
}
137+
if diff := pretty.Compare(got, tt.want); diff != "" {
138+
t.Errorf("AsanaPersonalAccessToken.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
139+
}
140+
})
141+
}
103142
}
104143
}
105144

pkg/detectors/asanapersonalaccesstoken/asanapersonalaccesstoken_test.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@ import (
1111
)
1212

1313
var (
14-
validPattern = "asana_token: 594776654034514343561917591881414702593902454625364993/1724908107002616220416212965:Yv3DoiSFhtsgUwN3AcnXWjK8zabQHKSHBRHpuNKVjz3oCcpyDIdXRm3GL4SUDkTMFoTbRDCHe8tTBHxdtoXItn"
15-
invalidPattern = "asana_token: 1724908107002616220416212965%594776654034514343561917591881414702593902454625364993:Yv3DoiSFhtsgUwN3AcnXWjK8zabQHKSHBRHpuNKVjz3oCcpyDIdXRm3GL4SUDkTMFoTbRDCHe8tTBHxdtoXItn-ij2gwtg/xn9vh4jvsokdfaic0bn"
14+
// Old format token
15+
validPatternOld = "asana_token: 594776654034514343561917591881414702593902454625364993/1724908107002616220416212965:Yv3DoiSFhtsgUwN3AcnXWjK8zabQHKSHBRHpuNKVjz3oCcpyDIdXRm3GL4SUDkTMFoTbRDCHe8tTBHxdtoXItn"
16+
// New format token with two forward slashes
17+
newValidPattern = "asana_token: 7/9823746598123746/8923746598123456:7f1a3c9be84d2a6c4e7d9c32bf1e7f88"
18+
invalidPattern = "asana_token: 1724908107002616220416212965%594776654034514343561917591881414702593902454625364993:Yv3DoiSFhtsgUwN3AcnXWjK8zabQHKSHBRHpuNKVjz3oCcpyDIdXRm3GL4SUDkTMFoTbRDCHe8tTBHxdtoXItn-ij2gwtg/xn9vh4jvsokdfaic0bn"
1619
)
1720

1821
func TestAsanaPersonalAccessToken_Pattern(t *testing.T) {
@@ -25,10 +28,15 @@ func TestAsanaPersonalAccessToken_Pattern(t *testing.T) {
2528
want []string
2629
}{
2730
{
28-
name: "valid pattern",
29-
input: validPattern,
31+
name: "valid pattern - old format",
32+
input: validPatternOld,
3033
want: []string{"594776654034514343561917591881414702593902454625364993/1724908107002616220416212965:Yv3DoiSFhtsgUwN3AcnXWjK8zabQHKSHBRHpuNKVjz3oCcpyDIdXRm3GL4SUDkTMFoTbRDCHe8tTBHxdtoXItn"},
3134
},
35+
{
36+
name: "valid pattern - new format",
37+
input: newValidPattern,
38+
want: []string{"7/9823746598123746/8923746598123456:7f1a3c9be84d2a6c4e7d9c32bf1e7f88"},
39+
},
3240
{
3341
name: "invalid pattern",
3442
input: invalidPattern,

0 commit comments

Comments
 (0)