Skip to content

Commit 23416c4

Browse files
authored
Add tekton object name info in byproduct items (#1461)
* Add tekton object name info in byproduct items The byproducts section in the provenance v2 attestation contains the results generated by all the taskRuns in the pipeline, but the items are missing a reference to the task that produced each one of them, making impossible to tell which result was produced from which task. This commit adds this information in the 'name' property of each byproduct item, in the form: <byproduct_type>/<object_name>/<result_name> * test: add missing task to e2e testdata The testdata file 'pipeline-with-repeated-results' was missing task t3 that exists in the example YAML. This was previously not caught by the tests but is now visible after improving the predicate comparison logic. Assisted by: Claude Code
1 parent 2ae36f6 commit 23416c4

File tree

12 files changed

+140
-88
lines changed

12 files changed

+140
-88
lines changed

docs/predicate/slsa/v2.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -507,11 +507,11 @@ This is the case where the top-level build spec (pipeline or task) is in-lined i
507507
},
508508
"byproducts": [
509509
{
510-
"name": "pipelineRunResults/IMAGE_URL",
510+
"name": "pipelineRunResults/buildimage/IMAGE_URL",
511511
"content": "Imdjci5pby9mb28vYmFyXG4i"
512512
},
513513
{
514-
"name": "pipelineRunResults/IMAGE_DIGEST",
514+
"name": "pipelineRunResults/buildimage/IMAGE_DIGEST",
515515
"content": "InNoYTI1NjowNWY5NWIyNmVkMTA2NjhiNzE4M2MxZTJkYTk4NjEwZTkxMzcyZmE5ZjUxMDA0NmQ0Y2U1ODEyYWRkYWQ4NmI1XG4i"
516516
}
517517
]

pkg/chains/formats/slsa/internal/results/results.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ var imageResultsNamesSuffixs = []string{
3030
}
3131

