Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fd840b72cb | |||
| 953e7f43bd |
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user