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.

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 bject 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 10, 2024
1 parent 6395432 commit 12d8357
Show file tree
Hide file tree
Showing 21 changed files with 1,686 additions and 277 deletions.
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
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)
}
}
161 changes: 119 additions & 42 deletions pkg/chains/formats/slsa/internal/metadata/metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,62 +25,139 @@ import (
)

func TestMetadata(t *testing.T) {
tr := &v1.TaskRun{ //nolint:staticcheck
ObjectMeta: metav1.ObjectMeta{
Name: "my-taskrun",
Namespace: "my-namespace",
Annotations: map[string]string{
"chains.tekton.dev/reproducible": "true",
tests := []struct {
name string
obj objects.TektonObject
expected slsa.BuildMetadata
}{
{

Check failure on line 33 in pkg/chains/formats/slsa/internal/metadata/metadata_test.go

View workflow job for this annotation

GitHub Actions / lint

33-56 lines are duplicate of `pkg/chains/formats/slsa/internal/metadata/metadata_test.go:57-80` (dupl)
name: "taskrun metadata",
obj: objects.NewTaskRunObjectV1(&v1.TaskRun{ //nolint:staticcheck
ObjectMeta: metav1.ObjectMeta{
Name: "my-taskrun",
Namespace: "my-namespace",
Annotations: map[string]string{
"chains.tekton.dev/reproducible": "true",
},
UID: "abhhf-12354-asjsdbjs23-3435353n",
},
Status: v1.TaskRunStatus{
TaskRunStatusFields: v1.TaskRunStatusFields{
StartTime: &metav1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 12, time.UTC)},
CompletionTime: &metav1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 24, time.UTC)},
},
},
}),
expected: slsa.BuildMetadata{
InvocationID: "abhhf-12354-asjsdbjs23-3435353n",
StartedOn: getPtr(time.Date(1995, time.December, 24, 6, 12, 12, 12, time.UTC)),
FinishedOn: getPtr(time.Date(1995, time.December, 24, 6, 12, 12, 24, time.UTC)),
},
UID: "abhhf-12354-asjsdbjs23-3435353n",
},
Status: v1.TaskRunStatus{
TaskRunStatusFields: v1.TaskRunStatusFields{
StartTime: &metav1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 12, time.UTC)},
CompletionTime: &metav1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 24, time.UTC)},
{

Check failure on line 57 in pkg/chains/formats/slsa/internal/metadata/metadata_test.go

View workflow job for this annotation

GitHub Actions / lint

57-80 lines are duplicate of `pkg/chains/formats/slsa/internal/metadata/metadata_test.go:33-56` (dupl)
name: "pipelinerun metadata",
obj: objects.NewPipelineRunObjectV1(&v1.PipelineRun{ //nolint:staticcheck
ObjectMeta: metav1.ObjectMeta{
Name: "my-taskrun",
Namespace: "my-namespace",
Annotations: map[string]string{
"chains.tekton.dev/reproducible": "true",
},
UID: "abhhf-12354-asjsdbjs23-3435353n",
},
Status: v1.PipelineRunStatus{
PipelineRunStatusFields: v1.PipelineRunStatusFields{
StartTime: &metav1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 12, time.UTC)},
CompletionTime: &metav1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 24, time.UTC)},
},
},
}),
expected: slsa.BuildMetadata{
InvocationID: "abhhf-12354-asjsdbjs23-3435353n",
StartedOn: getPtr(time.Date(1995, time.December, 24, 6, 12, 12, 12, time.UTC)),
FinishedOn: getPtr(time.Date(1995, time.December, 24, 6, 12, 12, 24, time.UTC)),
},
},
}
start := time.Date(1995, time.December, 24, 6, 12, 12, 12, time.UTC)
end := time.Date(1995, time.December, 24, 6, 12, 12, 24, time.UTC)
want := slsa.BuildMetadata{
InvocationID: "abhhf-12354-asjsdbjs23-3435353n",
StartedOn: &start,
FinishedOn: &end,
}
got := GetBuildMetadata(objects.NewTaskRunObjectV1(tr))
if d := cmp.Diff(want, got); d != "" {
t.Fatalf("metadata (-want, +got):\n%s", d)

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got := GetBuildMetadata(test.obj)
if d := cmp.Diff(test.expected, got); d != "" {
t.Fatalf("metadata (-want, +got):\n%s", d)
}
})
}
}

