@@ -22,41 +22,67 @@ import (
2222 "github.com/aquasecurity/trivy/pkg/log"
2323)
2424
25- func NewJsonScanner (opts ... options.ScannerOption ) * GenericScanner {
26- return NewScanner ("JSON" , types .SourceJSON , ParseFunc (parseJson ), opts ... )
25+ func NewJsonScanner (opts ... options.ScannerOption ) * GenericScanner [ * identityMarshaler ] {
26+ return NewScanner ("JSON" , types .SourceJSON , ParseFunc [ * identityMarshaler ] (parseJson ), opts ... )
2727}
2828
29- func NewYamlScanner (opts ... options.ScannerOption ) * GenericScanner {
30- return NewScanner ("YAML" , types .SourceYAML , ParseFunc (parseYaml ), opts ... )
29+ func NewYamlScanner (opts ... options.ScannerOption ) * GenericScanner [ * identityMarshaler ] {
30+ return NewScanner ("YAML" , types .SourceYAML , ParseFunc [ * identityMarshaler ] (parseYaml ), opts ... )
3131}
3232
33- func NewTomlScanner (opts ... options.ScannerOption ) * GenericScanner {
34- return NewScanner ("TOML" , types .SourceTOML , ParseFunc (parseTOML ), opts ... )
33+ func NewTomlScanner (opts ... options.ScannerOption ) * GenericScanner [ * identityMarshaler ] {
34+ return NewScanner ("TOML" , types .SourceTOML , ParseFunc [ * identityMarshaler ] (parseTOML ), opts ... )
3535}
3636
37- type configParser interface {
38- Parse (ctx context.Context , r io.Reader , path string ) (any , error )
37+ type RegoMarshaler interface {
38+ ToRego () any
39+ }
40+
41+ type identityMarshaler struct {
42+ value any
43+ }
44+
45+ func (r identityMarshaler ) ToRego () any {
46+ return r .value
47+ }
48+
49+ type configParser [T RegoMarshaler ] interface {
50+ Parse (ctx context.Context , r io.Reader , path string ) ([]T , error )
51+ }
52+
53+ type ParseFunc [T RegoMarshaler ] func (ctx context.Context , r io.Reader , path string ) ([]T , error )
54+
55+ func (f ParseFunc [T ]) Parse (ctx context.Context , r io.Reader , path string ) ([]T , error ) {
56+ return f (ctx , r , path )
57+ }
58+
59+ func WithSupportsInlineIgnore [T RegoMarshaler ](supports bool ) options.ScannerOption {
60+ return func (s options.ConfigurableScanner ) {
61+ if ss , ok := s .(* GenericScanner [T ]); ok {
62+ ss .supportsInlineIgnore = supports
63+ }
64+ }
3965}
4066
4167// GenericScanner is a scanner that scans a file as is without processing it
42- type GenericScanner struct {
68+ type GenericScanner [ T RegoMarshaler ] struct {
4369 * rego.RegoScannerProvider
4470 name string
4571 source types.Source
4672 logger * log.Logger
4773 options []options.ScannerOption
4874
49- parser configParser
75+ parser configParser [T ]
76+ supportsInlineIgnore bool
5077}
5178
52- type ParseFunc func (ctx context.Context , r io.Reader , path string ) (any , error )
53-
54- func (f ParseFunc ) Parse (ctx context.Context , r io.Reader , path string ) (any , error ) {
55- return f (ctx , r , path )
56- }
57-
58- func NewScanner (name string , source types.Source , parser configParser , opts ... options.ScannerOption ) * GenericScanner {
59- s := & GenericScanner {
79+ func NewScanner [T RegoMarshaler ](
80+ name string ,
81+ source types.Source ,
82+ parser configParser [T ],
83+ opts ... options.ScannerOption ,
84+ ) * GenericScanner [T ] {
85+ s := & GenericScanner [T ]{
6086 RegoScannerProvider : rego .NewRegoScannerProvider (opts ... ),
6187 name : name ,
6288 options : opts ,
@@ -72,41 +98,26 @@ func NewScanner(name string, source types.Source, parser configParser, opts ...o
7298 return s
7399}
74100
75- func (s * GenericScanner ) Name () string {
101+ func (s * GenericScanner [ T ] ) Name () string {
76102 return s .name
77103}
78104
79- func (s * GenericScanner ) ScanFS (ctx context.Context , fsys fs.FS , dir string ) (scan.Results , error ) {
80- fileset , err := s .parseFS (ctx , fsys , dir )
105+ func (s * GenericScanner [ T ] ) ScanFS (ctx context.Context , fsys fs.FS , rootDir string ) (scan.Results , error ) {
106+ fileMap , err := s .parseFS (ctx , fsys , rootDir )
81107 if err != nil {
82108 return nil , err
83109 }
84110
85- if len (fileset ) == 0 {
111+ if len (fileMap ) == 0 {
86112 return nil , nil
87113 }
88114
89115 var inputs []rego.Input
90- for path , val := range fileset {
91- switch v := val .(type ) {
92- case interface { ToRego () any }:
116+ for filePath , parsedObjects := range fileMap {
117+ for _ , parsedObj := range parsedObjects {
93118 inputs = append (inputs , rego.Input {
94- Path : path ,
95- Contents : v .ToRego (),
96- FS : fsys ,
97- })
98- case []any :
99- for _ , file := range v {
100- inputs = append (inputs , rego.Input {
101- Path : path ,
102- Contents : file ,
103- FS : fsys ,
104- })
105- }
106- default :
107- inputs = append (inputs , rego.Input {
108- Path : path ,
109- Contents : v ,
119+ Path : filePath ,
120+ Contents : parsedObj .ToRego (),
110121 FS : fsys ,
111122 })
112123 }
@@ -131,13 +142,9 @@ func (s *GenericScanner) ScanFS(ctx context.Context, fsys fs.FS, dir string) (sc
131142 return results , nil
132143}
133144
134- func (s * GenericScanner ) supportsIgnoreRules () bool {
135- return s .source == types .SourceDockerfile
136- }
137-
138- func (s * GenericScanner ) parseFS (ctx context.Context , fsys fs.FS , path string ) (map [string ]any , error ) {
139- files := make (map [string ]any )
140- if err := fs .WalkDir (fsys , filepath .ToSlash (path ), func (path string , entry fs.DirEntry , err error ) error {
145+ func (s * GenericScanner [T ]) parseFS (ctx context.Context , fsys fs.FS , rootDir string ) (map [string ][]T , error ) {
146+ parsedFiles := make (map [string ][]T )
147+ walkFn := func (filePath string , entry fs.DirEntry , err error ) error {
141148 select {
142149 case <- ctx .Done ():
143150 return ctx .Err ()
@@ -150,27 +157,29 @@ func (s *GenericScanner) parseFS(ctx context.Context, fsys fs.FS, path string) (
150157 return nil
151158 }
152159
153- f , err := fsys .Open (filepath .ToSlash (path ))
160+ f , err := fsys .Open (filepath .ToSlash (filePath ))
154161 if err != nil {
155162 return err
156163 }
157164 defer f .Close ()
158165
159- df , err := s .parser .Parse (ctx , f , path )
166+ parsedObjects , err := s .parser .Parse (ctx , f , filePath )
160167 if err != nil {
161- s .logger .Error ("Failed to parse file" , log .FilePath (path ), log .Err (err ))
168+ s .logger .Error ("Failed to parse file" , log .FilePath (filePath ), log .Err (err ))
162169 return nil
163170 }
164- files [ path ] = df
171+ parsedFiles [ filePath ] = parsedObjects
165172 return nil
166- }); err != nil {
173+ }
174+
175+ if err := fs .WalkDir (fsys , filepath .ToSlash (rootDir ), walkFn ); err != nil {
167176 return nil , err
168177 }
169- return files , nil
178+ return parsedFiles , nil
170179}
171180
172- func (s * GenericScanner ) applyIgnoreRules (fsys fs.FS , results scan.Results ) error {
173- if ! s .supportsIgnoreRules () {
181+ func (s * GenericScanner [ T ] ) applyIgnoreRules (fsys fs.FS , results scan.Results ) error {
182+ if ! s .supportsInlineIgnore {
174183 return nil
175184 }
176185
@@ -190,21 +199,21 @@ func (s *GenericScanner) applyIgnoreRules(fsys fs.FS, results scan.Results) erro
190199 return nil
191200}
192201
193- func parseJson (_ context.Context , r io.Reader , _ string ) (any , error ) {
202+ func parseJson (_ context.Context , r io.Reader , _ string ) ([] * identityMarshaler , error ) {
194203 var target any
195204 if err := json .NewDecoder (r ).Decode (& target ); err != nil {
196205 return nil , err
197206 }
198- return target , nil
207+ return [] * identityMarshaler {{ value : target }} , nil
199208}
200209
201- func parseYaml (_ context.Context , r io.Reader , _ string ) (any , error ) {
210+ func parseYaml (_ context.Context , r io.Reader , _ string ) ([] * identityMarshaler , error ) {
202211 contents , err := io .ReadAll (r )
203212 if err != nil {
204213 return nil , err
205214 }
206215
207- var results []any
216+ var documents []* identityMarshaler
208217
209218 marker := "\n ---\n "
210219 altMarker := "\r \n ---\r \n "
@@ -217,16 +226,16 @@ func parseYaml(_ context.Context, r io.Reader, _ string) (any, error) {
217226 if err := yaml .Unmarshal ([]byte (partial ), & target ); err != nil {
218227 return nil , err
219228 }
220- results = append (results , target )
229+ documents = append (documents , & identityMarshaler { target } )
221230 }
222231
223- return results , nil
232+ return documents , nil
224233}
225234
226- func parseTOML (_ context.Context , r io.Reader , _ string ) (any , error ) {
235+ func parseTOML (_ context.Context , r io.Reader , _ string ) ([] * identityMarshaler , error ) {
227236 var target any
228237 if _ , err := toml .NewDecoder (r ).Decode (& target ); err != nil {
229238 return nil , err
230239 }
231- return target , nil
240+ return [] * identityMarshaler {{ value : target }} , nil
232241}
0 commit comments