Skip to content
Merged
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
26 changes: 1 addition & 25 deletions pkg/cmd/attestation/artifact/oci/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"io"
"net/http"
"strings"

"github.com/google/go-containerregistry/pkg/authn"
Expand Down Expand Up @@ -69,33 +68,10 @@ func (c LiveClient) GetImageDigest(imgName string) (*v1.Hash, name.Reference, er
return &desc.Digest, name, nil
}

type noncompliantRegistryTransport struct{}

// RoundTrip will check if a request and associated response fulfill the following:
// 1. The response returns a 406 status code
// 2. The request path contains /referrers/
// If both conditions are met, the response's status code will be overwritten to 404
// This is a temporary solution to handle non compliant registries that return
// an unexpected status code 406 when the go-containerregistry library used
// by this code attempts to make a request to the referrers API.
// The go-containerregistry library can handle 404 response but not a 406 response.
// See the related go-containerregistry issue: https://github.com/google/go-containerregistry/issues/1962
func (a *noncompliantRegistryTransport) RoundTrip(req *http.Request) (*http.Response, error) {
resp, err := http.DefaultTransport.RoundTrip(req)
if err != nil {
return resp, err
}
if resp.StatusCode == http.StatusNotAcceptable && strings.Contains(req.URL.Path, "/referrers/") {
resp.StatusCode = http.StatusNotFound
}

return resp, nil
}

func (c LiveClient) GetAttestations(ref name.Reference, digest string) ([]*api.Attestation, error) {
attestations := make([]*api.Attestation, 0)

transportOpts := []remote.Option{remote.WithTransport(&noncompliantRegistryTransport{}), remote.WithAuthFromKeychain(authn.DefaultKeychain)}
transportOpts := []remote.Option{remote.WithAuthFromKeychain(authn.DefaultKeychain)}
referrers, err := remote.Referrers(ref.Context().Digest(digest), transportOpts...)
if err != nil {
return attestations, fmt.Errorf("error getting referrers: %w", err)
Expand Down
48 changes: 21 additions & 27 deletions pkg/cmd/attestation/verification/attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,43 +29,37 @@ type FetchRemoteAttestationsParams struct {

// GetLocalAttestations returns a slice of attestations read from a local bundle file.
func GetLocalAttestations(path string) ([]*api.Attestation, error) {
var attestations []*api.Attestation
var err error
fileExt := filepath.Ext(path)
switch fileExt {
case ".json":
attestations, err := loadBundleFromJSONFile(path)
if err != nil {
var pathErr *os.PathError
if errors.As(err, &pathErr) {
return nil, fmt.Errorf("bundle could not be loaded from JSON file at %s", path)
} else if errors.Is(err, bundle.ErrValidation) {
return nil, err
}
return nil, fmt.Errorf("bundle content could not be parsed")
}
return attestations, nil
case ".jsonl":
attestations, err := loadBundlesFromJSONLinesFile(path)
if err != nil {
var pathErr *os.PathError
if errors.As(err, &pathErr) {
return nil, fmt.Errorf("bundles could not be loaded from JSON lines file at %s", path)
} else if errors.Is(err, bundle.ErrValidation) {
return nil, err
}
return nil, fmt.Errorf("bundle content could not be parsed")
if fileExt == ".json" {
attestations, err = loadBundleFromJSONFile(path)
} else if fileExt == ".jsonl" {
attestations, err = loadBundlesFromJSONLinesFile(path)
} else {
return nil, ErrUnrecognisedBundleExtension
}

if err != nil {
var pathErr *os.PathError
if errors.As(err, &pathErr) {
return nil, fmt.Errorf("could not load content from file path %s: %w", path, err)
} else if errors.Is(err, bundle.ErrValidation) {
return nil, err
}
return attestations, nil
return nil, fmt.Errorf("bundle content could not be parsed: %w", err)
}
return nil, ErrUnrecognisedBundleExtension

return attestations, nil
}

func loadBundleFromJSONFile(path string) ([]*api.Attestation, error) {
localAttestation, err := bundle.LoadJSONFromPath(path)
b, err := bundle.LoadJSONFromPath(path)
if err != nil {
return nil, err
}

return []*api.Attestation{{Bundle: localAttestation}}, nil
return []*api.Attestation{{Bundle: b}}, nil
}

func loadBundlesFromJSONLinesFile(path string) ([]*api.Attestation, error) {
Expand Down
4 changes: 2 additions & 2 deletions pkg/cmd/attestation/verification/attestation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,15 @@ func TestGetLocalAttestations(t *testing.T) {
path := "../test/data/not-found-bundle.json"
attestations, err := GetLocalAttestations(path)

require.ErrorContains(t, err, "bundle could not be loaded from JSON file")
require.ErrorContains(t, err, "could not load content from file path")
require.Nil(t, attestations)
})

t.Run("with non-existent bundle file and JSON lines file", func(t *testing.T) {
path := "../test/data/not-found-bundle.jsonl"
attestations, err := GetLocalAttestations(path)

require.ErrorContains(t, err, "bundles could not be loaded from JSON lines file")
require.ErrorContains(t, err, "could not load content from file path")
require.Nil(t, attestations)
})

Expand Down