44 "fmt"
55 "os"
66 "os/exec"
7+ "regexp"
8+ "strings"
79
810 "codacy/cli-v2/utils/logger"
911
@@ -12,6 +14,11 @@ import (
1214 "github.com/spf13/cobra"
1315)
1416
17+ // validImageNamePattern validates Docker image references
18+ // Allows: registry/namespace/image:tag or image@sha256:digest
19+ // Based on Docker image reference specification
20+ var validImageNamePattern = regexp .MustCompile (`^[a-zA-Z0-9][a-zA-Z0-9._\-/:@]*$` )
21+
1522// Flag variables for container-scan command
1623var (
1724 severityFlag string
@@ -51,72 +58,91 @@ the command fails when vulnerabilities are found.`,
5158 Run : runContainerScan ,
5259}
5360
54- func runContainerScan (cmd * cobra.Command , args []string ) {
55- imageName := args [0 ]
61+ // validateImageName checks if the image name is a valid Docker image reference
62+ // and doesn't contain shell metacharacters that could be used for command injection
63+ func validateImageName (imageName string ) error {
64+ if imageName == "" {
65+ return fmt .Errorf ("image name cannot be empty" )
66+ }
5667
57- logger .Info ("Starting container scan" , logrus.Fields {
58- "image" : imageName ,
59- })
68+ // Check for maximum length (Docker has a practical limit)
69+ if len (imageName ) > 256 {
70+ return fmt .Errorf ("image name is too long (max 256 characters)" )
71+ }
6072
61- // Check if Trivy is installed
73+ // Validate against allowed pattern
74+ if ! validImageNamePattern .MatchString (imageName ) {
75+ return fmt .Errorf ("invalid image name format: contains disallowed characters" )
76+ }
77+
78+ // Additional check for dangerous shell metacharacters
79+ dangerousChars := []string {";" , "&" , "|" , "$" , "`" , "(" , ")" , "{" , "}" , "<" , ">" , "!" , "\\ " , "\n " , "\r " , "'" , "\" " }
80+ for _ , char := range dangerousChars {
81+ if strings .Contains (imageName , char ) {
82+ return fmt .Errorf ("invalid image name: contains disallowed character '%s'" , char )
83+ }
84+ }
85+
86+ return nil
87+ }
88+
89+ // getTrivyPath returns the path to the Trivy binary or exits if not found
90+ func getTrivyPath () string {
6291 trivyPath , err := exec .LookPath ("trivy" )
6392 if err != nil {
64- logger .Error ("Trivy not found" , logrus.Fields {
65- "error" : err .Error (),
66- })
93+ logger .Error ("Trivy not found" , logrus.Fields {"error" : err .Error ()})
6794 color .Red ("❌ Error: Trivy is not installed or not found in PATH" )
6895 fmt .Println ("Please install Trivy to use container scanning." )
6996 fmt .Println ("Visit: https://trivy.dev/latest/getting-started/installation/" )
7097 os .Exit (1 )
7198 }
99+ logger .Info ("Found Trivy" , logrus.Fields {"path" : trivyPath })
100+ return trivyPath
101+ }
72102
73- logger .Info ("Found Trivy" , logrus.Fields {
74- "path" : trivyPath ,
75- })
76-
77- // Build Trivy command arguments
78- trivyArgs := buildTrivyArgs (imageName )
79-
80- trivyCmd := exec .Command (trivyPath , trivyArgs ... )
81- trivyCmd .Stdout = os .Stdout
82- trivyCmd .Stderr = os .Stderr
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
110+ }
83111
84- logger .Info ("Running Trivy container scan" , logrus.Fields {
85- "command" : trivyCmd .String (),
86- })
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+ }
87120
88- fmt .Printf ("🔍 Scanning container image: %s\n \n " , imageName )
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+ }
89125
90- err = trivyCmd .Run ()
91- if err != nil {
92- // Check if the error is due to exit code 1 (vulnerabilities found)
93- if exitError , ok := err .(* exec.ExitError ); ok {
94- exitCode := exitError .ExitCode ()
95- logger .Warn ("Container scan completed with vulnerabilities" , logrus.Fields {
96- "image" : imageName ,
97- "exit_code" : exitCode ,
98- })
99- if exitCode == 1 {
100- fmt .Println ()
101- color .Red ("❌ Scanning failed: vulnerabilities found in the container image" )
102- os .Exit (1 )
103- }
104- }
126+ func runContainerScan (cmd * cobra.Command , args []string ) {
127+ imageName := args [0 ]
105128
106- // Other errors
107- logger .Error ("Failed to run Trivy" , logrus.Fields {
108- "error" : err .Error (),
109- })
110- color .Red ("❌ Error: Failed to run Trivy: %v" , err )
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 )
111132 os .Exit (1 )
112133 }
113134
114- logger .Info ("Container scan completed successfully" , logrus.Fields {
115- "image" : imageName ,
116- })
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 )
117144
118- fmt .Println ()
119- color .Green ("✅ Success: No vulnerabilities found matching the specified criteria" )
145+ handleTrivyResult (trivyCmd .Run (), imageName )
120146}
121147
122148// buildTrivyArgs constructs the Trivy command arguments based on flags
0 commit comments