Skip to content

Commit

Permalink
clairctl: start on clair cli tool
Browse files Browse the repository at this point in the history
Signed-off-by: Hank Donnay <hdonnay@redhat.com>
  • Loading branch information
hdonnay committed Mar 18, 2020
1 parent 42b1ba9 commit f1c4798
Show file tree
Hide file tree
Showing 5 changed files with 230 additions and 0 deletions.
8 changes: 8 additions & 0 deletions cmd/clairctl/debug.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package main

import (
"io/ioutil"
"log"
)

var debug = log.New(ioutil.Discard, "debug: ", log.LstdFlags|log.Lmsgprefix)
51 changes: 51 additions & 0 deletions cmd/clairctl/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package main

import (
"context"
"log"
"os"

"github.com/urfave/cli/v2"
)

var (
flagDebug bool
)

func main() {
var exit int
defer func() { os.Exit(exit) }()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

app := &cli.App{
Name: "clairctl",
Version: "0.1.0",
Description: "A command-line tool for clair v4.",
EnableBashCompletion: true,
Before: func(c *cli.Context) error {
if c.IsSet("D") {
debug.SetOutput(os.Stderr)
}
return nil
},
Commands: []*cli.Command{
ManifestCmd,
},
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "D",
Usage: "print debugging logs",
},
},
}
log.SetFlags(log.Flags())

if err := app.RunContext(ctx, os.Args); err != nil {
exit = 1
if err, ok := err.(cli.ExitCoder); ok {
exit = err.ExitCode()
}
log.Println(err)
}
}
155 changes: 155 additions & 0 deletions cmd/clairctl/manifest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package main

import (
"bufio"
"context"
"encoding/json"
"errors"
"net/http"
"net/url"
"os"
"path"
"strings"

"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/google/go-containerregistry/pkg/v1/remote/transport"
"github.com/quay/claircore"
"github.com/urfave/cli/v2"
"golang.org/x/sync/errgroup"
)

var ManifestCmd = &cli.Command{
Name: "manifest",
Description: "print a clair manifest for the provided container",
Action: manifestAction,
}

func manifestAction(c *cli.Context) error {
debug.Println("manifest")
args := c.Args()
if args.Len() == 0 {
return errors.New("missing needed arguments")
}

result := make(chan *claircore.Manifest)
done := make(chan struct{})
eg, ctx := errgroup.WithContext(c.Context)
go func() {
defer close(done)
buf := bufio.NewWriter(os.Stdout)
defer buf.Flush()
enc := json.NewEncoder(buf)
for m := range result {
enc.Encode(m)
buf.Flush()
}
}()

for i := 0; i < args.Len(); i++ {
name := args.Get(i)
debug.Printf("%s: fetching", name)
eg.Go(func() error {
m, err := Inspect(ctx, name)
if err != nil {
debug.Printf("%s: err: %v", name)
return err
}
debug.Printf("%s: ok", name)
result <- m
return nil
})
}
if err := eg.Wait(); err != nil {
return err
}
close(result)
<-done
return nil
}

