@@ -34,6 +34,7 @@ import (
3434 v1 "github.com/google/go-containerregistry/pkg/v1"
3535 "github.com/moby/term"
3636 "github.com/pkg/errors"
37+ "github.com/sirupsen/logrus"
3738 "github.com/spf13/cobra"
3839)
3940
@@ -56,12 +57,16 @@ func NewRootCmd(name string, isPlugin bool, dockerCli command.Cli) *cobra.Comman
5657 }
5758
5859 skill .Log .SetOutput (os .Stderr )
60+ skill .Log .SetFormatter (& logrus.TextFormatter {
61+ DisableTimestamp : true ,
62+ DisableLevelTruncation : true ,
63+ })
5964
6065 config := dockerCli .ConfigFile ()
6166
6267 var (
63- output , ociDir , image , workspace string
64- apiKeyStdin , includeCves bool
68+ output , ociDir , image , workspace string
69+ apiKeyStdin , includeCves , remediate bool
6570 )
6671
6772 logoutCommand := & cobra.Command {
@@ -198,11 +203,12 @@ func NewRootCmd(name string, isPlugin bool, dockerCli command.Cli) *cobra.Comman
198203 cve := args [0 ]
199204 var err error
200205 var sb * types.Sbom
206+ var img * v1.Image
201207
202208 if ociDir == "" {
203- sb , _ , err = sbom .IndexImage (image , dockerCli .Client ())
209+ sb , img , err = sbom .IndexImage (image , dockerCli .Client ())
204210 } else {
205- sb , _ , err = sbom .IndexPath (ociDir , image )
211+ sb , img , err = sbom .IndexPath (ociDir , image )
206212 }
207213 if err != nil {
208214 return err
@@ -216,24 +222,61 @@ func NewRootCmd(name string, isPlugin bool, dockerCli command.Cli) *cobra.Comman
216222
217223 if len (* cves ) > 0 {
218224 for _ , c := range * cves {
219- fmt .Println (fmt .Sprintf ("Detected %s at" , cve ))
220- fmt .Println ("" )
221- purl := c .Purl
225+ query .FormatCve (sb , & c )
226+
227+ if ! remediate {
228+ continue
229+ }
230+
231+ var remediation = make ([]string , 0 )
232+ layerIndex := - 1
222233 for _ , p := range sb .Artifacts {
223- if p .Purl == purl {
224- fmt .Println (fmt .Sprintf (" %s" , p .Purl ))
234+ if p .Purl == c .Purl {
225235 loc := p .Locations [0 ]
226236 for i , l := range sb .Source .Image .Config .RootFS .DiffIDs {
227- if l .String () == loc .DiffId {
228- h := sb .Source .Image .Config .History [i ]
229- fmt .Println (" " )
230- fmt .Println (fmt .Sprintf (" Instruction: %s" , h .CreatedBy ))
231- fmt .Println (fmt .Sprintf (" Layer %d: %s" , i , loc .Digest ))
237+ if l .String () == loc .DiffId && layerIndex < i {
238+ layerIndex = i
232239 }
233240 }
241+
242+ if rem := query .FormatPackageRemediation (p , c ); rem != "" {
243+ remediation = append (remediation , rem )
244+ }
234245 }
235246 }
247+
248+ // see if the package comes in via the base image
249+ s := StartInfoSpinner ("Detecting base image" )
250+ defer s .Stop ()
251+ baseImages , index , _ := query .Detect (img , true , workspace , apiKey )
252+ s .Stop ()
253+ var baseImage * query.Image
254+ if layerIndex <= index && baseImages != nil && len (* baseImages ) > 0 {
255+ baseImage = & (* baseImages )[0 ]
256+
257+ fmt .Println ("" )
258+ fmt .Println ("installed in base image" )
259+ fmt .Println ("" )
260+ fmt .Println (query .FormatImage (baseImage ))
261+ }
262+
263+ if baseImage != nil {
264+ s := StartInfoSpinner ("Finding alternative base images" )
265+ defer s .Stop ()
266+ aBaseImage , _ := query .ForBaseImageWithoutCve (c .SourceId , baseImage .Repository .Name , img , workspace , apiKey )
267+ s .Stop ()
268+ if aBaseImage != nil && len (* aBaseImage ) > 0 {
269+ e := []string {fmt .Sprintf ("Update base image\n \n Alternative base images not vulnerable to %s" , c .SourceId )}
270+ for _ , a := range * aBaseImage {
271+ e = append (e , query .FormatImage (& a ))
272+ }
273+ remediation = append (remediation , strings .Join (e , "\n \n " ))
274+ }
275+ }
276+
277+ query .FormatRemediation (remediation )
236278 }
279+
237280 os .Exit (1 )
238281 } else {
239282 fmt .Println (fmt .Sprintf ("%s not detected" , cve ))
@@ -245,6 +288,7 @@ func NewRootCmd(name string, isPlugin bool, dockerCli command.Cli) *cobra.Comman
245288 cveCommandFlags := cveCommand .Flags ()
246289 cveCommandFlags .StringVarP (& image , "image" , "i" , "" , "Image reference to index" )
247290 cveCommandFlags .StringVarP (& ociDir , "oci-dir" , "d" , "" , "Path to image in OCI format" )
291+ cveCommandFlags .BoolVarP (& remediate , "remediate" , "r" , false , "Include suggested remediation" )
248292
249293 diffCommand := & cobra.Command {
250294 Use : "diff [OPTIONS]" ,
0 commit comments