3232
// GetResultsWithoutBuildArtifacts returns all the results without those that are build artifacts.
33-
func GetResultsWithoutBuildArtifacts(results []objects.Result, resultTypePrefix string) ([]*slsa.ResourceDescriptor, error) {
33+
func GetResultsWithoutBuildArtifacts(objName string, results []objects.Result, resultTypePrefix string) ([]*slsa.ResourceDescriptor, error) {
3434
byProd := []*slsa.ResourceDescriptor{}
3535
for _, r := range results {
3636
if isBuildArtifact, err := artifacts.IsBuildArtifact(r); err != nil || isBuildArtifact {
@@ -47,7 +47,7 @@ func GetResultsWithoutBuildArtifacts(results []objects.Result, resultTypePrefix
4747
}
4848

4949
byProd = append(byProd, &slsa.ResourceDescriptor{
50-
Name: fmt.Sprintf(resultTypePrefix, r.Name),
50+
Name: fmt.Sprintf(resultTypePrefix, objName, r.Name),
5151
Content: content,
5252
MediaType: "application/json",
5353
})

pkg/chains/formats/slsa/internal/results/results_test.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ func TestGetResultsWithoutBuildArtifacts(t *testing.T) {
2828
tests := []struct {
2929
name string
3030
prefix string
31+
objName string
3132
results []objects.Result
3233
expected []*slsa.ResourceDescriptor
3334
}{
@@ -36,8 +37,9 @@ func TestGetResultsWithoutBuildArtifacts(t *testing.T) {
3637
expected: []*slsa.ResourceDescriptor{},
3738
},
3839
{
39-
name: "results without build artifacts",
40-
prefix: "taskRunResults/%s",
40+
name: "results without build artifacts",
41+
prefix: "taskRunResults/%s/%s",
42+
objName: "taskRun-name",
4143
results: []objects.Result{
4244
{
4345
Name: "result1",
@@ -124,31 +126,31 @@ func TestGetResultsWithoutBuildArtifacts(t *testing.T) {
124126
},
125127
expected: []*slsa.ResourceDescriptor{
126128
{
127-
Name: "taskRunResults/result1",
129+
Name: "taskRunResults/taskRun-name/result1",
128130
MediaType: "application/json",
129131
Content: toJSONString(t, v1.ParamValue{
130132
Type: v1.ParamTypeString,
131133
StringVal: "my-first-result",
132134
}),
133135
},
134136
{
135-
Name: "taskRunResults/res2-ARTIFACT_URI",
137+
Name: "taskRunResults/taskRun-name/res2-ARTIFACT_URI",
136138
MediaType: "application/json",
137139
Content: toJSONString(t, v1.ParamValue{
138140
Type: v1.ParamTypeString,
139141
StringVal: "gcr.io/my/image/fromstep2",
140142
}),
141143
},
142144
{
143-
Name: "taskRunResults/res2-ARTIFACT_DIGEST",
145+
Name: "taskRunResults/taskRun-name/res2-ARTIFACT_DIGEST",
144146
MediaType: "application/json",
145147
Content: toJSONString(t, v1.ParamValue{
146148
Type: v1.ParamTypeString,
147149
StringVal: "sha256:827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7",
148150
}),
149151
},
150152
{
151-
Name: "taskRunResults/res3-ARTIFACT_OUTPUTS",
153+
Name: "taskRunResults/taskRun-name/res3-ARTIFACT_OUTPUTS",
152154
MediaType: "application/json",
153155
Content: toJSONString(t, v1.ParamValue{
154156
Type: v1.ParamTypeObject,
@@ -159,7 +161,7 @@ func TestGetResultsWithoutBuildArtifacts(t *testing.T) {
159161
}),
160162
},
161163
{
162-
Name: "taskRunResults/res5-ARTIFACT_OUTPUTS",
164+
Name: "taskRunResults/taskRun-name/res5-ARTIFACT_OUTPUTS",
163165
MediaType: "application/json",
164166
Content: toJSONString(t, v1.ParamValue{
165167
Type: v1.ParamTypeObject,
@@ -176,7 +178,7 @@ func TestGetResultsWithoutBuildArtifacts(t *testing.T) {
176178

177179
for _, test := range tests {
178180
t.Run(test.name, func(t *testing.T) {
179-
got, err := GetResultsWithoutBuildArtifacts(test.results, test.prefix)
181+
got, err := GetResultsWithoutBuildArtifacts(test.objName, test.results, test.prefix)
180182

181183
if err != nil {
182184
t.Fatalf("Unexpected error: %v", err)

pkg/chains/formats/slsa/v2alpha4/internal/pipelinerun/pipelinerun.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import (
2929
)
3030

3131
const (
32-
pipelineRunResults = "pipelineRunResults/%s"
32+
pipelineRunResults = "pipelineRunResults/%s/%s"
3333
// JSONMediaType is the media type of json encoded content used in resource descriptors
3434
JSONMediaType = "application/json"
3535
)
@@ -54,7 +54,7 @@ func GenerateAttestation(ctx context.Context, pro *objects.PipelineRunObjectV1,
5454

5555
// byproducts contains the pipelineRunResults that are not subjects.
5656
func byproducts(pro *objects.PipelineRunObjectV1, slsaconfig *slsaconfig.SlsaConfig) ([]*intoto.ResourceDescriptor, error) {
57-
byProd, err := results.GetResultsWithoutBuildArtifacts(pro.GetResults(), pipelineRunResults)
57+
byProd, err := results.GetResultsWithoutBuildArtifacts(pro.GetName(), pro.GetResults(), pipelineRunResults)
5858
if err != nil {
5959
return nil, err
6060
}

pkg/chains/formats/slsa/v2alpha4/internal/pipelinerun/pipelinerun_test.go

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,16 @@ import (
3535
"google.golang.org/protobuf/testing/protocmp"
3636
"google.golang.org/protobuf/types/known/structpb"
3737
"google.golang.org/protobuf/types/known/timestamppb"
38+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3839
logtesting "knative.dev/pkg/logging/testing"
3940
)
4041

4142
func TestByProducts(t *testing.T) {
4243
resultValue := v1.ResultValue{Type: "string", StringVal: "result-value"}
4344
pr := &v1.PipelineRun{
45+
ObjectMeta: metav1.ObjectMeta{
46+
Name: "pipelineRun-name",
47+
},
4448
Status: v1.PipelineRunStatus{
4549
PipelineRunStatusFields: v1.PipelineRunStatusFields{
4650
Results: []v1.PipelineRunResult{
@@ -59,7 +63,7 @@ func TestByProducts(t *testing.T) {
5963
}
6064
want := []*intoto.ResourceDescriptor{
6165
{
62-
Name: "pipelineRunResults/result-name",
66+
Name: "pipelineRunResults/pipelineRun-name/result-name",
6367
Content: resultBytes,
6468
MediaType: JSONMediaType,
6569
},
@@ -147,19 +151,19 @@ func TestGenerateAttestation(t *testing.T) {
147151
},
148152
expectedByProducts: []*intoto.ResourceDescriptor{
149153
{
150-
Name: "pipelineRunResults/CHAINS-GIT_COMMIT",
154+
Name: "pipelineRunResults/pipelinerun-build/CHAINS-GIT_COMMIT",
151155
Content: []uint8(`"abcd"`),
152156
MediaType: JSONMediaType,
153157
}, {
154-
Name: "pipelineRunResults/CHAINS-GIT_URL",
158+
Name: "pipelineRunResults/pipelinerun-build/CHAINS-GIT_URL",
155159
Content: []uint8(`"https://git.test.com"`),
156160
MediaType: JSONMediaType,
157161
}, {
158-
Name: "pipelineRunResults/img-ARTIFACT_INPUTS",
162+
Name: "pipelineRunResults/pipelinerun-build/img-ARTIFACT_INPUTS",
159163
Content: []uint8(`{"digest":"sha256:827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7","uri":"abc"}`),
160164
MediaType: JSONMediaType,
161165
}, {
162-
Name: "pipelineRunResults/img_no_uri-ARTIFACT_OUTPUTS",
166+
Name: "pipelineRunResults/pipelinerun-build/img_no_uri-ARTIFACT_OUTPUTS",
163167
Content: []uint8(`{"digest":"sha256:827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7"}`),
164168
MediaType: JSONMediaType,
165169
},
@@ -251,39 +255,39 @@ func TestGenerateAttestation(t *testing.T) {
251255
},
252256
expectedByProducts: []*intoto.ResourceDescriptor{
253257
{
254-
Name: "pipelineRunResults/CHAINS-GIT_COMMIT",
258+
Name: "pipelineRunResults/pipelinerun-build/CHAINS-GIT_COMMIT",
255259
Content: []uint8(`"abcd"`),
256260
MediaType: JSONMediaType,
257261
}, {
258-
Name: "pipelineRunResults/CHAINS-GIT_URL",
262+
Name: "pipelineRunResults/pipelinerun-build/CHAINS-GIT_URL",
259263
Content: []uint8(`"https://git.test.com"`),
260264
MediaType: JSONMediaType,
261265
}, {
262-
Name: "pipelineRunResults/img-ARTIFACT_INPUTS",
266+
Name: "pipelineRunResults/pipelinerun-build/img-ARTIFACT_INPUTS",
263267
Content: []uint8(`{"digest":"sha256:827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7","uri":"abc"}`),
264268
MediaType: JSONMediaType,
265269
}, {
266-
Name: "pipelineRunResults/img_no_uri-ARTIFACT_OUTPUTS",
270+
Name: "pipelineRunResults/pipelinerun-build/img_no_uri-ARTIFACT_OUTPUTS",
267271
Content: []uint8(`{"digest":"sha256:827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7"}`),
268272
MediaType: JSONMediaType,
269273
}, {
270-
Name: "taskRunResults/some-uri_DIGEST",
274+
Name: "taskRunResults/git-clone/some-uri_DIGEST",
271275
Content: []uint8(`"sha256:d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"`),
272276
MediaType: JSONMediaType,
273277
}, {
274-
Name: "taskRunResults/some-uri",
278+
Name: "taskRunResults/git-clone/some-uri",
275279
Content: []uint8(`"pkg:deb/debian/[email protected]"`),
276280
MediaType: JSONMediaType,
277281
}, {
278-
Name: "stepResults/step1_result1-ARTIFACT_INPUTS",
282+
Name: "stepResults/git-clone/step1_result1-ARTIFACT_INPUTS",
279283
Content: []uint8(`{"digest":"sha1:7f2f46e1b97df36b2b82d1b1d87c81b8b3d21601","uri":"https://github.com/tektoncd/pipeline"}`),
280284
MediaType: JSONMediaType,
281285
}, {
282-
Name: "stepResults/step1_result1",
286+
Name: "stepResults/taskrun-build/step1_result1",
283287
Content: []uint8(`"result-value"`),
284288
MediaType: JSONMediaType,
285289
}, {
286-
Name: "stepResults/step1_result1-ARTIFACT_OUTPUTS",
290+
Name: "stepResults/taskrun-build/step1_result1-ARTIFACT_OUTPUTS",
287291
Content: []uint8(`{"digest":"sha256:827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7","uri":"gcr.io/my/image/fromstep2"}`),
288292
MediaType: JSONMediaType,
289293
},
@@ -388,35 +392,35 @@ func TestGenerateAttestation(t *testing.T) {
388392
},
389393
expectedByProducts: []*intoto.ResourceDescriptor{
390394
{
391-
Name: "pipelineRunResults/CHAINS-GIT_COMMIT",
395+
Name: "pipelineRunResults/pipelinerun-build/CHAINS-GIT_COMMIT",
392396
Content: []uint8(`"abcd"`),
393397
MediaType: JSONMediaType,
394398
}, {
395-
Name: "pipelineRunResults/CHAINS-GIT_URL",
399+
Name: "pipelineRunResults/pipelinerun-build/CHAINS-GIT_URL",
396400
Content: []uint8(`"https://git.test.com"`),
397401
MediaType: JSONMediaType,
398402
}, {
399-
Name: "pipelineRunResults/img-ARTIFACT_INPUTS",
403+
Name: "pipelineRunResults/pipelinerun-build/img-ARTIFACT_INPUTS",
400404
Content: []uint8(`{"digest":"sha256:827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7","uri":"abc"}`),
401405
MediaType: JSONMediaType,
402406
}, {
403-
Name: "pipelineRunResults/img_no_uri-ARTIFACT_OUTPUTS",
407+
Name: "pipelineRunResults/pipelinerun-build/img_no_uri-ARTIFACT_OUTPUTS",
404408
Content: []uint8(`{"digest":"sha256:827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7"}`),
405409
MediaType: JSONMediaType,
406410
}, {
407-
Name: "taskRunResults/some-uri_DIGEST",
411+
Name: "taskRunResults/git-clone/some-uri_DIGEST",
408412
Content: []uint8(`"sha256:d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"`),
409413
MediaType: JSONMediaType,
410414
}, {
411-
Name: "taskRunResults/some-uri",
415+
Name: "taskRunResults/git-clone/some-uri",
412416
Content: []uint8(`"pkg:deb/debian/[email protected]"`),
413417
MediaType: JSONMediaType,
414418
}, {
415-
Name: "stepResults/step1_result1-ARTIFACT_INPUTS",
419+
Name: "stepResults/git-clone/step1_result1-ARTIFACT_INPUTS",
416420
Content: []uint8(`{"digest":"sha1:7f2f46e1b97df36b2b82d1b1d87c81b8b3d21601","uri":"https://github.com/tektoncd/pipeline"}`),
417421
MediaType: JSONMediaType,
418422
}, {
419-
Name: "stepResults/step1_result1",
423+
Name: "stepResults/taskrun-build/step1_result1",
420424
Content: []uint8(`"result-value"`),
421425
MediaType: JSONMediaType,
422426
},

pkg/chains/formats/slsa/v2alpha4/internal/taskrun/taskrun.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ import (
2929
)
3030

3131
const (
32-
taskRunResults = "taskRunResults/%s"
33-
taskRunStepResults = "stepResults/%s"
32+
taskRunResults = "taskRunResults/%s/%s"
33+
taskRunStepResults = "stepResults/%s/%s"
3434
)
3535

3636
// GenerateAttestation returns the provenance for the given taskrun in SALSA 1.0 format.
@@ -55,13 +55,13 @@ func GenerateAttestation(ctx context.Context, tro *objects.TaskRunObjectV1, slsa
5555
func ByProducts(tro *objects.TaskRunObjectV1) ([]*intoto.ResourceDescriptor, error) {
5656
byProd := []*intoto.ResourceDescriptor{}
5757

58-
res, err := results.GetResultsWithoutBuildArtifacts(tro.GetResults(), taskRunResults)
58+
res, err := results.GetResultsWithoutBuildArtifacts(tro.GetName(), tro.GetResults(), taskRunResults)
5959
if err != nil {
6060
return nil, err
6161
}
6262
byProd = append(byProd, res...)
6363

64-
res, err = results.GetResultsWithoutBuildArtifacts(tro.GetStepResults(), taskRunStepResults)
64+
res, err = results.GetResultsWithoutBuildArtifacts(tro.GetName(), tro.GetStepResults(), taskRunStepResults)
6565
if err != nil {
6666
return nil, err
6767
}

pkg/chains/formats/slsa/v2alpha4/internal/taskrun/taskrun_test.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737
"google.golang.org/protobuf/testing/protocmp"
3838
"google.golang.org/protobuf/types/known/structpb"
3939
"google.golang.org/protobuf/types/known/timestamppb"
40+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
4041
logtesting "knative.dev/pkg/logging/testing"
4142
)
4243

@@ -45,6 +46,9 @@ const jsonMediaType = "application/json"
4546
func TestByProducts(t *testing.T) {
4647
resultValue := v1.ResultValue{Type: "string", StringVal: "result-value"}
4748
tr := &v1.TaskRun{
49+
ObjectMeta: metav1.ObjectMeta{
50+
Name: "taskRun-name",
51+
},
4852
Status: v1.TaskRunStatus{
4953
TaskRunStatusFields: v1.TaskRunStatusFields{
5054
Results: []v1.TaskRunResult{
@@ -63,7 +67,7 @@ func TestByProducts(t *testing.T) {
6367
}
6468
want := []*intoto.ResourceDescriptor{
6569
{
66-
Name: "taskRunResults/result-name",
70+
Name: "taskRunResults/taskRun-name/result-name",
6771
Content: resultBytes,
6872
MediaType: jsonMediaType,
6973
},
@@ -134,12 +138,12 @@ func TestTaskRunGenerateAttestation(t *testing.T) {
134138
},
135139
Byproducts: []*intoto.ResourceDescriptor{
136140
{
137-
Name: "stepResults/step1_result1",
141+
Name: "stepResults/taskrun-build/step1_result1",
138142
MediaType: "application/json",
139143
Content: []uint8(`"result-value"`),
140144
},
141145
{
142-
Name: "stepResults/step1_result1-ARTIFACT_OUTPUTS",
146+
Name: "stepResults/taskrun-build/step1_result1-ARTIFACT_OUTPUTS",
143147
MediaType: "application/json",
144148
Content: []uint8(`{"digest":"sha256:827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7","uri":"gcr.io/my/image/fromstep2"}`),
145149
},

pkg/chains/formats/slsa/v2alpha4/slsav2_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,12 @@ func TestTaskRunCreatePayload1(t *testing.T) {
169169
},
170170
Byproducts: []*intoto.ResourceDescriptor{
171171
{
172-
Name: "stepResults/step1_result1",
172+
Name: "stepResults/taskrun-build/step1_result1",
173173
Content: resultBytesStepResult,
174174
MediaType: jsonMediaType,
175175
},
176176
{
177-
Name: "stepResults/step1_result1-ARTIFACT_OUTPUTS",
177+
Name: "stepResults/taskrun-build/step1_result1-ARTIFACT_OUTPUTS",
178178
Content: resultBytesStepResultObj,
179179
MediaType: jsonMediaType,
180180
},
@@ -282,17 +282,17 @@ func TestTaskRunCreatePayload2(t *testing.T) {
282282
},
283283
Byproducts: []*intoto.ResourceDescriptor{
284284
{
285-
Name: "taskRunResults/some-uri_DIGEST",
285+
Name: "taskRunResults/git-clone/some-uri_DIGEST",
286286
Content: resultBytesDigest,
287287
MediaType: jsonMediaType,
288288
},
289289
{
290-
Name: "taskRunResults/some-uri",
290+
Name: "taskRunResults/git-clone/some-uri",
291291
Content: resultBytesURI,
292292
MediaType: jsonMediaType,
293293
},
294294
{
295-
Name: "stepResults/step1_result1-ARTIFACT_INPUTS",
295+
Name: "stepResults/git-clone/step1_result1-ARTIFACT_INPUTS",
296296
Content: resultBytesObj,
297297
MediaType: jsonMediaType,
298298
},

0 commit comments

Comments
 (0)