From a78c06970a6b351da65f449d61278b0838e774a5 Mon Sep 17 00:00:00 2001 From: Meredith Lancaster Date: Mon, 24 Mar 2025 17:28:00 -0600 Subject: [PATCH] pass predicate type to get attestation api methods Signed-off-by: Meredith Lancaster --- pkg/cmd/attestation/api/client.go | 21 ++++++++++-------- pkg/cmd/attestation/api/client_test.go | 30 +++++++++++++------------- pkg/cmd/attestation/api/mock_client.go | 20 ++++++++--------- 3 files changed, 37 insertions(+), 34 deletions(-) diff --git a/pkg/cmd/attestation/api/client.go b/pkg/cmd/attestation/api/client.go index 1e99a2a06..8c1af495f 100644 --- a/pkg/cmd/attestation/api/client.go +++ b/pkg/cmd/attestation/api/client.go @@ -39,8 +39,8 @@ type httpClient interface { } type Client interface { - GetByRepoAndDigest(repo, digest string, limit int) ([]*Attestation, error) - GetByOwnerAndDigest(owner, digest string, limit int) ([]*Attestation, error) + GetByRepoAndDigest(repo, digest, predicateType string, limit int) ([]*Attestation, error) + GetByOwnerAndDigest(owner, digest, predicateType string, limit int) ([]*Attestation, error) GetTrustDomain() (string, error) } @@ -61,21 +61,21 @@ func NewLiveClient(hc *http.Client, host string, l *ioconfig.Handler) *LiveClien } // GetByRepoAndDigest fetches the attestation by repo and digest -func (c *LiveClient) GetByRepoAndDigest(repo, digest string, limit int) ([]*Attestation, error) { +func (c *LiveClient) GetByRepoAndDigest(repo, digest, predicateType string, limit int) ([]*Attestation, error) { c.logger.VerbosePrintf("Fetching attestations for artifact digest %s\n\n", digest) url := fmt.Sprintf(GetAttestationByRepoAndSubjectDigestPath, repo, digest) - return c.getByURL(url, limit) + return c.getByURL(url, predicateType, limit) } // GetByOwnerAndDigest fetches attestation by owner and digest -func (c *LiveClient) GetByOwnerAndDigest(owner, digest string, limit int) ([]*Attestation, error) { +func (c *LiveClient) GetByOwnerAndDigest(owner, digest, predicateType string, limit int) ([]*Attestation, error) { c.logger.VerbosePrintf("Fetching attestations for artifact digest %s\n\n", digest) url := fmt.Sprintf(GetAttestationByOwnerAndSubjectDigestPath, owner, digest) - return c.getByURL(url, limit) + return c.getByURL(url, predicateType, limit) } -func (c *LiveClient) getByURL(url string, limit int) ([]*Attestation, error) { - attestations, err := c.getAttestations(url, limit) +func (c *LiveClient) getByURL(url, predicateType string, limit int) ([]*Attestation, error) { + attestations, err := c.getAttestations(url, predicateType, limit) if err != nil { return nil, err } @@ -94,7 +94,7 @@ func (c *LiveClient) GetTrustDomain() (string, error) { return c.getTrustDomain(MetaPath) } -func (c *LiveClient) getAttestations(url string, limit int) ([]*Attestation, error) { +func (c *LiveClient) getAttestations(url, predicateType string, limit int) ([]*Attestation, error) { perPage := limit if perPage <= 0 || perPage > maxLimitForFlag { return nil, fmt.Errorf("limit must be greater than 0 and less than or equal to %d", maxLimitForFlag) @@ -106,6 +106,9 @@ func (c *LiveClient) getAttestations(url string, limit int) ([]*Attestation, err // ref: https://github.com/cli/go-gh/blob/d32c104a9a25c9de3d7c7b07a43ae0091441c858/example_gh_test.go#L96 url = fmt.Sprintf("%s?per_page=%d", url, perPage) + if predicateType != "" { + url = fmt.Sprintf("%s&predicate_type=%s", url, predicateType) + } var attestations []*Attestation var resp AttestationsResponse diff --git a/pkg/cmd/attestation/api/client_test.go b/pkg/cmd/attestation/api/client_test.go index 787408a4e..2a62d5662 100644 --- a/pkg/cmd/attestation/api/client_test.go +++ b/pkg/cmd/attestation/api/client_test.go @@ -44,14 +44,14 @@ func NewClientWithMockGHClient(hasNextPage bool) Client { func TestGetByDigest(t *testing.T) { c := NewClientWithMockGHClient(false) - attestations, err := c.GetByRepoAndDigest(testRepo, testDigest, DefaultLimit) + attestations, err := c.GetByRepoAndDigest(testRepo, testDigest, "https://slsa.dev/provenance/v1", DefaultLimit) require.NoError(t, err) require.Equal(t, 5, len(attestations)) bundle := (attestations)[0].Bundle require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle.v0.3+json") - attestations, err = c.GetByOwnerAndDigest(testOwner, testDigest, DefaultLimit) + attestations, err = c.GetByOwnerAndDigest(testOwner, testDigest, "https://slsa.dev/provenance/v1", DefaultLimit) require.NoError(t, err) require.Equal(t, 5, len(attestations)) @@ -64,14 +64,14 @@ func TestGetByDigestGreaterThanLimit(t *testing.T) { limit := 3 // The method should return five results when the limit is not set - attestations, err := c.GetByRepoAndDigest(testRepo, testDigest, limit) + attestations, err := c.GetByRepoAndDigest(testRepo, testDigest, "https://slsa.dev/provenance/v1", limit) require.NoError(t, err) require.Equal(t, 3, len(attestations)) bundle := (attestations)[0].Bundle require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle.v0.3+json") - attestations, err = c.GetByOwnerAndDigest(testOwner, testDigest, limit) + attestations, err = c.GetByOwnerAndDigest(testOwner, testDigest, "https://slsa.dev/provenance/v1", limit) require.NoError(t, err) require.Equal(t, len(attestations), limit) @@ -81,14 +81,14 @@ func TestGetByDigestGreaterThanLimit(t *testing.T) { func TestGetByDigestWithNextPage(t *testing.T) { c := NewClientWithMockGHClient(true) - attestations, err := c.GetByRepoAndDigest(testRepo, testDigest, DefaultLimit) + attestations, err := c.GetByRepoAndDigest(testRepo, testDigest, "https://slsa.dev/provenance/v1", DefaultLimit) require.NoError(t, err) require.Equal(t, len(attestations), 10) bundle := (attestations)[0].Bundle require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle.v0.3+json") - attestations, err = c.GetByOwnerAndDigest(testOwner, testDigest, DefaultLimit) + attestations, err = c.GetByOwnerAndDigest(testOwner, testDigest, "https://slsa.dev/provenance/v1", DefaultLimit) require.NoError(t, err) require.Equal(t, len(attestations), 10) @@ -101,14 +101,14 @@ func TestGetByDigestGreaterThanLimitWithNextPage(t *testing.T) { limit := 7 // The method should return five results when the limit is not set - attestations, err := c.GetByRepoAndDigest(testRepo, testDigest, limit) + attestations, err := c.GetByRepoAndDigest(testRepo, testDigest, "https://slsa.dev/provenance/v1", limit) require.NoError(t, err) require.Equal(t, len(attestations), limit) bundle := (attestations)[0].Bundle require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle.v0.3+json") - attestations, err = c.GetByOwnerAndDigest(testOwner, testDigest, limit) + attestations, err = c.GetByOwnerAndDigest(testOwner, testDigest, "https://slsa.dev/provenance/v1", limit) require.NoError(t, err) require.Equal(t, len(attestations), limit) @@ -130,12 +130,12 @@ func TestGetByDigest_NoAttestationsFound(t *testing.T) { logger: io.NewTestHandler(), } - attestations, err := c.GetByRepoAndDigest(testRepo, testDigest, DefaultLimit) + attestations, err := c.GetByRepoAndDigest(testRepo, testDigest, "https://slsa.dev/provenance/v1", DefaultLimit) require.Error(t, err) require.IsType(t, ErrNoAttestationsFound, err) require.Nil(t, attestations) - attestations, err = c.GetByOwnerAndDigest(testOwner, testDigest, DefaultLimit) + attestations, err = c.GetByOwnerAndDigest(testOwner, testDigest, "https://slsa.dev/provenance/v1", DefaultLimit) require.Error(t, err) require.IsType(t, ErrNoAttestationsFound, err) require.Nil(t, attestations) @@ -153,11 +153,11 @@ func TestGetByDigest_Error(t *testing.T) { logger: io.NewTestHandler(), } - attestations, err := c.GetByRepoAndDigest(testRepo, testDigest, DefaultLimit) + attestations, err := c.GetByRepoAndDigest(testRepo, testDigest, "https://slsa.dev/provenance/v1", DefaultLimit) require.Error(t, err) require.Nil(t, attestations) - attestations, err = c.GetByOwnerAndDigest(testOwner, testDigest, DefaultLimit) + attestations, err = c.GetByOwnerAndDigest(testOwner, testDigest, "https://slsa.dev/provenance/v1", DefaultLimit) require.Error(t, err) require.Nil(t, attestations) } @@ -362,7 +362,7 @@ func TestGetAttestationsRetries(t *testing.T) { logger: io.NewTestHandler(), } - attestations, err := c.GetByRepoAndDigest(testRepo, testDigest, DefaultLimit) + attestations, err := c.GetByRepoAndDigest(testRepo, testDigest, "https://slsa.dev/provenance/v1", DefaultLimit) require.NoError(t, err) // assert the error path was executed; because this is a paged @@ -375,7 +375,7 @@ func TestGetAttestationsRetries(t *testing.T) { require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle.v0.3+json") // same test as above, but for GetByOwnerAndDigest: - attestations, err = c.GetByOwnerAndDigest(testOwner, testDigest, DefaultLimit) + attestations, err = c.GetByOwnerAndDigest(testOwner, testDigest, "https://slsa.dev/provenance/v1", DefaultLimit) require.NoError(t, err) // because we haven't reset the mock, we have added 2 more failed requests @@ -401,7 +401,7 @@ func TestGetAttestationsMaxRetries(t *testing.T) { logger: io.NewTestHandler(), } - _, err := c.GetByRepoAndDigest(testRepo, testDigest, DefaultLimit) + _, err := c.GetByRepoAndDigest(testRepo, testDigest, "https://slsa.dev/provenance/v1", DefaultLimit) require.Error(t, err) fetcher.AssertNumberOfCalls(t, "OnREST500Error", 4) diff --git a/pkg/cmd/attestation/api/mock_client.go b/pkg/cmd/attestation/api/mock_client.go index b2fd334c0..8e6dcdd6f 100644 --- a/pkg/cmd/attestation/api/mock_client.go +++ b/pkg/cmd/attestation/api/mock_client.go @@ -7,17 +7,17 @@ import ( ) type MockClient struct { - OnGetByRepoAndDigest func(repo, digest string, limit int) ([]*Attestation, error) - OnGetByOwnerAndDigest func(owner, digest string, limit int) ([]*Attestation, error) + OnGetByRepoAndDigest func(repo, digest, predicateType string, limit int) ([]*Attestation, error) + OnGetByOwnerAndDigest func(owner, digest, predicateType string, limit int) ([]*Attestation, error) OnGetTrustDomain func() (string, error) } -func (m MockClient) GetByRepoAndDigest(repo, digest string, limit int) ([]*Attestation, error) { - return m.OnGetByRepoAndDigest(repo, digest, limit) +func (m MockClient) GetByRepoAndDigest(repo, digest, predicateType string, limit int) ([]*Attestation, error) { + return m.OnGetByRepoAndDigest(repo, digest, predicateType, limit) } -func (m MockClient) GetByOwnerAndDigest(owner, digest string, limit int) ([]*Attestation, error) { - return m.OnGetByOwnerAndDigest(owner, digest, limit) +func (m MockClient) GetByOwnerAndDigest(owner, digest, predicateType string, limit int) ([]*Attestation, error) { + return m.OnGetByOwnerAndDigest(owner, digest, predicateType, limit) } func (m MockClient) GetTrustDomain() (string, error) { @@ -28,23 +28,23 @@ func makeTestAttestation() Attestation { return Attestation{Bundle: data.SigstoreBundle(nil), BundleURL: "https://example.com"} } -func OnGetByRepoAndDigestSuccess(repo, digest string, limit int) ([]*Attestation, error) { +func OnGetByRepoAndDigestSuccess(repo, digest, predicateType string, limit int) ([]*Attestation, error) { att1 := makeTestAttestation() att2 := makeTestAttestation() return []*Attestation{&att1, &att2}, nil } -func OnGetByRepoAndDigestFailure(repo, digest string, limit int) ([]*Attestation, error) { +func OnGetByRepoAndDigestFailure(repo, digest, predicateType string, limit int) ([]*Attestation, error) { return nil, fmt.Errorf("failed to fetch by repo and digest") } -func OnGetByOwnerAndDigestSuccess(owner, digest string, limit int) ([]*Attestation, error) { +func OnGetByOwnerAndDigestSuccess(owner, digest, predicateType string, limit int) ([]*Attestation, error) { att1 := makeTestAttestation() att2 := makeTestAttestation() return []*Attestation{&att1, &att2}, nil } -func OnGetByOwnerAndDigestFailure(owner, digest string, limit int) ([]*Attestation, error) { +func OnGetByOwnerAndDigestFailure(owner, digest, predicateType string, limit int) ([]*Attestation, error) { return nil, fmt.Errorf("failed to fetch by owner and digest") }