func TestMetadataInTimeZone(t *testing.T) {
tz := time.FixedZone("Test Time", int((12 * time.Hour).Seconds()))
tr := &v1.TaskRun{ //nolint:staticcheck
ObjectMeta: metav1.ObjectMeta{
Name: "my-taskrun",
Namespace: "my-namespace",
Annotations: map[string]string{
"chains.tekton.dev/reproducible": "true",

tests := []struct {
name string
obj objects.TektonObject
expected slsa.BuildMetadata
}{
{
name: "taskrun metadata",
obj: objects.NewTaskRunObjectV1(&v1.TaskRun{ //nolint:staticcheck
ObjectMeta: metav1.ObjectMeta{
Name: "my-taskrun",
Namespace: "my-namespace",
Annotations: map[string]string{
"chains.tekton.dev/reproducible": "true",
},
UID: "abhhf-12354-asjsdbjs23-3435353n",
},
Status: v1.TaskRunStatus{
TaskRunStatusFields: v1.TaskRunStatusFields{
StartTime: &metav1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 12, tz)},
CompletionTime: &metav1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 24, tz)},
},
},
}),
expected: slsa.BuildMetadata{
InvocationID: "abhhf-12354-asjsdbjs23-3435353n",
StartedOn: getPtr(time.Date(1995, time.December, 24, 6, 12, 12, 12, tz).UTC()),
FinishedOn: getPtr(time.Date(1995, time.December, 24, 6, 12, 12, 24, tz).UTC()),
},
UID: "abhhf-12354-asjsdbjs23-3435353n",
},
Status: v1.TaskRunStatus{
TaskRunStatusFields: v1.TaskRunStatusFields{
StartTime: &metav1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 12, tz)},
CompletionTime: &metav1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 24, tz)},
{
name: "pipelinerun metadata",
obj: objects.NewPipelineRunObjectV1(&v1.PipelineRun{ //nolint:staticcheck
ObjectMeta: metav1.ObjectMeta{
Name: "my-taskrun",
Namespace: "my-namespace",
Annotations: map[string]string{
"chains.tekton.dev/reproducible": "true",
},
UID: "abhhf-12354-asjsdbjs23-3435353n",
},
Status: v1.PipelineRunStatus{
PipelineRunStatusFields: v1.PipelineRunStatusFields{
StartTime: &metav1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 12, tz)},
CompletionTime: &metav1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 24, tz)},
},
},
}),
expected: slsa.BuildMetadata{
InvocationID: "abhhf-12354-asjsdbjs23-3435353n",
StartedOn: getPtr(time.Date(1995, time.December, 24, 6, 12, 12, 12, tz).UTC()),
FinishedOn: getPtr(time.Date(1995, time.December, 24, 6, 12, 12, 24, tz).UTC()),
},
},
}
start := time.Date(1995, time.December, 24, 6, 12, 12, 12, tz).UTC()
end := time.Date(1995, time.December, 24, 6, 12, 12, 24, tz).UTC()
want := slsa.BuildMetadata{
InvocationID: "abhhf-12354-asjsdbjs23-3435353n",
StartedOn: &start,
FinishedOn: &end,
}
got := GetBuildMetadata(objects.NewTaskRunObjectV1(tr))
if d := cmp.Diff(want, got); d != "" {
t.Fatalf("metadata (-want, +got):\n%s", d)

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got := GetBuildMetadata(test.obj)
if d := cmp.Diff(test.expected, got); d != "" {
t.Fatalf("metadata (-want, +got):\n%s", d)
}
})
}
}

func getPtr(t time.Time) *time.Time {
return &t
}
Loading

0 comments on commit 12d8357

Please sign in to comment.