github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/fanal/analyzer/secret/secret_test.go (about) 1 package secret_test 2 3 import ( 4 "context" 5 "os" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 11 "github.com/devseccon/trivy/pkg/fanal/analyzer" 12 "github.com/devseccon/trivy/pkg/fanal/analyzer/secret" 13 "github.com/devseccon/trivy/pkg/fanal/types" 14 ) 15 16 func TestSecretAnalyzer(t *testing.T) { 17 wantFinding1 := types.SecretFinding{ 18 RuleID: "rule1", 19 Category: "general", 20 Title: "Generic Rule", 21 Severity: "HIGH", 22 StartLine: 2, 23 EndLine: 2, 24 Match: "generic secret line secret=\"*********\"", 25 Code: types.Code{ 26 Lines: []types.Line{ 27 { 28 Number: 1, 29 Content: "--- ignore block start ---", 30 IsCause: false, 31 Annotation: "", 32 Truncated: false, 33 Highlighted: "--- ignore block start ---", 34 FirstCause: false, 35 LastCause: false, 36 }, 37 { 38 Number: 2, 39 Content: "generic secret line secret=\"*********\"", 40 IsCause: true, 41 Annotation: "", 42 Truncated: false, 43 Highlighted: "generic secret line secret=\"*********\"", 44 FirstCause: true, 45 LastCause: true, 46 }, 47 { 48 Number: 3, 49 Content: "--- ignore block stop ---", 50 IsCause: false, 51 Annotation: "", 52 Truncated: false, 53 Highlighted: "--- ignore block stop ---", 54 FirstCause: false, 55 LastCause: false, 56 }, 57 }, 58 }, 59 } 60 wantFinding2 := types.SecretFinding{ 61 RuleID: "rule1", 62 Category: "general", 63 Title: "Generic Rule", 64 Severity: "HIGH", 65 StartLine: 4, 66 EndLine: 4, 67 Match: "secret=\"**********\"", 68 Code: types.Code{ 69 Lines: []types.Line{ 70 { 71 Number: 2, 72 Content: "generic secret line secret=\"*********\"", 73 IsCause: false, 74 Highlighted: "generic secret line secret=\"*********\"", 75 }, 76 { 77 Number: 3, 78 Content: "--- ignore block stop ---", 79 IsCause: false, 80 Highlighted: "--- ignore block stop ---", 81 }, 82 { 83 Number: 4, 84 Content: "secret=\"**********\"", 85 IsCause: true, 86 Highlighted: "secret=\"**********\"", 87 FirstCause: true, 88 LastCause: true, 89 }, 90 { 91 Number: 5, 92 Content: "credentials: { user: \"username\" password: \"123456789\" }", 93 Highlighted: "credentials: { user: \"username\" password: \"123456789\" }", 94 }, 95 }, 96 }, 97 } 98 tests := []struct { 99 name string 100 configPath string 101 filePath string 102 dir string 103 want *analyzer.AnalysisResult 104 }{ 105 { 106 name: "return results", 107 configPath: "testdata/config.yaml", 108 filePath: "testdata/secret.txt", 109 dir: ".", 110 want: &analyzer.AnalysisResult{ 111 Secrets: []types.Secret{ 112 { 113 FilePath: "testdata/secret.txt", 114 Findings: []types.SecretFinding{wantFinding1, wantFinding2}, 115 }, 116 }, 117 }, 118 }, 119 { 120 name: "image scan return result", 121 configPath: "testdata/image-config.yaml", 122 filePath: "testdata/secret.txt", 123 want: &analyzer.AnalysisResult{ 124 Secrets: []types.Secret{ 125 { 126 FilePath: "/testdata/secret.txt", 127 Findings: []types.SecretFinding{wantFinding1, wantFinding2}, 128 }, 129 }, 130 }, 131 }, 132 { 133 name: "image scan return nil", 134 configPath: "testdata/image-config.yaml", 135 filePath: "testdata/secret.doc", 136 want: nil, 137 }, 138 { 139 name: "return nil when no results", 140 configPath: "", 141 filePath: "testdata/secret.txt", 142 want: nil, 143 }, 144 { 145 name: "skip binary file", 146 configPath: "", 147 filePath: "testdata/binaryfile", 148 want: nil, 149 }, 150 } 151 152 for _, tt := range tests { 153 t.Run(tt.name, func(t *testing.T) { 154 a := &secret.SecretAnalyzer{} 155 err := a.Init(analyzer.AnalyzerOptions{ 156 SecretScannerOption: analyzer.SecretScannerOption{ConfigPath: tt.configPath}, 157 }) 158 require.NoError(t, err) 159 content, err := os.Open(tt.filePath) 160 require.NoError(t, err) 161 fi, err := content.Stat() 162 require.NoError(t, err) 163 164 got, err := a.Analyze(context.TODO(), analyzer.AnalysisInput{ 165 FilePath: tt.filePath, 166 Dir: tt.dir, 167 Content: content, 168 Info: fi, 169 }) 170 171 require.NoError(t, err) 172 assert.Equal(t, tt.want, got) 173 }) 174 } 175 } 176 177 func TestSecretRequire(t *testing.T) { 178 tests := []struct { 179 name string 180 filePath string 181 want bool 182 }{ 183 { 184 name: "pass regular file", 185 filePath: "testdata/secret.txt", 186 want: true, 187 }, 188 { 189 name: "skip small file", 190 filePath: "testdata/emptyfile", 191 want: false, 192 }, 193 { 194 name: "skip folder", 195 filePath: "testdata/node_modules/secret.txt", 196 want: false, 197 }, 198 { 199 name: "skip file", 200 filePath: "testdata/package-lock.json", 201 want: false, 202 }, 203 { 204 name: "skip extension", 205 filePath: "testdata/secret.doc", 206 want: false, 207 }, 208 } 209 210 for _, tt := range tests { 211 t.Run(tt.name, func(t *testing.T) { 212 a := secret.SecretAnalyzer{} 213 err := a.Init(analyzer.AnalyzerOptions{ 214 SecretScannerOption: analyzer.SecretScannerOption{ 215 ConfigPath: "testdata/skip-tests-config.yaml", 216 }, 217 }) 218 require.NoError(t, err) 219 220 fi, err := os.Stat(tt.filePath) 221 require.NoError(t, err) 222 223 got := a.Required(tt.filePath, fi) 224 assert.Equal(t, tt.want, got) 225 }) 226 } 227 }