Skip to content
This repository was archived by the owner on Jul 18, 2025. It is now read-only.

Commit 8e5737b

Browse files
committed
Some more progress
Signed-off-by: Christian Dupuis <[email protected]>
1 parent d5d5e77 commit 8e5737b

File tree

12 files changed

+837
-25
lines changed

12 files changed

+837
-25
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,5 @@ $ docker-index cve --image <IMAGE> CVE_ID
3737

3838
* `--image <IMAGE>` can either be a local image id or fully qualified image name from a remote registry
3939
* `--oci-dir <DIR>` can point to a local image in OCI directory format
40+
* `--remediate` include suggested remediation in the output
4041
* `CVE_ID` can be any known CVE id

commands/cmd.go

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -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\nAlternative 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]",

commands/spinner.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright © 2022 Docker, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package commands
18+
19+
import (
20+
"fmt"
21+
"time"
22+
23+
"github.com/briandowns/spinner"
24+
"github.com/gookit/color"
25+
)
26+
27+
func StartInfoSpinner(text string) *spinner.Spinner {
28+
return StartSpinner(color.Cyan.Sprint("INFO"), text)
29+
}
30+
31+
func StartSpinner(level string, text string) *spinner.Spinner {
32+
s := spinner.New(spinner.CharSets[14], 100*time.Millisecond)
33+
s.Prefix = fmt.Sprintf("%s %s ", level, text)
34+
s.Color("yellow")
35+
s.Start()
36+
return s
37+
}

go.mod

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,21 @@ require (
88
github.com/anchore/syft v0.59.0
99
github.com/aquasecurity/trivy v0.30.4
1010
github.com/atomist-skills/go-skill v0.0.6-0.20221003172518-c3d268e1f3f1
11+
github.com/briandowns/spinner v1.12.0
1112
github.com/docker/cli v20.10.21+incompatible
1213
github.com/docker/docker v20.10.17+incompatible
14+
github.com/dustin/go-humanize v1.0.0
1315
github.com/google/go-containerregistry v0.11.0
1416
github.com/google/uuid v1.3.0
17+
github.com/gookit/color v1.5.2
1518
github.com/jedib0t/go-pretty/v6 v6.4.0
1619
github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae
1720
github.com/opencontainers/go-digest v1.0.0
1821
github.com/opencontainers/image-spec v1.0.3-0.20220303224323-02efb9a75ee1
1922
github.com/pkg/errors v0.9.1
23+
github.com/sirupsen/logrus v1.9.0
2024
github.com/spf13/cobra v1.5.0
25+
github.com/xeonx/timeago v1.0.0-rc5
2126
olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3
2227
)
2328

@@ -72,10 +77,10 @@ require (
7277
github.com/docker/go-metrics v0.0.1 // indirect
7378
github.com/docker/go-units v0.5.0 // indirect
7479
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
75-
github.com/dustin/go-humanize v1.0.0 // indirect
7680
github.com/ekzhu/minhash-lsh v0.0.0-20171225071031-5c06ee8586a1 // indirect
7781
github.com/emirpasic/gods v1.12.0 // indirect
7882
github.com/facebookincubator/nvdtools v0.1.4 // indirect
83+
github.com/fatih/color v1.13.0 // indirect
7984
github.com/fvbommel/sortorder v1.0.2 // indirect
8085
github.com/gabriel-vasile/mimetype v1.4.0 // indirect
8186
github.com/go-enry/go-license-detector/v4 v4.3.0 // indirect
@@ -92,7 +97,6 @@ require (
9297
github.com/golang/snappy v0.0.4 // indirect
9398
github.com/google/go-cmp v0.5.9 // indirect
9499
github.com/google/licenseclassifier/v2 v2.0.0-pre5 // indirect
95-
github.com/gookit/color v1.5.2 // indirect
96100
github.com/gorilla/mux v1.8.0 // indirect
97101
github.com/hashicorp/errwrap v1.1.0 // indirect
98102
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
@@ -112,6 +116,7 @@ require (
112116
github.com/klauspost/pgzip v1.2.5 // indirect
113117
github.com/knqyf263/go-rpmdb v0.0.0-20220629110411-9a3bd2ebb923 // indirect
114118
github.com/knqyf263/nested v0.0.1 // indirect
119+
github.com/mattn/go-colorable v0.1.12 // indirect
115120
github.com/mattn/go-isatty v0.0.14 // indirect
116121
github.com/mattn/go-runewidth v0.0.13 // indirect
117122
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
@@ -150,7 +155,6 @@ require (
150155
github.com/sergi/go-diff v1.2.0 // indirect
151156
github.com/shogo82148/go-shuffle v0.0.0-20170808115208-59829097ff3b // indirect
152157
github.com/shopspring/decimal v1.2.0 // indirect
153-
github.com/sirupsen/logrus v1.9.0 // indirect
154158
github.com/spdx/tools-golang v0.3.0 // indirect
155159
github.com/spf13/afero v1.8.2 // indirect
156160
github.com/spf13/cast v1.5.0 // indirect

go.sum

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,8 @@ github.com/bmatcuk/doublestar/v4 v4.0.2/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTS
255255
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
256256
github.com/bradleyjkemp/cupaloy/v2 v2.7.0 h1:AT0vOjO68RcLyenLCHOGZzSNiuto7ziqzq6Q1/3xzMQ=
257257
github.com/bradleyjkemp/cupaloy/v2 v2.7.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0=
258+
github.com/briandowns/spinner v1.12.0 h1:72O0PzqGJb6G3KgrcIOtL/JAGGZ5ptOMCn9cUHmqsmw=
259+
github.com/briandowns/spinner v1.12.0/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ=
258260
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
259261
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
260262
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
@@ -551,6 +553,7 @@ github.com/facebookincubator/nvdtools v0.1.4/go.mod h1:0/FIVnSEl9YHXLq3tKBPpKaI0
551553
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
552554
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
553555
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
556+
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
554557
github.com/fatih/set v0.2.1 h1:nn2CaJyknWE/6txyUDGwysr3G5QC6xWB/PtVjPBbeaA=
555558
github.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0CI=
556559
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
@@ -787,7 +790,6 @@ github.com/googleapis/go-type-adapters v1.0.0 h1:9XdMn+d/G57qq1s8dNc5IesGCXHf6V2
787790
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
788791
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
789792
github.com/gookit/color v1.2.5/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg=
790-
github.com/gookit/color v1.4.2 h1:tXy44JFSFkKnELV6WaMo/lLfu/meqITX3iAV52do7lk=
791793
github.com/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI=
792794
github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg=
793795
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -988,8 +990,11 @@ github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHef
988990
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
989991
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
990992
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
993+
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
991994
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
995+
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
992996
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
997+
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
993998
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
994999
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
9951000
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
@@ -1418,6 +1423,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:
14181423
github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
14191424
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
14201425
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
1426+
github.com/xeonx/timeago v1.0.0-rc5 h1:pwcQGpaH3eLfPtXeyPA4DmHWjoQt0Ea7/++FwpxqLxg=
1427+
github.com/xeonx/timeago v1.0.0-rc5/go.mod h1:qDLrYEFynLO7y5Ho7w3GwgtYgpy5UfhcXIIQvMKVDkA=
14211428
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
14221429
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
14231430
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
@@ -1803,6 +1810,7 @@ golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBc
18031810
golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
18041811
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
18051812
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1813+
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
18061814
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
18071815
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
18081816
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

0 commit comments

Comments
 (0)