Skip to content

Commit

Permalink
Add new v2alpha4 version for PipelineRuns
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
renzodavid9 committed May 14, 2024
1 parent 490fd52 commit 0cbce63
Show file tree
Hide file tree
Showing 23 changed files with 1,693 additions and 278 deletions.
5 changes: 3 additions & 2 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Supported keys include:

| Key | Description | Supported Values | Default |
| :--------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------- | :-------- |
| `artifacts.pipelinerun.format` | The format to store `PipelineRun` payloads in. | `in-toto`, `slsa/v1`, `slsa/v2alpha2`, `slsa/v2alpha3` | `in-toto` |
| `artifacts.pipelinerun.format` | The format to store `PipelineRun` payloads in. | `in-toto`, `slsa/v1`, `slsa/v2alpha2`, `slsa/v2alpha3`, `slsa/v2alpha4` | `in-toto` |
| `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` |
| `artifacts.pipelinerun.signer` | The signature backend to sign `PipelineRun` payloads with. | `x509`, `kms` | `x509` |
| `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"` |
Expand All @@ -46,7 +46,8 @@ Supported keys include:
> - For grafeas storage backend, currently we only support Container Analysis. We will make grafeas server address configurabe within a short time.
> - `slsa/v1` is an alias of `in-toto` for backwards compatibility.
> - `slsa/v2alpha2` corresponds to the slsav1.0 spec. and uses now deprecated [`v1beta1` Tekton Objects](https://tekton.dev/docs/pipelines/pipeline-api/#tekton.dev/v1beta1)
> - `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.
> - `slsa/v2alpha3` corresponds to the slsav1.0 spec. and uses latest [`v1` Tekton Objects](https://tekton.dev/docs/pipelines/pipeline-api/#tekton.dev/v1).
> - `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.

### OCI Configuration
Expand Down
2 changes: 1 addition & 1 deletion docs/slsa-provenance.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ spec:

Only the result `second-ARTIFACT_OUTPUTS` will be considered as a `subject` due to it uses the `*ARTIFACT_OUTPUTS` type hint format, and has `isBuildArtifact` set to `true`.

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, the following TaskRun:
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. For instance, the following TaskRun:

```yaml
apiVersion: tekton.dev/v1alpha1
Expand Down
35 changes: 35 additions & 0 deletions examples/v2alpha4/pipeline-with-object-type-hinting.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
name: pipeline-test-run
spec:
pipelineSpec:
results:
- name: output1-ARTIFACT_OUTPUTS
value: $(tasks.t1.results.output1)
- name: output2-ARTIFACT_OUTPUTS
value: $(tasks.t1.results.output2)
tasks:
- name: t1
taskSpec:
results:
- name: output1
type: object
properties:
uri: {}
digest: {}
isBuildArtifact: {}

- name: output2
type: object
properties:
uri: {}
digest: {}

steps:
- name: step1
image: busybox:glibc
script: |
echo -n "Hello!"
echo -n "{\"uri\":\"gcr.io/foo/img1\", \"digest\":\"sha256:586789aa031fafc7d78a5393cdc772e0b55107ea54bb8bcf3f2cdac6c6da51ee\", \"isBuildArtifact\": \"true\" }" > $(results.output1.path)
echo -n "{\"uri\":\"gcr.io/foo/img2\", \"digest\":\"sha256:586789aa031fafc7d78a5393cdc772e0b55107ea54bb8bcf3f2cdac6c6da51ee\"}" > $(results.output2.path)
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
externalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/external_parameters"
internalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/internal_parameters"
resolveddependencies "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/resolved_dependencies"
"github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/slsaconfig"
"github.com/tektoncd/chains/pkg/chains/objects"
)

Expand Down Expand Up @@ -55,3 +56,30 @@ func GetTaskRunBuildDefinition(ctx context.Context, tro *objects.TaskRunObjectV1

return getBuildDefinition(buildDefinitionType, rd, externalParams, internalParams), nil
}

// GetBuildDefinition returns the buildDefinition for the given PipelineRun based on the configured buildType. This will default to the slsa buildType

Check warning on line 60 in pkg/chains/formats/slsa/internal/build_definition/build_definition.go

View workflow job for this annotation

GitHub Actions / lint

exported: comment on exported function GetPipelineRunBuildDefinition should be of the form "GetPipelineRunBuildDefinition ..." (revive)
func GetPipelineRunBuildDefinition(ctx context.Context, pro *objects.PipelineRunObjectV1, slsaconfig *slsaconfig.SlsaConfig, resolveOpts resolveddependencies.ResolveOptions) (slsa.ProvenanceBuildDefinition, error) {
buildDefinitionType := slsaconfig.BuildType
if slsaconfig.BuildType == "" {
buildDefinitionType = buildtypes.SlsaBuildType
}

td, err := resolveddependencies.GetTaskDescriptor(buildDefinitionType)
if err != nil {
return slsa.ProvenanceBuildDefinition{}, err
}

rd, err := resolveddependencies.PipelineRun(ctx, pro, slsaconfig, resolveOpts, td)
if err != nil {
return slsa.ProvenanceBuildDefinition{}, err
}

externalParams := externalparameters.PipelineRun(pro)

internalParams, err := internalparameters.GetInternalParamters(pro, buildDefinitionType)
if err != nil {
return slsa.ProvenanceBuildDefinition{}, err
}

return getBuildDefinition(buildDefinitionType, rd, externalParams, internalParams), nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@ import (

"github.com/google/go-cmp/cmp"
slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1"
v1resourcedescriptor "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1"
externalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/external_parameters"
internalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/internal_parameters"
resolveddependencies "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/resolved_dependencies"
"github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/slsaconfig"
"github.com/tektoncd/chains/pkg/chains/objects"
"github.com/tektoncd/chains/pkg/internal/objectloader"
)

func TestGetBuildDefinition(t *testing.T) {
func TestGetTaskRunBuildDefinition(t *testing.T) {
tr, err := objectloader.TaskRunFromFile("../../testdata/slsa-v2alpha4/taskrun1.json")
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -100,7 +102,7 @@ func TestGetBuildDefinition(t *testing.T) {
}
}

func TestUnsupportedBuildType(t *testing.T) {
func TestTaskRunnUnsupportedBuildType(t *testing.T) {
tr, err := objectloader.TaskRunFromFile("../../testdata/slsa-v2alpha4/taskrun1.json")
if err != nil {
t.Fatal(err)
Expand All @@ -114,3 +116,101 @@ func TestUnsupportedBuildType(t *testing.T) {
t.Errorf("getBuildDefinition(): -want +got: %s", diff)
}
}

func TestGetPipelineRunBuildDefinition(t *testing.T) {
pr := createPro("../../testdata/slsa-v2alpha3/pipelinerun1.json")
pr.Annotations = map[string]string{
"annotation1": "annotation1",
}
pr.Labels = map[string]string{
"label1": "label1",
}
tests := []struct {
name string
config *slsaconfig.SlsaConfig
want slsa.ProvenanceBuildDefinition
}{
{
name: "test slsa build type",
config: &slsaconfig.SlsaConfig{BuildType: "https://tekton.dev/chains/v2/slsa"},
want: slsa.ProvenanceBuildDefinition{
BuildType: "https://tekton.dev/chains/v2/slsa",
ExternalParameters: externalparameters.PipelineRun(pr),
InternalParameters: internalparameters.SLSAInternalParameters(pr),
ResolvedDependencies: getResolvedDependencies(pr, resolveddependencies.AddSLSATaskDescriptor),
},
},
{
name: "test tekton build type",
config: &slsaconfig.SlsaConfig{BuildType: "https://tekton.dev/chains/v2/slsa-tekton"},
want: slsa.ProvenanceBuildDefinition{
BuildType: "https://tekton.dev/chains/v2/slsa-tekton",
ExternalParameters: externalparameters.PipelineRun(pr),
InternalParameters: internalparameters.TektonInternalParameters(pr),
ResolvedDependencies: getResolvedDependencies(pr, resolveddependencies.AddTektonTaskDescriptor),
},
},
{
name: "test default build type",
config: &slsaconfig.SlsaConfig{BuildType: "https://tekton.dev/chains/v2/slsa"},
want: slsa.ProvenanceBuildDefinition{
BuildType: "https://tekton.dev/chains/v2/slsa",
ExternalParameters: externalparameters.PipelineRun(pr),
InternalParameters: internalparameters.SLSAInternalParameters(pr),
ResolvedDependencies: getResolvedDependencies(pr, resolveddependencies.AddSLSATaskDescriptor),
},
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
bd, err := GetPipelineRunBuildDefinition(context.TODO(), pr, tc.config, resolveddependencies.ResolveOptions{})
if err != nil {
t.Fatalf("Did not expect an error but got %v", err)
}

if diff := cmp.Diff(tc.want, bd); diff != "" {
t.Errorf("getBuildDefinition(): -want +got: %v", diff)
}
})
}
}

func createPro(path string) *objects.PipelineRunObjectV1 {
pr, err := objectloader.PipelineRunFromFile(path)
if err != nil {
panic(err)
}
tr1, err := objectloader.TaskRunFromFile("../../testdata/slsa-v2alpha3/taskrun1.json")
if err != nil {
panic(err)
}
tr2, err := objectloader.TaskRunFromFile("../../testdata/slsa-v2alpha3/taskrun2.json")
if err != nil {
panic(err)
}
p := objects.NewPipelineRunObjectV1(pr)
p.AppendTaskRun(tr1)
p.AppendTaskRun(tr2)
return p
}

func getResolvedDependencies(pr *objects.PipelineRunObjectV1, addTasks func(*objects.TaskRunObjectV1) (*v1resourcedescriptor.ResourceDescriptor, error)) []v1resourcedescriptor.ResourceDescriptor { //nolint:staticcheck
rd, err := resolveddependencies.PipelineRun(context.Background(), pr, &slsaconfig.SlsaConfig{}, resolveddependencies.ResolveOptions{}, addTasks)
if err != nil {
return []v1resourcedescriptor.ResourceDescriptor{}
}
return rd
}

func TestPipelineRunUnsupportedBuildType(t *testing.T) {
pr := createPro("../../testdata/slsa-v2alpha3/pipelinerun1.json")

got, err := GetPipelineRunBuildDefinition(context.Background(), pr, &slsaconfig.SlsaConfig{BuildType: "bad-buildtype"}, resolveddependencies.ResolveOptions{})
if err == nil {
t.Error("getBuildDefinition(): expected error got nil")
}
if diff := cmp.Diff(slsa.ProvenanceBuildDefinition{}, got); diff != "" {
t.Errorf("getBuildDefinition(): -want +got: %s", diff)
}
}

0 comments on commit 0cbce63

Please sign in to comment.