Skip to content

Commit 9a67b0f

Browse files
authored
PipelineRuns with v2alpha4 to process StepActions (tektoncd#1118)
* Add new v2alpha4 version for PipelineRuns This new version will now process the information from any associated StepAction from the executed PipelineRun when `artifacts.pipelinerun.enable-deep-inspection` is set to `true`. Also, the way chains read results from PipelineRuns to populate the `subjects` field is changing: now the user has to explicitly mark a result as a subject using an object type-hinted tag (*ARTIFACT_OUTPUTS) + the new `isBuildArtifact` property in the value. Refactors to share logic between v2alph3 and v2alpha4. * Fix issue when reading *IMAGE_URL / *IMAGE_DIGEST type hint results when two or more tasks/steps are using the same prefix.
1 parent 8e9373e commit 9a67b0f

File tree

28 files changed

+1910
-354
lines changed

28 files changed

+1910
-354
lines changed

docs/config.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Supported keys include:
3535

3636
| Key | Description | Supported Values | Default |
3737
| :--------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------- | :-------- |
38-
| `artifacts.pipelinerun.format` | The format to store `PipelineRun` payloads in. | `in-toto`, `slsa/v1`, `slsa/v2alpha3` | `in-toto` |
38+
| `artifacts.pipelinerun.format` | The format to store `PipelineRun` payloads in. | `in-toto`, `slsa/v1`, `slsa/v2alpha3`, `slsa/v2alpha4` | `in-toto` |
3939
| `artifacts.pipelinerun.storage` | The storage backend to store `PipelineRun` signatures in. Multiple backends can be specified with comma-separated list ("tekton,oci"). To disable the `PipelineRun` artifact input an empty string (""). | `tekton`, `oci`, `gcs`, `docdb`, `grafeas` | `tekton` |
4040
| `artifacts.pipelinerun.signer` | The signature backend to sign `PipelineRun` payloads with. | `x509`, `kms` | `x509` |
4141
| `artifacts.pipelinerun.enable-deep-inspection` | This boolean option will configure whether Chains should inspect child taskruns in order to capture inputs/outputs within a pipelinerun. `"false"` means that Chains only checks pipeline level results, whereas `"true"` means Chains inspects both pipeline level and task level results. | `"true"`, `"false"` | `"false"` |
@@ -45,6 +45,7 @@ Supported keys include:
4545
> - For grafeas storage backend, currently we only support Container Analysis. We will make grafeas server address configurabe within a short time.
4646
> - `slsa/v1` is an alias of `in-toto` for backwards compatibility.
4747
> - `slsa/v2alpha3` corresponds to the slsav1.0 spec. and uses latest [`v1` Tekton Objects](https://tekton.dev/docs/pipelines/pipeline-api/#tekton.dev/v1). Recommended format for new chains users who want the slsav1.0 spec.
48+
> - `slsa/v2alpha4` corresponds to the slsav1.0 spec. and uses latest [`v1` Tekton Objects](https://tekton.dev/docs/pipelines/pipeline-api/#tekton.dev/v1). It reads type-hinted results from [StepActions](https://tekton.dev/docs/pipelines/pipeline-api/#tekton.dev/v1alpha1.StepAction) when `artifacts.pipelinerun.enable-deep-inspection` is set to `true`. Recommended format for new chains users who want the slsav1.0 spec.
4849
4950

5051
### OCI Configuration

docs/slsa-provenance.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ spec:
373373
374374
`second-ARTIFACT_OUTPUTS`, `third-IMAGE_URL`/`third-IMAGE_DIGEST`, and `IMAGES` will be considered as `subject`. `first-ARTIFACT_OUTPUTS` doesn't specify `isBuildArtifact: true` so it is not count as `subject`.
375375
376-
Chains' `v2alpha4` formatter now automatically reads type-hinted results from StepActions associated to the executed TaskRun; users no longer need to manually surface these results from the StepActions when the appropriate type hints are in place. For instance, with the following TaskRun:
376+
Chains' `v2alpha4` formatter now automatically reads type-hinted results from StepActions associated to the executed TaskRun/PipelineRun; users no longer need to manually surface these results from the StepActions when the appropriate type hints are in place. PipelineRuns require `artifacts.pipelinerun.enable-deep-inspection: true` for this functionality to work. For instance, with the following TaskRun:
377377
378378
```yaml
379379
apiVersion: tekton.dev/v1alpha1
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
apiVersion: tekton.dev/v1
2+
kind: PipelineRun
3+
metadata:
4+
name: pipeline-test-run
5+
spec:
6+
pipelineSpec:
7+
results:
8+
- name: output1-ARTIFACT_OUTPUTS
9+
value: $(tasks.t1.results.output1)
10+
- name: output2-ARTIFACT_OUTPUTS
11+
value: $(tasks.t1.results.output2)
12+
tasks:
13+
- name: t1
14+
taskSpec:
15+
results:
16+
- name: output1
17+
type: object
18+
properties:
19+
uri: {}
20+
digest: {}
21+
isBuildArtifact: {}
22+
23+
- name: output2
24+
type: object
25+
properties:
26+
uri: {}
27+
digest: {}
28+
29+
steps:
30+
- name: step1
31+
image: busybox:glibc
32+
script: |
33+
echo -n "Hello!"
34+
echo -n "{\"uri\":\"gcr.io/foo/img1\", \"digest\":\"sha256:586789aa031fafc7d78a5393cdc772e0b55107ea54bb8bcf3f2cdac6c6da51ee\", \"isBuildArtifact\": \"true\" }" > $(results.output1.path)
35+
echo -n "{\"uri\":\"gcr.io/foo/img2\", \"digest\":\"sha256:586789aa031fafc7d78a5393cdc772e0b55107ea54bb8bcf3f2cdac6c6da51ee\"}" > $(results.output2.path)

pkg/artifacts/signable.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -299,14 +299,7 @@ func ExtractStructuredTargetFromResults(ctx context.Context, objResults []object
299299
}
300300

301301
// TODO(#592): support structured results using Run
302-
results := []objects.Result{}
303302
for _, res := range objResults {
304-
results = append(results, objects.Result{
305-
Name: res.Name,
306-
Value: res.Value,
307-
})
308-
}
309-
for _, res := range results {
310303
if strings.HasSuffix(res.Name, categoryMarker) {
311304
valid, err := isStructuredResult(res, categoryMarker)
312305
if err != nil {

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
externalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/external_parameters"
2323
internalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/internal_parameters"
2424
resolveddependencies "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/resolved_dependencies"
25+
"github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/slsaconfig"
2526
"github.com/tektoncd/chains/pkg/chains/objects"
2627
"google.golang.org/protobuf/encoding/protojson"
2728
"google.golang.org/protobuf/types/known/structpb"
@@ -62,6 +63,46 @@ func GetTaskRunBuildDefinition(ctx context.Context, tro *objects.TaskRunObjectV1
6263
}, nil
6364
}
6465

66+
// GetPipelineRunBuildDefinition returns the buildDefinition for the given PipelineRun based on the configured buildType. This will default to the slsa buildType
67+
func GetPipelineRunBuildDefinition(ctx context.Context, pro *objects.PipelineRunObjectV1, slsaconfig *slsaconfig.SlsaConfig, resolveOpts resolveddependencies.ResolveOptions) (slsa.BuildDefinition, error) {
68+
buildDefinitionType := slsaconfig.BuildType
69+
if slsaconfig.BuildType == "" {
70+
buildDefinitionType = buildtypes.SlsaBuildType
71+
}
72+
73+
td, err := resolveddependencies.GetTaskDescriptor(buildDefinitionType)
74+
if err != nil {
75+
return slsa.BuildDefinition{}, err
76+
}
77+
78+
rd, err := resolveddependencies.PipelineRun(ctx, pro, slsaconfig, resolveOpts, td)
79+
if err != nil {
80+
return slsa.BuildDefinition{}, err
81+
}
82+
83+
externalParams := externalparameters.PipelineRun(pro)
84+
structExternalParams, err := getStruct(externalParams)
85+
if err != nil {
86+
return slsa.BuildDefinition{}, err
87+
}
88+
89+
internalParams, err := internalparameters.GetInternalParamters(pro, buildDefinitionType)
90+
if err != nil {
91+
return slsa.BuildDefinition{}, err
92+
}
93+
structInternalParams, err := getStruct(internalParams)
94+
if err != nil {
95+
return slsa.BuildDefinition{}, err
96+
}
97+
98+
return slsa.BuildDefinition{
99+
BuildType: buildDefinitionType,
100+
ExternalParameters: structExternalParams,
101+
InternalParameters: structInternalParams,
102+
ResolvedDependencies: rd,
103+
}, nil
104+
}
105+
65106
func getStruct(data map[string]any) (*structpb.Struct, error) {
66107
bytes, err := json.Marshal(data)
67108
if err != nil {

pkg/chains/formats/slsa/internal/build_definition/build_definition_test.go

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,18 @@ import (
1919

2020
"github.com/google/go-cmp/cmp"
2121
slsa "github.com/in-toto/attestation/go/predicates/provenance/v1"
22+
intoto "github.com/in-toto/attestation/go/v1"
2223
externalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/external_parameters"
2324
internalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/internal_parameters"
2425
resolveddependencies "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/resolved_dependencies"
26+
"github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/slsaconfig"
2527
"github.com/tektoncd/chains/pkg/chains/objects"
2628
"github.com/tektoncd/chains/pkg/internal/objectloader"
2729
"google.golang.org/protobuf/testing/protocmp"
2830
"google.golang.org/protobuf/types/known/structpb"
2931
)
3032

31-
func TestGetBuildDefinition(t *testing.T) {
33+
func TestGetTaskRunBuildDefinition(t *testing.T) {
3234
tr, err := objectloader.TaskRunFromFile("../../testdata/slsa-v2alpha4/taskrun1.json")
3335
if err != nil {
3436
t.Fatal(err)
@@ -103,7 +105,7 @@ func TestGetBuildDefinition(t *testing.T) {
103105
}
104106
}
105107

106-
func TestUnsupportedBuildType(t *testing.T) {
108+
func TestTaskRunUnsupportedBuildType(t *testing.T) {
107109
tr, err := objectloader.TaskRunFromFile("../../testdata/slsa-v2alpha4/taskrun1.json")
108110
if err != nil {
109111
t.Fatal(err)
@@ -127,3 +129,102 @@ func getProtoStruct(t *testing.T, data map[string]any) *structpb.Struct {
127129

128130
return protoStruct
129131
}
132+
133+
func TestGetPipelineRunBuildDefinition(t *testing.T) {
134+
pr := createPro("../../testdata/slsa-v2alpha3/pipelinerun1.json")
135+
pr.Annotations = map[string]string{
136+
"annotation1": "annotation1",
137+
}
138+
pr.Labels = map[string]string{
139+
"label1": "label1",
140+
}
141+
tests := []struct {
142+
name string
143+
config *slsaconfig.SlsaConfig
144+
want slsa.BuildDefinition
145+
}{
146+
{
147+
name: "test slsa build type",
148+
config: &slsaconfig.SlsaConfig{BuildType: "https://tekton.dev/chains/v2/slsa"},
149+
want: slsa.BuildDefinition{
150+
BuildType: "https://tekton.dev/chains/v2/slsa",
151+
ExternalParameters: getProtoStruct(t, externalparameters.PipelineRun(pr)),
152+
InternalParameters: getProtoStruct(t, internalparameters.SLSAInternalParameters(pr)),
153+
ResolvedDependencies: getResolvedDependencies(pr, resolveddependencies.AddSLSATaskDescriptor),
154+
},
155+
},
156+
{
157+
name: "test tekton build type",
158+
config: &slsaconfig.SlsaConfig{BuildType: "https://tekton.dev/chains/v2/slsa-tekton"},
159+
want: slsa.BuildDefinition{
160+
BuildType: "https://tekton.dev/chains/v2/slsa-tekton",
161+
ExternalParameters: getProtoStruct(t, externalparameters.PipelineRun(pr)),
162+
InternalParameters: getProtoStruct(t, internalparameters.TektonInternalParameters(pr)),
163+
ResolvedDependencies: getResolvedDependencies(pr, resolveddependencies.AddTektonTaskDescriptor),
164+
},
165+
},
166+
{
167+
name: "test default build type",
168+
config: &slsaconfig.SlsaConfig{BuildType: "https://tekton.dev/chains/v2/slsa"},
169+
want: slsa.BuildDefinition{
170+
BuildType: "https://tekton.dev/chains/v2/slsa",
171+
ExternalParameters: getProtoStruct(t, externalparameters.PipelineRun(pr)),
172+
InternalParameters: getProtoStruct(t, internalparameters.SLSAInternalParameters(pr)),
173+
ResolvedDependencies: getResolvedDependencies(pr, resolveddependencies.AddSLSATaskDescriptor),
174+
},
175+
},
176+
}
177+
178+
for i := range tests {
179+
tc := &tests[i]
180+
t.Run(tc.name, func(t *testing.T) {
181+
bd, err := GetPipelineRunBuildDefinition(context.TODO(), pr, tc.config, resolveddependencies.ResolveOptions{})
182+
if err != nil {
183+
t.Fatalf("Did not expect an error but got %v", err)
184+
}
185+
186+
if diff := cmp.Diff(&tc.want, &bd, protocmp.Transform()); diff != "" {
187+
t.Errorf("getBuildDefinition(): -want +got: %v", diff)
188+
}
189+
})
190+
}
191+
}
192+
193+
func createPro(path string) *objects.PipelineRunObjectV1 {
194+
pr, err := objectloader.PipelineRunFromFile(path)
195+
if err != nil {
196+
panic(err)
197+
}
198+
tr1, err := objectloader.TaskRunFromFile("../../testdata/slsa-v2alpha3/taskrun1.json")
199+
if err != nil {
200+
panic(err)
201+
}
202+
tr2, err := objectloader.TaskRunFromFile("../../testdata/slsa-v2alpha3/taskrun2.json")
203+
if err != nil {
204+
panic(err)
205+
}
206+
p := objects.NewPipelineRunObjectV1(pr)
207+
p.AppendTaskRun(tr1)
208+
p.AppendTaskRun(tr2)
209+
return p
210+
}
211+
212+
func getResolvedDependencies(pr *objects.PipelineRunObjectV1, addTasks func(*objects.TaskRunObjectV1) (*intoto.ResourceDescriptor, error)) []*intoto.ResourceDescriptor {
213+
rd, err := resolveddependencies.PipelineRun(context.Background(), pr, &slsaconfig.SlsaConfig{}, resolveddependencies.ResolveOptions{}, addTasks)
214+
if err != nil {
215+
return []*intoto.ResourceDescriptor{}
216+
}
217+
return rd
218+
}
219+
220+
func TestPipelineRunUnsupportedBuildType(t *testing.T) {
221+
pr := createPro("../../testdata/slsa-v2alpha3/pipelinerun1.json")
222+
223+
got, err := GetPipelineRunBuildDefinition(context.Background(), pr, &slsaconfig.SlsaConfig{BuildType: "bad-buildtype"}, resolveddependencies.ResolveOptions{})
224+
if err == nil {
225+
t.Error("getBuildDefinition(): expected error got nil")
226+
}
227+
if diff := cmp.Diff(&slsa.BuildDefinition{}, &got, protocmp.Transform()); diff != "" {
228+
t.Errorf("getBuildDefinition(): -want +got: %s", diff)
229+
}
230+
}

0 commit comments

Comments
 (0)