Skip to content

Commit 05f3dff

Browse files
authored
feat(referrer): kind parameter support (#434)
Signed-off-by: Miguel Martinez Trivino <[email protected]>
1 parent bf91cd0 commit 05f3dff

File tree

10 files changed

+147
-87
lines changed

10 files changed

+147
-87
lines changed

app/cli/cmd/referrer_discover.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ import (
2323
)
2424

2525
func newReferrerDiscoverCmd() *cobra.Command {
26-
var digest string
26+
var digest, kind string
2727

2828
cmd := &cobra.Command{
2929
Use: "discover",
3030
Short: "(Preview) inspect pieces of evidence or artifacts stored through Chainloop",
3131
RunE: func(cmd *cobra.Command, args []string) error {
32-
res, err := action.NewReferrerDiscover(actionOpts).Run(context.Background(), digest)
32+
res, err := action.NewReferrerDiscover(actionOpts).Run(context.Background(), digest, kind)
3333
if err != nil {
3434
return err
3535
}
@@ -42,6 +42,7 @@ func newReferrerDiscoverCmd() *cobra.Command {
4242
cmd.Flags().StringVarP(&digest, "digest", "d", "", "hash of the attestation, piece of evidence or artifact, i.e sha256:deadbeef")
4343
err := cmd.MarkFlagRequired("digest")
4444
cobra.CheckErr(err)
45+
cmd.Flags().StringVarP(&kind, "kind", "k", "", "optional kind of the referrer, used to disambiguate between multiple referrers with the same digest")
4546

4647
return cmd
4748
}

app/cli/internal/action/referrer_discover.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ func NewReferrerDiscover(cfg *ActionsOpts) *ReferrerDiscover {
3838
return &ReferrerDiscover{cfg}
3939
}
4040

41-
func (action *ReferrerDiscover) Run(ctx context.Context, digest string) (*ReferrerItem, error) {
41+
func (action *ReferrerDiscover) Run(ctx context.Context, digest, kind string) (*ReferrerItem, error) {
4242
client := pb.NewReferrerServiceClient(action.cfg.CPConnection)
43-
resp, err := client.Discover(ctx, &pb.ReferrerServiceDiscoverRequest{Digest: digest})
43+
resp, err := client.Discover(ctx, &pb.ReferrerServiceDiscoverRequest{
44+
Digest: digest, Kind: kind,
45+
})
4446
if err != nil {
4547
return nil, err
4648
}

app/controlplane/api/controlplane/v1/referrer.pb.go

Lines changed: 47 additions & 36 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/controlplane/api/controlplane/v1/referrer.pb.validate.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/controlplane/api/controlplane/v1/referrer.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ service ReferrerService {
3131

3232
message ReferrerServiceDiscoverRequest {
3333
string digest = 1 [(validate.rules).string = {min_len: 1}];
34+
// Optional kind of referrer, i.e CONTAINER_IMAGE, GIT_HEAD, ...
35+
// Used to filter and resolve ambiguities
36+
string kind = 2;
3437
}
3538

3639
message ReferrerServiceDiscoverResponse {

app/controlplane/api/gen/frontend/controlplane/v1/referrer.ts

Lines changed: 22 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/controlplane/internal/biz/referrer.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ type ReferrerRepo interface {
5757
// GetFromRoot returns the referrer identified by the provided content digest, including its first-level references
5858
// For example if sha:deadbeef represents an attestation, the result will contain the attestation + materials associated to it
5959
// OrgIDs represent an allowList of organizations where the referrers should be looked for
60-
GetFromRoot(ctx context.Context, digest string, orgIDS []uuid.UUID) (*StoredReferrer, error)
60+
GetFromRoot(ctx context.Context, digest, kind string, orgIDS []uuid.UUID) (*StoredReferrer, error)
6161
}
6262

6363
type ReferrerUseCase struct {
@@ -104,7 +104,7 @@ func (s *ReferrerUseCase) ExtractAndPersist(ctx context.Context, att *dsse.Envel
104104
// GetFromRoot returns the referrer identified by the provided content digest, including its first-level references
105105
// For example if sha:deadbeef represents an attestation, the result will contain the attestation + materials associated to it
106106
// It only returns referrers that belong to organizations the user is member of
107-
func (s *ReferrerUseCase) GetFromRoot(ctx context.Context, digest string, userID string) (*StoredReferrer, error) {
107+
func (s *ReferrerUseCase) GetFromRoot(ctx context.Context, digest string, rootKind, userID string) (*StoredReferrer, error) {
108108
userUUID, err := uuid.Parse(userID)
109109
if err != nil {
110110
return nil, NewErrInvalidUUID(err)
@@ -123,7 +123,7 @@ func (s *ReferrerUseCase) GetFromRoot(ctx context.Context, digest string, userID
123123
orgIDs = append(orgIDs, m.OrganizationID)
124124
}
125125

126-
ref, err := s.repo.GetFromRoot(ctx, digest, orgIDs)
126+
ref, err := s.repo.GetFromRoot(ctx, digest, rootKind, orgIDs)
127127
if err != nil {
128128
if errors.As(err, &ErrAmbiguousReferrer{}) {
129129
return nil, NewErrValidation(fmt.Errorf("please provide the referrer kind: %w", err))

app/controlplane/internal/biz/referrer_integration_test.go

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -86,21 +86,21 @@ func (s *referrerIntegrationTestSuite) TestExtractAndPersists() {
8686
s.T().Run("it can store properly the first time", func(t *testing.T) {
8787
err := s.Referrer.ExtractAndPersist(ctx, envelope, s.org1.ID)
8888
s.NoError(err)
89-
prevStoredRef, err = s.Referrer.GetFromRoot(ctx, wantReferrerAtt.Digest, s.user.ID)
89+
prevStoredRef, err = s.Referrer.GetFromRoot(ctx, wantReferrerAtt.Digest, "", s.user.ID)
9090
s.NoError(err)
9191
})
9292

9393
s.T().Run("and it's idempotent", func(t *testing.T) {
9494
err := s.Referrer.ExtractAndPersist(ctx, envelope, s.org1.ID)
9595
s.NoError(err)
96-
ref, err := s.Referrer.GetFromRoot(ctx, wantReferrerAtt.Digest, s.user.ID)
96+
ref, err := s.Referrer.GetFromRoot(ctx, wantReferrerAtt.Digest, "", s.user.ID)
9797
s.NoError(err)
9898
// Check it's the same referrer than previously retrieved, including timestamps
9999
s.Equal(prevStoredRef, ref)
100100
})
101101

102102
s.T().Run("contains all the info", func(t *testing.T) {
103-
got, err := s.Referrer.GetFromRoot(ctx, wantReferrerAtt.Digest, s.user.ID)
103+
got, err := s.Referrer.GetFromRoot(ctx, wantReferrerAtt.Digest, "", s.user.ID)
104104
s.NoError(err)
105105
// parent i.e attestation
106106
s.Equal(wantReferrerAtt.Digest, got.Digest)
@@ -119,15 +119,15 @@ func (s *referrerIntegrationTestSuite) TestExtractAndPersists() {
119119

120120
s.T().Run("can't be accessed by a second user in another org", func(t *testing.T) {
121121
// the user2 has not access to org1
122-
got, err := s.Referrer.GetFromRoot(ctx, wantReferrerAtt.Digest, s.user2.ID)
122+
got, err := s.Referrer.GetFromRoot(ctx, wantReferrerAtt.Digest, "", s.user2.ID)
123123
s.True(biz.IsNotFound(err))
124124
s.Nil(got)
125125
})
126126

127127
s.T().Run("but another org can be attached", func(t *testing.T) {
128128
err = s.Referrer.ExtractAndPersist(ctx, envelope, s.org2.ID)
129129
s.NoError(err)
130-
got, err := s.Referrer.GetFromRoot(ctx, wantReferrerAtt.Digest, s.user.ID)
130+
got, err := s.Referrer.GetFromRoot(ctx, wantReferrerAtt.Digest, "", s.user.ID)
131131
s.NoError(err)
132132
require.Len(t, got.OrgIDs, 2)
133133
s.Contains(got.OrgIDs, s.org1UUID)
@@ -136,21 +136,21 @@ func (s *referrerIntegrationTestSuite) TestExtractAndPersists() {
136136
// and it's idempotent (no new orgs added)
137137
err = s.Referrer.ExtractAndPersist(ctx, envelope, s.org2.ID)
138138
s.NoError(err)
139-
got, err = s.Referrer.GetFromRoot(ctx, wantReferrerAtt.Digest, s.user.ID)
139+
got, err = s.Referrer.GetFromRoot(ctx, wantReferrerAtt.Digest, "", s.user.ID)
140140
s.NoError(err)
141141
require.Len(t, got.OrgIDs, 2)
142142
})
143143

144144
s.T().Run("and now user2 has access to it since it has access to org2", func(t *testing.T) {
145145
err = s.Referrer.ExtractAndPersist(ctx, envelope, s.org2.ID)
146146
s.NoError(err)
147-
got, err := s.Referrer.GetFromRoot(ctx, wantReferrerAtt.Digest, s.user2.ID)
147+
got, err := s.Referrer.GetFromRoot(ctx, wantReferrerAtt.Digest, "", s.user2.ID)
148148
s.NoError(err)
149149
require.Len(t, got.OrgIDs, 2)
150150
})
151151

152152
s.T().Run("you can ask for info about materials that are subjects", func(t *testing.T) {
153-
got, err := s.Referrer.GetFromRoot(ctx, wantReferrerContainerImage.Digest, s.user.ID)
153+
got, err := s.Referrer.GetFromRoot(ctx, wantReferrerContainerImage.Digest, "", s.user.ID)
154154
s.NoError(err)
155155
// parent i.e attestation
156156
s.Equal(wantReferrerContainerImage.Digest, got.Digest)
@@ -164,7 +164,7 @@ func (s *referrerIntegrationTestSuite) TestExtractAndPersists() {
164164
})
165165

166166
s.T().Run("it might not have references", func(t *testing.T) {
167-
got, err := s.Referrer.GetFromRoot(ctx, wantReferrerSarif.Digest, s.user.ID)
167+
got, err := s.Referrer.GetFromRoot(ctx, wantReferrerSarif.Digest, "", s.user.ID)
168168
s.NoError(err)
169169
// parent i.e attestation
170170
s.Equal(wantReferrerSarif.Digest, got.Digest)
@@ -174,7 +174,7 @@ func (s *referrerIntegrationTestSuite) TestExtractAndPersists() {
174174
})
175175

176176
s.T().Run("or not to exist", func(t *testing.T) {
177-
got, err := s.Referrer.GetFromRoot(ctx, "sha256:deadbeef", s.user.ID)
177+
got, err := s.Referrer.GetFromRoot(ctx, "sha256:deadbeef", "", s.user.ID)
178178
s.True(biz.IsNotFound(err))
179179
s.Nil(got)
180180
})
@@ -199,14 +199,29 @@ func (s *referrerIntegrationTestSuite) TestExtractAndPersists() {
199199
s.NoError(err)
200200

201201
// but retrieval should fail. In the future we will ask the user to provide the artifact type in these cases of ambiguity
202-
got, err := s.Referrer.GetFromRoot(ctx, wantReferrerSarif.Digest, s.user.ID)
202+
got, err := s.Referrer.GetFromRoot(ctx, wantReferrerSarif.Digest, "", s.user.ID)
203203
s.Nil(got)
204204
s.ErrorContains(err, "present in 2 kinds")
205205
})
206206

207+
s.T().Run("it should not fail on retrieval if we filter out by one kind", func(t *testing.T) {
208+
// but retrieval should fail. In the future we will ask the user to provide the artifact type in these cases of ambiguity
209+
got, err := s.Referrer.GetFromRoot(ctx, wantReferrerSarif.Digest, "SARIF", s.user.ID)
210+
s.NoError(err)
211+
s.Equal(wantReferrerSarif.Digest, got.Digest)
212+
s.Equal(true, got.Downloadable)
213+
s.Equal("SARIF", got.Kind)
214+
215+
got, err = s.Referrer.GetFromRoot(ctx, wantReferrerSarif.Digest, "ARTIFACT", s.user.ID)
216+
s.NoError(err)
217+
s.Equal(wantReferrerSarif.Digest, got.Digest)
218+
s.Equal(true, got.Downloadable)
219+
s.Equal("ARTIFACT", got.Kind)
220+
})
221+
207222
s.T().Run("now there should a container image pointing to two attestations", func(t *testing.T) {
208223
// but retrieval should fail. In the future we will ask the user to provide the artifact type in these cases of ambiguity
209-
got, err := s.Referrer.GetFromRoot(ctx, wantReferrerContainerImage.Digest, s.user.ID)
224+
got, err := s.Referrer.GetFromRoot(ctx, wantReferrerContainerImage.Digest, "", s.user.ID)
210225
s.NoError(err)
211226
// it should be referenced by two attestations since it's subject of both
212227
require.Len(t, got.References, 2)

0 commit comments

Comments
 (0)