@@ -145,7 +145,7 @@ func handleTrivyResult(err error, imageName string) {
145145 os .Exit (1 )
146146}
147147
148- func runContainerScan (cmd * cobra.Command , args []string ) {
148+ func runContainerScan (_ * cobra.Command , args []string ) {
149149 var images []string
150150
151151 if len (args ) > 0 {
@@ -217,62 +217,69 @@ func handleScanError(err error, imageName string) {
217217 color .Red ("❌ Error scanning %s: %v" , imageName , err )
218218}
219219
220+ // printFoundImages displays the found images to the user
221+ func printFoundImages (source string , images []string ) {
222+ color .Cyan ("📄 Found images in %s:" , source )
223+ for _ , img := range images {
224+ fmt .Printf (" • %s\n " , img )
225+ }
226+ fmt .Println ()
227+ }
228+
220229// detectImages auto-detects images from Dockerfile or docker-compose.yml
221230func detectImages () []string {
222231 // Priority 0: Check explicit --dockerfile flag
223232 if dockerfileFlag != "" {
224- if images := parseDockerfile (dockerfileFlag ); len (images ) > 0 {
225- color .Cyan ("📄 Found images in %s:" , dockerfileFlag )
226- for _ , img := range images {
227- fmt .Printf (" • %s\n " , img )
228- }
229- fmt .Println ()
230- return images
231- }
232- color .Yellow ("⚠️ No FROM instructions found in %s" , dockerfileFlag )
233- return nil
233+ return detectFromDockerfile (dockerfileFlag , true )
234234 }
235235
236236 // Priority 0: Check explicit --compose-file flag
237237 if composeFileFlag != "" {
238- if images := parseDockerCompose (composeFileFlag ); len (images ) > 0 {
239- color .Cyan ("📄 Found images in %s:" , composeFileFlag )
240- for _ , img := range images {
241- fmt .Printf (" • %s\n " , img )
242- }
243- fmt .Println ()
244- return images
245- }
246- color .Yellow ("⚠️ No images found in %s" , composeFileFlag )
247- return nil
238+ return detectFromCompose (composeFileFlag , true )
248239 }
249240
250241 // Priority 1: Auto-detect Dockerfile in current directory
251- if images := parseDockerfile ("Dockerfile" ); len (images ) > 0 {
252- color .Cyan ("📄 Found images in Dockerfile:" )
253- for _ , img := range images {
254- fmt .Printf (" • %s\n " , img )
255- }
256- fmt .Println ()
242+ if images := detectFromDockerfile ("Dockerfile" , false ); images != nil {
257243 return images
258244 }
259245
260246 // Priority 2: Auto-detect docker-compose files
261247 composeFiles := []string {"docker-compose.yml" , "docker-compose.yaml" , "compose.yml" , "compose.yaml" }
262248 for _ , composeFile := range composeFiles {
263- if images := parseDockerCompose (composeFile ); len (images ) > 0 {
264- color .Cyan ("📄 Found images in %s:" , composeFile )
265- for _ , img := range images {
266- fmt .Printf (" • %s\n " , img )
267- }
268- fmt .Println ()
249+ if images := detectFromCompose (composeFile , false ); images != nil {
269250 return images
270251 }
271252 }
272253
273254 return nil
274255}
275256
257+ // detectFromDockerfile tries to detect images from a Dockerfile
258+ func detectFromDockerfile (path string , showWarning bool ) []string {
259+ images := parseDockerfile (path )
260+ if len (images ) > 0 {
261+ printFoundImages (path , images )
262+ return images
263+ }
264+ if showWarning {
265+ color .Yellow ("⚠️ No FROM instructions found in %s" , path )
266+ }
267+ return nil
268+ }
269+
270+ // detectFromCompose tries to detect images from a docker-compose file
271+ func detectFromCompose (path string , showWarning bool ) []string {
272+ images := parseDockerCompose (path )
273+ if len (images ) > 0 {
274+ printFoundImages (path , images )
275+ return images
276+ }
277+ if showWarning {
278+ color .Yellow ("⚠️ No images found in %s" , path )
279+ }
280+ return nil
281+ }
282+
276283// parseDockerfile extracts FROM images from a Dockerfile
277284func parseDockerfile (path string ) []string {
278285 file , err := os .Open (path )
@@ -330,41 +337,60 @@ func parseDockerCompose(path string) []string {
330337 seen := make (map [string ]bool )
331338
332339 for serviceName , service := range config .Services {
333- // If service has an image defined, use it
334- if service .Image != "" && ! seen [service .Image ] {
335- seen [service .Image ] = true
336- images = append (images , service .Image )
337- }
340+ images = processServiceImage (service .Image , images , seen )
341+ images = processServiceBuild (serviceName , service .Build , images , seen )
342+ }
338343
339- // If service has a build context with Dockerfile, parse it
340- if service .Build != nil {
341- dockerfilePath := "Dockerfile"
342- if service .Build .Dockerfile != "" {
343- dockerfilePath = service .Build .Dockerfile
344- }
345- if service .Build .Context != "" {
346- dockerfilePath = filepath .Join (service .Build .Context , dockerfilePath )
347- }
344+ return images
345+ }
348346
349- if dockerfileImages := parseDockerfile (dockerfilePath ); len (dockerfileImages ) > 0 {
350- for _ , img := range dockerfileImages {
351- if ! seen [img ] {
352- seen [img ] = true
353- images = append (images , img )
354- logger .Info ("Found base image from Dockerfile" , logrus.Fields {
355- "service" : serviceName ,
356- "dockerfile" : dockerfilePath ,
357- "image" : img ,
358- })
359- }
360- }
361- }
362- }
347+ // processServiceImage adds a service's image to the list if not already seen
348+ func processServiceImage (image string , images []string , seen map [string ]bool ) []string {
349+ if image != "" && ! seen [image ] {
350+ seen [image ] = true
351+ images = append (images , image )
352+ }
353+ return images
354+ }
355+
356+ // processServiceBuild extracts images from a service's build context Dockerfile
357+ func processServiceBuild (serviceName string , build * struct {
358+ Context string `yaml:"context"`
359+ Dockerfile string `yaml:"dockerfile"`
360+ }, images []string , seen map [string ]bool ) []string {
361+ if build == nil {
362+ return images
363363 }
364364
365+ dockerfilePath := resolveDockerfilePath (build .Context , build .Dockerfile )
366+ dockerfileImages := parseDockerfile (dockerfilePath )
367+
368+ for _ , img := range dockerfileImages {
369+ if ! seen [img ] {
370+ seen [img ] = true
371+ images = append (images , img )
372+ logger .Info ("Found base image from Dockerfile" , logrus.Fields {
373+ "service" : serviceName ,
374+ "dockerfile" : dockerfilePath ,
375+ "image" : img ,
376+ })
377+ }
378+ }
365379 return images
366380}
367381
382+ // resolveDockerfilePath constructs the full path to a Dockerfile
383+ func resolveDockerfilePath (context , dockerfile string ) string {
384+ path := "Dockerfile"
385+ if dockerfile != "" {
386+ path = dockerfile
387+ }
388+ if context != "" {
389+ path = filepath .Join (context , path )
390+ }
391+ return path
392+ }
393+
368394// buildTrivyArgs constructs the Trivy command arguments based on flags
369395func buildTrivyArgs (imageName string ) []string {
370396 args := []string {
0 commit comments