Skip to content

Fixed gitlab detector #4371

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Aug 13, 2025
32 changes: 18 additions & 14 deletions pkg/detectors/gitlab/v1/gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,29 +67,29 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result

matches := keyPat.FindAllStringSubmatch(dataStr, -1)
for _, match := range matches {
resMatch := strings.TrimSpace(match[1])

// ignore v2 detectors which have a prefix of `glpat-`
if strings.Contains(match[0], "glpat-") {
continue
}
resMatch := strings.TrimSpace(match[1])

// to avoid false positives
if detectors.StringShannonEntropy(resMatch) < 3.6 {
continue
}

s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_Gitlab,
Raw: []byte(resMatch),
ExtraData: map[string]string{},
}
s1.ExtraData = map[string]string{
"rotation_guide": "https://howtorotate.com/docs/tutorials/gitlab/",
"version": fmt.Sprintf("%d", s.Version()),
}
for _, endpoint := range s.Endpoints() {
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_Gitlab,
Raw: []byte(resMatch),
Copy link
Contributor

@amanfcp amanfcp Aug 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a single data string, if we have 2 set of credentials and only 2nd endpoint is correct, it would not be possible to identify why one result is verified and the other is not.

Suggested change
Raw: []byte(resMatch),
Raw: []byte(resMatch),
RawV2: []byte(resMatch + endpoint),

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had considered this change but hesitated, concerned it might duplicate existing results in the Enterprise.
I think @rosecodym can comment better on this change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, you're right. Raw/RawV2 is like a primary key, and updating it even slightly can have impacts on the enterprise data, so let's not touch that. Instead, we can store the endpoint in the extra data.

Copy link
Contributor

@amanfcp amanfcp Aug 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could cause problems in diagnosing issues later on in enterprise too. This just might require migration.
Also, I'm positive that "adding" a RawV2 won't require migration
@rosecodym awaiting your response.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, adding a RawV2 that wasn't there before is fine and won't affect the deduplication fingerprinting.
Changing Raw or RawV2 will cause issues though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @dustin-decker for the clarification - I updated the code.

ExtraData: map[string]string{
"rotation_guide": "https://howtorotate.com/docs/tutorials/gitlab/",
"version": fmt.Sprintf("%d", s.Version()),
},
}

if verify {
for _, endpoint := range s.Endpoints() {
if verify {
isVerified, extraData, verificationErr := VerifyGitlab(ctx, s.getClient(), endpoint, resMatch)
s1.Verified = isVerified
maps.Copy(s1.ExtraData, extraData)
Expand All @@ -102,11 +102,15 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
"key": resMatch,
"host": endpoint,
}

// if secret is verified with one endpoint, break the loop to continue to next secret
results = append(results, s1)
break
}
}
}

results = append(results, s1)
results = append(results, s1)
}
}

return results, nil
Expand Down
2 changes: 2 additions & 0 deletions pkg/detectors/gitlab/v1/gitlab_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ func TestGitlab_FromChunk(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.s.SetCloudEndpoint("https://gitlab.com")
tt.s.UseCloudEndpoint(true)
got, err := tt.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)
Expand Down
2 changes: 2 additions & 0 deletions pkg/detectors/gitlab/v1/gitlab_v1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ var (

func TestGitLab_Pattern(t *testing.T) {
d := Scanner{}
d.SetCloudEndpoint("https://gitlab.com")
d.UseCloudEndpoint(true)
ahoCorasickCore := ahocorasick.NewAhoCorasickCore([]detectors.Detector{d})

tests := []struct {
Expand Down
2 changes: 2 additions & 0 deletions pkg/detectors/gitlab/v2/gitlab_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ func TestGitlabV2_FromChunk_WithV1Secrets(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.s.SetCloudEndpoint("https://gitlab.com")
tt.s.UseCloudEndpoint(true)
got, err := tt.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)
Expand Down
32 changes: 18 additions & 14 deletions pkg/detectors/gitlab/v2/gitlab_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,20 +59,20 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result

matches := keyPat.FindAllStringSubmatch(dataStr, -1)
for _, match := range matches {

resMatch := strings.TrimSpace(match[1])
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_Gitlab,
Raw: []byte(resMatch),
ExtraData: map[string]string{},
}
s1.ExtraData = map[string]string{
"rotation_guide": "https://howtorotate.com/docs/tutorials/gitlab/",
"version": fmt.Sprintf("%d", s.Version()),
}

if verify {
for _, endpoint := range s.Endpoints() {
for _, endpoint := range s.Endpoints() {
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_Gitlab,
Raw: []byte(resMatch),
ExtraData: map[string]string{
"rotation_guide": "https://howtorotate.com/docs/tutorials/gitlab/",
"version": fmt.Sprintf("%d", s.Version()),
},
}

if verify {

isVerified, extraData, verificationErr := v1.VerifyGitlab(ctx, s.getClient(), endpoint, resMatch)
s1.Verified = isVerified
maps.Copy(s1.ExtraData, extraData)
Expand All @@ -85,11 +85,15 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
"key": resMatch,
"host": endpoint,
}

// if secret is verified with one endpoint, break the loop to continue to next secret
results = append(results, s1)
break
}
}
}

results = append(results, s1)
results = append(results, s1)
}
}

return results, nil
Expand Down
2 changes: 2 additions & 0 deletions pkg/detectors/gitlab/v2/gitlab_v2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ var (

func TestGitLab_Pattern(t *testing.T) {
d := Scanner{}
d.SetCloudEndpoint("https://gitlab.com")
d.UseCloudEndpoint(true)
ahoCorasickCore := ahocorasick.NewAhoCorasickCore([]detectors.Detector{d})

tests := []struct {
Expand Down