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

Commit 43e34d6

Browse files
committed
Improve docker image and logging
Signed-off-by: Christian Dupuis <[email protected]>
1 parent c1ce655 commit 43e34d6

File tree

9 files changed

+151
-84
lines changed

9 files changed

+151
-84
lines changed

.github/workflows/docker-publish.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ env:
1717
# Use docker.io for Docker Hub if empty
1818
REGISTRY: ghcr.io
1919
# github.repository as <account>/<repo>
20-
IMAGE_NAME: ${{ github.repository }}
20+
IMAGE_NAME: docker/docker-index
2121
SHA: ${{ github.event.pull_request.head.sha || github.event.after }}
2222
DOCKERFILE_PATH: Dockerfile
2323

commands/cmd.go

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"github.com/docker/index-cli-plugin/query"
3232
"github.com/docker/index-cli-plugin/sbom"
3333
"github.com/docker/index-cli-plugin/types"
34+
"github.com/docker/index-cli-plugin/util"
3435
v1 "github.com/google/go-containerregistry/pkg/v1"
3536
"github.com/moby/term"
3637
"github.com/pkg/errors"
@@ -57,10 +58,14 @@ func NewRootCmd(name string, isPlugin bool, dockerCli command.Cli) *cobra.Comman
5758
}
5859

5960
skill.Log.SetOutput(os.Stderr)
60-
skill.Log.SetFormatter(&logrus.TextFormatter{
61-
DisableTimestamp: true,
62-
DisableLevelTruncation: true,
63-
})
61+
if dockerCli.Out().IsTerminal() {
62+
skill.Log.SetFormatter(&logrus.TextFormatter{
63+
DisableTimestamp: true,
64+
DisableLevelTruncation: true,
65+
})
66+
} else {
67+
skill.Log.SetFormatter(&logrus.JSONFormatter{})
68+
}
6469

6570
config := dockerCli.ConfigFile()
6671

@@ -112,9 +117,9 @@ func NewRootCmd(name string, isPlugin bool, dockerCli command.Cli) *cobra.Comman
112117
var sb *types.Sbom
113118

114119
if ociDir == "" {
115-
sb, _, err = sbom.IndexImage(image, dockerCli.Client())
120+
sb, _, err = sbom.IndexImage(image, dockerCli)
116121
} else {
117-
sb, _, err = sbom.IndexPath(ociDir, image)
122+
sb, _, err = sbom.IndexPath(ociDir, image, dockerCli)
118123
}
119124
if err != nil {
120125
return err
@@ -175,9 +180,9 @@ func NewRootCmd(name string, isPlugin bool, dockerCli command.Cli) *cobra.Comman
175180
var sb *types.Sbom
176181
var img *v1.Image
177182
if ociDir == "" {
178-
sb, img, err = sbom.IndexImage(image, dockerCli.Client())
183+
sb, img, err = sbom.IndexImage(image, dockerCli)
179184
} else {
180-
sb, img, err = sbom.IndexPath(ociDir, image)
185+
sb, img, err = sbom.IndexPath(ociDir, image, dockerCli)
181186
}
182187
if err != nil {
183188
return err
@@ -206,9 +211,9 @@ func NewRootCmd(name string, isPlugin bool, dockerCli command.Cli) *cobra.Comman
206211
var img *v1.Image
207212

208213
if ociDir == "" {
209-
sb, img, err = sbom.IndexImage(image, dockerCli.Client())
214+
sb, img, err = sbom.IndexImage(image, dockerCli)
210215
} else {
211-
sb, img, err = sbom.IndexPath(ociDir, image)
216+
sb, img, err = sbom.IndexPath(ociDir, image, dockerCli)
212217
}
213218
if err != nil {
214219
return err
@@ -246,7 +251,7 @@ func NewRootCmd(name string, isPlugin bool, dockerCli command.Cli) *cobra.Comman
246251
}
247252

248253
// see if the package comes in via the base image
249-
s := StartInfoSpinner("Detecting base image")
254+
s := util.StartInfoSpinner("Detecting base image", dockerCli.Out().IsTerminal())
250255
defer s.Stop()
251256
baseImages, index, _ := query.Detect(img, true, workspace, apiKey)
252257
s.Stop()
@@ -261,7 +266,7 @@ func NewRootCmd(name string, isPlugin bool, dockerCli command.Cli) *cobra.Comman
261266
}
262267

263268
if baseImage != nil {
264-
s := StartInfoSpinner("Finding alternative base images")
269+
s := util.StartInfoSpinner("Finding alternative base images", dockerCli.Out().IsTerminal())
265270
defer s.Stop()
266271
aBaseImage, _ := query.ForBaseImageWithoutCve(c.SourceId, baseImage.Repository.Name, img, workspace, apiKey)
267272
s.Stop()
@@ -294,7 +299,7 @@ func NewRootCmd(name string, isPlugin bool, dockerCli command.Cli) *cobra.Comman
294299
Use: "diff [OPTIONS]",
295300
Short: "Diff images",
296301
RunE: func(cmd *cobra.Command, args []string) error {
297-
return sbom.DiffImages(args[0], args[1], dockerCli.Client(), "", "")
302+
return sbom.DiffImages(args[0], args[1], dockerCli, "", "")
298303
},
299304
}
300305

commands/spinner.go

Lines changed: 0 additions & 37 deletions
This file was deleted.

query/package_cve.edn

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@
2525

2626
(or-join [?v ?source-id]
2727
[?v :vulnerability/cve-id ?source-id]
28-
(and
29-
[(missing? $ ?v :vulnerability/cve-id)]
30-
[?v :vulnerability/source-id ?source-id]))
28+
[?v :vulnerability/source-id ?source-id])
3129
[?v :vulnerability/source ?source]
3230
[?v :vulnerability/advisories ?adv]
3331

