Skip to content

Commit f8360a0

Browse files
authored
feat(referrer): store backlinks unconditionally (#712)
Signed-off-by: Miguel Martinez Trivino <[email protected]>
1 parent daaa968 commit f8360a0

File tree

3 files changed

+60
-28
lines changed

3 files changed

+60
-28
lines changed

app/controlplane/internal/biz/referrer.go

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,10 @@ func extractReferrers(att *dsse.Envelope) ([]*Referrer, error) {
305305

306306
materialReferrer := referrersMap[materialRef]
307307

308-
// Add the reference to the attestation
308+
// We create a bidirectional link between the attestation and the material
309+
// material -> attestation (1-1)
310+
materialReferrer.References = []*Referrer{{Digest: attestationReferrer.Digest, Kind: attestationReferrer.Kind}}
311+
// attestation -> material (1-N)
309312
attestationReferrer.References = append(attestationReferrer.References, &Referrer{
310313
Digest: materialReferrer.Digest, Kind: materialReferrer.Kind,
311314
})
@@ -317,6 +320,8 @@ func extractReferrers(att *dsse.Envelope) ([]*Referrer, error) {
317320
return nil, fmt.Errorf("extracting predicate: %w", err)
318321
}
319322

323+
// Materials can also be subjects, but there are cases that we will have a subject that is not a material
324+
// For example, a git head commit, that's why we need to also add the subjects as referrers (if needed)
320325
for _, subject := range statement.Subject {
321326
subjectReferrer, err := intotoSubjectToReferrer(subject)
322327
if err != nil {
@@ -329,17 +334,20 @@ func extractReferrers(att *dsse.Envelope) ([]*Referrer, error) {
329334

330335
subjectRef := newRef(subjectReferrer.Digest, subjectReferrer.Kind)
331336

332-
// check if we already have a referrer for this digest and set it otherwise
333-
// this is the case for example for git.Head ones
334-
if _, ok := referrersMap[subjectRef]; !ok {
335-
referrersMap[subjectRef] = subjectReferrer
336-
// add it to the list of of attestation-referenced digests
337-
attestationReferrer.References = append(attestationReferrer.References,
338-
&Referrer{
339-
Digest: subjectReferrer.Digest, Kind: subjectReferrer.Kind,
340-
})
337+
// check if we already have a referrer for this digest and skip if it's the case
338+
if _, ok := referrersMap[subjectRef]; ok {
339+
continue
341340
}
342341

342+
// We are now in the case where a subject is not a material, i.e a git head commit, we need to add it to the referrers
343+
// with a bidirectional link to the attestation like we did for the materials
344+
referrersMap[subjectRef] = subjectReferrer
345+
// add it to the list of of attestation-referenced digests
346+
attestationReferrer.References = append(attestationReferrer.References,
347+
&Referrer{
348+
Digest: subjectReferrer.Digest, Kind: subjectReferrer.Kind,
349+
})
350+
343351
// Update referrer to point to the attestation
344352
referrersMap[subjectRef].References = []*Referrer{{Digest: attestationReferrer.Digest, Kind: attestationReferrer.Kind}}
345353
}

app/controlplane/internal/biz/referrer_integration_test.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ func (s *referrerIntegrationTestSuite) TestExtractAndPersists() {
244244
require.Len(t, got.OrgIDs, 2)
245245
})
246246

247-
s.T().Run("you can ask for info about materials that are subjects", func(t *testing.T) {
247+
s.T().Run("subject materials are returned connected to the attestation", func(t *testing.T) {
248248
got, err := s.Referrer.GetFromRootUser(ctx, wantReferrerContainerImage.Digest, "", s.user.ID)
249249
s.NoError(err)
250250
// parent i.e attestation
@@ -258,14 +258,13 @@ func (s *referrerIntegrationTestSuite) TestExtractAndPersists() {
258258
s.Equal(wantReferrerAtt.Downloadable, got.References[0].Downloadable)
259259
})
260260

261-
s.T().Run("it might not have references", func(t *testing.T) {
261+
s.T().Run("non-subject materials also are connected to the attestation", func(t *testing.T) {
262262
got, err := s.Referrer.GetFromRootUser(ctx, wantReferrerSarif.Digest, "", s.user.ID)
263263
s.NoError(err)
264-
// parent i.e attestation
265-
s.Equal(wantReferrerSarif.Digest, got.Digest)
266-
s.Equal(wantReferrerSarif.Downloadable, got.Downloadable)
267-
s.Equal(wantReferrerSarif.Kind, got.Kind)
268-
require.Len(t, got.References, 0)
264+
require.Len(t, got.References, 1)
265+
s.Equal(wantReferrerAtt.Digest, got.References[0].Digest)
266+
s.Equal(wantReferrerAtt.Kind, got.References[0].Kind)
267+
s.Equal(wantReferrerAtt.Downloadable, got.References[0].Downloadable)
269268
})
270269

271270
s.T().Run("or it does not exist", func(t *testing.T) {

app/controlplane/internal/biz/referrer_test.go

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,18 +79,33 @@ func (s *referrerTestSuite) TestInitialization() {
7979
}
8080

8181
func (s *referrerTestSuite) TestExtractReferrers() {
82+
var fullAttReferrer = &Referrer{
83+
Digest: "sha256:1a077137aef7ca208b80c339769d0d7eecacc2850368e56e834cda1750ce413a",
84+
Kind: "ATTESTATION",
85+
}
86+
87+
var withDuplicatedRefferer = &Referrer{
88+
Digest: "sha256:47e94045e8ffb5ea9a4939a03a21c5ad26f4ea7d463ac6ec46dac15349f45b3f",
89+
Kind: "ATTESTATION",
90+
}
91+
92+
var withGitSubject = &Referrer{
93+
Digest: "sha256:de36d470d792499b1489fc0e6623300fc8822b8f0d2981bb5ec563f8dde723c7",
94+
Kind: "ATTESTATION",
95+
}
96+
8297
testCases := []struct {
8398
name string
8499
inputPath string
85100
expectErr bool
86101
want []*Referrer
87102
}{
88103
{
89-
name: "basic",
104+
name: "all materials linked bidirectionally to the attestation",
90105
inputPath: "testdata/attestations/full.json",
91106
want: []*Referrer{
92107
{
93-
Digest: "sha256:1a077137aef7ca208b80c339769d0d7eecacc2850368e56e834cda1750ce413a",
108+
Digest: fullAttReferrer.Digest,
94109
Kind: "ATTESTATION",
95110
Downloadable: true,
96111
Metadata: map[string]string{
@@ -117,11 +132,14 @@ func (s *referrerTestSuite) TestExtractReferrers() {
117132
{
118133
Digest: "sha256:264f55a6ff9cec2f4742a9faacc033b29f65c04dd4480e71e23579d484288d61",
119134
Kind: "CONTAINER_IMAGE",
135+
// There is a link back to the attestation
136+
References: []*Referrer{fullAttReferrer},
120137
},
121138
{
122139
Digest: "sha256:16159bb881eb4ab7eb5d8afc5350b0feeed1e31c0a268e355e74f9ccbe885e0c",
123140
Kind: "SBOM_CYCLONEDX_JSON",
124141
Downloadable: true,
142+
References: []*Referrer{fullAttReferrer},
125143
},
126144
},
127145
},
@@ -167,7 +185,7 @@ func (s *referrerTestSuite) TestExtractReferrers() {
167185
inputPath: "testdata/attestations/with-duplicated-sha.json",
168186
want: []*Referrer{
169187
{
170-
Digest: "sha256:47e94045e8ffb5ea9a4939a03a21c5ad26f4ea7d463ac6ec46dac15349f45b3f",
188+
Digest: withDuplicatedRefferer.Digest,
171189
Kind: "ATTESTATION",
172190
Downloadable: true,
173191
Metadata: map[string]string{
@@ -196,32 +214,37 @@ func (s *referrerTestSuite) TestExtractReferrers() {
196214
},
197215
},
198216
{
199-
Digest: "sha256:264f55a6ff9cec2f4742a9faacc033b29f65c04dd4480e71e23579d484288d61",
200-
Kind: "CONTAINER_IMAGE",
217+
Digest: "sha256:264f55a6ff9cec2f4742a9faacc033b29f65c04dd4480e71e23579d484288d61",
218+
Kind: "CONTAINER_IMAGE",
219+
References: []*Referrer{withDuplicatedRefferer},
201220
},
202221
{
203222
Digest: "sha256:16159bb881eb4ab7eb5d8afc5350b0feeed1e31c0a268e355e74f9ccbe885e0c",
204223
Kind: "SBOM_CYCLONEDX_JSON",
205224
Downloadable: true,
225+
References: []*Referrer{withDuplicatedRefferer},
206226
},
207227
{
208228
Digest: "sha256:264f55a6ff9cec2f4742a9faacc033b29f65c04dd4480e71e23579d484288d61",
209229
Kind: "SBOM_CYCLONEDX_JSON",
210230
Downloadable: true,
231+
References: []*Referrer{withDuplicatedRefferer},
211232
},
212233
},
213234
},
214235
{
215236
name: "with git subject",
216237
inputPath: "testdata/attestations/with-git-subject.json",
217238
want: []*Referrer{
239+
// NOTE: the result is sorted by kind
218240
{
219241
Digest: "sha256:385c4188b9c080499413f2e0fa0b3951ed107b5f0cb35c2f2b1f07a7be9a7512",
220242
Kind: "ARTIFACT",
221243
Downloadable: true,
244+
References: []*Referrer{withGitSubject},
222245
},
223246
{
224-
Digest: "sha256:de36d470d792499b1489fc0e6623300fc8822b8f0d2981bb5ec563f8dde723c7",
247+
Digest: withGitSubject.Digest,
225248
Kind: "ATTESTATION",
226249
Downloadable: true,
227250
Metadata: map[string]string{
@@ -260,10 +283,9 @@ func (s *referrerTestSuite) TestExtractReferrers() {
260283
{
261284
Digest: "sha256:fbd9335f55d83d8aaf9ab1a539b0f2a87b444e8c54f34c9a1ca9d7df15605db4",
262285
Kind: "CONTAINER_IMAGE",
263-
// the container image is a subject in the attestation
264286
References: []*Referrer{
265287
{
266-
Digest: "sha256:de36d470d792499b1489fc0e6623300fc8822b8f0d2981bb5ec563f8dde723c7",
288+
Digest: withGitSubject.Digest,
267289
Kind: "ATTESTATION",
268290
},
269291
},
@@ -274,7 +296,7 @@ func (s *referrerTestSuite) TestExtractReferrers() {
274296
// the git commit a subject in the attestation
275297
References: []*Referrer{
276298
{
277-
Digest: "sha256:de36d470d792499b1489fc0e6623300fc8822b8f0d2981bb5ec563f8dde723c7",
299+
Digest: withGitSubject.Digest,
278300
Kind: "ATTESTATION",
279301
},
280302
},
@@ -283,23 +305,26 @@ func (s *referrerTestSuite) TestExtractReferrers() {
283305
Digest: "sha256:b4bd86d5855f94bcac0a92d3100ae7b85d050bd2e5fb9037a200e5f5f0b073a2",
284306
Kind: "OPENVEX",
285307
Downloadable: true,
308+
References: []*Referrer{withGitSubject},
286309
},
287310
{
288311
Digest: "sha256:c4a63494f9289dd9fd44f841efb4f5b52765c2de6332f2d86e5f6c0340b40a95",
289312
Kind: "SARIF",
290313
Downloadable: true,
314+
References: []*Referrer{withGitSubject},
291315
},
292316
{
293317
Digest: "sha256:16159bb881eb4ab7eb5d8afc5350b0feeed1e31c0a268e355e74f9ccbe885e0c",
294318
Kind: "SBOM_CYCLONEDX_JSON",
295319
Downloadable: true,
320+
References: []*Referrer{withGitSubject},
296321
},
297322
},
298323
},
299324
}
300325

301326
for _, tc := range testCases {
302-
s.T().Run(tc.name, func(t *testing.T) {
327+
s.Run(tc.name, func() {
303328
// Load attestation
304329
attJSON, err := os.ReadFile(tc.inputPath)
305330
require.NoError(s.T(), err)
@@ -313,7 +338,7 @@ func (s *referrerTestSuite) TestExtractReferrers() {
313338
}
314339

315340
require.NoError(s.T(), err)
316-
assert.Equal(s.T(), tc.want, got)
341+
s.Equal(tc.want, got)
317342
})
318343
}
319344
}

0 commit comments

Comments
 (0)