Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PipelineRuns with v2alpha4 to process StepActions #1118

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Supported keys include:

| Key | Description | Supported Values | Default |
| :--------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------- | :-------- |
| `artifacts.pipelinerun.format` | The format to store `PipelineRun` payloads in. | `in-toto`, `slsa/v1`, `slsa/v2alpha3` | `in-toto` |
| `artifacts.pipelinerun.format` | The format to store `PipelineRun` payloads in. | `in-toto`, `slsa/v1`, `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 @@ -45,6 +45,7 @@ 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/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/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 @@ -373,7 +373,7 @@ spec:

`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`.

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:
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:

```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)
7 changes: 0 additions & 7 deletions pkg/artifacts/signable.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,14 +299,7 @@ func ExtractStructuredTargetFromResults(ctx context.Context, objResults []object
}

// TODO(#592): support structured results using Run
results := []objects.Result{}
for _, res := range objResults {
results = append(results, objects.Result{
Name: res.Name,
Value: res.Value,
})
}
for _, res := range results {
if strings.HasSuffix(res.Name, categoryMarker) {
valid, err := isStructuredResult(res, categoryMarker)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,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"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/types/known/structpb"
Expand Down Expand Up @@ -62,6 +63,46 @@ func GetTaskRunBuildDefinition(ctx context.Context, tro *objects.TaskRunObjectV1
}, nil
}

// GetPipelineRunBuildDefinition returns the buildDefinition for the given PipelineRun based on the configured buildType. This will default to the slsa buildType
func GetPipelineRunBuildDefinition(ctx context.Context, pro *objects.PipelineRunObjectV1, slsaconfig *slsaconfig.SlsaConfig, resolveOpts resolveddependencies.ResolveOptions) (slsa.BuildDefinition, error) {
buildDefinitionType := slsaconfig.BuildType
if slsaconfig.BuildType == "" {
buildDefinitionType = buildtypes.SlsaBuildType
}

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

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

externalParams := externalparameters.PipelineRun(pro)
structExternalParams, err := getStruct(externalParams)
if err != nil {
return slsa.BuildDefinition{}, err
}

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

return slsa.BuildDefinition{
BuildType: buildDefinitionType,
ExternalParameters: structExternalParams,
InternalParameters: structInternalParams,
ResolvedDependencies: rd,
}, nil
}

func getStruct(data map[string]any) (*structpb.Struct, error) {
bytes, err := json.Marshal(data)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,18 @@ import (

"github.com/google/go-cmp/cmp"
slsa "github.com/in-toto/attestation/go/predicates/provenance/v1"
intoto "github.com/in-toto/attestation/go/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"
"google.golang.org/protobuf/testing/protocmp"
"google.golang.org/protobuf/types/known/structpb"
)

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 @@ -103,7 +105,7 @@ func TestGetBuildDefinition(t *testing.T) {
}
}

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

return protoStruct
}

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.BuildDefinition
}{
{
name: "test slsa build type",
config: &slsaconfig.SlsaConfig{BuildType: "https://tekton.dev/chains/v2/slsa"},
want: slsa.BuildDefinition{
BuildType: "https://tekton.dev/chains/v2/slsa",
ExternalParameters: getProtoStruct(t, externalparameters.PipelineRun(pr)),
InternalParameters: getProtoStruct(t, 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.BuildDefinition{
BuildType: "https://tekton.dev/chains/v2/slsa-tekton",
ExternalParameters: getProtoStruct(t, externalparameters.PipelineRun(pr)),
InternalParameters: getProtoStruct(t, 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.BuildDefinition{
BuildType: "https://tekton.dev/chains/v2/slsa",
ExternalParameters: getProtoStruct(t, externalparameters.PipelineRun(pr)),
InternalParameters: getProtoStruct(t, internalparameters.SLSAInternalParameters(pr)),
ResolvedDependencies: getResolvedDependencies(pr, resolveddependencies.AddSLSATaskDescriptor),
},
},
}

for i := range tests {
tc := &tests[i]
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, protocmp.Transform()); 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) (*intoto.ResourceDescriptor, error)) []*intoto.ResourceDescriptor {
rd, err := resolveddependencies.PipelineRun(context.Background(), pr, &slsaconfig.SlsaConfig{}, resolveddependencies.ResolveOptions{}, addTasks)
if err != nil {
return []*intoto.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.BuildDefinition{}, &got, protocmp.Transform()); diff != "" {
t.Errorf("getBuildDefinition(): -want +got: %s", diff)
}
}
Loading
Loading