query/query.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ func QueryCves(sb *types.Sbom, cve string, workspace string, apiKey string) (*[]
8181
return nil, errors.Wrapf(err, "failed to unmarshal response")
8282
}
8383
if len(result.Query.Data) > 0 {
84-
if len(result.Query.Data) == 1 {
84+
if len(result.Query.Data[0].Cves) == 1 {
8585
skill.Log.Infof("Detected %d vulnerability", len(result.Query.Data[0].Cves))
8686
} else {
8787
skill.Log.Infof("Detected %d vulnerabilities", len(result.Query.Data[0].Cves))
@@ -99,6 +99,7 @@ func query(query string, name string, workspace string, apiKey string) (*http.Re
9999

100100
}
101101
query = fmt.Sprintf(`{:queries [{:name "query" :query %s}]}`, query)
102+
skill.Log.Debugf("Query %s", query)
102103
client := &http.Client{}
103104
req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(query))
104105
if err != nil {
@@ -117,5 +118,6 @@ func query(query string, name string, workspace string, apiKey string) (*http.Re
117118
if err != nil {
118119
return nil, errors.Wrapf(err, "failed to run query")
119120
}
121+
skill.Log.Debugf("Query response %s", resp.Status)
120122
return resp, nil
121123
}

registry/save.go

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ package registry
1818

1919
import (
2020
"context"
21+
"fmt"
2122
"os"
2223
"path/filepath"
2324
"strings"
2425

2526
"github.com/atomist-skills/go-skill"
26-
"github.com/docker/docker/client"
27+
"github.com/docker/cli/cli/command"
28+
"github.com/docker/index-cli-plugin/util"
2729
"github.com/dustin/go-humanize"
2830
"github.com/google/go-containerregistry/pkg/authn"
2931
"github.com/google/go-containerregistry/pkg/name"
@@ -32,7 +34,6 @@ import (
3234
"github.com/google/go-containerregistry/pkg/v1/remote"
3335
"github.com/google/go-containerregistry/pkg/v1/tarball"
3436
"github.com/pkg/errors"
35-
"github.com/sirupsen/logrus"
3637
)
3738

3839
type ImageId struct {
@@ -67,13 +68,13 @@ type ImageCache struct {
6768
Ref *name.Reference
6869

6970
copy bool
71+
cli command.Cli
7072
}
7173

7274
func (c *ImageCache) StoreImage() error {
7375
if !c.copy {
7476
return nil
7577
}
76-
skill.Log.Infof("Copying image %s", c.Name)
7778
skill.Log.Debugf("Copying image to %s", c.ImagePath)
7879
u := make(chan v1.Update, 200)
7980
errchan := make(chan error)
@@ -87,27 +88,25 @@ func (c *ImageCache) StoreImage() error {
8788
var update v1.Update
8889
var err error
8990
var pp int64
91+
spinner := util.StartSpinner("info", "Copying image", c.cli.Out().IsTerminal())
92+
defer spinner.Stop()
9093
for {
9194
select {
9295
case update = <-u:
9396
p := 100 * update.Complete / update.Total
94-
if p%10 == 0 && pp != p {
95-
skill.Log.WithFields(logrus.Fields{
96-
"event": "copy",
97+
if pp != p {
98+
spinner.WithFields(util.Fields{
99+
"event": "progress",
97100
"total": update.Total,
98101
"complete": update.Complete,
99-
}).Debugf("Copying image %3d%% %s/%s", p, humanize.Bytes(uint64(update.Complete)), humanize.Bytes(uint64(update.Total)))
102+
}).Update(fmt.Sprintf("Copying image %d%% %s/%s", p, humanize.Bytes(uint64(update.Complete)), humanize.Bytes(uint64(update.Total))))
100103
pp = p
101104
}
102105
case err = <-errchan:
103106
if err != nil {
104107
return err
105108
} else {
106-
skill.Log.WithFields(logrus.Fields{
107-
"event": "copy",
108-
"total": update.Total,
109-
"complete": update.Complete,
110-
}).Debugf("Copying image completed")
109+
spinner.Stop()
111110
skill.Log.Infof("Copied image")
112111
return nil
113112
}
@@ -126,7 +125,7 @@ func (c *ImageCache) Cleanup() {
126125
}
127126

128127
// SaveImage stores the v1.Image at path returned in OCI format
129-
func SaveImage(image string, client client.APIClient) (*ImageCache, error) {
128+
func SaveImage(image string, cli command.Cli) (*ImageCache, error) {
130129
ref, err := name.ParseReference(image)
131130
if err != nil {
132131
return nil, errors.Wrapf(err, "failed to parse reference: %s", image)
@@ -155,11 +154,11 @@ func SaveImage(image string, client client.APIClient) (*ImageCache, error) {
155154

156155
desc, err := remote.Get(ref, withAuth())
157156
if err != nil {
158-
img, err := daemon.Image(ImageId{name: image}, daemon.WithClient(client))
157+
img, err := daemon.Image(ImageId{name: image}, daemon.WithClient(cli.Client()))
159158
if err != nil {
160159
return nil, errors.Wrapf(err, "failed to pull image: %s", image)
161160
} else {
162-
im, _, err := client.ImageInspectWithRaw(context.Background(), image)
161+
im, _, err := cli.Client().ImageInspectWithRaw(context.Background(), image)
163162
if err != nil {
164163
return nil, errors.Wrapf(err, "failed to get local image: %s", image)
165164
}
@@ -174,6 +173,7 @@ func SaveImage(image string, client client.APIClient) (*ImageCache, error) {
174173
Ref: &ref,
175174
ImagePath: imagePath,
176175
copy: true,
176+
cli: cli,
177177
}, nil
178178
}
179179
} else {
@@ -200,6 +200,7 @@ func SaveImage(image string, client client.APIClient) (*ImageCache, error) {
200200
Ref: &ref,
201201
ImagePath: imagePath,
202202
copy: true,
203+
cli: cli,
203204
}, nil
204205
}
205206
}

sbom/diff.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222
"sync"
2323

2424
"github.com/anchore/packageurl-go"
25-
"github.com/docker/docker/client"
25+
"github.com/docker/cli/cli/command"
2626
"github.com/docker/index-cli-plugin/internal"
2727
"github.com/docker/index-cli-plugin/types"
2828
"github.com/gookit/color"
@@ -58,12 +58,12 @@ func init() {
5858
}
5959
}
6060

61-
func DiffImages(image1 string, image2 string, client client.APIClient, workspace string, apikey string) error {
61+
func DiffImages(image1 string, image2 string, cli command.Cli, workspace string, apikey string) error {
6262
resultChan := make(chan ImageIndexResult, 2)
6363
var wg sync.WaitGroup
6464
wg.Add(2)
65-
go indexImageAsync(&wg, image1, client, resultChan)
66-
go indexImageAsync(&wg, image2, client, resultChan)
65+
go indexImageAsync(&wg, image1, cli, resultChan)
66+
go indexImageAsync(&wg, image2, cli, resultChan)
6767
wg.Wait()
6868
close(resultChan)
6969

sbom/index.go

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@ import (
2525
"sync"
2626

2727
"github.com/atomist-skills/go-skill"
28-
"github.com/docker/docker/client"
28+
"github.com/docker/cli/cli/command"
2929
"github.com/docker/index-cli-plugin/internal"
3030
"github.com/docker/index-cli-plugin/query"
3131
"github.com/docker/index-cli-plugin/registry"
3232
"github.com/docker/index-cli-plugin/types"
33+
"github.com/docker/index-cli-plugin/util"
3334
"github.com/google/go-containerregistry/pkg/name"
3435
v1 "github.com/google/go-containerregistry/pkg/v1"
3536
"github.com/pkg/errors"
@@ -42,9 +43,9 @@ type ImageIndexResult struct {
4243
Error error
4344
}
4445

45-
func indexImageAsync(wg *sync.WaitGroup, image string, client client.APIClient, resultChan chan<- ImageIndexResult) {
46+
func indexImageAsync(wg *sync.WaitGroup, image string, cli command.Cli, resultChan chan<- ImageIndexResult) {
4647
defer wg.Done()
47-
sbom, img, err := IndexImage(image, client)
48+
sbom, img, err := IndexImage(image, cli)
4849
cves, err := query.QueryCves(sbom, "", "", "")
4950
if err == nil {
5051
sbom.Vulnerabilities = *cves
@@ -57,23 +58,23 @@ func indexImageAsync(wg *sync.WaitGroup, image string, client client.APIClient,
5758
}
5859
}
5960

60-
func IndexPath(path string, name string) (*types.Sbom, *v1.Image, error) {
61+
func IndexPath(path string, name string, cli command.Cli) (*types.Sbom, *v1.Image, error) {
6162
cache, err := registry.ReadImage(name, path)
6263
if err != nil {
6364
return nil, nil, errors.Wrap(err, "failed to read image")
6465
}
65-
return indexImage(cache)
66+
return indexImage(cache, cli)
6667
}
6768

68-
func IndexImage(image string, client client.APIClient) (*types.Sbom, *v1.Image, error) {
69-
cache, err := registry.SaveImage(image, client)
69+
func IndexImage(image string, cli command.Cli) (*types.Sbom, *v1.Image, error) {
70+
cache, err := registry.SaveImage(image, cli)
7071
if err != nil {
7172
return nil, nil, errors.Wrap(err, "failed to copy image")
7273
}
73-
return indexImage(cache)
74+
return indexImage(cache, cli)
7475
}
7576

76-
func indexImage(cache *registry.ImageCache) (*types.Sbom, *v1.Image, error) {
77+
func indexImage(cache *registry.ImageCache, cli command.Cli) (*types.Sbom, *v1.Image, error) {
7778
// see if we can re-use an existing sbom
7879
sbomPath := filepath.Join(cache.Path, "sbom.json")
7980
if _, ok := os.LookupEnv("ATOMIST_NO_CACHE"); !ok {
@@ -101,7 +102,8 @@ func indexImage(cache *registry.ImageCache) (*types.Sbom, *v1.Image, error) {
101102
lm := createLayerMapping(*cache.Image)
102103
skill.Log.Debugf("Created layer mapping")
103104

104-
skill.Log.Info("Indexing")
105+
s := util.StartSpinner("info", "Indexing", cli.Out().IsTerminal())
106+
defer s.Stop()
105107
trivyResultChan := make(chan types.IndexResult)
106108
syftResultChan := make(chan types.IndexResult)
107109
go trivySbom(cache.ImagePath, lm, trivyResultChan)
@@ -118,6 +120,7 @@ func indexImage(cache *registry.ImageCache) (*types.Sbom, *v1.Image, error) {
118120

119121
packages := types.MergePackages(syftResult, trivyResult)
120122

123+
s.Stop()
121124
skill.Log.Infof(`Indexed %d packages`, len(packages))
122125

123126
manifest, _ := (*cache.Image).RawManifest()

0 commit comments

Comments
 (0)