func Inspect(ctx context.Context, r string) (*claircore.Manifest, error) {
ref, err := name.ParseReference(r)
if err != nil {
return nil, err
}
repo := ref.Context()
auth, err := authn.DefaultKeychain.Resolve(repo)
if err != nil {
return nil, err
}
rt, err := transport.New(repo.Registry, auth, http.DefaultTransport, []string{repo.Scope("pull")})
if err != nil {
return nil, err
}

desc, err := remote.Get(ref, remote.WithTransport(rt))
if err != nil {
return nil, err
}
img, err := desc.Image()
if err != nil {
return nil, err
}

h, err := img.Digest()
if err != nil {
return nil, err
}
ccd, err := claircore.ParseDigest(h.String())
if err != nil {
return nil, err
}
out := claircore.Manifest{
Hash: ccd,
}
debug.Printf("%s: found manifest %v", r, ccd)

ls, err := img.Layers()
if err != nil {
return nil, err
}
debug.Printf("%s: found %d layers", r, len(ls))

rURL := url.URL{
Scheme: repo.Scheme(),
Host: repo.RegistryStr(),
}
c := http.Client{
Transport: rt,
}

for _, l := range ls {
d, err := l.Digest()
if err != nil {
return nil, err
}
ccd, err := claircore.ParseDigest(d.String())
if err != nil {
return nil, err
}
u, err := rURL.Parse(path.Join("/", "v2", strings.TrimPrefix(repo.RepositoryStr(), repo.RegistryStr()), "blobs", d.String()))
if err != nil {
return nil, err
}
req, err := http.NewRequestWithContext(ctx, http.MethodHead, u.String(), nil)
if err != nil {
return nil, err
}
res, err := c.Do(req)
if err != nil {
return nil, err
}
res.Body.Close()

res.Request.Header.Del("User-Agent")
out.Layers = append(out.Layers, &claircore.Layer{
Hash: ccd,
URI: res.Request.URL.String(),
Headers: res.Request.Header,
})
}

return &out, nil
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@ go 1.13

require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/google/go-containerregistry v0.0.0-20191206185556-eb7c14b719c6
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79
github.com/klauspost/compress v1.9.4
github.com/mattn/go-sqlite3 v1.11.0 // indirect
github.com/prometheus/client_golang v0.9.4 // indirect
github.com/prometheus/procfs v0.0.8 // indirect
github.com/quay/claircore v0.0.17
github.com/rs/zerolog v1.16.0
github.com/urfave/cli/v2 v2.2.0
go.opentelemetry.io/otel v0.2.1
go.opentelemetry.io/otel/exporter/metric/prometheus v0.2.2-0.20200111012159-d85178b63b15
go.opentelemetry.io/otel/exporter/trace/jaeger v0.2.1
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
golang.org/x/tools v0.0.0-20191210200704-1bcf67c9cb49 // indirect
gopkg.in/square/go-jose.v2 v2.4.1
gopkg.in/yaml.v2 v2.2.5
Expand Down
13 changes: 13 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/crgimenes/goconfig v1.2.1/go.mod h1:NLkiEPjGZF4p1jzt3S7stOW7z/MJqvCRwJuDmC7b8fw=
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -59,11 +62,13 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017 h1:2HQmlpI3yI9deH18Q6xiSOIjXD4sLI55Y/gfpa8/558=
github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.6.0-rc.1.0.20180327202408-83389a148052+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v1.13.1 h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo=
github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
Expand Down Expand Up @@ -186,6 +191,7 @@ github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-containerregistry v0.0.0-20191206185556-eb7c14b719c6 h1:G+394moNSOPMULZX40YUbVJ4rVuIkmLNvJG5qEX3tTM=
github.com/google/go-containerregistry v0.0.0-20191206185556-eb7c14b719c6/go.mod h1:rodaC7jYStJ2mjR8Y+5a/jCzcRPFRH74KmqSnJC88co=
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
Expand Down Expand Up @@ -404,7 +410,10 @@ github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OK
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/rs/zerolog v1.16.0 h1:AaELmZdcJHT8m6oZ5py4213cdFK8XGXkB3dFdAQ+P7Q=
github.com/rs/zerolog v1.16.0/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
github.com/securego/gosec v0.0.0-20191002120514-e680875ea14d/go.mod h1:w5+eXa0mYznDkHaMCXA4XYffjlH+cy1oyKbfzJXa2Do=
Expand All @@ -417,6 +426,8 @@ github.com/shopspring/decimal v0.0.0-20190905144223-a36b5d85f337 h1:Da9XEUfFxgyD
github.com/shopspring/decimal v0.0.0-20190905144223-a36b5d85f337/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
Expand Down Expand Up @@ -463,6 +474,8 @@ github.com/ultraware/funlen v0.0.2 h1:Av96YVBwwNSe4MLR7iI/BIa3VyI7/djnto/pK3Uxbd
github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
github.com/ultraware/whitespace v0.0.4 h1:If7Va4cM03mpgrNH9k49/VOicWpGoG70XPBFFODYDsg=
github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA=
github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4=
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/uudashr/gocognit v0.0.0-20190926065955-1655d0de0517/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM=
github.com/uudashr/gocognit v1.0.0 h1:NST9SQhYHpFiyKdXn8UAiogdB1xkt5RnA1/rR/oBcGw=
github.com/uudashr/gocognit v1.0.0/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM=
Expand Down

0 comments on commit f1c4798

Please sign in to comment.