Compare commits

...

2 Commits

Author SHA1 Message Date
ahmed fd840b72cb updating secret to s1 to match convention 2023-09-11 16:07:19 -04:00
ahmed 953e7f43bd update gitlabv2 to tri-state 2023-09-11 14:36:48 -04:00
5 changed files with 108 additions and 146 deletions
+7 -7
View File
@@ -53,7 +53,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
resMatch = keyString[len(keyString)-1] resMatch = keyString[len(keyString)-1]
} }
secret := detectors.Result{ s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_Gitlab, DetectorType: detectorspb.DetectorType_Gitlab,
Raw: []byte(match[1]), Raw: []byte(match[1]),
} }
@@ -84,26 +84,26 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
// 401 is bad key // 401 is bad key
switch res.StatusCode { switch res.StatusCode {
case http.StatusOK: case http.StatusOK:
secret.Verified = true s1.Verified = true
case http.StatusForbidden: case http.StatusForbidden:
// Good key but not the right scope // Good key but not the right scope
secret.Verified = true s1.Verified = true
case http.StatusUnauthorized: case http.StatusUnauthorized:
// Nothing to do; zero values are the ones we want // Nothing to do; zero values are the ones we want
default: default:
secret.VerificationError = fmt.Errorf("unexpected HTTP response status %d", res.StatusCode) s1.VerificationError = fmt.Errorf("unexpected HTTP response status %d", res.StatusCode)
} }
} else { } else {
secret.VerificationError = err s1.VerificationError = err
} }
} }
} }
if !secret.Verified && detectors.IsKnownFalsePositive(string(secret.Raw), detectors.DefaultFalsePositives, true) { if !s1.Verified && detectors.IsKnownFalsePositive(string(s1.Raw), detectors.DefaultFalsePositives, true) {
continue continue
} }
results = append(results, secret) results = append(results, s1)
} }
return results, nil return results, nil
+3 -2
View File
@@ -6,11 +6,12 @@ package gitlab
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"testing" "testing"
"time" "time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/trufflesecurity/trufflehog/v3/pkg/common" "github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
-115
View File
@@ -1,115 +0,0 @@
package gitlab
import (
"context"
"fmt"
"testing"
"time"
"github.com/kylelemons/godebug/pretty"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
)
func TestGitlabv2_FromChunk(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors4")
if err != nil {
t.Fatalf("could not get test secrets from GCP: %s", err)
}
secret := testSecrets.MustGetField("GITLABV2")
secretInactive := testSecrets.MustGetField("GITLABV2_INACTIVE")
type args struct {
ctx context.Context
data []byte
verify bool
}
tests := []struct {
name string
s Scanner
args args
want []detectors.Result
wantErr bool
}{
{
name: "found",
s: Scanner{},
args: args{
ctx: context.Background(),
data: []byte(fmt.Sprintf("You can find a gitlab secret %s within", secret)),
verify: true,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_Gitlab,
Verified: true,
},
},
wantErr: false,
},
{
name: "found, unverified",
s: Scanner{},
args: args{
ctx: context.Background(),
data: []byte(fmt.Sprintf("You can find a gitlab secret %s within", secretInactive)),
verify: true,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_Gitlab,
Verified: false,
},
},
wantErr: false,
},
{
name: "not found",
s: Scanner{},
args: args{
ctx: context.Background(),
data: []byte("You cannot find the secret within"),
verify: true,
},
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("Gitlab.FromData() error = %v, wantErr %v", err, tt.wantErr)
return
}
for i := range got {
if len(got[i].Raw) == 0 {
t.Fatal("no raw secret present")
}
got[i].Raw = nil
}
if diff := pretty.Compare(got, tt.want); diff != "" {
t.Errorf("Gitlab.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
}
})
}
}
func BenchmarkFromData2(benchmark *testing.B) {
ctx := context.Background()
s := Scanner{}
for name, data := range detectors.MustGetBenchmarkData() {
benchmark.Run(name, func(b *testing.B) {
b.ResetTimer()
for n := 0; n < b.N; n++ {
_, err := s.FromData(ctx, false, data)
if err != nil {
b.Fatal(err)
}
}
})
}
}
+25 -8
View File
@@ -11,7 +11,10 @@ import (
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
) )
type Scanner struct{ detectors.EndpointSetter } type Scanner struct {
client *http.Client
detectors.EndpointSetter
}
// Ensure the Scanner satisfies the interfaces at compile time. // Ensure the Scanner satisfies the interfaces at compile time.
var _ detectors.Detector = (*Scanner)(nil) var _ detectors.Detector = (*Scanner)(nil)
@@ -22,7 +25,8 @@ func (Scanner) Version() int { return 2 }
func (Scanner) DefaultEndpoint() string { return "https://gitlab.com" } func (Scanner) DefaultEndpoint() string { return "https://gitlab.com" }
var ( var (
keyPat = regexp.MustCompile(`\b(glpat-[a-zA-Z0-9\-=_]{20,22})\b`) defaultClient = common.SaneHttpClient()
keyPat = regexp.MustCompile(`\b(glpat-[a-zA-Z0-9\-=_]{20,22})\b`)
) )
// Keywords are used for efficiently pre-filtering chunks. // Keywords are used for efficiently pre-filtering chunks.
@@ -42,7 +46,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
continue continue
} }
secret := detectors.Result{ s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_Gitlab, DetectorType: detectorspb.DetectorType_Gitlab,
Raw: []byte(match[1]), Raw: []byte(match[1]),
} }
@@ -52,7 +56,10 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
// they all grant access to different parts of the API. I couldn't find an endpoint that every // they all grant access to different parts of the API. I couldn't find an endpoint that every
// one of these scopes has access to, so we just check an example endpoint for each scope. If any // one of these scopes has access to, so we just check an example endpoint for each scope. If any
// of them contain data, we know we have a valid key, but if they all fail, we don't // of them contain data, we know we have a valid key, but if they all fail, we don't
client := common.SaneHttpClient() client := s.client
if client == nil {
client = defaultClient
}
for _, baseURL := range s.Endpoints(s.DefaultEndpoint()) { for _, baseURL := range s.Endpoints(s.DefaultEndpoint()) {
// test `read_user` scope // test `read_user` scope
req, err := http.NewRequestWithContext(ctx, "GET", baseURL+"/api/v4/user", nil) req, err := http.NewRequestWithContext(ctx, "GET", baseURL+"/api/v4/user", nil)
@@ -67,19 +74,29 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
// 200 means good key and has `read_user` scope // 200 means good key and has `read_user` scope
// 403 means good key but not the right scope // 403 means good key but not the right scope
// 401 is bad key // 401 is bad key
if res.StatusCode == http.StatusOK || res.StatusCode == http.StatusForbidden { switch res.StatusCode {
secret.Verified = true case http.StatusOK:
s1.Verified = true
case http.StatusForbidden:
// Good key but not the right scope
s1.Verified = true
case http.StatusUnauthorized:
// Nothing to do; zero values are the ones we want
default:
s1.VerificationError = fmt.Errorf("unexpected HTTP response status %d", res.StatusCode)
} }
} else {
s1.VerificationError = err
} }
} }
} }
if !secret.Verified && detectors.IsKnownFalsePositive(string(secret.Raw), detectors.DefaultFalsePositives, true) { if !s1.Verified && detectors.IsKnownFalsePositive(string(s1.Raw), detectors.DefaultFalsePositives, true) {
continue continue
} }
results = append(results, secret) results = append(results, s1)
} }
return return
+73 -14
View File
@@ -9,7 +9,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/kylelemons/godebug/pretty" "github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/trufflesecurity/trufflehog/v3/pkg/common" "github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
@@ -18,7 +19,7 @@ import (
func TestGitlab_FromChunk(t *testing.T) { func TestGitlab_FromChunk(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel() defer cancel()
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors2") testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors4")
if err != nil { if err != nil {
t.Fatalf("could not get test secrets from GCP: %s", err) t.Fatalf("could not get test secrets from GCP: %s", err)
} }
@@ -31,18 +32,19 @@ func TestGitlab_FromChunk(t *testing.T) {
verify bool verify bool
} }
tests := []struct { tests := []struct {
name string name string
s Scanner s Scanner
args args args args
want []detectors.Result want []detectors.Result
wantErr bool wantErr bool
wantVerificationErr bool
}{ }{
{ {
name: "found, verified", name: "found, verified",
s: Scanner{}, s: Scanner{},
args: args{ args: args{
ctx: context.Background(), ctx: context.Background(),
data: []byte(fmt.Sprintf("You can find a aws secret %s within", secret)), data: []byte(fmt.Sprintf("You can find a gitlab secret %s within", secret)),
verify: true, verify: true,
}, },
want: []detectors.Result{ want: []detectors.Result{
@@ -58,10 +60,65 @@ func TestGitlab_FromChunk(t *testing.T) {
s: Scanner{}, s: Scanner{},
args: args{ args: args{
ctx: context.Background(), ctx: context.Background(),
data: []byte(fmt.Sprintf("You can find a aws secret %s within", secretInactive)), data: []byte(fmt.Sprintf("You can find a gitlab secret %s within", secretInactive)),
verify: true, verify: true,
}, },
want: nil, want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_Gitlab,
Verified: false,
},
},
wantErr: false,
},
{
name: "found, would be verified but for timeout",
s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)},
args: args{
ctx: context.Background(),
data: []byte(fmt.Sprintf("You can find a gitlab super secret %s within", secret)),
verify: true,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_Gitlab,
Verified: false,
},
},
wantErr: false,
wantVerificationErr: true,
},
{
name: "found and valid but unexpected api response",
s: Scanner{client: common.ConstantResponseHttpClient(500, "")},
args: args{
ctx: context.Background(),
data: []byte(fmt.Sprintf("You can find a gitlab super secret %s within", secret)),
verify: true,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_Gitlab,
Verified: false,
},
},
wantErr: false,
wantVerificationErr: true,
},
{
name: "found, good key but wrong scope",
s: Scanner{client: common.ConstantResponseHttpClient(403, "")},
args: args{
ctx: context.Background(),
data: []byte(fmt.Sprintf("You can find a gitlab super secret %s within", secret)),
verify: true,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_Gitlab,
Verified: true,
},
},
wantErr: false, wantErr: false,
}, },
{ {
@@ -78,8 +135,7 @@ func TestGitlab_FromChunk(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
s := Scanner{} got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
t.Errorf("Gitlab.FromData() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("Gitlab.FromData() error = %v, wantErr %v", err, tt.wantErr)
return return
@@ -88,9 +144,12 @@ func TestGitlab_FromChunk(t *testing.T) {
if len(got[i].Raw) == 0 { if len(got[i].Raw) == 0 {
t.Fatal("no raw secret present") t.Fatal("no raw secret present")
} }
got[i].Raw = nil if (got[i].VerificationError != nil) != tt.wantVerificationErr {
t.Fatalf(" wantVerificationError = %v, verification error = %v,", tt.wantVerificationErr, got[i].VerificationError)
}
} }
if diff := pretty.Compare(got, tt.want); diff != "" { opts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "VerificationError")
if diff := cmp.Diff(got, tt.want, opts); diff != "" {
t.Errorf("Gitlab.FromData() %s diff: (-got +want)\n%s", tt.name, diff) t.Errorf("Gitlab.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
} }
}) })