Skip to content

Commit 851f9a2

Browse files
allow list of images as argument
1 parent 25dcb9b commit 851f9a2

File tree

1 file changed

+57
-42
lines changed

1 file changed

+57
-42
lines changed

cmd/container_scan.go

Lines changed: 57 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -34,27 +34,30 @@ func init() {
3434
}
3535

3636
var 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
4141
By default, scans for HIGH and CRITICAL vulnerabilities in OS packages,
4242
ignoring unfixed issues. Use flags to override these defaults.
4343
4444
The --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

Comments
 (0)