@@ -57,24 +57,25 @@ func NewScanner(a applier.Applier, osPkgScanner ospkg.Scanner, langPkgScanner la
57
57
}
58
58
59
59
// Scan scans the artifact and return results.
60
- func (s Scanner ) Scan (ctx context.Context , target , artifactKey string , blobKeys []string , options types.ScanOptions ) (types.Results , ftypes.OS , error ) {
61
- artifactDetail , err := s .applier .ApplyLayers (artifactKey , blobKeys )
60
+ func (s Scanner ) Scan (ctx context.Context , targetName , artifactKey string , blobKeys []string , options types.ScanOptions ) (
61
+ types.Results , ftypes.OS , error ) {
62
+ detail , err := s .applier .ApplyLayers (artifactKey , blobKeys )
62
63
switch {
63
64
case errors .Is (err , analyzer .ErrUnknownOS ):
64
65
log .Logger .Debug ("OS is not detected." )
65
66
66
67
// Packages may contain OS-independent binary information even though OS is not detected.
67
- if len (artifactDetail .Packages ) != 0 {
68
- artifactDetail .OS = ftypes.OS {Family : "none" }
68
+ if len (detail .Packages ) != 0 {
69
+ detail .OS = ftypes.OS {Family : "none" }
69
70
}
70
71
71
72
// If OS is not detected and repositories are detected, we'll try to use repositories as OS.
72
- if artifactDetail .Repository != nil {
73
- log .Logger .Debugf ("Package repository: %s %s" , artifactDetail .Repository .Family , artifactDetail .Repository .Release )
74
- log .Logger .Debugf ("Assuming OS is %s %s." , artifactDetail .Repository .Family , artifactDetail .Repository .Release )
75
- artifactDetail .OS = ftypes.OS {
76
- Family : artifactDetail .Repository .Family ,
77
- Name : artifactDetail .Repository .Release ,
73
+ if detail .Repository != nil {
74
+ log .Logger .Debugf ("Package repository: %s %s" , detail .Repository .Family , detail .Repository .Release )
75
+ log .Logger .Debugf ("Assuming OS is %s %s." , detail .Repository .Family , detail .Repository .Release )
76
+ detail .OS = ftypes.OS {
77
+ Family : detail .Repository .Family ,
78
+ Name : detail .Repository .Release ,
78
79
}
79
80
}
80
81
case errors .Is (err , analyzer .ErrNoPkgsDetected ):
@@ -84,29 +85,46 @@ func (s Scanner) Scan(ctx context.Context, target, artifactKey string, blobKeys
84
85
return nil , ftypes.OS {}, xerrors .Errorf ("failed to apply layers: %w" , err )
85
86
}
86
87
88
+ target := types.ScanTarget {
89
+ Name : targetName ,
90
+ OS : detail .OS ,
91
+ Repository : detail .Repository ,
92
+ Packages : mergePkgs (detail .Packages , detail .ImageConfig .Packages , options ),
93
+ Applications : detail .Applications ,
94
+ Misconfigurations : mergeMisconfigurations (targetName , detail ),
95
+ Secrets : mergeSecrets (targetName , detail ),
96
+ Licenses : detail .Licenses ,
97
+ CustomResources : detail .CustomResources ,
98
+ }
99
+
100
+ return s .ScanTarget (ctx , target , options )
101
+ }
102
+
103
+ func (s Scanner ) ScanTarget (ctx context.Context , target types.ScanTarget , options types.ScanOptions ) (types.Results , ftypes.OS , error ) {
87
104
var eosl bool
88
105
var results , pkgResults types.Results
106
+ var err error
89
107
90
108
// By default, we need to remove dev dependencies from the result
91
109
// IncludeDevDeps option allows you not to remove them
92
- excludeDevDeps (artifactDetail .Applications , options .IncludeDevDeps )
110
+ excludeDevDeps (target .Applications , options .IncludeDevDeps )
93
111
94
112
// Fill OS packages and language-specific packages
95
113
if options .ListAllPackages {
96
- if res := s .osPkgScanner .Packages (target , artifactDetail , options ); len (res .Packages ) != 0 {
114
+ if res := s .osPkgScanner .Packages (target , options ); len (res .Packages ) != 0 {
97
115
pkgResults = append (pkgResults , res )
98
116
}
99
- pkgResults = append (pkgResults , s .langPkgScanner .Packages (artifactDetail , options )... )
117
+ pkgResults = append (pkgResults , s .langPkgScanner .Packages (target , options )... )
100
118
}
101
119
102
120
// Scan packages for vulnerabilities
103
121
if options .Scanners .Enabled (types .VulnerabilityScanner ) {
104
122
var vulnResults types.Results
105
- vulnResults , eosl , err = s .scanVulnerabilities (target , artifactDetail , options )
123
+ vulnResults , eosl , err = s .scanVulnerabilities (target , options )
106
124
if err != nil {
107
125
return nil , ftypes.OS {}, xerrors .Errorf ("failed to detect vulnerabilities: %w" , err )
108
126
}
109
- artifactDetail .OS .Eosl = eosl
127
+ target .OS .Eosl = eosl
110
128
111
129
// Merge package results into vulnerability results
112
130
mergedResults := s .fillPkgsInVulns (pkgResults , vulnResults )
@@ -117,45 +135,20 @@ func (s Scanner) Scan(ctx context.Context, target, artifactKey string, blobKeys
117
135
results = append (results , pkgResults ... )
118
136
}
119
137
120
- // Scan IaC config files
121
- if ShouldScanMisconfigOrRbac (options .Scanners ) {
122
- configResults := s .MisconfsToResults (artifactDetail .Misconfigurations )
123
- results = append (results , configResults ... )
124
- }
138
+ // Store misconfigurations
139
+ results = append (results , s .misconfsToResults (target .Misconfigurations , options )... )
125
140
126
- // Scan secrets
127
- if options .Scanners .Enabled (types .SecretScanner ) {
128
- secretResults := s .secretsToResults (artifactDetail .Secrets )
129
- results = append (results , secretResults ... )
130
- }
141
+ // Store secrets
142
+ results = append (results , s .secretsToResults (target .Secrets , options )... )
131
143
132
144
// Scan licenses
133
- if options .Scanners .Enabled (types .LicenseScanner ) {
134
- licenseResults := s .scanLicenses (artifactDetail , options .LicenseCategories )
135
- results = append (results , licenseResults ... )
136
- }
137
-
138
- // Scan misconfigurations on container image config
139
- if options .ImageConfigScanners .Enabled (types .MisconfigScanner ) {
140
- if im := artifactDetail .ImageConfig .Misconfiguration ; im != nil {
141
- im .FilePath = target // Set the target name to the file path as container image config is not a real file.
142
- results = append (results , s .MisconfsToResults ([]ftypes.Misconfiguration {* im })... )
143
- }
144
- }
145
-
146
- // Scan secrets on container image config
147
- if options .ImageConfigScanners .Enabled (types .SecretScanner ) {
148
- if is := artifactDetail .ImageConfig .Secret ; is != nil {
149
- is .FilePath = target // Set the target name to the file path as container image config is not a real file.
150
- results = append (results , s .secretsToResults ([]ftypes.Secret {* is })... )
151
- }
152
- }
145
+ results = append (results , s .scanLicenses (target , options )... )
153
146
154
147
// For WASM plugins and custom analyzers
155
- if len (artifactDetail .CustomResources ) != 0 {
148
+ if len (target .CustomResources ) != 0 {
156
149
results = append (results , types.Result {
157
150
Class : types .ClassCustom ,
158
- CustomResources : artifactDetail .CustomResources ,
151
+ CustomResources : target .CustomResources ,
159
152
})
160
153
}
161
154
@@ -170,16 +163,16 @@ func (s Scanner) Scan(ctx context.Context, target, artifactKey string, blobKeys
170
163
return nil , ftypes.OS {}, xerrors .Errorf ("post scan error: %w" , err )
171
164
}
172
165
173
- return results , artifactDetail .OS , nil
166
+ return results , target .OS , nil
174
167
}
175
168
176
- func (s Scanner ) scanVulnerabilities (target string , detail ftypes. ArtifactDetail , options types.ScanOptions ) (
169
+ func (s Scanner ) scanVulnerabilities (target types. ScanTarget , options types.ScanOptions ) (
177
170
types.Results , bool , error ) {
178
171
var eosl bool
179
172
var results types.Results
180
173
181
174
if slices .Contains (options .VulnType , types .VulnTypeOS ) {
182
- vuln , detectedEOSL , err := s .osPkgScanner .Scan (target , detail , options )
175
+ vuln , detectedEOSL , err := s .osPkgScanner .Scan (target , options )
183
176
if err != nil {
184
177
return nil , false , xerrors .Errorf ("unable to scan OS packages: %w" , err )
185
178
} else if vuln .Target != "" {
@@ -189,7 +182,7 @@ func (s Scanner) scanVulnerabilities(target string, detail ftypes.ArtifactDetail
189
182
}
190
183
191
184
if slices .Contains (options .VulnType , types .VulnTypeLibrary ) {
192
- vulns , err := s .langPkgScanner .Scan (detail , options )
185
+ vulns , err := s .langPkgScanner .Scan (target , options )
193
186
if err != nil {
194
187
return nil , false , xerrors .Errorf ("failed to scan application libraries: %w" , err )
195
188
}
@@ -217,6 +210,14 @@ func (s Scanner) fillPkgsInVulns(pkgResults, vulnResults types.Results) types.Re
217
210
return results
218
211
}
219
212
213
+ func (s Scanner ) misconfsToResults (misconfs []ftypes.Misconfiguration , options types.ScanOptions ) types.Results {
214
+ if ! ShouldScanMisconfigOrRbac (options .Scanners ) {
215
+ return nil
216
+ }
217
+
218
+ return s .MisconfsToResults (misconfs )
219
+ }
220
+
220
221
// MisconfsToResults is exported for trivy-plugin-aqua purposes only
221
222
func (s Scanner ) MisconfsToResults (misconfs []ftypes.Misconfiguration ) types.Results {
222
223
log .Logger .Infof ("Detected config files: %d" , len (misconfs ))
@@ -254,7 +255,11 @@ func (s Scanner) MisconfsToResults(misconfs []ftypes.Misconfiguration) types.Res
254
255
return results
255
256
}
256
257
257
- func (s Scanner ) secretsToResults (secrets []ftypes.Secret ) types.Results {
258
+ func (s Scanner ) secretsToResults (secrets []ftypes.Secret , options types.ScanOptions ) types.Results {
259
+ if ! options .Scanners .Enabled (types .SecretScanner ) {
260
+ return nil
261
+ }
262
+
258
263
var results types.Results
259
264
for _ , secret := range secrets {
260
265
log .Logger .Debugf ("Secret file: %s" , secret .FilePath )
@@ -268,15 +273,17 @@ func (s Scanner) secretsToResults(secrets []ftypes.Secret) types.Results {
268
273
return results
269
274
}
270
275
271
- func (s Scanner ) scanLicenses (detail ftypes.ArtifactDetail ,
272
- categories map [ftypes.LicenseCategory ][]string ) types.Results {
273
- scanner := licensing .NewScanner (categories )
276
+ func (s Scanner ) scanLicenses (target types.ScanTarget , options types.ScanOptions ) types.Results {
277
+ if ! options .Scanners .Enabled (types .LicenseScanner ) {
278
+ return nil
279
+ }
274
280
275
281
var results types.Results
282
+ scanner := licensing .NewScanner (options .LicenseCategories )
276
283
277
284
// License - OS packages
278
285
var osPkgLicenses []types.DetectedLicense
279
- for _ , pkg := range detail .Packages {
286
+ for _ , pkg := range target .Packages {
280
287
for _ , license := range pkg .Licenses {
281
288
category , severity := scanner .Scan (license )
282
289
osPkgLicenses = append (osPkgLicenses , types.DetectedLicense {
@@ -296,7 +303,7 @@ func (s Scanner) scanLicenses(detail ftypes.ArtifactDetail,
296
303
})
297
304
298
305
// License - language-specific packages
299
- for _ , app := range detail .Applications {
306
+ for _ , app := range target .Applications {
300
307
var langLicenses []types.DetectedLicense
301
308
for _ , lib := range app .Libraries {
302
309
for _ , license := range lib .Licenses {
@@ -311,21 +318,21 @@ func (s Scanner) scanLicenses(detail ftypes.ArtifactDetail,
311
318
}
312
319
}
313
320
314
- target := app .FilePath
315
- if t , ok := langpkg .PkgTargets [app .Type ]; ok && target == "" {
321
+ targetName := app .FilePath
322
+ if t , ok := langpkg .PkgTargets [app .Type ]; ok && targetName == "" {
316
323
// When the file path is empty, we will overwrite it with the pre-defined value.
317
- target = t
324
+ targetName = t
318
325
}
319
326
results = append (results , types.Result {
320
- Target : target ,
327
+ Target : targetName ,
321
328
Class : types .ClassLicense ,
322
329
Licenses : langLicenses ,
323
330
})
324
331
}
325
332
326
333
// License - file header or license file
327
334
var fileLicenses []types.DetectedLicense
328
- for _ , license := range detail .Licenses {
335
+ for _ , license := range target .Licenses {
329
336
for _ , finding := range license .Findings {
330
337
category , severity := scanner .Scan (finding .Name )
331
338
fileLicenses = append (fileLicenses , types.DetectedLicense {
@@ -420,3 +427,46 @@ func excludeDevDeps(apps []ftypes.Application, include bool) {
420
427
})
421
428
}
422
429
}
430
+
431
+ func mergePkgs (pkgs , pkgsFromCommands []ftypes.Package , options types.ScanOptions ) []ftypes.Package {
432
+ if ! options .ScanRemovedPackages || len (pkgsFromCommands ) == 0 {
433
+ return pkgs
434
+ }
435
+
436
+ // pkg has priority over pkgsFromCommands
437
+ uniqPkgs := make (map [string ]struct {})
438
+ for _ , pkg := range pkgs {
439
+ uniqPkgs [pkg .Name ] = struct {}{}
440
+ }
441
+ for _ , pkg := range pkgsFromCommands {
442
+ if _ , ok := uniqPkgs [pkg .Name ]; ok {
443
+ continue
444
+ }
445
+ pkgs = append (pkgs , pkg )
446
+ }
447
+ return pkgs
448
+ }
449
+
450
+ // mergeMisconfigurations merges misconfigurations on container image config
451
+ func mergeMisconfigurations (targetName string , detail ftypes.ArtifactDetail ) []ftypes.Misconfiguration {
452
+ if detail .ImageConfig .Misconfiguration == nil {
453
+ return detail .Misconfigurations
454
+ }
455
+
456
+ // Append misconfigurations on container image config
457
+ misconf := detail .ImageConfig .Misconfiguration
458
+ misconf .FilePath = targetName // Set the target name to the file path as container image config is not a real file.
459
+ return append (detail .Misconfigurations , * misconf )
460
+ }
461
+
462
+ // mergeSecrets merges secrets on container image config.
463
+ func mergeSecrets (targetName string , detail ftypes.ArtifactDetail ) []ftypes.Secret {
464
+ if detail .ImageConfig .Secret == nil {
465
+ return detail .Secrets
466
+ }
467
+
468
+ // Append secrets on container image config
469
+ secret := detail .ImageConfig .Secret
470
+ secret .FilePath = targetName // Set the target name to the file path as container image config is not a real file.
471
+ return append (detail .Secrets , * secret )
472
+ }
0 commit comments