initial pass at fetching bundles with sas urls
Signed-off-by: Meredith Lancaster <malancas@github.com>
This commit is contained in:
parent
30066b0042
commit
bfd140c0e5
6 changed files with 71 additions and 2 deletions
1
go.mod
1
go.mod
|
|
@ -92,6 +92,7 @@ require (
|
|||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-openapi/validate v0.24.0 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/certificate-transparency-go v1.2.1 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/css v1.0.0 // indirect
|
||||
|
|
|
|||
2
go.sum
2
go.sum
|
|
@ -198,6 +198,8 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l
|
|||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/certificate-transparency-go v1.2.1 h1:4iW/NwzqOqYEEoCBEFP+jPbBXbLqMpq3CifMyOnDUME=
|
||||
github.com/google/certificate-transparency-go v1.2.1/go.mod h1:bvn/ytAccv+I6+DGkqpvSsEdiVGramgaSC6RD3tEmeE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ func newErrNoAttestations(name, digest string) ErrNoAttestations {
|
|||
|
||||
type Attestation struct {
|
||||
Bundle *bundle.Bundle `json:"bundle"`
|
||||
SASUrl string `json:"signedAccessSignatureUrl"`
|
||||
}
|
||||
|
||||
type AttestationsResponse struct {
|
||||
|
|
|
|||
|
|
@ -1,16 +1,21 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/cli/cli/v2/api"
|
||||
ioconfig "github.com/cli/cli/v2/pkg/cmd/attestation/io"
|
||||
"github.com/golang/snappy"
|
||||
v1 "github.com/sigstore/protobuf-specs/gen/pb-go/bundle/v1"
|
||||
"github.com/sigstore/sigstore-go/pkg/bundle"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -25,6 +30,7 @@ type apiClient interface {
|
|||
}
|
||||
|
||||
type Client interface {
|
||||
FetchAttestationsWithSASURL(attestations []*Attestation) ([]*Attestation, error)
|
||||
GetByRepoAndDigest(repo, digest string, limit int) ([]*Attestation, error)
|
||||
GetByOwnerAndDigest(owner, digest string, limit int) ([]*Attestation, error)
|
||||
GetTrustDomain() (string, error)
|
||||
|
|
@ -130,6 +136,49 @@ func (c *LiveClient) getAttestations(url, name, digest string, limit int) ([]*At
|
|||
return attestations, nil
|
||||
}
|
||||
|
||||
func (c *LiveClient) FetchAttestationsWithSASURL(attestations []*Attestation) ([]*Attestation, error) {
|
||||
fetched := make([]*Attestation, len(attestations))
|
||||
for i, a := range attestations {
|
||||
b, err := c.fetchAttestationWithSASURL(a)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch attestation with SAS URL: %w", err)
|
||||
}
|
||||
fetched[i] = &Attestation{
|
||||
Bundle: b,
|
||||
}
|
||||
}
|
||||
return fetched, nil
|
||||
}
|
||||
|
||||
func (c *LiveClient) fetchAttestationWithSASURL(a *Attestation) (*bundle.Bundle, error) {
|
||||
if a.SASUrl == "" {
|
||||
return a.Bundle, nil
|
||||
}
|
||||
|
||||
parsed, err := url.Parse(a.SASUrl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resp []byte
|
||||
if err = c.api.REST(parsed.Host, http.MethodGet, parsed.Path, nil, &resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var decompressedBytes []byte
|
||||
_, err = snappy.Decode(decompressedBytes, resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var pbBundle *v1.Bundle
|
||||
if err = json.Unmarshal(decompressedBytes, pbBundle); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return bundle.NewBundle(pbBundle)
|
||||
}
|
||||
|
||||
func shouldRetry(err error) bool {
|
||||
var httpError api.HTTPError
|
||||
if errors.As(err, &httpError) {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@ type MockClient struct {
|
|||
OnGetTrustDomain func() (string, error)
|
||||
}
|
||||
|
||||
func (m MockClient) FetchAttestationsWithSASURL(attestations []*Attestation) ([]*Attestation, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m MockClient) GetByRepoAndDigest(repo, digest string, limit int) ([]*Attestation, error) {
|
||||
return m.OnGetByRepoAndDigest(repo, digest, limit)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,13 +127,25 @@ func GetRemoteAttestations(c FetchAttestationsConfig) ([]*api.Attestation, error
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch attestations from %s: %w", c.Repo, err)
|
||||
}
|
||||
return attestations, nil
|
||||
|
||||
fetched, err := c.APIClient.FetchAttestationsWithSASURL(attestations)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch bundles from SAS URL: %w", err)
|
||||
}
|
||||
|
||||
return fetched, nil
|
||||
} else if c.Owner != "" {
|
||||
attestations, err := c.APIClient.GetByOwnerAndDigest(c.Owner, c.Digest, c.Limit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch attestations from %s: %w", c.Owner, err)
|
||||
}
|
||||
return attestations, nil
|
||||
|
||||
fetched, err := c.APIClient.FetchAttestationsWithSASURL(attestations)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch bundles from SAS URL: %w", err)
|
||||
}
|
||||
|
||||
return fetched, nil
|
||||
}
|
||||
return nil, fmt.Errorf("owner or repo must be provided")
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue