From 748ff50ada8b7b056e605226eadbe9acf4988f23 Mon Sep 17 00:00:00 2001 From: Kemosabert Date: Wed, 25 Sep 2024 17:50:58 +0200 Subject: [PATCH 1/6] improve finding of full fragment by checking preceeding newlines --- detect/detect.go | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/detect/detect.go b/detect/detect.go index 5b3b7b365..52b22f4dc 100644 --- a/detect/detect.go +++ b/detect/detect.go @@ -270,13 +270,8 @@ func (d *Detector) detectRule(fragment Fragment, rule config.Rule) []report.Find if matchIndex[1] > loc.endLineIndex { loc.endLineIndex = matchIndex[1] } - - full_fragment := "" - if( len(fragment.Raw) > 250 ){ - full_fragment = strings.TrimSpace(fragment.Raw[0:250]) - }else{ - full_fragment = strings.TrimSpace(fragment.Raw[0:]) - } + + full_fragment := findFullLine(fragment, secret) finding := report.Finding{ Description: rule.Description, @@ -413,3 +408,37 @@ func (d *Detector) addFinding(finding report.Finding) { func (d *Detector) addCommit(commit string) { d.commitMap[commit] = true } + +// this function knows how to find the full line based on the secret and the newline chars it is between +func findFullLine(fragment Fragment, secret string) string { + re := regexp.MustCompile(`\r\n|\r|\n`) // regex to match all known newline chars + + secretStartingIdx := strings.Index(fragment.Raw, secret) + if secretStartingIdx == -1 { + return "" + } + + newlineIndices := re.FindAllStringIndex(fragment.Raw, -1) // find all newline char idx + + // find the nearest previous newline + prevNewlineIndex := 0 + for _, match := range newlineIndices { + if match[0] < secretStartingIdx { + prevNewlineIndex = match[1] // move past the newline character + } else { + break + } + } + + // find the nearest next newline + nextNewlineIndex := len(fragment.Raw) + for _, match := range newlineIndices { + if match[0] > secretStartingIdx { + nextNewlineIndex = match[0] // start of the next newline + break + } + } + + // return substring between indices + return strings.TrimSpace(fragment.Raw[prevNewlineIndex:nextNewlineIndex]) +} From 4244f53b74ddd1866603a42967cc643200755582 Mon Sep 17 00:00:00 2001 From: Kemosabert Date: Wed, 25 Sep 2024 17:51:50 +0200 Subject: [PATCH 2/6] take multi line secrets into account --- detect/detect.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/detect/detect.go b/detect/detect.go index 52b22f4dc..542f4d4cb 100644 --- a/detect/detect.go +++ b/detect/detect.go @@ -418,6 +418,8 @@ func findFullLine(fragment Fragment, secret string) string { return "" } + secretEndingIdx := secretStartingIdx + len(secret) + newlineIndices := re.FindAllStringIndex(fragment.Raw, -1) // find all newline char idx // find the nearest previous newline @@ -433,7 +435,7 @@ func findFullLine(fragment Fragment, secret string) string { // find the nearest next newline nextNewlineIndex := len(fragment.Raw) for _, match := range newlineIndices { - if match[0] > secretStartingIdx { + if match[0] > secretEndingIdx { nextNewlineIndex = match[0] // start of the next newline break } From 991184bc2093e59aa7d89d63c36334ca164f67a8 Mon Sep 17 00:00:00 2001 From: Kemosabert Date: Wed, 25 Sep 2024 17:53:36 +0200 Subject: [PATCH 3/6] update comments --- detect/detect.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/detect/detect.go b/detect/detect.go index 542f4d4cb..5ad15648e 100644 --- a/detect/detect.go +++ b/detect/detect.go @@ -413,12 +413,14 @@ func (d *Detector) addCommit(commit string) { func findFullLine(fragment Fragment, secret string) string { re := regexp.MustCompile(`\r\n|\r|\n`) // regex to match all known newline chars - secretStartingIdx := strings.Index(fragment.Raw, secret) + secretStartingIdx := strings.Index(fragment.Raw, secret) // start of secret in fragment + + // check if secret is found if secretStartingIdx == -1 { return "" } - secretEndingIdx := secretStartingIdx + len(secret) + secretEndingIdx := secretStartingIdx + len(secret) // end of secret in fragment newlineIndices := re.FindAllStringIndex(fragment.Raw, -1) // find all newline char idx From 3c2844b920170b9ec263cbd6448f3a1ce5e270e1 Mon Sep 17 00:00:00 2001 From: Kemosabert Date: Wed, 25 Sep 2024 17:55:50 +0200 Subject: [PATCH 4/6] add bunch of unit test --- detect/detect_test.go | 73 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/detect/detect_test.go b/detect/detect_test.go index 201829f95..9572c431d 100644 --- a/detect/detect_test.go +++ b/detect/detect_test.go @@ -716,3 +716,76 @@ func moveDotGit(t *testing.T, from, to string) { require.NoError(t, err) } } + +func TestFindSecretLine(t *testing.T) { + tests := []struct { + name string + fragment string + secret string + expected string + }{ + { + name: "Secret in middle of line with \\n", + fragment: "Line 1\nThis is a line with some secret data.\nAnother line follows here.", + secret: "secret", + expected: "This is a line with some secret data.", + }, + { + name: "Secret in middle of line with \\r\\n", + fragment: "Line 1\r\nThis is a line with some secret data.\r\nAnother line follows here.", + secret: "secret", + expected: "This is a line with some secret data.", + }, + { + name: "Secret in middle of line with \\r", + fragment: "Line 1\rThis is a line with some secret data.\rAnother line follows here.", + secret: "secret", + expected: "This is a line with some secret data.", + }, + { + name: "Secret at start of string", + fragment: "secret is at the start\nAnother line follows here.", + secret: "secret", + expected: "secret is at the start", + }, + { + name: "Secret at end of string", + fragment: "Line 1\nAnother line follows here with secret", + secret: "secret", + expected: "Another line follows here with secret", + }, + { + name: "Secret in single line string", + fragment: "This is a secret line.", + secret: "secret", + expected: "This is a secret line.", + }, + { + name: "Secret with no newlines around", + fragment: "This is a line with secret in the middle and no newlines.", + secret: "secret", + expected: "This is a line with secret in the middle and no newlines.", + }, + { + name: "Secret not found", + fragment: "This is a line with no secrets.", + secret: "secret", + expected: "", + }, + { + name: "Multiple newlines", + fragment: "\n\nThis is a line with a secret in between\n\n", + secret: "secret", + expected: "This is a line with a secret in between", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := findFullLine(Fragment{Raw: tt.fragment}, tt.secret) + if result != tt.expected { + t.Errorf("got %q, want %q", result, tt.expected) + } + }) + } +} From 1cc1dfa6f1d271320df9d7055661450b0f4a7362 Mon Sep 17 00:00:00 2001 From: Kemosabert Date: Thu, 26 Sep 2024 15:21:28 +0200 Subject: [PATCH 5/6] update algo --- detect/detect.go | 62 ++++++++++++++++++++++++++++++------------- detect/detect_test.go | 4 +-- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/detect/detect.go b/detect/detect.go index 5ad15648e..eb53ea8d2 100644 --- a/detect/detect.go +++ b/detect/detect.go @@ -411,38 +411,62 @@ func (d *Detector) addCommit(commit string) { // this function knows how to find the full line based on the secret and the newline chars it is between func findFullLine(fragment Fragment, secret string) string { - re := regexp.MustCompile(`\r\n|\r|\n`) // regex to match all known newline chars secretStartingIdx := strings.Index(fragment.Raw, secret) // start of secret in fragment - - // check if secret is found if secretStartingIdx == -1 { return "" } secretEndingIdx := secretStartingIdx + len(secret) // end of secret in fragment - newlineIndices := re.FindAllStringIndex(fragment.Raw, -1) // find all newline char idx - // find the nearest previous newline - prevNewlineIndex := 0 - for _, match := range newlineIndices { - if match[0] < secretStartingIdx { - prevNewlineIndex = match[1] // move past the newline character - } else { - break + prevNewlineIndex := findIndexAfterPreviousNewline(fragment.Raw, secretStartingIdx) + // find the nearest next newline + nextNewlineIndex := findIndexBeforeNextNewline(fragment.Raw, secretEndingIdx) + + // return substring between indices + return strings.TrimSpace(fragment.Raw[prevNewlineIndex:nextNewlineIndex]) +} + +func findIndexAfterPreviousNewline(fragment string, startIdx int) int { + if startIdx <= 0 { + return 0 + } + + re, err := regexp.Compile(`\r|\n`) + if err != nil { + return 0 + } + + for i := startIdx - 1; i >= 1; i-- { + char := fragment[i] + + if isNewline := re.Match([]byte{char}); isNewline { + return i } } - // find the nearest next newline - nextNewlineIndex := len(fragment.Raw) - for _, match := range newlineIndices { - if match[0] > secretEndingIdx { - nextNewlineIndex = match[0] // start of the next newline - break + return 0 +} + +func findIndexBeforeNextNewline(fragment string, startIdx int) int { + maxIdx := len(fragment) + if startIdx == maxIdx { + return maxIdx + } + + re, err := regexp.Compile(`\r|\n`) + if err != nil { + return maxIdx + } + + for i := startIdx + 1; i < maxIdx-1; i++ { + char := fragment[i] + + if isNewline := re.Match([]byte{char}); isNewline { + return i } } - // return substring between indices - return strings.TrimSpace(fragment.Raw[prevNewlineIndex:nextNewlineIndex]) + return maxIdx } diff --git a/detect/detect_test.go b/detect/detect_test.go index 9572c431d..4046761dc 100644 --- a/detect/detect_test.go +++ b/detect/detect_test.go @@ -9,7 +9,6 @@ import ( "github.com/spf13/viper" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/zricethezav/gitleaks/v8/config" "github.com/zricethezav/gitleaks/v8/report" "github.com/zricethezav/gitleaks/v8/sources" @@ -496,6 +495,7 @@ func TestFromGitStaged(t *testing.T) { StartColumn: 18, EndColumn: 37, Line: "\n\taws_token2 := \"AKIALALEMEL33243OLIA\" // this one is not", + FullLine: "aws_token := \"AKIALALEMEL33243OLIA\" // fingerprint of that secret is added to .gitleaksignore", Match: "AKIALALEMEL33243OLIA", Secret: "AKIALALEMEL33243OLIA", File: "api/api.go", @@ -769,7 +769,7 @@ func TestFindSecretLine(t *testing.T) { { name: "Secret not found", fragment: "This is a line with no secrets.", - secret: "secret", + secret: "hello", expected: "", }, { From 5f611db8e34cd8564c7e097d24bd451e70ddba5d Mon Sep 17 00:00:00 2001 From: Kemosabert Date: Thu, 26 Sep 2024 15:50:40 +0200 Subject: [PATCH 6/6] ensure it gets correct occurence --- detect/detect.go | 34 +++++++++++++----- detect/detect_test.go | 83 ++++++++++++++++++++++++++++++------------- 2 files changed, 83 insertions(+), 34 deletions(-) diff --git a/detect/detect.go b/detect/detect.go index eb53ea8d2..4d25155f0 100644 --- a/detect/detect.go +++ b/detect/detect.go @@ -271,7 +271,7 @@ func (d *Detector) detectRule(fragment Fragment, rule config.Rule) []report.Find loc.endLineIndex = matchIndex[1] } - full_fragment := findFullLine(fragment, secret) + full_fragment := findFullLine(fragment, loc, secret) finding := report.Finding{ Description: rule.Description, @@ -410,24 +410,40 @@ func (d *Detector) addCommit(commit string) { } // this function knows how to find the full line based on the secret and the newline chars it is between -func findFullLine(fragment Fragment, secret string) string { +func findFullLine(fragment Fragment, loc Location, secret string) string { - secretStartingIdx := strings.Index(fragment.Raw, secret) // start of secret in fragment - if secretStartingIdx == -1 { + secretLocation := findRelevantOccurenceOfSecret(fragment.Raw, secret, loc) + if secretLocation == nil { return "" } - secretEndingIdx := secretStartingIdx + len(secret) // end of secret in fragment + secretStartingIdx := secretLocation[0] // start of secret in fragment + secretEndingIdx := secretLocation[1] // end of secret in fragment // find the nearest previous newline - prevNewlineIndex := findIndexAfterPreviousNewline(fragment.Raw, secretStartingIdx) + prevNewlineIndex := findIndexAfterPreviousNewline(fragment.Raw, secretStartingIdx-1) // find the nearest next newline - nextNewlineIndex := findIndexBeforeNextNewline(fragment.Raw, secretEndingIdx) + nextNewlineIndex := findIndexBeforeNextNewline(fragment.Raw, secretEndingIdx+1) // return substring between indices return strings.TrimSpace(fragment.Raw[prevNewlineIndex:nextNewlineIndex]) } +// this function checks which occurence of the secret is relevant based on the location provided +func findRelevantOccurenceOfSecret(fragment string, secret string, loc Location) []int { + re := regexp.MustCompile(regexp.QuoteMeta(secret)) + matches := re.FindAllStringIndex(fragment, -1) + + // Extract the start indices + for _, match := range matches { + if match[0] >= loc.startLineIndex && match[1] <= loc.endLineIndex { + return match + } + } + + return nil +} + func findIndexAfterPreviousNewline(fragment string, startIdx int) int { if startIdx <= 0 { return 0 @@ -438,7 +454,7 @@ func findIndexAfterPreviousNewline(fragment string, startIdx int) int { return 0 } - for i := startIdx - 1; i >= 1; i-- { + for i := startIdx; i >= 0; i-- { char := fragment[i] if isNewline := re.Match([]byte{char}); isNewline { @@ -460,7 +476,7 @@ func findIndexBeforeNextNewline(fragment string, startIdx int) int { return maxIdx } - for i := startIdx + 1; i < maxIdx-1; i++ { + for i := startIdx; i < maxIdx; i++ { char := fragment[i] if isNewline := re.Match([]byte{char}); isNewline { diff --git a/detect/detect_test.go b/detect/detect_test.go index 4046761dc..25aaf411f 100644 --- a/detect/detect_test.go +++ b/detect/detect_test.go @@ -67,6 +67,7 @@ func TestDetect(t *testing.T) { Match: "AKIALALEMEL33243OKIA", File: "tmp.go", Line: `awsToken := \"AKIALALEMEL33243OKIA\"`, + FullLine: `awsToken := \"AKIALALEMEL33243OKIA\"`, RuleID: "aws-access-key", Tags: []string{"key", "AWS"}, StartLine: 0, @@ -89,6 +90,7 @@ func TestDetect(t *testing.T) { Secret: "pypi-AgEIcHlwaS5vcmcAAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAAB", Match: "pypi-AgEIcHlwaS5vcmcAAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAAB", Line: `pypi-AgEIcHlwaS5vcmcAAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAAB`, + FullLine: `pypi-AgEIcHlwaS5vcmcAAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAAB`, File: "tmp.go", RuleID: "pypi-upload-token", Tags: []string{"key", "pypi"}, @@ -112,6 +114,7 @@ func TestDetect(t *testing.T) { Secret: "AKIALALEMEL33243OLIA", Match: "AKIALALEMEL33243OLIA", Line: `awsToken := \"AKIALALEMEL33243OLIA\"`, + FullLine: `awsToken := \"AKIALALEMEL33243OLIA\"`, File: "tmp.go", RuleID: "aws-access-key", Tags: []string{"key", "AWS"}, @@ -135,6 +138,7 @@ func TestDetect(t *testing.T) { Match: "BUNDLE_ENTERPRISE__CONTRIBSYS__COM=cafebabe:deadbeef;", Secret: "cafebabe:deadbeef", Line: `export BUNDLE_ENTERPRISE__CONTRIBSYS__COM=cafebabe:deadbeef;`, + FullLine: `export BUNDLE_ENTERPRISE__CONTRIBSYS__COM=cafebabe:deadbeef;`, File: "tmp.sh", RuleID: "sidekiq-secret", Tags: []string{}, @@ -159,6 +163,7 @@ func TestDetect(t *testing.T) { Secret: "cafebabe:deadbeef", File: "tmp.sh", Line: `echo hello1; export BUNDLE_ENTERPRISE__CONTRIBSYS__COM="cafebabe:deadbeef" && echo hello2`, + FullLine: `echo hello1; export BUNDLE_ENTERPRISE__CONTRIBSYS__COM="cafebabe:deadbeef" && echo hello2`, RuleID: "sidekiq-secret", Tags: []string{}, Entropy: 2.6098502, @@ -182,6 +187,7 @@ func TestDetect(t *testing.T) { Secret: "cafeb4b3:d3adb33f", File: "tmp.sh", Line: `url = "http://cafeb4b3:d3adb33f@enterprise.contribsys.com:80/path?param1=true¶m2=false#heading1"`, + FullLine: `url = "http://cafeb4b3:d3adb33f@enterprise.contribsys.com:80/path?param1=true¶m2=false#heading1"`, RuleID: "sidekiq-sensitive-url", Tags: []string{}, Entropy: 2.984234, @@ -229,6 +235,7 @@ func TestDetect(t *testing.T) { Match: "Discord_Public_Key = \"e7322523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5\"", Secret: "e7322523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5", Line: `const Discord_Public_Key = "e7322523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5"`, + FullLine: `const Discord_Public_Key = "e7322523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5"`, File: "tmp.go", RuleID: "discord-api-key", Tags: []string{}, @@ -260,6 +267,7 @@ func TestDetect(t *testing.T) { Match: "Key = \"e7322523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5\"", Secret: "e7322523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5", Line: `const Discord_Public_Key = "e7322523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5"`, + FullLine: `const Discord_Public_Key = "e7322523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5"`, File: "tmp.py", RuleID: "generic-api-key", Tags: []string{}, @@ -372,6 +380,7 @@ func TestFromGit(t *testing.T) { StartColumn: 19, EndColumn: 38, Line: "\n awsToken := \"AKIALALEMEL33243OLIA\"", + FullLine: "awsToken := \"AKIALALEMEL33243OLIA\"", Secret: "AKIALALEMEL33243OLIA", Match: "AKIALALEMEL33243OLIA", File: "main.go", @@ -394,6 +403,7 @@ func TestFromGit(t *testing.T) { Secret: "AKIALALEMEL33243OLIA", Match: "AKIALALEMEL33243OLIA", Line: "\n\taws_token := \"AKIALALEMEL33243OLIA\"", + FullLine: "aws_token := \"AKIALALEMEL33243OLIA\"", File: "foo/foo.go", Date: "2021-11-02T23:48:06Z", Commit: "491504d5a31946ce75e22554cc34203d8e5ff3ca", @@ -420,6 +430,7 @@ func TestFromGit(t *testing.T) { EndColumn: 36, Secret: "AKIALALEMEL33243OLIA", Line: "\n\taws_token := \"AKIALALEMEL33243OLIA\"", + FullLine: "aws_token := \"AKIALALEMEL33243OLIA\"", Match: "AKIALALEMEL33243OLIA", Date: "2021-11-02T23:48:06Z", File: "foo/foo.go", @@ -495,7 +506,7 @@ func TestFromGitStaged(t *testing.T) { StartColumn: 18, EndColumn: 37, Line: "\n\taws_token2 := \"AKIALALEMEL33243OLIA\" // this one is not", - FullLine: "aws_token := \"AKIALALEMEL33243OLIA\" // fingerprint of that secret is added to .gitleaksignore", + FullLine: "aws_token2 := \"AKIALALEMEL33243OLIA\" // this one is not", Match: "AKIALALEMEL33243OLIA", Secret: "AKIALALEMEL33243OLIA", File: "api/api.go", @@ -568,6 +579,7 @@ func TestFromFiles(t *testing.T) { Match: "AKIALALEMEL33243OLIA", Secret: "AKIALALEMEL33243OLIA", Line: "\n\tawsToken := \"AKIALALEMEL33243OLIA\"", + FullLine: "awsToken := \"AKIALALEMEL33243OLIA\"", File: "../testdata/repos/nogit/main.go", SymlinkFile: "", RuleID: "aws-access-key", @@ -590,6 +602,7 @@ func TestFromFiles(t *testing.T) { Match: "AKIALALEMEL33243OLIA", Secret: "AKIALALEMEL33243OLIA", Line: "\n\tawsToken := \"AKIALALEMEL33243OLIA\"", + FullLine: "awsToken := \"AKIALALEMEL33243OLIA\"", File: "../testdata/repos/nogit/main.go", RuleID: "aws-access-key", Tags: []string{"key", "AWS"}, @@ -657,6 +670,7 @@ func TestDetectWithSymlinks(t *testing.T) { Match: "-----BEGIN OPENSSH PRIVATE KEY-----", Secret: "-----BEGIN OPENSSH PRIVATE KEY-----", Line: "-----BEGIN OPENSSH PRIVATE KEY-----", + FullLine: "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW", File: "../testdata/repos/symlinks/source_file/id_ed25519", SymlinkFile: "../testdata/repos/symlinks/file_symlink/symlinked_id_ed25519", RuleID: "apkey", @@ -720,61 +734,80 @@ func moveDotGit(t *testing.T, from, to string) { func TestFindSecretLine(t *testing.T) { tests := []struct { name string - fragment string + fragment Fragment + loc Location secret string expected string }{ { - name: "Secret in middle of line with \\n", - fragment: "Line 1\nThis is a line with some secret data.\nAnother line follows here.", - secret: "secret", - expected: "This is a line with some secret data.", - }, - { - name: "Secret in middle of line with \\r\\n", - fragment: "Line 1\r\nThis is a line with some secret data.\r\nAnother line follows here.", + name: "Secret within a line with \\n", + fragment: Fragment{ + Raw: "Line 1\nThis is a line with some secret data.\nAnother line follows here.", + }, + loc: Location{startLineIndex: 7, endLineIndex: 50}, secret: "secret", expected: "This is a line with some secret data.", }, { - name: "Secret in middle of line with \\r", - fragment: "Line 1\rThis is a line with some secret data.\rAnother line follows here.", + name: "Secret within a line with \\r\\n", + fragment: Fragment{ + Raw: "Line 1\r\nThis is a line with some secret data.\r\nAnother line follows here.", + }, + loc: Location{startLineIndex: 8, endLineIndex: 51}, secret: "secret", expected: "This is a line with some secret data.", }, { - name: "Secret at start of string", - fragment: "secret is at the start\nAnother line follows here.", + name: "Secret at start of string", + fragment: Fragment{ + Raw: "secret is at the start\nAnother line follows here.", + }, + loc: Location{startLineIndex: 0, endLineIndex: 21}, secret: "secret", expected: "secret is at the start", }, { - name: "Secret at end of string", - fragment: "Line 1\nAnother line follows here with secret", + name: "Secret at end of string", + fragment: Fragment{ + Raw: "Line 1\nAnother line follows here with secret", + }, + loc: Location{startLineIndex: 29, endLineIndex: 45}, secret: "secret", expected: "Another line follows here with secret", }, { - name: "Secret in single line string", - fragment: "This is a secret line.", + name: "Secret in single line string", + fragment: Fragment{ + Raw: "This is a secret line.", + }, + loc: Location{startLineIndex: 0, endLineIndex: 23}, secret: "secret", expected: "This is a secret line.", }, { - name: "Secret with no newlines around", - fragment: "This is a line with secret in the middle and no newlines.", + name: "Secret with no newlines around", + fragment: Fragment{ + Raw: "This is a line with secret in the middle and no newlines.", + }, + loc: Location{startLineIndex: 0, endLineIndex: 57}, secret: "secret", expected: "This is a line with secret in the middle and no newlines.", }, { - name: "Secret not found", - fragment: "This is a line with no secrets.", + name: "Secret not found", + fragment: Fragment{ + Raw: "This is a line with no secrets.", + }, + loc: Location{startLineIndex: 0, endLineIndex: 30}, secret: "hello", expected: "", }, { - name: "Multiple newlines", - fragment: "\n\nThis is a line with a secret in between\n\n", + name: "Multiple newlines", + fragment: Fragment{ + Raw: "\n\nThis is a line with a secret in between\n\n", + }, + loc: Location{startLineIndex: 2, endLineIndex: 40}, secret: "secret", expected: "This is a line with a secret in between", }, @@ -782,7 +815,7 @@ func TestFindSecretLine(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := findFullLine(Fragment{Raw: tt.fragment}, tt.secret) + result := findFullLine(tt.fragment, tt.loc, tt.secret) if result != tt.expected { t.Errorf("got %q, want %q", result, tt.expected) }