diff --git a/.gitignore b/.gitignore index d28eb59b..4aed4979 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,7 @@ talisman_darwin_* talisman_windows_* vendor/ gitrepo/data/* -.talismanrc +detector/.talismanrc .vscode/** coverage.out coverage.txt \ No newline at end of file diff --git a/.talismanrc b/.talismanrc new file mode 100644 index 00000000..226866a5 --- /dev/null +++ b/.talismanrc @@ -0,0 +1,2 @@ +scopeconfig: +- scope: go diff --git a/checksumcalculator/checksumcalculator.go b/checksumcalculator/checksumcalculator.go index 58a8a86d..80b59606 100644 --- a/checksumcalculator/checksumcalculator.go +++ b/checksumcalculator/checksumcalculator.go @@ -3,8 +3,8 @@ package checksumcalculator import ( "fmt" "os" - "talisman/detector" "talisman/gitrepo" + "talisman/talismanrc" "talisman/utility" yaml "gopkg.in/yaml.v2" @@ -27,18 +27,18 @@ func (cc *ChecksumCalculator) SuggestTalismanRC() string { gitTrackedFilesAsAdditions := repo.TrackedFilesAsAdditions() //Adding staged files for calculation gitTrackedFilesAsAdditions = append(gitTrackedFilesAsAdditions, repo.StagedAdditions()...) - var fileIgnoreConfigs []detector.FileIgnoreConfig + var fileIgnoreConfigs []talismanrc.FileIgnoreConfig result := "" for _, pattern := range cc.fileNamePatterns { collectiveChecksum := cc.calculateCollectiveChecksumForPattern(pattern, gitTrackedFilesAsAdditions) if collectiveChecksum != "" { - fileIgnoreConfig := detector.FileIgnoreConfig{FileName: pattern, Checksum: collectiveChecksum, IgnoreDetectors: []string{}} + fileIgnoreConfig := talismanrc.FileIgnoreConfig{FileName: pattern, Checksum: collectiveChecksum, IgnoreDetectors: []string{}} fileIgnoreConfigs = append(fileIgnoreConfigs, fileIgnoreConfig) } } if len(fileIgnoreConfigs) != 0 { result = result + fmt.Sprintf("\n\x1b[33m.talismanrc format for given file names / patterns\x1b[0m\n") - talismanRCIgnoreConfig := detector.TalismanRCIgnore{FileIgnoreConfig: fileIgnoreConfigs} + talismanRCIgnoreConfig := talismanrc.TalismanRCIgnore{FileIgnoreConfig: fileIgnoreConfigs} m, _ := yaml.Marshal(&talismanRCIgnoreConfig) result = result + string(m) } diff --git a/detector/base64_aggressive_detector_test.go b/detector/base64_aggressive_detector_test.go index c645e855..3b9c0a16 100644 --- a/detector/base64_aggressive_detector_test.go +++ b/detector/base64_aggressive_detector_test.go @@ -4,10 +4,13 @@ import ( "testing" "talisman/gitrepo" + "talisman/talismanrc" "github.com/stretchr/testify/assert" ) +var talismanRCIgnore = &talismanrc.TalismanRCIgnore{} + func TestShouldFlagPotentialAWSAccessKeysInAggressiveMode(t *testing.T) { const awsAccessKeyIDExample string = "AKIAIOSFODNN7EXAMPLE\n" results := NewDetectionResults() @@ -15,7 +18,7 @@ func TestShouldFlagPotentialAWSAccessKeysInAggressiveMode(t *testing.T) { filename := "filename" additions := []gitrepo.Addition{gitrepo.NewAddition(filename, content)} - NewFileContentDetector().AggressiveMode().Test(additions, TalismanRCIgnore{}, results) + NewFileContentDetector().AggressiveMode().Test(additions, talismanRCIgnore, results) assert.True(t, results.HasFailures(), "Expected file to not to contain base64 encoded texts") } @@ -26,7 +29,7 @@ func TestShouldFlagPotentialAWSAccessKeysAtPropertyDefinitionInAggressiveMode(t filename := "filename" additions := []gitrepo.Addition{gitrepo.NewAddition(filename, content)} - NewFileContentDetector().AggressiveMode().Test(additions, TalismanRCIgnore{}, results) + NewFileContentDetector().AggressiveMode().Test(additions, talismanRCIgnore, results) assert.True(t, results.HasFailures(), "Expected file to not to contain base64 encoded texts") } @@ -37,7 +40,7 @@ func TestShouldNotFlagPotentialSecretsWithinSafeJavaCodeEvenInAggressiveMode(t * filename := "filename" additions := []gitrepo.Addition{gitrepo.NewAddition(filename, content)} - NewFileContentDetector().AggressiveMode().Test(additions, TalismanRCIgnore{}, results) + NewFileContentDetector().AggressiveMode().Test(additions, talismanRCIgnore, results) if results == nil { additions = nil } diff --git a/detector/checksum_compare.go b/detector/checksum_compare.go index 6067eb3d..89ddae67 100644 --- a/detector/checksum_compare.go +++ b/detector/checksum_compare.go @@ -2,16 +2,17 @@ package detector import ( "talisman/gitrepo" + "talisman/talismanrc" "talisman/utility" ) type ChecksumCompare struct { additions []gitrepo.Addition - ignoreConfig TalismanRCIgnore + ignoreConfig *talismanrc.TalismanRCIgnore } //NewChecksumCompare returns new instance of the ChecksumCompare -func NewChecksumCompare(gitAdditions []gitrepo.Addition, talismanRCIgnoreConfig TalismanRCIgnore) *ChecksumCompare { +func NewChecksumCompare(gitAdditions []gitrepo.Addition, talismanRCIgnoreConfig *talismanrc.TalismanRCIgnore) *ChecksumCompare { cc := ChecksumCompare{additions: gitAdditions, ignoreConfig: talismanRCIgnoreConfig} return &cc } @@ -30,17 +31,17 @@ func (cc *ChecksumCompare) IsScanNotRequired(addition gitrepo.Addition) bool { } -//FilterIgnoresBasedOnChecksums filters the file ignores from the TalismanRCIgnore which doesn't have any checksum value or having mismatched checksum value from the .talsimanrc -func (cc *ChecksumCompare) FilterIgnoresBasedOnChecksums() TalismanRCIgnore { - finalIgnores := []FileIgnoreConfig{} +//FilterIgnoresBasedOnChecksums filters the file ignores from the talismanrc.TalismanRCIgnore which doesn't have any checksum value or having mismatched checksum value from the .talsimanrc +func (cc *ChecksumCompare) FilterIgnoresBasedOnChecksums() talismanrc.TalismanRCIgnore { + finalIgnores := []talismanrc.FileIgnoreConfig{} for _, ignore := range cc.ignoreConfig.FileIgnoreConfig { currentCollectiveChecksum := cc.calculateCollectiveChecksumForPattern(ignore.FileName, cc.additions) - // Compare with previous checksum from FileIgnoreConfig + // Compare with previous checksum from talismanrc.FileIgnoreConfig if ignore.Checksum == currentCollectiveChecksum { finalIgnores = append(finalIgnores, ignore) } } - rc := TalismanRCIgnore{} + rc := talismanrc.TalismanRCIgnore{} rc.FileIgnoreConfig = finalIgnores return rc } diff --git a/detector/checksum_compare_test.go b/detector/checksum_compare_test.go index 6f3916cd..05614090 100644 --- a/detector/checksum_compare_test.go +++ b/detector/checksum_compare_test.go @@ -2,6 +2,7 @@ package detector import ( "talisman/gitrepo" + "talisman/talismanrc" "talisman/utility" "testing" @@ -36,7 +37,7 @@ fileignoreconfig: ` func TestShouldConsiderBothFilesForDetection(t *testing.T) { - rc := NewTalismanRCIgnore([]byte(talismanRCWithInCorrectChecksum)) + rc := talismanrc.NewTalismanRCIgnore([]byte(talismanRCWithInCorrectChecksum)) addition1 := gitrepo.NewAddition("some_file.pem", make([]byte, 0)) addition2 := gitrepo.NewAddition("test/some_file.pem", make([]byte, 0)) cc := NewChecksumCompare([]gitrepo.Addition{addition1, addition2}, rc) @@ -49,7 +50,7 @@ func TestShouldConsiderBothFilesForDetection(t *testing.T) { func TestShouldNotConsiderBothFilesForDetection(t *testing.T) { addition1 := gitrepo.NewAddition("some_file.pem", make([]byte, 0)) addition2 := gitrepo.NewAddition("test/some_file.pem", make([]byte, 0)) - rc := NewTalismanRCIgnore([]byte(talismanRCWithCorrectChecksum)) + rc := talismanrc.NewTalismanRCIgnore([]byte(talismanRCWithCorrectChecksum)) cc := NewChecksumCompare([]gitrepo.Addition{addition1, addition2}, rc) filteredRC := cc.FilterIgnoresBasedOnChecksums() @@ -60,7 +61,7 @@ func TestShouldNotConsiderBothFilesForDetection(t *testing.T) { func TestShouldConsiderOneFileForDetection(t *testing.T) { addition1 := gitrepo.NewAddition("some_file.pem", make([]byte, 0)) addition2 := gitrepo.NewAddition("test/some1_file.pem", make([]byte, 0)) - rc := NewTalismanRCIgnore([]byte(talismanRCWithOneCorrectChecksum)) + rc := talismanrc.NewTalismanRCIgnore([]byte(talismanRCWithOneCorrectChecksum)) cc := NewChecksumCompare([]gitrepo.Addition{addition1, addition2}, rc) filteredRC := cc.FilterIgnoresBasedOnChecksums() @@ -71,7 +72,7 @@ func TestShouldConsiderOneFileForDetection(t *testing.T) { func TestShouldConsiderBothFilesForDetectionIfTalismanRCIsEmpty(t *testing.T) { addition1 := gitrepo.NewAddition("some_file.pem", make([]byte, 0)) addition2 := gitrepo.NewAddition("test/some_file.pem", make([]byte, 0)) - rc := NewTalismanRCIgnore([]byte{}) + rc := talismanrc.NewTalismanRCIgnore([]byte{}) cc := NewChecksumCompare([]gitrepo.Addition{addition1, addition2}, rc) filteredRC := cc.FilterIgnoresBasedOnChecksums() diff --git a/detector/detection_results.go b/detector/detection_results.go index aa117848..2a7ab0a0 100644 --- a/detector/detection_results.go +++ b/detector/detection_results.go @@ -2,15 +2,17 @@ package detector import ( "fmt" - "github.com/spf13/afero" - "gopkg.in/yaml.v2" "log" "os" "strings" "talisman/gitrepo" "talisman/prompt" + "talisman/talismanrc" "talisman/utility" + "github.com/spf13/afero" + "gopkg.in/yaml.v2" + "github.com/olekukonko/tablewriter" ) @@ -302,17 +304,17 @@ func (r *DetectionResults) Report(fs afero.Fs, ignoreFile string, promptContext } func (r *DetectionResults) suggestTalismanRC(fs afero.Fs, ignoreFile string, filePaths []string, promptContext prompt.PromptContext) { - var entriesToAdd []FileIgnoreConfig + var entriesToAdd []talismanrc.FileIgnoreConfig for _, filePath := range filePaths { currentChecksum := utility.CollectiveSHA256Hash([]string{filePath}) - fileIgnoreConfig := FileIgnoreConfig{filePath, currentChecksum, []string{}} + fileIgnoreConfig := talismanrc.FileIgnoreConfig{filePath, currentChecksum, []string{}} entriesToAdd = append(entriesToAdd, fileIgnoreConfig) } if promptContext.Interactive { confirmedEntries := getUserConfirmation(entriesToAdd, promptContext) - addToTalismanIgnoreFile(confirmedEntries, fs, ignoreFile) + talismanrc.Get().AddFileIgnores(confirmedEntries) } else { printTalismanIgnoreSuggestion(entriesToAdd) return @@ -320,8 +322,8 @@ func (r *DetectionResults) suggestTalismanRC(fs afero.Fs, ignoreFile string, fil } -func getUserConfirmation(configs []FileIgnoreConfig, promptContext prompt.PromptContext) []FileIgnoreConfig { - confirmed := []FileIgnoreConfig{} +func getUserConfirmation(configs []talismanrc.FileIgnoreConfig, promptContext prompt.PromptContext) []talismanrc.FileIgnoreConfig { + confirmed := []talismanrc.FileIgnoreConfig{} for _, config := range configs { if confirm(config, promptContext) { confirmed = append(confirmed, config) @@ -330,8 +332,8 @@ func getUserConfirmation(configs []FileIgnoreConfig, promptContext prompt.Prompt return confirmed } -func printTalismanIgnoreSuggestion(entriesToAdd []FileIgnoreConfig) { - talismanRcIgnoreConfig := TalismanRCIgnore{FileIgnoreConfig: entriesToAdd} +func printTalismanIgnoreSuggestion(entriesToAdd []talismanrc.FileIgnoreConfig) { + talismanRcIgnoreConfig := talismanrc.TalismanRCIgnore{FileIgnoreConfig: entriesToAdd} ignoreEntries, _ := yaml.Marshal(&talismanRcIgnoreConfig) suggestString := fmt.Sprintf("\n\x1b[33mIf you are absolutely sure that you want to ignore the " + "above files from talisman detectors, consider pasting the following format in .talismanrc file" + @@ -340,31 +342,7 @@ func printTalismanIgnoreSuggestion(entriesToAdd []FileIgnoreConfig) { fmt.Println(string(ignoreEntries)) } -func addToTalismanIgnoreFile(entriesToAdd []FileIgnoreConfig, fs afero.Fs, ignoreFile string) { - - if len(entriesToAdd) > 0 { - talismanRcIgnoreConfig := TalismanRCIgnore{FileIgnoreConfig: entriesToAdd} - ignoreEntries, _ := yaml.Marshal(&talismanRcIgnoreConfig) - file, err := fs.OpenFile(ignoreFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - log.Printf("error opening %s: %s", ignoreFile, err) - } - defer func() { - err := file.Close() - if err != nil { - log.Printf("error closing %s: %s", ignoreFile, err) - } - - }() - - _, err = file.WriteString(string(ignoreEntries)) - if err != nil { - log.Printf("error writing to %s: %s", ignoreFile, err) - } - } -} - -func confirm(config FileIgnoreConfig, promptContext prompt.PromptContext) bool { +func confirm(config talismanrc.FileIgnoreConfig, promptContext prompt.PromptContext) bool { bytes, err := yaml.Marshal(&config) if err != nil { log.Printf("error marshalling file ignore config: %s", err) diff --git a/detector/detection_results_test.go b/detector/detection_results_test.go index 0de000c9..b0305a6f 100644 --- a/detector/detection_results_test.go +++ b/detector/detection_results_test.go @@ -1,13 +1,15 @@ package detector import ( - "github.com/golang/mock/gomock" - "github.com/spf13/afero" "strings" mock "talisman/internal/mock/prompt" "talisman/prompt" + "talisman/talismanrc" "testing" + "github.com/golang/mock/gomock" + "github.com/spf13/afero" + "github.com/stretchr/testify/assert" ) @@ -78,6 +80,9 @@ func TestTalismanRCSuggestionWhenThereAreFailures(t *testing.T) { assert.NoError(t, err) ignoreFile := file.Name() + talismanrc.SetFs(fs) + talismanrc.SetRcFilename(ignoreFile) + existingContent := `fileignoreconfig: - filename: existing.pem checksum: 123444ddssa75333b25b6275f97680604add51b84eb8f4a3b9dcbbc652e6f27ac @@ -131,11 +136,6 @@ scopeconfig: [] results.Fail("some_file.pem", "filecontent", "Bomb", []string{}) expectedFileContent := `fileignoreconfig: -- filename: existing.pem - checksum: 123444ddssa75333b25b6275f97680604add51b84eb8f4a3b9dcbbc652e6f27ac - ignore_detectors: [] -scopeconfig: [] -fileignoreconfig: - filename: some_file.pem checksum: 87139cc4d975333b25b6275f97680604add51b84eb8f4a3b9dcbbc652e6f27ac ignore_detectors: [] @@ -175,7 +175,6 @@ scopeconfig: [] assert.Equal(t, expectedFileContent, string(bytesFromFile)) }) - err = fs.Remove(ignoreFile) assert.NoError(t, err) } diff --git a/detector/detector.go b/detector/detector.go index 29ad930e..cd5ce618 100644 --- a/detector/detector.go +++ b/detector/detector.go @@ -3,13 +3,14 @@ package detector import ( "os" "talisman/gitrepo" + "talisman/talismanrc" ) //Detector represents a single kind of test to be performed against a set of Additions //Detectors are expected to honor the ignores that are passed in and log them in the results //Detectors are expected to signal any errors to the results type Detector interface { - Test(additions []gitrepo.Addition, ignoreConfig TalismanRCIgnore, result *DetectionResults) + Test(additions []gitrepo.Addition, ignoreConfig *talismanrc.TalismanRCIgnore, result *DetectionResults) } //Chain represents a chain of Detectors. @@ -42,7 +43,7 @@ func (dc *Chain) AddDetector(d Detector) *Chain { //Test validates the additions against each detector in the chain. //The results are passed in from detector to detector and thus collect all errors from all detectors -func (dc *Chain) Test(additions []gitrepo.Addition, ignoreConfig TalismanRCIgnore, result *DetectionResults) { +func (dc *Chain) Test(additions []gitrepo.Addition, ignoreConfig *talismanrc.TalismanRCIgnore, result *DetectionResults) { wd, _ := os.Getwd() repo := gitrepo.RepoLocatedAt(wd) gitTrackedFilesAsAdditions := repo.TrackedFilesAsAdditions() diff --git a/detector/detector_test.go b/detector/detector_test.go index e6665a07..095a6ef0 100644 --- a/detector/detector_test.go +++ b/detector/detector_test.go @@ -4,6 +4,7 @@ import ( "testing" "talisman/gitrepo" + "talisman/talismanrc" "github.com/stretchr/testify/assert" ) @@ -11,7 +12,7 @@ import ( func TestEmptyValidationChainPassesAllValidations(t *testing.T) { v := NewChain() results := NewDetectionResults() - v.Test(nil, TalismanRCIgnore{}, results) + v.Test(nil, &talismanrc.TalismanRCIgnore{}, results) assert.False(t, results.HasFailures(), "Empty validation chain is expected to always pass") } @@ -20,18 +21,18 @@ func TestValidationChainWithFailingValidationAlwaysFails(t *testing.T) { v.AddDetector(PassingDetection{}) v.AddDetector(FailingDetection{}) results := NewDetectionResults() - v.Test(nil, TalismanRCIgnore{}, results) + v.Test(nil, &talismanrc.TalismanRCIgnore{}, results) assert.False(t, results.Successful(), "Expected validation chain with a failure to fail.") } type FailingDetection struct{} -func (v FailingDetection) Test(additions []gitrepo.Addition, ignoreConfig TalismanRCIgnore, result *DetectionResults) { +func (v FailingDetection) Test(additions []gitrepo.Addition, ignoreConfig *talismanrc.TalismanRCIgnore, result *DetectionResults) { result.Fail("some_file", "filecontent", "FAILED BY DESIGN", []string{}) } type PassingDetection struct{} -func (p PassingDetection) Test(additions []gitrepo.Addition, ignoreConfig TalismanRCIgnore, result *DetectionResults) { +func (p PassingDetection) Test(additions []gitrepo.Addition, ignoreConfig *talismanrc.TalismanRCIgnore, result *DetectionResults) { } diff --git a/detector/filecontent_detector.go b/detector/filecontent_detector.go index 0f095a20..be28f53a 100644 --- a/detector/filecontent_detector.go +++ b/detector/filecontent_detector.go @@ -6,6 +6,7 @@ import ( "strings" "sync" "talisman/gitrepo" + "talisman/talismanrc" log "github.com/Sirupsen/logrus" ) @@ -71,7 +72,7 @@ type content struct { results []string } -func (fc *FileContentDetector) Test(additions []gitrepo.Addition, ignoreConfig TalismanRCIgnore, result *DetectionResults) { +func (fc *FileContentDetector) Test(additions []gitrepo.Addition, ignoreConfig *talismanrc.TalismanRCIgnore, result *DetectionResults) { contentTypes := []struct { contentType fn @@ -105,7 +106,7 @@ func (fc *FileContentDetector) Test(additions []gitrepo.Addition, ignoreConfig T return } - if string(addition.Name) == DefaultRCFileName { + if string(addition.Name) == talismanrc.DefaultRCFileName { content := re.ReplaceAllString(string(addition.Data), "") data := []byte(content) addition.Data = data @@ -157,7 +158,7 @@ func processContent(c content, result *DetectionResults) { log.WithFields(log.Fields{ "filePath": c.path, }).Info(c.contentType.getInfo()) - if string(c.name) == DefaultRCFileName { + if string(c.name) == talismanrc.DefaultRCFileName { result.Warn(c.path, "filecontent", fmt.Sprintf(c.contentType.getMessageFormat(), res), []string{}) } else { result.Fail(c.path, "filecontent", fmt.Sprintf(c.contentType.getMessageFormat(), res), []string{}) diff --git a/detector/filecontent_detector_test.go b/detector/filecontent_detector_test.go index b8ecc83d..52414943 100644 --- a/detector/filecontent_detector_test.go +++ b/detector/filecontent_detector_test.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" "talisman/gitrepo" + "talisman/talismanrc" "testing" "github.com/stretchr/testify/assert" @@ -20,7 +21,7 @@ func TestShouldNotFlagSafeText(t *testing.T) { filename := "filename" additions := []gitrepo.Addition{gitrepo.NewAddition(filename, content)} - NewFileContentDetector().Test(additions, TalismanRCIgnore{}, results) + NewFileContentDetector().Test(additions, &talismanrc.TalismanRCIgnore{}, results) assert.False(t, results.HasFailures(), "Expected file to not to contain base64 encoded texts") } @@ -30,7 +31,7 @@ func TestShouldIgnoreFileIfNeeded(t *testing.T) { filename := "filename" additions := []gitrepo.Addition{gitrepo.NewAddition(filename, content)} - NewFileContentDetector().Test(additions, NewTalismanRCIgnore([]byte(talismanRCContents)), results) + NewFileContentDetector().Test(additions, talismanrc.NewTalismanRCIgnore([]byte(talismanRCContents)), results) assert.True(t, results.Successful(), "Expected file %s to be ignored by pattern", filename) } @@ -44,7 +45,7 @@ func TestShouldNotFlag4CharSafeText(t *testing.T) { filename := "filename" additions := []gitrepo.Addition{gitrepo.NewAddition(filename, content)} - NewFileContentDetector().Test(additions, TalismanRCIgnore{}, results) + NewFileContentDetector().Test(additions, talismanRCIgnore, results) assert.False(t, results.HasFailures(), "Expected file to not to contain base64 encoded texts") } @@ -55,7 +56,7 @@ func TestShouldNotFlagLowEntropyBase64Text(t *testing.T) { filename := "filename" additions := []gitrepo.Addition{gitrepo.NewAddition(filename, content)} - NewFileContentDetector().Test(additions, TalismanRCIgnore{}, results) + NewFileContentDetector().Test(additions, talismanRCIgnore, results) assert.False(t, results.HasFailures(), "Expected file to not to contain base64 encoded texts") } @@ -67,7 +68,7 @@ func TestShouldFlagPotentialAWSSecretKeys(t *testing.T) { additions := []gitrepo.Addition{gitrepo.NewAddition(filename, content)} filePath := additions[0].Path - NewFileContentDetector().Test(additions, TalismanRCIgnore{}, results) + NewFileContentDetector().Test(additions, talismanRCIgnore, results) expectedMessage := fmt.Sprintf("Expected file to not to contain base64 encoded texts such as: %s", awsSecretAccessKey) assert.True(t, results.HasFailures(), "Expected file to not to contain base64 encoded texts") assert.Equal(t, expectedMessage, getFailureMessages(results, filePath)[0]) @@ -82,7 +83,7 @@ func TestShouldFlagPotentialJWT(t *testing.T) { additions := []gitrepo.Addition{gitrepo.NewAddition(filename, content)} filePath := additions[0].Path - NewFileContentDetector().Test(additions, TalismanRCIgnore{}, results) + NewFileContentDetector().Test(additions, talismanRCIgnore, results) expectedMessage := fmt.Sprintf("Expected file to not to contain base64 encoded texts such as: %s", jwt) assert.True(t, results.HasFailures(), "Expected file to not to contain base64 encoded texts") assert.Equal(t, expectedMessage, getFailureMessages(results, filePath)[0]) @@ -97,7 +98,7 @@ func TestShouldFlagPotentialSecretsWithinJavaCode(t *testing.T) { additions := []gitrepo.Addition{gitrepo.NewAddition(filename, content)} filePath := additions[0].Path - NewFileContentDetector().Test(additions, TalismanRCIgnore{}, results) + NewFileContentDetector().Test(additions, talismanRCIgnore, results) expectedMessage := "Expected file to not to contain base64 encoded texts such as: accessKey=\"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\";" assert.True(t, results.HasFailures(), "Expected file to not to contain base64 encoded texts") assert.Equal(t, expectedMessage, getFailureMessages(results, filePath)[0]) @@ -111,7 +112,7 @@ func TestShouldNotFlagPotentialSecretsWithinSafeJavaCode(t *testing.T) { filename := "filename" additions := []gitrepo.Addition{gitrepo.NewAddition(filename, content)} - NewFileContentDetector().Test(additions, TalismanRCIgnore{}, results) + NewFileContentDetector().Test(additions, talismanRCIgnore, results) assert.False(t, results.HasFailures(), "Expected file to not to contain base64 encoded texts") } @@ -122,7 +123,7 @@ func TestShouldNotFlagPotentialSecretsWithinSafeLongMethodName(t *testing.T) { filename := "filename" additions := []gitrepo.Addition{gitrepo.NewAddition(filename, content)} - NewFileContentDetector().Test(additions, TalismanRCIgnore{}, results) + NewFileContentDetector().Test(additions, talismanRCIgnore, results) assert.False(t, results.HasFailures(), "Expected file to not to contain base64 encoded texts") } @@ -134,7 +135,7 @@ func TestShouldFlagPotentialSecretsEncodedInHex(t *testing.T) { additions := []gitrepo.Addition{gitrepo.NewAddition(filename, content)} filePath := additions[0].Path - NewFileContentDetector().Test(additions, TalismanRCIgnore{}, results) + NewFileContentDetector().Test(additions, talismanRCIgnore, results) expectedMessage := "Expected file to not to contain hex encoded texts such as: " + hex assert.Equal(t, expectedMessage, getFailureMessages(results, filePath)[0]) assert.Len(t, results.Results, 1) @@ -150,7 +151,7 @@ func TestResultsShouldContainHexTextsIfHexAndBase64ExistInFile(t *testing.T) { additions := []gitrepo.Addition{gitrepo.NewAddition(filename, content)} filePath := additions[0].Path - NewFileContentDetector().Test(additions, TalismanRCIgnore{}, results) + NewFileContentDetector().Test(additions, talismanRCIgnore, results) expectedMessage := "Expected file to not to contain hex encoded texts such as: " + hex messageReceived := strings.Join(getFailureMessages(results, filePath), " ") assert.Regexp(t, expectedMessage, messageReceived, "Should contain hex detection message") @@ -167,7 +168,7 @@ func TestResultsShouldContainBase64TextsIfHexAndBase64ExistInFile(t *testing.T) additions := []gitrepo.Addition{gitrepo.NewAddition(filename, content)} filePath := additions[0].Path - NewFileContentDetector().Test(additions, TalismanRCIgnore{}, results) + NewFileContentDetector().Test(additions, talismanRCIgnore, results) expectedMessage := "Expected file to not to contain base64 encoded texts such as: " + base64 messageReceived := strings.Join(getFailureMessages(results, filePath), " ") assert.Regexp(t, expectedMessage, messageReceived, "Should contain base64 detection message") @@ -182,7 +183,7 @@ func TestResultsShouldContainCreditCardNumberIfCreditCardNumberExistInFile(t *te additions := []gitrepo.Addition{gitrepo.NewAddition(filename, content)} filePath := additions[0].Path - NewFileContentDetector().Test(additions, TalismanRCIgnore{}, results) + NewFileContentDetector().Test(additions, talismanRCIgnore, results) expectedMessage := "Expected file to not to contain credit card numbers such as: " + creditCardNumber assert.Equal(t, expectedMessage, getFailureMessages(results, filePath)[0]) assert.Len(t, results.Results, 1) diff --git a/detector/filename_detector.go b/detector/filename_detector.go index c8ef8c97..d51cd052 100644 --- a/detector/filename_detector.go +++ b/detector/filename_detector.go @@ -5,6 +5,7 @@ import ( "regexp" "talisman/gitrepo" + "talisman/talismanrc" log "github.com/Sirupsen/logrus" ) @@ -60,6 +61,7 @@ var ( regexp.MustCompile(`^\.?gnucash$`), } ) + //FileNameDetector represents tests performed against the fileName of the Additions. //The Paths of the supplied Additions are tested against the configured patterns and if any of them match, it is logged as a failure during the run type FileNameDetector struct { @@ -77,10 +79,10 @@ func NewFileNameDetector(patterns []*regexp.Regexp) Detector { } //Test tests the fileNames of the Additions to ensure that they don't look suspicious -func (fd FileNameDetector) Test(additions []gitrepo.Addition, ignoreConfig TalismanRCIgnore, result *DetectionResults) { +func (fd FileNameDetector) Test(additions []gitrepo.Addition, ignoreConfig *talismanrc.TalismanRCIgnore, result *DetectionResults) { cc := NewChecksumCompare(additions, ignoreConfig) for _, addition := range additions { - if ignoreConfig.Deny(addition, "filename") || cc.IsScanNotRequired(addition){ + if ignoreConfig.Deny(addition, "filename") || cc.IsScanNotRequired(addition) { log.WithFields(log.Fields{ "filePath": addition.Path, }).Info("Ignoring addition as it was specified to be ignored.") diff --git a/detector/filename_detector_test.go b/detector/filename_detector_test.go index 9bb05de8..2f8eb2ad 100644 --- a/detector/filename_detector_test.go +++ b/detector/filename_detector_test.go @@ -4,10 +4,11 @@ package detector //https://github.com/jandre/safe-commit-hook import ( - "testing" "regexp" + "testing" "talisman/gitrepo" + "talisman/talismanrc" "github.com/stretchr/testify/assert" ) @@ -143,12 +144,12 @@ func shouldIgnoreFilesWhichWouldOtherwiseTriggerErrors(fileName, ignore string, func shouldNotFailWithDefaultDetectorAndIgnores(fileName, ignore string, t *testing.T) { results := NewDetectionResults() - fileIgnoreConfig := FileIgnoreConfig{} + fileIgnoreConfig := talismanrc.FileIgnoreConfig{} fileIgnoreConfig.FileName = ignore fileIgnoreConfig.IgnoreDetectors = make([]string, 1) fileIgnoreConfig.IgnoreDetectors[0] = "filename" - talismanRCIgnore := TalismanRCIgnore{} - talismanRCIgnore.FileIgnoreConfig = make([]FileIgnoreConfig, 1) + talismanRCIgnore := &talismanrc.TalismanRCIgnore{} + talismanRCIgnore.FileIgnoreConfig = make([]talismanrc.FileIgnoreConfig, 1) talismanRCIgnore.FileIgnoreConfig[0] = fileIgnoreConfig DefaultFileNameDetector().Test(additionsNamed(fileName), talismanRCIgnore, results) @@ -158,13 +159,13 @@ func shouldNotFailWithDefaultDetectorAndIgnores(fileName, ignore string, t *test func shouldFailWithSpecificPattern(fileName, pattern string, t *testing.T) { results := NewDetectionResults() pt := regexp.MustCompile(pattern) - NewFileNameDetector([]*regexp.Regexp{pt}).Test(additionsNamed(fileName), TalismanRCIgnore{}, results) + NewFileNameDetector([]*regexp.Regexp{pt}).Test(additionsNamed(fileName), talismanRCIgnore, results) assert.True(t, results.HasFailures(), "Expected file %s to fail the check against the %s pattern", fileName, pattern) } func shouldFailWithDefaultDetector(fileName, pattern string, t *testing.T) { results := NewDetectionResults() - DefaultFileNameDetector().Test(additionsNamed(fileName), TalismanRCIgnore{}, results) + DefaultFileNameDetector().Test(additionsNamed(fileName), talismanRCIgnore, results) assert.True(t, results.HasFailures(), "Expected file %s to fail the check against default detector. Missing pattern %s?", fileName, pattern) } diff --git a/detector/filesize_detector.go b/detector/filesize_detector.go index 7fc99e37..d73ff7e8 100644 --- a/detector/filesize_detector.go +++ b/detector/filesize_detector.go @@ -4,6 +4,7 @@ import ( "fmt" "talisman/gitrepo" + "talisman/talismanrc" log "github.com/Sirupsen/logrus" ) @@ -20,7 +21,7 @@ func NewFileSizeDetector(size int) Detector { return FileSizeDetector{size} } -func (fd FileSizeDetector) Test(additions []gitrepo.Addition, ignoreConfig TalismanRCIgnore, result *DetectionResults) { +func (fd FileSizeDetector) Test(additions []gitrepo.Addition, ignoreConfig *talismanrc.TalismanRCIgnore, result *DetectionResults) { cc := NewChecksumCompare(additions, ignoreConfig) for _, addition := range additions { if ignoreConfig.Deny(addition, "filesize") || cc.IsScanNotRequired(addition) { diff --git a/detector/filesize_detector_test.go b/detector/filesize_detector_test.go index 0f8fac5c..5b5177dd 100644 --- a/detector/filesize_detector_test.go +++ b/detector/filesize_detector_test.go @@ -4,6 +4,7 @@ import ( "testing" "talisman/gitrepo" + "talisman/talismanrc" "github.com/stretchr/testify/assert" ) @@ -12,7 +13,7 @@ func TestShouldFlagLargeFiles(t *testing.T) { results := NewDetectionResults() content := []byte("more than one byte") additions := []gitrepo.Addition{gitrepo.NewAddition("filename", content)} - NewFileSizeDetector(2).Test(additions, TalismanRCIgnore{}, results) + NewFileSizeDetector(2).Test(additions, talismanRCIgnore, results) assert.True(t, results.HasFailures(), "Expected file to fail the check against file size detector.") } @@ -20,7 +21,7 @@ func TestShouldNotFlagSmallFiles(t *testing.T) { results := NewDetectionResults() content := []byte("m") additions := []gitrepo.Addition{gitrepo.NewAddition("filename", content)} - NewFileSizeDetector(2).Test(additions, TalismanRCIgnore{}, results) + NewFileSizeDetector(2).Test(additions, talismanRCIgnore, results) assert.False(t, results.HasFailures(), "Expected file to not to fail the check against file size detector.") } @@ -29,12 +30,12 @@ func TestShouldNotFlagIgnoredLargeFiles(t *testing.T) { content := []byte("more than one byte") filename := "filename" - fileIgnoreConfig := FileIgnoreConfig{} + fileIgnoreConfig := talismanrc.FileIgnoreConfig{} fileIgnoreConfig.FileName = filename fileIgnoreConfig.IgnoreDetectors = make([]string, 1) fileIgnoreConfig.IgnoreDetectors[0] = "filesize" - talismanRCIgnore := TalismanRCIgnore{} - talismanRCIgnore.FileIgnoreConfig = make([]FileIgnoreConfig, 1) + talismanRCIgnore := talismanRCIgnore + talismanRCIgnore.FileIgnoreConfig = make([]talismanrc.FileIgnoreConfig, 1) talismanRCIgnore.FileIgnoreConfig[0] = fileIgnoreConfig additions := []gitrepo.Addition{gitrepo.NewAddition(filename, content)} diff --git a/detector/pattern_detector.go b/detector/pattern_detector.go index af6c0d76..abf61580 100644 --- a/detector/pattern_detector.go +++ b/detector/pattern_detector.go @@ -2,10 +2,12 @@ package detector import ( "fmt" - log "github.com/Sirupsen/logrus" "regexp" "sync" "talisman/gitrepo" + "talisman/talismanrc" + + log "github.com/Sirupsen/logrus" ) type PatternDetector struct { @@ -39,7 +41,7 @@ type match struct { } //Test tests the contents of the Additions to ensure that they don't look suspicious -func (detector PatternDetector) Test(additions []gitrepo.Addition, ignoreConfig TalismanRCIgnore, result *DetectionResults) { +func (detector PatternDetector) Test(additions []gitrepo.Addition, ignoreConfig *talismanrc.TalismanRCIgnore, result *DetectionResults) { cc := NewChecksumCompare(additions, ignoreConfig) matches := make(chan match, 512) ignoredFilePaths := make(chan gitrepo.FilePath, 512) @@ -89,7 +91,7 @@ func (detector PatternDetector) processIgnore(ignoredFilePath gitrepo.FilePath, func (detector PatternDetector) processMatch(match match, result *DetectionResults) { for _, detection := range match.detections { if detection != "" { - if string(match.name) == DefaultRCFileName { + if string(match.name) == talismanrc.DefaultRCFileName { log.WithFields(log.Fields{ "filePath": match.path, "pattern": detection, diff --git a/detector/pattern_detector_test.go b/detector/pattern_detector_test.go index 5b259302..631726b8 100644 --- a/detector/pattern_detector_test.go +++ b/detector/pattern_detector_test.go @@ -2,6 +2,7 @@ package detector import ( "talisman/gitrepo" + "talisman/talismanrc" "testing" "github.com/stretchr/testify/assert" @@ -26,8 +27,8 @@ func TestShouldIgnorePasswordPatterns(t *testing.T) { content := []byte("\"password\" : UnsafePassword") filename := "secret.txt" additions := []gitrepo.Addition{gitrepo.NewAddition(filename, content)} - fileIgnoreConfig := FileIgnoreConfig{filename, "833b6c24c8c2c5c7e1663226dc401b29c005492dc76a1150fc0e0f07f29d4cc3", []string{"filecontent"}} - ignores := TalismanRCIgnore{FileIgnoreConfig:[]FileIgnoreConfig{fileIgnoreConfig}} + fileIgnoreConfig := talismanrc.FileIgnoreConfig{filename, "833b6c24c8c2c5c7e1663226dc401b29c005492dc76a1150fc0e0f07f29d4cc3", []string{"filecontent"}} + ignores := &talismanrc.TalismanRCIgnore{FileIgnoreConfig: []talismanrc.FileIgnoreConfig{fileIgnoreConfig}} NewPatternDetector().Test(additions, ignores, results) assert.True(t, results.Successful(), "Expected file %s to be ignored by pattern", filename) @@ -36,7 +37,7 @@ func TestShouldIgnorePasswordPatterns(t *testing.T) { func shouldPassDetectionOfSecretPattern(filename string, content []byte, t *testing.T) { results := NewDetectionResults() additions := []gitrepo.Addition{gitrepo.NewAddition(filename, content)} - NewPatternDetector().Test(additions, TalismanRCIgnore{}, results) + NewPatternDetector().Test(additions, talismanRCIgnore, results) expected := "Potential secret pattern : " + string(content) assert.Equal(t, expected, getFailureMessage(results, additions)) assert.Len(t, results.Results, 1) diff --git a/git_testing/git_testing.go b/git_testing/git_testing.go index 8aa38dc4..f8a4a65d 100644 --- a/git_testing/git_testing.go +++ b/git_testing/git_testing.go @@ -13,6 +13,7 @@ import ( ) var Logger *logrus.Entry +var gitConfigFile string type GitTesting struct { gitRoot string @@ -22,6 +23,11 @@ func Init(gitRoot string) *GitTesting { os.MkdirAll(gitRoot, 0777) testingRepo := &GitTesting{gitRoot} testingRepo.ExecCommand("git", "init", ".") + gitConfigFileObject, _ := ioutil.TempFile("/tmp", "gitConfigForTalismanTests") + gitConfigFile = gitConfigFileObject.Name() + testingRepo.CreateFileWithContents(gitConfigFile, `[user] + email = talisman-test-user@example.com + name = Talisman Test User`) return testingRepo } @@ -142,6 +148,7 @@ func (git *GitTesting) ExecCommand(commandName string, args ...string) string { var output []byte git.doInGitRoot(func() { result := exec.Command(commandName, args...) + //result.Env = []string{"GIT_CONFIG=" + gitConfigFile} var err error output, err = result.Output() git.die(fmt.Sprintf("when executing command %s %v in %s", commandName, args, git.gitRoot), err) diff --git a/go.sum b/go.sum index 20c18104..6a3966ab 100644 --- a/go.sum +++ b/go.sum @@ -15,16 +15,20 @@ github.com/drhodes/golorem v0.0.0-20120624033213-6e38d8d5e455 h1:WqCK3j5a2lJAQS/ github.com/drhodes/golorem v0.0.0-20120624033213-6e38d8d5e455/go.mod h1:NsKVpF4h4j13Vm6Cx7Kf0V03aJKjfaStvm5rvK4+FyQ= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/hashicorp/go-version v1.0.0 h1:21MVWPKDphxa7ineQQTrCU5brh7OuVVAzGOCnnCPtE8= github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ= github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.4 h1:5Myjjh3JY/NaAi4IsUbHADytDyl1VE1Y9PXDlL+P/VQ= github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -34,9 +38,10 @@ github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/ github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/goveralls v0.0.3 h1:GnFhBAK0wJmxZBum88FqDzcDPLjAk9sL0HzhmW+9bo8= github.com/mattn/goveralls v0.0.3/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mitchellh/gox v0.4.0 h1:lfGJxY7ToLJQjHHwi0EX6uYBdK78egf954SQl13PQJc= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mitchellh/gox v1.0.1 h1:x0jD3dcHk9a9xPSDN6YEL4xL6Qz0dvNYm8yZqui5chI= github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4= github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY= @@ -45,11 +50,13 @@ github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8u github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5 h1:8dUaAV7K4uHsF56JQWkprecIQKdPHtR9jCHF5nB8uzc= @@ -63,6 +70,7 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1 h1:R4dVlxdmKenVdMRS/tTspEpSTRWINYrHD8ySIU9yCIU= golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190425150028-36563e24a262 h1:qsl9y/CJx34tuA7QCPNp86JNJe4spst6Ff8MjvPUdPg= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -70,4 +78,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/runner.go b/runner.go index e00ca8df..48860936 100644 --- a/runner.go +++ b/runner.go @@ -2,16 +2,17 @@ package main import ( "fmt" - "github.com/spf13/afero" "log" - "os" "talisman/checksumcalculator" "talisman/detector" "talisman/gitrepo" "talisman/prompt" "talisman/report" "talisman/scanner" + "talisman/talismanrc" "talisman/utility" + + "github.com/spf13/afero" ) const ( @@ -49,7 +50,7 @@ func (r *Runner) Scan(reportDirectory string) int { fmt.Printf("\n\n") utility.CreateArt("Running Scan..") additions := scanner.GetAdditions() - ignores := detector.TalismanRCIgnore{} + ignores := &talismanrc.TalismanRCIgnore{} detector.DefaultChain().Test(additions, ignores, r.results) reportsPath, err := report.GenerateReport(r.results, reportDirectory) if err != nil { @@ -74,9 +75,9 @@ func (r *Runner) RunChecksumCalculator(fileNamePatterns []string) int { } func (r *Runner) doRun() { - rcConfigIgnores := detector.ReadConfigFromRCFile(readRepoFile()) + rcConfigIgnores := talismanrc.Get() scopeMap := getScopeConfig() - additionsToScan := detector.IgnoreAdditionsByScope(r.additions, rcConfigIgnores, scopeMap); + additionsToScan := rcConfigIgnores.IgnoreAdditionsByScope(r.additions, scopeMap) detector.DefaultChain().Test(additionsToScan, rcConfigIgnores, r.results) } @@ -94,7 +95,7 @@ func (r *Runner) printReport(promptContext prompt.PromptContext) { } if r.results.HasIgnores() || r.results.HasFailures() { fs := afero.NewOsFs() - r.results.Report(fs, detector.DefaultRCFileName, promptContext) + r.results.Report(fs, talismanrc.DefaultRCFileName, promptContext) } } @@ -104,9 +105,3 @@ func (r *Runner) exitStatus() int { } return CompletedSuccessfully } - -func readRepoFile() func(string) ([]byte, error) { - wd, _ := os.Getwd() - repo := gitrepo.RepoLocatedAt(wd) - return repo.ReadRepoFileOrNothing -} diff --git a/detector/ignores.go b/talismanrc/talismanrc.go similarity index 59% rename from detector/ignores.go rename to talismanrc/talismanrc.go index d272b3f4..4940dbe4 100644 --- a/detector/ignores.go +++ b/talismanrc/talismanrc.go @@ -1,12 +1,16 @@ -package detector +package talismanrc import ( - "gopkg.in/yaml.v2" "log" + "os" "reflect" "regexp" "strings" + logr "github.com/Sirupsen/logrus" + "github.com/spf13/afero" + "gopkg.in/yaml.v2" + "talisman/gitrepo" ) @@ -25,6 +29,9 @@ var ( commentPattern = regexp.MustCompile(LinePattern) ignorePattern = regexp.MustCompile(IgnoreDetectorCommentPattern) emptyStringPattern = regexp.MustCompile(`^\s*$`) + fs = afero.NewOsFs() + currentRCFileName = DefaultRCFileName + cachedConfig TalismanRCIgnore ) //Ignores represents a set of patterns that have been configured to be ignored by the Detectors. @@ -32,16 +39,17 @@ var ( type Ignores struct { patterns []Ignore } + //Ignore represents a single pattern and its comment type Ignore struct { - pattern string - comment string + pattern string + comment string ignoredDetectors []string } type FileIgnoreConfig struct { - FileName string `yaml:"filename"` - Checksum string `yaml:"checksum"` + FileName string `yaml:"filename"` + Checksum string `yaml:"checksum"` IgnoreDetectors []string `yaml:"ignore_detectors"` } @@ -54,28 +62,45 @@ type TalismanRCIgnore struct { ScopeConfig []ScopeConfig `yaml:"scopeconfig"` } -func (ignore TalismanRCIgnore) IsEmpty() bool { +func SetFs(_fs afero.Fs) { + fs = _fs +} + +func SetRcFilename(rcFileName string) { + currentRCFileName = rcFileName +} + +func Get() *TalismanRCIgnore { + return ReadConfigFromRCFile(readRepoFile()) +} + +func (ignore *TalismanRCIgnore) IsEmpty() bool { return reflect.DeepEqual(TalismanRCIgnore{}, ignore) } -func ReadConfigFromRCFile(repoFileRead func(string) ([]byte, error)) TalismanRCIgnore { - fileContents, error := repoFileRead(DefaultRCFileName) +func ReadConfigFromRCFile(repoFileRead func(string) ([]byte, error)) *TalismanRCIgnore { + fileContents, error := repoFileRead(currentRCFileName) if error != nil { panic(error) } return NewTalismanRCIgnore(fileContents) } +func readRepoFile() func(string) ([]byte, error) { + wd, _ := os.Getwd() + repo := gitrepo.RepoLocatedAt(wd) + return repo.ReadRepoFileOrNothing +} -func NewTalismanRCIgnore(fileContents []byte) (TalismanRCIgnore) { +func NewTalismanRCIgnore(fileContents []byte) *TalismanRCIgnore { talismanRCIgnore := TalismanRCIgnore{} err := yaml.Unmarshal([]byte(fileContents), &talismanRCIgnore) if err != nil { log.Println("Unable to parse .talismanrc") log.Printf("error: %v", err) - return talismanRCIgnore + return &talismanRCIgnore } - return talismanRCIgnore + return &talismanRCIgnore } func NewIgnore(pattern string, comment string) Ignore { @@ -86,8 +111,8 @@ func NewIgnore(pattern string, comment string) Ignore { } return Ignore{ - pattern: pattern, - comment: comment, + pattern: pattern, + comment: comment, ignoredDetectors: ignoredDetectors, } } @@ -112,16 +137,16 @@ func NewIgnores(lines ...string) Ignores { } //AcceptsAll returns true if there are no rules specified -func (i TalismanRCIgnore) AcceptsAll() bool { +func (i *TalismanRCIgnore) AcceptsAll() bool { return len(i.effectiveRules("any-detector")) == 0 } //Accept answers true if the Addition.Path is configured to be checked by the detectors -func (i TalismanRCIgnore) Accept(addition gitrepo.Addition, detectorName string) bool { +func (i *TalismanRCIgnore) Accept(addition gitrepo.Addition, detectorName string) bool { return !i.Deny(addition, detectorName) } -func IgnoreAdditionsByScope(additions []gitrepo.Addition, rcConfigIgnores TalismanRCIgnore, scopeMap map[string][]string) []gitrepo.Addition { +func (rcConfigIgnores *TalismanRCIgnore) IgnoreAdditionsByScope(additions []gitrepo.Addition, scopeMap map[string][]string) []gitrepo.Addition { var applicableScopeFileNames []string if rcConfigIgnores.ScopeConfig != nil { for _, scope := range rcConfigIgnores.ScopeConfig { @@ -144,8 +169,51 @@ func IgnoreAdditionsByScope(additions []gitrepo.Addition, rcConfigIgnores Talism } return result } + +func (rcConfigIgnores *TalismanRCIgnore) AddFileIgnores(entriesToAdd []FileIgnoreConfig) { + if len(entriesToAdd) > 0 { + logr.Debugf("Adding entries: %v", entriesToAdd) + talismanRcIgnoreConfig := Get() + talismanRcIgnoreConfig.FileIgnoreConfig = combineFileIgnores(talismanRcIgnoreConfig.FileIgnoreConfig, entriesToAdd) + ignoreEntries, _ := yaml.Marshal(&talismanRcIgnoreConfig) + file, err := fs.OpenFile(currentRCFileName, os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + log.Printf("error opening %s: %s", currentRCFileName, err) + } + defer func() { + err := file.Close() + if err != nil { + log.Printf("error closing %s: %s", currentRCFileName, err) + } + + }() + logr.Debugf("Writing talismanrc: %v", string(ignoreEntries)) + _, err = file.WriteString(string(ignoreEntries)) + if err != nil { + log.Printf("error writing to %s: %s", currentRCFileName, err) + } + } +} + +func combineFileIgnores(exsiting, incoming []FileIgnoreConfig) []FileIgnoreConfig { + existingMap := make(map[string]FileIgnoreConfig) + for _, fIC := range exsiting { + existingMap[fIC.FileName] = fIC + } + for _, fIC := range incoming { + existingMap[fIC.FileName] = fIC + } + result := make([]FileIgnoreConfig, len(existingMap)) + index := 0 + for _, fIC := range existingMap { + result[index] = fIC + index++ + } + return result +} + //Deny answers true if the Addition.Path is configured to be ignored and not checked by the detectors -func (i TalismanRCIgnore) Deny(addition gitrepo.Addition, detectorName string) bool { +func (i *TalismanRCIgnore) Deny(addition gitrepo.Addition, detectorName string) bool { result := false for _, pattern := range i.effectiveRules(detectorName) { result = result || addition.Matches(pattern) @@ -153,7 +221,7 @@ func (i TalismanRCIgnore) Deny(addition gitrepo.Addition, detectorName string) b return result } -func (i TalismanRCIgnore) effectiveRules(detectorName string) []string { +func (i *TalismanRCIgnore) effectiveRules(detectorName string) []string { var result []string for _, ignore := range i.FileIgnoreConfig { if ignore.isEffective(detectorName) { diff --git a/detector/ignores_test.go b/talismanrc/talismanrc_test.go similarity index 72% rename from detector/ignores_test.go rename to talismanrc/talismanrc_test.go index 7d1970a7..27b0a83f 100644 --- a/detector/ignores_test.go +++ b/talismanrc/talismanrc_test.go @@ -1,4 +1,4 @@ -package detector +package talismanrc import ( "testing" @@ -38,33 +38,6 @@ func TestShouldParseIgnoreLinesProperly(t *testing.T) { } -//Need to work on this test case as it deals with matching file names throughout directories and sub directories which talismanrc does not yet support -// func TestRawPatterns(t *testing.T) { -// assertAccepts("foo", "", "bar", t) -// assertAccepts("foo", "", "foobar", t) -// assertAccepts("foo", "", "foo/bar", t) -// assertAccepts("foo", "", "foo/bar/baz", t) - -// assertDenies("foo", "", "foo", t) -// assertDenies("foo", "", "bar/foo", t) -// assertDenies("foo", "", "bar/baz/foo", t) -// } - -//Need to work on this test case as it deals with wildcards and talismanrc does not yet support wildcards -// func TestSingleStarPatterns(t *testing.T) { -// assertAccepts("foo*", "", "bar", t) -// assertAccepts("foo*", "", "foo/bar", t) -// assertAccepts("foo*", "", "foo/bar/baz", t) - -// assertDenies("foo*", "", "foo", t) -// assertDenies("foo*", "", "foobar", t) - -// assertAccepts("*.pem", "", "foo.txt", t) -// assertAccepts("*.pem", "", "pem.go", t) -// assertDenies("*.pem", "", "secret.pem", t) -// assertDenies("*.pem", "", "foo/bar/secret.pem", t) -// } - func TestDirectoryPatterns(t *testing.T) { assertAccepts("foo/", "", "bar", t) assertAccepts("foo/", "", "foo", t) @@ -87,9 +60,9 @@ func TestIgnoreAdditionsByScope(t *testing.T) { nodeIgnores := []string{"node.lock", "*yarn.lock"} javaIgnores := []string{"java.lock"} goIgnores := []string{"go.lock", "Gopkg.lock", "vendors/"} - scopesMap := map[string] []string {"node": nodeIgnores, "java":javaIgnores, "go": goIgnores} + scopesMap := map[string][]string{"node": nodeIgnores, "java": javaIgnores, "go": goIgnores} - filteredAdditions := IgnoreAdditionsByScope(additions, talismanRCIgnoreConfig, scopesMap); + filteredAdditions := talismanRCIgnoreConfig.IgnoreAdditionsByScope(additions, scopesMap) assert.NotContains(t, filteredAdditions, file1) assert.NotContains(t, filteredAdditions, file2) @@ -98,18 +71,6 @@ func TestIgnoreAdditionsByScope(t *testing.T) { assert.NotContains(t, filteredAdditions, file5) } -//Need to work on this test case as it deals with comments and talismanrc does not deal in comments -//func TestCommentPatterns(t *testing.T) { -// assertAccepts("foo # some comment", "bar", t) -// assertDenies("foo # some comment", "foo", t) -// -// assertDenies("foo* # comment", "foo", t) -// assertAccepts("foo* # comment", "bar", t) -// -// assertAccepts("foo/ # comment", "bar", t) -// assertDenies("foo/ # comment", "foo/bar", t) -//} - func TestIgnoringDetectors(t *testing.T) { assertDeniesDetector("foo", "someDetector", "foo", "someDetector", t) assertAcceptsDetector("foo", "someDetector", "foo", "someOtherDetector", t) @@ -135,7 +96,7 @@ func testAddition(path string) gitrepo.Addition { return gitrepo.NewAddition(path, make([]byte, 0)) } -func CreateTalismanRCIgnoreWithFileName(filename string, detector string) TalismanRCIgnore { +func CreateTalismanRCIgnoreWithFileName(filename string, detector string) *TalismanRCIgnore { fileIgnoreConfig := FileIgnoreConfig{} fileIgnoreConfig.FileName = filename if detector != "" { @@ -145,10 +106,10 @@ func CreateTalismanRCIgnoreWithFileName(filename string, detector string) Talism talismanRCIgnore := TalismanRCIgnore{} talismanRCIgnore.FileIgnoreConfig = make([]FileIgnoreConfig, 1) talismanRCIgnore.FileIgnoreConfig[0] = fileIgnoreConfig - return talismanRCIgnore + return &talismanRCIgnore } -func CreateTalismanRCIgnoreWithScopeIgnore(scopesToIgnore []string) TalismanRCIgnore { +func CreateTalismanRCIgnoreWithScopeIgnore(scopesToIgnore []string) *TalismanRCIgnore { var scopeConfigs []ScopeConfig for _, scopeIgnore := range scopesToIgnore { scopeIgnoreConfig := ScopeConfig{} @@ -156,8 +117,8 @@ func CreateTalismanRCIgnoreWithScopeIgnore(scopesToIgnore []string) TalismanRCIg scopeConfigs = append(scopeConfigs, scopeIgnoreConfig) } - talismanRCIgnore := TalismanRCIgnore{ ScopeConfig: scopeConfigs} - return talismanRCIgnore + talismanRCIgnore := TalismanRCIgnore{ScopeConfig: scopeConfigs} + return &talismanRCIgnore } func SingleIgnore(pattern string, comment string, ignoredDetectors ...string) Ignores {