Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spdx initial support #1930

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 92 additions & 75 deletions cmd/clairctl/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/google/go-containerregistry/pkg/v1/remote/transport"
"github.com/quay/claircore"
"github.com/quay/zlog"
spdxtools "github.com/spdx/tools-golang/spdx/v2/v2_3"
"github.com/tomnomnom/linkheader"

"github.com/quay/clair/v4/cmd"
Expand Down Expand Up @@ -105,7 +106,28 @@ var (
errNovelManifest = errors.New("manifest unknown to the system")
)

func (c *Client) IndexReport(ctx context.Context, id claircore.Digest, m *claircore.Manifest) error {
func (c *Client) SPDXReport(ctx context.Context, id claircore.Digest, m *claircore.Manifest) (*spdxtools.Document, error) {
var report = spdxtools.Document{}
err := c.GetIndexReport(ctx, id, m, &report, "application/spdx+json")
if err != nil {
return nil, err
}
return &report, nil
}

func (c *Client) IndexReport(ctx context.Context, id claircore.Digest, m *claircore.Manifest) (*claircore.IndexReport, error) {
var report = claircore.IndexReport{}
err := c.GetIndexReport(ctx, id, m, &report, "application/json")
if err != nil {
return nil, err
}
if !report.Success && report.Err != "" {
return nil, errors.New("indexer error: " + report.Err)
}
return &report, nil
}

func (c *Client) GetIndexReport(ctx context.Context, id claircore.Digest, m *claircore.Manifest, dest interface{}, mediaType string) error {
var (
req *http.Request
res *http.Response
Expand All @@ -121,6 +143,7 @@ func (c *Client) IndexReport(ctx context.Context, id claircore.Digest, m *clairc
if err != nil {
return err
}
req.Header.Add("Accept", mediaType)
res, err = c.client.Do(req)
if err != nil {
zlog.Debug(ctx).
Expand All @@ -130,97 +153,90 @@ func (c *Client) IndexReport(ctx context.Context, id claircore.Digest, m *clairc
return err
}
defer res.Body.Close()
ev := zlog.Debug(ctx).
zlog.Debug(ctx).
Str("method", res.Request.Method).
Str("path", res.Request.URL.Path).
Str("status", res.Status)
if ev.Enabled() && res.ContentLength > 0 && res.ContentLength <= 256 {
var buf bytes.Buffer
buf.ReadFrom(io.LimitReader(res.Body, 256))
ev.Stringer("body", &buf)
}
ev.Send()
switch res.StatusCode {
case http.StatusNotFound, http.StatusOK:
case http.StatusNotModified:
return nil
default:
return fmt.Errorf("unexpected return status: %d", res.StatusCode)
}

if m == nil {
ev := zlog.Debug(ctx).
Stringer("manifest", id)
if res.StatusCode == http.StatusNotFound {
ev.Msg("don't have needed manifest")
return errNovelManifest
var rd io.Reader
switch res.StatusCode {
case http.StatusOK, http.StatusNotModified:
rd = res.Body
case http.StatusNotFound:
if m == nil {
ev := zlog.Debug(ctx).
Stringer("manifest", id)
if res.StatusCode == http.StatusNotFound {
ev.Msg("don't have needed manifest")
return errNovelManifest
}
ev.Msg("manifest may be out-of-date")
return errNeedManifest
}
ru, err := c.host.Parse(path.Join(c.host.RequestURI(), httptransport.IndexAPIPath))
if err != nil {
zlog.Debug(ctx).
Err(err).
Msg("unable to construct index_report url")
return err
}
ev.Msg("manifest may be out-of-date")
return errNeedManifest
}
ru, err := c.host.Parse(path.Join(c.host.RequestURI(), httptransport.IndexAPIPath))
if err != nil {
zlog.Debug(ctx).
Err(err).
Msg("unable to construct index_report url")
return err
}

req, err = c.request(ctx, ru, http.MethodPost)
if err != nil {
return err
}
req.Body = codec.JSONReader(m)
res, err = c.client.Do(req)
if err != nil {
req, err = c.request(ctx, ru, http.MethodPost)
if err != nil {
return err
}
req.Header.Add("Accept", mediaType)
req.Body = codec.JSONReader(m)
res, err = c.client.Do(req)
if err != nil {
zlog.Debug(ctx).
Err(err).
Stringer("url", req.URL).
Msg("request failed")
return err
}
defer res.Body.Close()
zlog.Debug(ctx).
Err(err).
Stringer("url", req.URL).
Msg("request failed")
return err
}
defer res.Body.Close()
zlog.Debug(ctx).
Str("method", res.Request.Method).
Str("path", res.Request.URL.Path).
Str("status", res.Status).
Send()
switch res.StatusCode {
case http.StatusOK:
case http.StatusCreated:
//
Str("method", res.Request.Method).
Str("path", res.Request.URL.Path).
Str("status", res.Status).
Send()
switch res.StatusCode {
case http.StatusOK:
case http.StatusCreated:
//
default:
return fmt.Errorf("unexpected return status: %d", res.StatusCode)
}
switch {
case res.ContentLength > 0 && res.ContentLength < 32+9:
// Less than the size of the digest representation, something's up.
var buf bytes.Buffer
// Ignore error, because what would we do with it here?
ct, _ := buf.ReadFrom(res.Body)
zlog.Info(ctx).
Int64("size", ct).
Stringer("response", &buf).
Msg("body seems short")
return fmt.Errorf("body seems short: %d bytes", ct)
case res.ContentLength < 0: // Streaming
fallthrough
default:
rd = res.Body
}
default:
return fmt.Errorf("unexpected return status: %d", res.StatusCode)
}
var rd io.Reader
switch {
case res.ContentLength > 0 && res.ContentLength < 32+9:
// Less than the size of the digest representation, something's up.
var buf bytes.Buffer
// Ignore error, because what would we do with it here?
ct, _ := buf.ReadFrom(res.Body)
zlog.Info(ctx).
Int64("size", ct).
Stringer("response", &buf).
Msg("body seems short")
rd = &buf
case res.ContentLength < 0: // Streaming
fallthrough
default:
rd = res.Body
}
var report claircore.IndexReport

dec := codec.GetDecoder(rd)
defer codec.PutDecoder(dec)
if err := dec.Decode(&report); err != nil {
if err := dec.Decode(&dest); err != nil {
zlog.Debug(ctx).
Err(err).
Msg("unable to decode json payload")
return err
}
if !report.Success && report.Err != "" {
return errors.New("indexer error: " + report.Err)
}

if v := res.Header.Get("etag"); v != "" {
ls := linkheader.ParseMultiple(res.Header[http.CanonicalHeaderKey("link")]).
FilterByRel("https://projectquay.io/clair/v1/index_report")
Expand All @@ -232,6 +248,7 @@ func (c *Client) IndexReport(ctx context.Context, id claircore.Digest, m *clairc
c.setValidator(ctx, u.Path, v)
}
}

return nil
}

Expand Down
1 change: 1 addition & 0 deletions cmd/clairctl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ func main() {
DeleteCmd,
CheckConfigCmd,
AdminCmd,
IndexCmd,
},
Flags: []cli.Flag{
&cli.BoolFlag{
Expand Down
2 changes: 1 addition & 1 deletion cmd/clairctl/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ func reportAction(c *cli.Context) error {
zlog.Debug(ctx).
Int("attempt", ct).
Msg("requesting index_report")
err = cc.IndexReport(ctx, d, m)
_, err = cc.IndexReport(ctx, d, m)
switch {
case err == nil:
case errors.Is(err, errNeedManifest):
Expand Down
26 changes: 17 additions & 9 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,14 @@ require (
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.20.0
go.opentelemetry.io/otel/sdk v1.21.0
go.opentelemetry.io/otel/trace v1.21.0
golang.org/x/net v0.17.0
golang.org/x/net v0.18.0
golang.org/x/sync v0.5.0
golang.org/x/time v0.4.0
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
Expand Down Expand Up @@ -80,24 +81,31 @@ require (
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sirupsen/logrus v1.9.1 // indirect
github.com/spdx/tools-golang v0.5.3 // indirect
github.com/ulikunitz/xz v0.5.11 // indirect
github.com/vbatts/tar-split v0.11.3 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
go.opentelemetry.io/otel/metric v1.21.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/crypto v0.15.0 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/sys v0.14.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/tools v0.12.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.15.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.40.0 // indirect
modernc.org/ccgo/v3 v3.16.13 // indirect
modernc.org/libc v1.24.1 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.6.0 // indirect
modernc.org/libc v1.29.0 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.7.2 // indirect
modernc.org/opt v0.1.3 // indirect
modernc.org/sqlite v1.26.0 // indirect
modernc.org/sqlite v1.27.0 // indirect
modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.1 // indirect
)

replace github.com/quay/claircore => ../claircore

replace github.com/quay/clair/config => ./config

replace github.com/quay/claircore/toolkit => ../claircore/toolkit
Loading
Loading