@@ -34,27 +34,30 @@ func init() {
3434}
3535
3636var containerScanCmd = & cobra.Command {
37- Use : "container-scan [FLAGS] <IMAGE_NAME>" ,
37+ Use : "container-scan [FLAGS] <IMAGE_NAME> [IMAGE_NAME...] " ,
3838 Short : "Scan container images for vulnerabilities using Trivy" ,
39- Long : `Scan container images for vulnerabilities using Trivy.
39+ Long : `Scan one or more container images for vulnerabilities using Trivy.
4040
4141By default, scans for HIGH and CRITICAL vulnerabilities in OS packages,
4242ignoring unfixed issues. Use flags to override these defaults.
4343
4444The --exit-code 1 flag is always applied (not user-configurable) to ensure
45- the command fails when vulnerabilities are found.` ,
46- Example : ` # Default behavior (HIGH,CRITICAL severity, os packages only)
45+ the command fails when vulnerabilities are found in any image .` ,
46+ Example : ` # Scan a single image
4747 codacy-cli container-scan myapp:latest
4848
49- # Scan only for CRITICAL vulnerabilities
50- codacy-cli container-scan --severity CRITICAL myapp:latest
49+ # Scan multiple images
50+ codacy-cli container-scan myapp:latest nginx:alpine redis:7
51+
52+ # Scan only for CRITICAL vulnerabilities across multiple images
53+ codacy-cli container-scan --severity CRITICAL myapp:latest nginx:alpine
5154
5255 # Scan all severities and package types
5356 codacy-cli container-scan --severity LOW,MEDIUM,HIGH,CRITICAL --pkg-types os,library myapp:latest
5457
5558 # Include unfixed vulnerabilities
5659 codacy-cli container-scan --ignore-unfixed=false myapp:latest` ,
57- Args : cobra .ExactArgs (1 ),
60+ Args : cobra .MinimumNArgs (1 ),
5861 Run : runContainerScan ,
5962}
6063
@@ -100,49 +103,61 @@ func getTrivyPath() string {
100103 return trivyPath
101104}
102105
103- // handleTrivyResult processes the Trivy command result and exits appropriately
104- func handleTrivyResult (err error , imageName string ) {
105- if err == nil {
106- logger .Info ("Container scan completed successfully" , logrus.Fields {"image" : imageName })
107- fmt .Println ()
108- color .Green ("✅ Success: No vulnerabilities found matching the specified criteria" )
109- return
106+ func runContainerScan (cmd * cobra.Command , args []string ) {
107+ imageNames := args
108+
109+ // Validate all image names first
110+ for _ , imageName := range imageNames {
111+ if err := validateImageName (imageName ); err != nil {
112+ logger .Error ("Invalid image name" , logrus.Fields {"image" : imageName , "error" : err .Error ()})
113+ color .Red ("❌ Error: %v" , err )
114+ os .Exit (1 )
115+ }
110116 }
111117
112- if exitError , ok := err .(* exec.ExitError ); ok && exitError .ExitCode () == 1 {
113- logger .Warn ("Container scan completed with vulnerabilities" , logrus.Fields {
114- "image" : imageName , "exit_code" : 1 ,
115- })
116- fmt .Println ()
117- color .Red ("❌ Scanning failed: vulnerabilities found in the container image" )
118- os .Exit (1 )
119- }
118+ logger .Info ("Starting container scan" , logrus.Fields {"images" : imageNames , "count" : len (imageNames )})
120119
121- logger .Error ("Failed to run Trivy" , logrus.Fields {"error" : err .Error ()})
122- color .Red ("❌ Error: Failed to run Trivy: %v" , err )
123- os .Exit (1 )
124- }
120+ trivyPath := getTrivyPath ()
121+ hasVulnerabilities := false
122+
123+ for i , imageName := range imageNames {
124+ if len (imageNames ) > 1 {
125+ fmt .Printf ("\n 📦 [%d/%d] Scanning image: %s\n " , i + 1 , len (imageNames ), imageName )
126+ fmt .Println (strings .Repeat ("-" , 50 ))
127+ } else {
128+ fmt .Printf ("🔍 Scanning container image: %s\n \n " , imageName )
129+ }
125130
126- func runContainerScan (cmd * cobra.Command , args []string ) {
127- imageName := args [0 ]
131+ trivyCmd := exec .Command (trivyPath , buildTrivyArgs (imageName )... )
132+ trivyCmd .Stdout = os .Stdout
133+ trivyCmd .Stderr = os .Stderr
134+
135+ logger .Info ("Running Trivy container scan" , logrus.Fields {"command" : trivyCmd .String ()})
136+
137+ if err := trivyCmd .Run (); err != nil {
138+ if exitError , ok := err .(* exec.ExitError ); ok && exitError .ExitCode () == 1 {
139+ logger .Warn ("Vulnerabilities found in image" , logrus.Fields {"image" : imageName })
140+ hasVulnerabilities = true
141+ } else {
142+ logger .Error ("Failed to run Trivy" , logrus.Fields {"error" : err .Error (), "image" : imageName })
143+ color .Red ("❌ Error: Failed to run Trivy for %s: %v" , imageName , err )
144+ os .Exit (1 )
145+ }
146+ } else {
147+ logger .Info ("No vulnerabilities found in image" , logrus.Fields {"image" : imageName })
148+ }
149+ }
128150
129- if err := validateImageName (imageName ); err != nil {
130- logger .Error ("Invalid image name" , logrus.Fields {"image" : imageName , "error" : err .Error ()})
131- color .Red ("❌ Error: %v" , err )
151+ // Print summary for multiple images
152+ fmt .Println ()
153+ if hasVulnerabilities {
154+ logger .Warn ("Container scan completed with vulnerabilities" , logrus.Fields {"images" : imageNames })
155+ color .Red ("❌ Scanning failed: vulnerabilities found in one or more container images" )
132156 os .Exit (1 )
133157 }
134158
135- logger .Info ("Starting container scan" , logrus.Fields {"image" : imageName })
136-
137- trivyPath := getTrivyPath ()
138- trivyCmd := exec .Command (trivyPath , buildTrivyArgs (imageName )... )
139- trivyCmd .Stdout = os .Stdout
140- trivyCmd .Stderr = os .Stderr
141-
142- logger .Info ("Running Trivy container scan" , logrus.Fields {"command" : trivyCmd .String ()})
143- fmt .Printf ("🔍 Scanning container image: %s\n \n " , imageName )
144-
145- handleTrivyResult (trivyCmd .Run (), imageName )
159+ logger .Info ("Container scan completed successfully" , logrus.Fields {"images" : imageNames })
160+ color .Green ("✅ Success: No vulnerabilities found matching the specified criteria" )
146161}
147162
148163// buildTrivyArgs constructs the Trivy command arguments based on flags
0 commit comments