diff --git a/pkg/chains/formats/slsa/internal/external_parameters/external_parameters.go b/pkg/chains/formats/slsa/internal/external_parameters/external_parameters.go index f31e4313f1..0921cbb3b8 100644 --- a/pkg/chains/formats/slsa/internal/external_parameters/external_parameters.go +++ b/pkg/chains/formats/slsa/internal/external_parameters/external_parameters.go @@ -19,6 +19,7 @@ package externalparameters import ( "fmt" + "github.com/tektoncd/chains/pkg/chains/objects" v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" ) @@ -35,3 +36,25 @@ func BuildConfigSource(provenance *v1.Provenance) map[string]string { } return buildConfigSource } + +// PipelineRun adds the pipeline run spec and provenance if available +func PipelineRun(pro *objects.PipelineRunObjectV1) map[string]any { + externalParams := make(map[string]any) + + if provenance := pro.GetRemoteProvenance(); provenance != nil { + externalParams["buildConfigSource"] = BuildConfigSource(provenance) + } + externalParams["runSpec"] = pro.Spec + return externalParams +} + +// TaskRun adds the task run spec and provenance if available +func TaskRun(tro *objects.TaskRunObjectV1) map[string]any { + externalParams := make(map[string]any) + + if provenance := tro.GetRemoteProvenance(); provenance != nil { + externalParams["buildConfigSource"] = BuildConfigSource(provenance) + } + externalParams["runSpec"] = tro.Spec + return externalParams +} diff --git a/pkg/chains/formats/slsa/internal/external_parameters/external_parameters_test.go b/pkg/chains/formats/slsa/internal/external_parameters/external_parameters_test.go index 3dfcabf8c4..10a3b411b3 100644 --- a/pkg/chains/formats/slsa/internal/external_parameters/external_parameters_test.go +++ b/pkg/chains/formats/slsa/internal/external_parameters/external_parameters_test.go @@ -20,9 +20,31 @@ import ( "strings" "testing" + "github.com/google/go-cmp/cmp" + "github.com/tektoncd/chains/pkg/chains/objects" + "github.com/tektoncd/chains/pkg/internal/objectloader" v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" ) +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 TestBuildConfigSource(t *testing.T) { digest := map[string]string{"alg1": "hex1", "alg2": "hex2"} provenance := &v1.Provenance{ @@ -61,3 +83,136 @@ func TestBuildConfigSource(t *testing.T) { t.Errorf("buildConfigSource() does not contain correct path: want: %s got: %s", want["path"], got["path"]) } } + +func TestPipelineRun(t *testing.T) { + tests := []struct { + name string + inputPipelineRunFile string + expectedExternalParameters map[string]any + }{ + { + name: "simple pipelinerun", + inputPipelineRunFile: "../../testdata/slsa-v2alpha3/pipelinerun1.json", + expectedExternalParameters: map[string]any{ + "runSpec": v1.PipelineRunSpec{ + PipelineRef: &v1.PipelineRef{Name: "test-pipeline"}, + Params: v1.Params{ + { + Name: "IMAGE", + Value: v1.ParamValue{Type: "string", StringVal: "test.io/test/image"}, + }, + }, + TaskRunTemplate: v1.PipelineTaskRunTemplate{ + ServiceAccountName: "pipeline", + }, + }, + }, + }, + { + name: "pipelinerun with remote resolver", + inputPipelineRunFile: "../../testdata/slsa-v2alpha3/pipelinerun-remote-resolver.json", + expectedExternalParameters: map[string]any{ + "runSpec": v1.PipelineRunSpec{ + PipelineRef: &v1.PipelineRef{ + ResolverRef: v1.ResolverRef{ + Resolver: "git", + Params: v1.Params{ + {Name: "url", Value: v1.ParamValue{Type: "string", StringVal: "https://github.com/tektoncd/catalog"}}, + {Name: "revision", Value: v1.ParamValue{Type: "string", StringVal: "main"}}, + {Name: "pathInRepo", Value: v1.ParamValue{Type: "string", StringVal: "pipeline/build-push-gke-deploy/0.1/build-push-gke-deploy.yaml"}}, + }, + }, + }, + Params: v1.Params{ + {Name: "pathToContext", Value: v1.ParamValue{Type: "string", StringVal: "gke-deploy/example/app"}}, + {Name: "pathToKubernetesConfigs", Value: v1.ParamValue{Type: "string", StringVal: "gke-deploy/example/app/config"}}, + }, + TaskRunTemplate: v1.PipelineTaskRunTemplate{ + ServiceAccountName: "default", + }, + }, + "buildConfigSource": map[string]string{ + "path": "pipeline/build-push-gke-deploy/0.1/build-push-gke-deploy.yaml", + "ref": "sha1:4df486f198c3c2616ab129186fb30a74f580b5a1", + "repository": "git+https://github.com/tektoncd/catalog", + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + pro := createPro(test.inputPipelineRunFile) + got := PipelineRun(pro) + if diff := cmp.Diff(test.expectedExternalParameters, got); diff != "" { + t.Errorf("PipelineRun(): -want +got: %s", diff) + } + }) + } +} + +func TestTaskRun(t *testing.T) { + tests := []struct { + name string + inputTaskRunFile string + expectedExternalParameters map[string]any + }{ + { + name: "simple taskrun", + inputTaskRunFile: "../../testdata/slsa-v2alpha3/taskrun1.json", + expectedExternalParameters: map[string]any{ + "runSpec": v1.TaskRunSpec{ + Params: v1.Params{ + {Name: "IMAGE", Value: v1.ParamValue{Type: "string", StringVal: "test.io/test/image"}}, + {Name: "CHAINS-GIT_COMMIT", Value: v1.ParamValue{Type: "string", StringVal: "taskrun"}}, + {Name: "CHAINS-GIT_URL", Value: v1.ParamValue{Type: "string", StringVal: "https://git.test.com"}}, + }, + ServiceAccountName: "default", + TaskRef: &v1.TaskRef{Name: "build", Kind: "Task"}, + }, + }, + }, + { + name: "taskrun with remote resolver", + inputTaskRunFile: "../../testdata/slsa-v2alpha3/taskrun-remote-resolver.json", + expectedExternalParameters: map[string]any{ + "runSpec": v1.TaskRunSpec{ + Params: v1.Params{ + {Name: "ARGS", Value: v1.ParamValue{Type: "array", ArrayVal: []string{"help"}}}, + }, + ServiceAccountName: "default", + TaskRef: &v1.TaskRef{ + Kind: "Task", + ResolverRef: v1.ResolverRef{ + Resolver: "git", + Params: []v1.Param{ + {Name: "url", Value: v1.ParamValue{Type: "string", StringVal: "https://github.com/tektoncd/catalog.git"}}, + {Name: "revision", Value: v1.ParamValue{Type: "string", StringVal: "main"}}, + {Name: "pathInRepo", Value: v1.ParamValue{Type: "string", StringVal: "task/gcloud/0.3/gcloud.yaml"}}, + }, + }, + }, + }, + "buildConfigSource": map[string]string{ + "ref": "sha1:4df486f198c3c2616ab129186fb30a74f580b5a1", + "repository": "git+https://github.com/tektoncd/catalog.git", + "path": "task/gcloud/0.3/gcloud.yaml", + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + tr, err := objectloader.TaskRunFromFile(test.inputTaskRunFile) + if err != nil { + t.Fatal(err) + } + + got := TaskRun(objects.NewTaskRunObjectV1(tr)) + if diff := cmp.Diff(test.expectedExternalParameters, got); diff != "" { + t.Errorf("TaskRun(): -want +got: %s", diff) + } + }) + } +} diff --git a/pkg/chains/formats/slsa/internal/resolved_dependencies/resolved_dependencies.go b/pkg/chains/formats/slsa/internal/resolved_dependencies/resolved_dependencies.go index 93667eb55b..2cc1a8b60c 100644 --- a/pkg/chains/formats/slsa/internal/resolved_dependencies/resolved_dependencies.go +++ b/pkg/chains/formats/slsa/internal/resolved_dependencies/resolved_dependencies.go @@ -17,10 +17,19 @@ limitations under the License. package resolveddependencies import ( + "context" "encoding/json" + "fmt" "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" - v1 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" + slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" + "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/material" + "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/slsaconfig" + "github.com/tektoncd/chains/pkg/chains/objects" + v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + "go.uber.org/zap" + "knative.dev/pkg/logging" ) const ( @@ -34,13 +43,19 @@ const ( InputResultName = "inputs/result" // PipelineResourceName is the name of the resolved dependency of pipeline resource. PipelineResourceName = "pipelineResource" + // v1beta1SpecResourceLabel is the name of the label that contains information about TaskRun resources. + v1beta1SpecResourceLabel = "tekton.dev/v1beta1-spec-resources" ) +// used to toggle the fields in see AddTektonTaskDescriptor +// and AddSLSATaskDescriptor +type addTaskDescriptorContent func(*objects.TaskRunObjectV1) (*slsa.ResourceDescriptor, error) //nolint:staticcheck + // ConvertMaterialToResolvedDependency converts a SLSAv0.2 Material to a resolved dependency -func ConvertMaterialsToResolvedDependencies(mats []common.ProvenanceMaterial, name string) []v1.ResourceDescriptor { - rds := []v1.ResourceDescriptor{} +func ConvertMaterialsToResolvedDependencies(mats []common.ProvenanceMaterial, name string) []slsa.ResourceDescriptor { + rds := []slsa.ResourceDescriptor{} for _, mat := range mats { - rd := v1.ResourceDescriptor{} + rd := slsa.ResourceDescriptor{} rd.URI = mat.URI rd.Digest = mat.Digest if len(name) > 0 { @@ -53,15 +68,15 @@ func ConvertMaterialsToResolvedDependencies(mats []common.ProvenanceMaterial, na // RemoveDuplicateResolvedDependencies removes duplicate resolved dependencies from the slice of resolved dependencies. // Original order of resolved dependencies is retained. -func RemoveDuplicateResolvedDependencies(resolvedDependencies []v1.ResourceDescriptor) ([]v1.ResourceDescriptor, error) { - out := make([]v1.ResourceDescriptor, 0, len(resolvedDependencies)) +func RemoveDuplicateResolvedDependencies(resolvedDependencies []slsa.ResourceDescriptor) ([]slsa.ResourceDescriptor, error) { + out := make([]slsa.ResourceDescriptor, 0, len(resolvedDependencies)) // make map to store seen resolved dependencies seen := map[string]bool{} for _, resolvedDependency := range resolvedDependencies { // Since resolvedDependencies contain names, we want to ignore those while checking for duplicates. // Therefore, make a copy of the resolved dependency that only contains the uri and digest fields. - rDep := v1.ResourceDescriptor{} + rDep := slsa.ResourceDescriptor{} rDep.URI = resolvedDependency.URI rDep.Digest = resolvedDependency.Digest // pipelinTasks store content with the slsa-tekton buildType @@ -86,3 +101,200 @@ func RemoveDuplicateResolvedDependencies(resolvedDependencies []v1.ResourceDescr } return out, nil } + +// AddTektonTaskDescriptor returns the more verbose resolved dependency content. this adds the name, uri, digest +// and content if possible. +func AddTektonTaskDescriptor(tr *objects.TaskRunObjectV1) (*slsa.ResourceDescriptor, error) { //nolint:staticcheck + rd := slsa.ResourceDescriptor{} + storedTr, err := json.Marshal(tr) + if err != nil { + return nil, err + } + + rd.Name = PipelineTaskConfigName + rd.Content = storedTr + if tr.Status.Provenance != nil && tr.Status.Provenance.RefSource != nil { + rd.URI = tr.Status.Provenance.RefSource.URI + rd.Digest = tr.Status.Provenance.RefSource.Digest + } + + return &rd, nil +} + +// AddSLSATaskDescriptor resolves dependency content for the more generic slsa verifiers. just logs +// the name, uri and digest. +func AddSLSATaskDescriptor(tr *objects.TaskRunObjectV1) (*slsa.ResourceDescriptor, error) { //nolint:staticcheck + if tr.Status.Provenance != nil && tr.Status.Provenance.RefSource != nil { + return &slsa.ResourceDescriptor{ + Name: PipelineTaskConfigName, + URI: tr.Status.Provenance.RefSource.URI, + Digest: tr.Status.Provenance.RefSource.Digest, + }, nil + } + return nil, nil +} + +// fromPipelineTask adds the resolved dependencies from pipeline tasks +// such as pipeline task uri/digest for remote pipeline tasks and step and sidecar images. +func fromPipelineTask(logger *zap.SugaredLogger, pro *objects.PipelineRunObjectV1, addTasks addTaskDescriptorContent) ([]slsa.ResourceDescriptor, error) { + pSpec := pro.Status.PipelineSpec + resolvedDependencies := []slsa.ResourceDescriptor{} + if pSpec != nil { + pipelineTasks := pSpec.Tasks + pipelineTasks = append(pipelineTasks, pSpec.Finally...) + for _, t := range pipelineTasks { + tr := pro.GetTaskRunFromTask(t.Name) + // Ignore Tasks that did not execute during the PipelineRun. + if tr == nil || tr.Status.CompletionTime == nil { + logger.Infof("taskrun status not found for task %s", t.Name) + continue + } + rd, err := addTasks(tr) + if err != nil { + logger.Errorf("error storing taskRun %s, error: %s", t.Name, err) + continue + } + + if rd != nil { + resolvedDependencies = append(resolvedDependencies, *rd) + } + + mats := []common.ProvenanceMaterial{} + + // add step images + stepMaterials, err := material.FromStepImages(tr) + if err != nil { + return nil, err + } + mats = append(mats, stepMaterials...) + + // add sidecar images + sidecarMaterials, err := material.FromSidecarImages(tr) + if err != nil { + return nil, err + } + mats = append(mats, sidecarMaterials...) + + // convert materials to resolved dependencies + resolvedDependencies = append(resolvedDependencies, ConvertMaterialsToResolvedDependencies(mats, "")...) + } + } + return resolvedDependencies, nil +} + +// taskDependencies gather all dependencies in a task and adds them to resolvedDependencies +func taskDependencies(ctx context.Context, tro *objects.TaskRunObjectV1) ([]slsa.ResourceDescriptor, error) { + var resolvedDependencies []slsa.ResourceDescriptor + var err error + mats := []common.ProvenanceMaterial{} + + // add step and sidecar images + stepMaterials, err := material.FromStepImages(tro) + if err != nil { + return nil, err + } + mats = append(mats, stepMaterials...) + + sidecarMaterials, err := material.FromSidecarImages(tro) + if err != nil { + return nil, err + } + mats = append(mats, sidecarMaterials...) + resolvedDependencies = append(resolvedDependencies, ConvertMaterialsToResolvedDependencies(mats, "")...) + + mats = material.FromTaskParamsAndResults(ctx, tro) + // convert materials to resolved dependencies + resolvedDependencies = append(resolvedDependencies, ConvertMaterialsToResolvedDependencies(mats, InputResultName)...) + + // add task resources + // ===== + // convert to v1beta1 and add any task resources + serializedResources := tro.Annotations[v1beta1SpecResourceLabel] + var resources v1beta1.TaskRunResources //nolint:staticcheck + shouldReplace := false + if err := json.Unmarshal([]byte(serializedResources), &resources); err == nil { + shouldReplace = true + + } + trV1Beta1 := &v1beta1.TaskRun{} //nolint:staticcheck + fmt.Printf("%v", tro.GetObject().(*v1.TaskRun)) + if err := trV1Beta1.ConvertFrom(ctx, tro.GetObject().(*v1.TaskRun)); err == nil { + if shouldReplace { + trV1Beta1.Spec.Resources = &resources //nolint:staticcheck + } + mats = material.FromTaskResources(ctx, trV1Beta1) + + } + + // convert materials to resolved dependencies + resolvedDependencies = append(resolvedDependencies, + ConvertMaterialsToResolvedDependencies(mats, PipelineResourceName)...) + + // remove duplicate resolved dependencies + resolvedDependencies, err = RemoveDuplicateResolvedDependencies(resolvedDependencies) + if err != nil { + return nil, err + } + + return resolvedDependencies, nil +} + +// TaskRun constructs `predicate.resolvedDependencies` section by collecting all the artifacts that influence a taskrun such as source code repo and step&sidecar base images. +func TaskRun(ctx context.Context, tro *objects.TaskRunObjectV1) ([]slsa.ResourceDescriptor, error) { + var resolvedDependencies []slsa.ResourceDescriptor + var err error + + // add top level task config + if p := tro.Status.Provenance; p != nil && p.RefSource != nil { + rd := slsa.ResourceDescriptor{ + Name: TaskConfigName, + URI: p.RefSource.URI, + Digest: p.RefSource.Digest, + } + resolvedDependencies = append(resolvedDependencies, rd) + } + + rds, err := taskDependencies(ctx, tro) + if err != nil { + return nil, err + } + resolvedDependencies = append(resolvedDependencies, rds...) + + return resolvedDependencies, nil +} + +// PipelineRun constructs `predicate.resolvedDependencies` section by collecting all the artifacts that influence a pipeline run such as source code repo and step&sidecar base images. +func PipelineRun(ctx context.Context, pro *objects.PipelineRunObjectV1, slsaconfig *slsaconfig.SlsaConfig, addTasks addTaskDescriptorContent) ([]slsa.ResourceDescriptor, error) { + var err error + var resolvedDependencies []slsa.ResourceDescriptor + logger := logging.FromContext(ctx) + + // add pipeline config to resolved dependencies + if p := pro.Status.Provenance; p != nil && p.RefSource != nil { + rd := slsa.ResourceDescriptor{ + Name: PipelineConfigName, + URI: p.RefSource.URI, + Digest: p.RefSource.Digest, + } + resolvedDependencies = append(resolvedDependencies, rd) + } + + // add resolved dependencies from pipeline tasks + rds, err := fromPipelineTask(logger, pro, addTasks) + if err != nil { + return nil, err + } + resolvedDependencies = append(resolvedDependencies, rds...) + + // add resolved dependencies from pipeline results + mats := material.FromPipelineParamsAndResults(ctx, pro, slsaconfig) + // convert materials to resolved dependencies + resolvedDependencies = append(resolvedDependencies, ConvertMaterialsToResolvedDependencies(mats, InputResultName)...) + + // remove duplicate resolved dependencies + resolvedDependencies, err = RemoveDuplicateResolvedDependencies(resolvedDependencies) + if err != nil { + return nil, err + } + return resolvedDependencies, nil +} diff --git a/pkg/chains/formats/slsa/internal/resolved_dependencies/resolved_dependencies_test.go b/pkg/chains/formats/slsa/internal/resolved_dependencies/resolved_dependencies_test.go index e3516423df..8e9d0f88ab 100644 --- a/pkg/chains/formats/slsa/internal/resolved_dependencies/resolved_dependencies_test.go +++ b/pkg/chains/formats/slsa/internal/resolved_dependencies/resolved_dependencies_test.go @@ -17,13 +17,26 @@ limitations under the License. package resolveddependencies import ( + "encoding/json" + "strings" "testing" "github.com/google/go-cmp/cmp" "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" v1slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" + "github.com/tektoncd/chains/internal/backport" + "github.com/tektoncd/chains/pkg/artifacts" + "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/slsaconfig" + "github.com/tektoncd/chains/pkg/chains/objects" + "github.com/tektoncd/chains/pkg/internal/objectloader" + v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" + logtesting "knative.dev/pkg/logging/testing" ) +const digest = "sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b7" + func TestRemoveDuplicates(t *testing.T) { tests := []struct { name string @@ -239,3 +252,348 @@ func TestRemoveDuplicates(t *testing.T) { }) } } + +func createPro(path string) *objects.PipelineRunObjectV1 { + var err error + 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 tektonTaskRuns() map[string][]byte { + trs := make(map[string][]byte) + 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) + } + + tr1Desc, err := json.Marshal(tr1) + if err != nil { + panic(err) + } + trs[tr1.Name] = tr1Desc + + tr2Desc, err := json.Marshal(tr2) + if err != nil { + panic(err) + } + trs[tr2.Name] = tr2Desc + + return trs +} + +func TestTaskRun(t *testing.T) { + tests := []struct { + name string + obj objects.TektonObject //nolint:staticcheck + want []v1slsa.ResourceDescriptor + }{ + { + name: "resolvedDependencies from pipeline resources", + obj: objects.NewTaskRunObjectV1Beta1(&v1beta1.TaskRun{ //nolint:staticcheck + Spec: v1beta1.TaskRunSpec{ + Resources: &v1beta1.TaskRunResources{ //nolint:all //incompatible with pipelines v0.45 + Inputs: []v1beta1.TaskResourceBinding{ //nolint:all //incompatible with pipelines v0.45 + { + PipelineResourceBinding: v1beta1.PipelineResourceBinding{ //nolint:all //incompatible with pipelines v0.45 + Name: "nil-resource-spec", + }, + }, { + PipelineResourceBinding: v1beta1.PipelineResourceBinding{ //nolint:all //incompatible with pipelines v0.45 + Name: "repo", + ResourceSpec: &v1alpha1.PipelineResourceSpec{ //nolint:all //incompatible with pipelines v0.45 + Params: []v1alpha1.ResourceParam{ //nolint:all //incompatible with pipelines v0.45 + {Name: "url", Value: "https://github.com/GoogleContainerTools/distroless"}, + }, + Type: backport.PipelineResourceTypeGit, + }, + }, + }, + }, + }, + }, + Status: v1beta1.TaskRunStatus{ + TaskRunStatusFields: v1beta1.TaskRunStatusFields{ + TaskRunResults: []v1beta1.TaskRunResult{ + { + Name: "img1_input" + "-" + artifacts.ArtifactsInputsResultName, + Value: *v1beta1.NewObject(map[string]string{ + "uri": "gcr.io/foo/bar", + "digest": digest, + }), + }, + }, + ResourcesResult: []v1beta1.PipelineResourceResult{ + { + ResourceName: "repo", + Key: "commit", + Value: "50c56a48cfb3a5a80fa36ed91c739bdac8381cbe", + }, { + ResourceName: "repo", + Key: "url", + Value: "https://github.com/GoogleContainerTools/distroless", + }, + }, + }, + }, + }), + want: []v1slsa.ResourceDescriptor{ + { + Name: "inputs/result", + URI: "gcr.io/foo/bar", + Digest: common.DigestSet{ + "sha256": strings.TrimPrefix(digest, "sha256:"), + }, + }, + { + Name: "pipelineResource", + URI: "git+https://github.com/GoogleContainerTools/distroless.git", + Digest: common.DigestSet{ + "sha1": "50c56a48cfb3a5a80fa36ed91c739bdac8381cbe", + }, + }, + }, + }, + { + name: "resolvedDependencies from remote task", + obj: objects.NewTaskRunObjectV1(&v1.TaskRun{ //nolint:staticcheck + Status: v1.TaskRunStatus{ + TaskRunStatusFields: v1.TaskRunStatusFields{ + Provenance: &v1.Provenance{ + RefSource: &v1.RefSource{ + URI: "git+github.com/something.git", + Digest: map[string]string{ + "sha1": "abcd1234", + }, + }, + }, + }, + }, + }), + want: []v1slsa.ResourceDescriptor{ + { + Name: "task", + URI: "git+github.com/something.git", + Digest: common.DigestSet{ + "sha1": "abcd1234", + }, + }, + }, + }, + { + name: "git resolvedDependencies from taskrun params", + obj: objects.NewTaskRunObjectV1(&v1.TaskRun{ //nolint:staticcheck + Spec: v1.TaskRunSpec{ + Params: []v1.Param{{ + Name: "CHAINS-GIT_COMMIT", + Value: *v1.NewStructuredValues("my-commit"), + }, { + Name: "CHAINS-GIT_URL", + Value: *v1.NewStructuredValues("github.com/something"), + }}, + }, + }), + want: []v1slsa.ResourceDescriptor{ + { + Name: "inputs/result", + URI: "git+github.com/something.git", + Digest: common.DigestSet{ + "sha1": "my-commit", + }, + }, + }, + }, + { + name: "resolvedDependencies from step images", + obj: objects.NewTaskRunObjectV1(&v1.TaskRun{ //nolint:staticcheck + Status: v1.TaskRunStatus{ + TaskRunStatusFields: v1.TaskRunStatusFields{ + Steps: []v1.StepState{{ + Name: "git-source-repo-jwqcl", + ImageID: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init@sha256:b963f6e7a69617db57b685893256f978436277094c21d43b153994acd8a01247", + }, { + Name: "git-source-repo-repeat-again-jwqcl", + ImageID: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init@sha256:b963f6e7a69617db57b685893256f978436277094c21d43b153994acd8a01247", + }, { + Name: "build", + ImageID: "gcr.io/cloud-marketplace-containers/google/bazel@sha256:010a1ecd1a8c3610f12039a25b823e3a17bd3e8ae455a53e340dcfdd37a49964", + }}, + }, + }, + }), + want: []v1slsa.ResourceDescriptor{ + { + URI: "oci://gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init", + Digest: common.DigestSet{ + "sha256": "b963f6e7a69617db57b685893256f978436277094c21d43b153994acd8a01247", + }, + }, + { + URI: "oci://gcr.io/cloud-marketplace-containers/google/bazel", + Digest: common.DigestSet{ + "sha256": "010a1ecd1a8c3610f12039a25b823e3a17bd3e8ae455a53e340dcfdd37a49964", + }, + }, + }, + }, + { + name: "resolvedDependencies from step and sidecar images", + obj: objects.NewTaskRunObjectV1(&v1.TaskRun{ //nolint:staticcheck + Status: v1.TaskRunStatus{ + TaskRunStatusFields: v1.TaskRunStatusFields{ + Steps: []v1.StepState{{ + Name: "git-source-repo-jwqcl", + ImageID: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init@sha256:b963f6e7a69617db57b685893256f978436277094c21d43b153994acd8a01247", + }, { + Name: "git-source-repo-repeat-again-jwqcl", + ImageID: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init@sha256:b963f6e7a69617db57b685893256f978436277094c21d43b153994acd8a01247", + }, { + Name: "build", + ImageID: "gcr.io/cloud-marketplace-containers/google/bazel@sha256:010a1ecd1a8c3610f12039a25b823e3a17bd3e8ae455a53e340dcfdd37a49964", + }}, + Sidecars: []v1.SidecarState{{ + Name: "sidecar-jwqcl", + ImageID: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/sidecar-git-init@sha256:a1234f6e7a69617db57b685893256f978436277094c21d43b153994acd8a09567", + }}, + }, + }, + }), + want: []v1slsa.ResourceDescriptor{ + { + URI: "oci://gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init", + Digest: common.DigestSet{ + "sha256": "b963f6e7a69617db57b685893256f978436277094c21d43b153994acd8a01247", + }, + }, { + URI: "oci://gcr.io/cloud-marketplace-containers/google/bazel", + Digest: common.DigestSet{ + "sha256": "010a1ecd1a8c3610f12039a25b823e3a17bd3e8ae455a53e340dcfdd37a49964", + }, + }, { + URI: "oci://gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/sidecar-git-init", + Digest: common.DigestSet{ + "sha256": "a1234f6e7a69617db57b685893256f978436277094c21d43b153994acd8a09567", + }, + }, + }, + }} + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + ctx := logtesting.TestContextWithLogger(t) + var input *objects.TaskRunObjectV1 + var err error + if obj, ok := tc.obj.(*objects.TaskRunObjectV1); ok { + input = obj + } + + if trV1Beta1, ok := tc.obj.GetObject().(*v1beta1.TaskRun); ok { //nolint:staticcheck + trV1 := &v1.TaskRun{} + if err := trV1Beta1.ConvertTo(ctx, trV1); err == nil { + if trV1Beta1.Spec.Resources != nil { //nolint:staticcheck + jsonData, err := json.Marshal(trV1Beta1.Spec.Resources) //nolint:staticcheck + if err != nil { + t.Errorf("Error serializing to JSON: %v", err) + } + trV1.Annotations["tekton.dev/v1beta1-spec-resources"] = string(jsonData) + } + input = objects.NewTaskRunObjectV1(trV1) + } + } + + rd, err := TaskRun(ctx, input) + if err != nil { + t.Fatalf("Did not expect an error but got %v", err) + } + if diff := cmp.Diff(tc.want, rd); diff != "" { + t.Errorf("ResolvedDependencies(): -want +got: %s", diff) + } + }) + } +} + +func TestPipelineRun(t *testing.T) { + taskRuns := tektonTaskRuns() + tests := []struct { + name string + taskDescriptor addTaskDescriptorContent + want []v1slsa.ResourceDescriptor + }{ + { + name: "test slsa build type", + taskDescriptor: AddSLSATaskDescriptor, + want: []v1slsa.ResourceDescriptor{ + {Name: "pipeline", URI: "git+https://github.com/test", Digest: common.DigestSet{"sha1": "28b123"}}, + {Name: "pipelineTask", URI: "git+https://github.com/catalog", Digest: common.DigestSet{"sha1": "x123"}}, + { + URI: "oci://gcr.io/test1/test1", + Digest: common.DigestSet{"sha256": "d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"}, + }, + {Name: "pipelineTask", URI: "git+https://github.com/test", Digest: common.DigestSet{"sha1": "ab123"}}, + { + URI: "oci://gcr.io/test2/test2", + Digest: common.DigestSet{"sha256": "4d6dd704ef58cb214dd826519929e92a978a57cdee43693006139c0080fd6fac"}, + }, + { + URI: "oci://gcr.io/test3/test3", + Digest: common.DigestSet{"sha256": "f1a8b8549c179f41e27ff3db0fe1a1793e4b109da46586501a8343637b1d0478"}, + }, + {Name: "inputs/result", URI: "abc", Digest: common.DigestSet{"sha256": "827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7"}}, + {Name: "inputs/result", URI: "git+https://git.test.com.git", Digest: common.DigestSet{"sha1": "abcd"}}, + }, + }, + { + name: "test tekton build type", + taskDescriptor: AddTektonTaskDescriptor, + want: []v1slsa.ResourceDescriptor{ + {Name: "pipeline", URI: "git+https://github.com/test", Digest: common.DigestSet{"sha1": "28b123"}}, + {Name: "pipelineTask", URI: "git+https://github.com/catalog", Digest: common.DigestSet{"sha1": "x123"}, Content: taskRuns["git-clone"]}, + { + URI: "oci://gcr.io/test1/test1", + Digest: common.DigestSet{"sha256": "d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"}, + }, + {Name: "pipelineTask", URI: "git+https://github.com/test", Digest: common.DigestSet{"sha1": "ab123"}, Content: taskRuns["taskrun-build"]}, + { + URI: "oci://gcr.io/test2/test2", + Digest: common.DigestSet{"sha256": "4d6dd704ef58cb214dd826519929e92a978a57cdee43693006139c0080fd6fac"}, + }, + { + URI: "oci://gcr.io/test3/test3", + Digest: common.DigestSet{"sha256": "f1a8b8549c179f41e27ff3db0fe1a1793e4b109da46586501a8343637b1d0478"}, + }, + {Name: "inputs/result", URI: "abc", Digest: common.DigestSet{"sha256": "827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7"}}, + {Name: "inputs/result", URI: "git+https://git.test.com.git", Digest: common.DigestSet{"sha1": "abcd"}}, + }, + }, + } + + ctx := logtesting.TestContextWithLogger(t) + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + pro := createPro("../../testdata/slsa-v2alpha3/pipelinerun1.json") + got, err := PipelineRun(ctx, pro, &slsaconfig.SlsaConfig{DeepInspectionEnabled: false}, tc.taskDescriptor) + if err != nil { + t.Error(err) + } + if d := cmp.Diff(tc.want, got); d != "" { + t.Errorf("PipelineRunResolvedDependencies(): -want +got: %s", got) + } + }) + } +} diff --git a/pkg/chains/formats/slsa/testdata/slsa-v2alpha3/pipelinerun-remote-resolver.json b/pkg/chains/formats/slsa/testdata/slsa-v2alpha3/pipelinerun-remote-resolver.json new file mode 100644 index 0000000000..e4fe52f6f9 --- /dev/null +++ b/pkg/chains/formats/slsa/testdata/slsa-v2alpha3/pipelinerun-remote-resolver.json @@ -0,0 +1,113 @@ +{ + "metadata": { + "name": "build-push-gke-deploy-run-2", + "uid": "5e28bf07-ed8f-4fe2-bfa0-d1f2cb90e5de" + }, + "spec": { + "params": [ + { + "name": "pathToContext", + "value": "gke-deploy/example/app" + }, + { + "name": "pathToKubernetesConfigs", + "value": "gke-deploy/example/app/config" + } + ], + "pipelineRef": { + "params": [ + { + "name": "url", + "value": "https://github.com/tektoncd/catalog" + }, + { + "name": "revision", + "value": "main" + }, + { + "name": "pathInRepo", + "value": "pipeline/build-push-gke-deploy/0.1/build-push-gke-deploy.yaml" + } + ], + "resolver": "git" + }, + "taskRunTemplate": { + "serviceAccountName": "default" + } + }, + "status": { + "childReferences": [ + { + "apiVersion": "tekton.dev/v1", + "kind": "TaskRun", + "name": "build-push-gke-deploy-run-2-kaniko", + "pipelineTaskName": "kaniko" + } + ], + "conditions": [ + { + "lastTransitionTime": "2024-04-29T20:45:15Z", + "message": "Tasks Completed: 0 (Failed: 0, Cancelled 0), Incomplete: 2, Skipped: 0", + "reason": "Running", + "status": "Unknown", + "type": "Succeeded" + } + ], + "pipelineSpec": { + "description": "This Pipeline builds, pushes, and deploys your application to a Google Kubernetes Engine cluster using gke-deploy.", + "params": [ + { + "default": ".", + "description": "The path to the build context relative to your source repo's root. This is used by Kaniko.", + "name": "pathToContext", + "type": "string" + }, + { + "description": "The path to the Kubernetes configs to deploy, relative to your source repo's root.", + "name": "pathToKubernetesConfigs", + "type": "string" + } + ], + "tasks": [ + { + "name": "gke-deploy", + "params": [ + { + "name": "ARGS", + "value": [ + "run", + "--image=gcr.io/foo/gke-deploy-tekton-demo:1.0.0", + "--filename=$(workspaces.source.path)/gke-deploy/example/app/config" + ] + } + ], + "taskRef": { + "kind": "Task", + "name": "gke-deploy" + }, + "workspaces": [ + { + "name": "source", + "workspace": "source" + } + ] + } + ], + "workspaces": [ + { + "description": "The workspace containing the source code which is to be build, pushed and deployed", + "name": "source" + } + ] + }, + "provenance": { + "refSource": { + "digest": { + "sha1": "4df486f198c3c2616ab129186fb30a74f580b5a1" + }, + "entryPoint": "pipeline/build-push-gke-deploy/0.1/build-push-gke-deploy.yaml", + "uri": "git+https://github.com/tektoncd/catalog" + } + } + } +} diff --git a/pkg/chains/formats/slsa/testdata/slsa-v2alpha3/taskrun-remote-resolver.json b/pkg/chains/formats/slsa/testdata/slsa-v2alpha3/taskrun-remote-resolver.json new file mode 100644 index 0000000000..0773bad31f --- /dev/null +++ b/pkg/chains/formats/slsa/testdata/slsa-v2alpha3/taskrun-remote-resolver.json @@ -0,0 +1,122 @@ +{ + "metadata": { + "name": "run-deploy", + "labels": { + "tekton.dev/task": "gcloud" + }, + "uid": "9d828161-17bb-4eb9-bcb3-1d5f9eeb8c25" + }, + "spec": { + "params": [ + { + "name": "ARGS", + "value": [ + "help" + ] + } + ], + "serviceAccountName": "default", + "taskRef": { + "kind": "Task", + "params": [ + { + "name": "url", + "value": "https://github.com/tektoncd/catalog.git" + }, + { + "name": "revision", + "value": "main" + }, + { + "name": "pathInRepo", + "value": "task/gcloud/0.3/gcloud.yaml" + } + ], + "resolver": "git" + } + }, + "status": { + "completionTime": "2024-04-29T19:20:34Z", + "conditions": [ + { + "lastTransitionTime": "2024-04-29T19:20:34Z", + "message": "All Steps have completed executing", + "reason": "Succeeded", + "status": "True", + "type": "Succeeded" + } + ], + "podName": "run-deploy-pod", + "provenance": { + "featureFlags": { + "EnableAPIFields": "beta", + "ResultExtractionMethod": "termination-message" + }, + "refSource": { + "digest": { + "sha1": "4df486f198c3c2616ab129186fb30a74f580b5a1" + }, + "entryPoint": "task/gcloud/0.3/gcloud.yaml", + "uri": "git+https://github.com/tektoncd/catalog.git" + } + }, + "startTime": "2024-04-29T19:19:33Z", + "steps": [ + { + "container": "step-gcloud", + "imageID": "gcr.io/google.com/cloudsdktool/cloud-sdk@sha256:f01eb4375c0b8af5488bc717b9b43323b5033d2d0ab5c565e4100a4226e9ac38", + "name": "gcloud", + "terminated": { + "containerID": "containerd://d18a954ecb902aca2a0bbdb83f45d757ad15ad5e352b78b82adfeacb11657b2d", + "exitCode": 0, + "finishedAt": "2024-04-29T19:20:31Z", + "reason": "Completed", + "startedAt": "2024-04-29T19:20:29Z" + }, + "terminationReason": "Completed" + } + ], + "taskSpec": { + "description": "This task performs operations on Google Cloud Platform resources using gcloud.", + "params": [ + { + "default": "gcr.io/google.com/cloudsdktool/cloud-sdk", + "description": "gcloud CLI container image to run this task", + "name": "gcloud-image", + "type": "string" + }, + { + "default": "slim", + "description": "gcloud CLI version run this task", + "name": "version", + "type": "string" + }, + { + "default": [ + "help" + ], + "description": "gcloud CLI arguments to run", + "name": "ARGS", + "type": "array" + }, + { + "default": "gcloud $@", + "description": "CLI script to execute", + "name": "SCRIPT", + "type": "string" + } + ], + "steps": [ + { + "args": [ + "help" + ], + "computeResources": {}, + "image": "gcr.io/google.com/cloudsdktool/cloud-sdk:slim", + "name": "gcloud", + "script": "gcloud $@\n" + } + ] + } + } +} diff --git a/pkg/chains/formats/slsa/v2alpha3/internal/external_parameters/external_parameters.go b/pkg/chains/formats/slsa/v2alpha3/internal/external_parameters/external_parameters.go deleted file mode 100644 index 6dfc21b9dd..0000000000 --- a/pkg/chains/formats/slsa/v2alpha3/internal/external_parameters/external_parameters.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -Copyright 2023 The Tekton Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package externalparameters - -import ( - externalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/external_parameters" - "github.com/tektoncd/chains/pkg/chains/objects" -) - -// PipelineRun adds the pipeline run spec and provenance if available -func PipelineRun(pro *objects.PipelineRunObjectV1) map[string]any { - externalParams := make(map[string]any) - - if provenance := pro.GetRemoteProvenance(); provenance != nil { - externalParams["buildConfigSource"] = externalparameters.BuildConfigSource(provenance) - } - externalParams["runSpec"] = pro.Spec - return externalParams -} - -// TaskRun adds the task run spec and provenance if available -func TaskRun(tro *objects.TaskRunObjectV1) map[string]any { - externalParams := make(map[string]any) - - if provenance := tro.GetRemoteProvenance(); provenance != nil { - externalParams["buildConfigSource"] = externalparameters.BuildConfigSource(provenance) - } - externalParams["runSpec"] = tro.Spec - return externalParams -} diff --git a/pkg/chains/formats/slsa/v2alpha3/internal/external_parameters/external_parameters_test.go b/pkg/chains/formats/slsa/v2alpha3/internal/external_parameters/external_parameters_test.go deleted file mode 100644 index 73d643671e..0000000000 --- a/pkg/chains/formats/slsa/v2alpha3/internal/external_parameters/external_parameters_test.go +++ /dev/null @@ -1,94 +0,0 @@ -/* -Copyright 2023 The Tekton Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package externalparameters - -import ( - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/tektoncd/chains/pkg/chains/objects" - "github.com/tektoncd/chains/pkg/internal/objectloader" - v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" -) - -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 TestPipelineRun(t *testing.T) { - pro := createPro("../../../testdata/slsa-v2alpha3/pipelinerun1.json") - - got := PipelineRun(pro) - - want := map[string]any{ - "runSpec": v1.PipelineRunSpec{ - PipelineRef: &v1.PipelineRef{Name: "test-pipeline"}, - Params: v1.Params{ - { - Name: "IMAGE", - Value: v1.ParamValue{Type: "string", StringVal: "test.io/test/image"}, - }, - }, - TaskRunTemplate: v1.PipelineTaskRunTemplate{ - ServiceAccountName: "pipeline", - }, - }, - } - - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("PipelineRun(): -want +got: %s", diff) - } -} - -func TestTaskRun(t *testing.T) { - tr, err := objectloader.TaskRunFromFile("../../../testdata/slsa-v2alpha3/taskrun1.json") - if err != nil { - t.Fatal(err) - } - got := TaskRun(objects.NewTaskRunObjectV1(tr)) - - want := map[string]any{ - "runSpec": v1.TaskRunSpec{ - Params: v1.Params{ - {Name: "IMAGE", Value: v1.ParamValue{Type: "string", StringVal: "test.io/test/image"}}, - {Name: "CHAINS-GIT_COMMIT", Value: v1.ParamValue{Type: "string", StringVal: "taskrun"}}, - {Name: "CHAINS-GIT_URL", Value: v1.ParamValue{Type: "string", StringVal: "https://git.test.com"}}, - }, - ServiceAccountName: "default", - TaskRef: &v1.TaskRef{Name: "build", Kind: "Task"}, - }, - } - - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("TaskRun(): -want +got: %s", diff) - } -} diff --git a/pkg/chains/formats/slsa/v2alpha3/internal/pipelinerun/pipelinerun.go b/pkg/chains/formats/slsa/v2alpha3/internal/pipelinerun/pipelinerun.go index 2c25407ec0..3c24410991 100644 --- a/pkg/chains/formats/slsa/v2alpha3/internal/pipelinerun/pipelinerun.go +++ b/pkg/chains/formats/slsa/v2alpha3/internal/pipelinerun/pipelinerun.go @@ -22,10 +22,10 @@ import ( slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" "github.com/tektoncd/chains/pkg/chains/formats/slsa/extract" buildtypes "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/build_types" + 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" - externalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha3/internal/external_parameters" - resolveddependencies "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha3/internal/resolved_dependencies" "github.com/tektoncd/chains/pkg/chains/objects" ) diff --git a/pkg/chains/formats/slsa/v2alpha3/internal/pipelinerun/pipelinerun_test.go b/pkg/chains/formats/slsa/v2alpha3/internal/pipelinerun/pipelinerun_test.go index ec155c0497..229caf69de 100644 --- a/pkg/chains/formats/slsa/v2alpha3/internal/pipelinerun/pipelinerun_test.go +++ b/pkg/chains/formats/slsa/v2alpha3/internal/pipelinerun/pipelinerun_test.go @@ -28,10 +28,10 @@ import ( 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" "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/compare" + 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" - externalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha3/internal/external_parameters" - resolveddependencies "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha3/internal/resolved_dependencies" "github.com/tektoncd/chains/pkg/chains/objects" "github.com/tektoncd/chains/pkg/internal/objectloader" v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" diff --git a/pkg/chains/formats/slsa/v2alpha3/internal/resolved_dependencies/resolved_dependencies.go b/pkg/chains/formats/slsa/v2alpha3/internal/resolved_dependencies/resolved_dependencies.go deleted file mode 100644 index 81ef61d2f4..0000000000 --- a/pkg/chains/formats/slsa/v2alpha3/internal/resolved_dependencies/resolved_dependencies.go +++ /dev/null @@ -1,233 +0,0 @@ -/* -Copyright 2023 The Tekton Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package resolveddependencies - -import ( - "context" - "encoding/json" - "fmt" - - "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" - slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/material" - 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" - v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" - "go.uber.org/zap" - "knative.dev/pkg/logging" -) - -// used to toggle the fields in resolvedDependencies. see AddTektonTaskDescriptor -// and AddSLSATaskDescriptor -type addTaskDescriptorContent func(*objects.TaskRunObjectV1) (*slsa.ResourceDescriptor, error) //nolint:staticcheck - -// the more verbose resolved dependency content. this adds the name, uri, digest -// and content if possible. -func AddTektonTaskDescriptor(tr *objects.TaskRunObjectV1) (*slsa.ResourceDescriptor, error) { //nolint:staticcheck - rd := slsa.ResourceDescriptor{} - storedTr, err := json.Marshal(tr) - if err != nil { - return nil, err - } - - rd.Name = resolveddependencies.PipelineTaskConfigName - rd.Content = storedTr - if tr.Status.Provenance != nil && tr.Status.Provenance.RefSource != nil { - rd.URI = tr.Status.Provenance.RefSource.URI - rd.Digest = tr.Status.Provenance.RefSource.Digest - } - - return &rd, nil -} - -// resolved dependency content for the more generic slsa verifiers. just logs -// the name, uri and digest. -func AddSLSATaskDescriptor(tr *objects.TaskRunObjectV1) (*slsa.ResourceDescriptor, error) { //nolint:staticcheck - if tr.Status.Provenance != nil && tr.Status.Provenance.RefSource != nil { - return &slsa.ResourceDescriptor{ - Name: resolveddependencies.PipelineTaskConfigName, - URI: tr.Status.Provenance.RefSource.URI, - Digest: tr.Status.Provenance.RefSource.Digest, - }, nil - } - return nil, nil -} - -// fromPipelineTask adds the resolved dependencies from pipeline tasks -// such as pipeline task uri/digest for remote pipeline tasks and step and sidecar images. -func fromPipelineTask(logger *zap.SugaredLogger, pro *objects.PipelineRunObjectV1, addTasks addTaskDescriptorContent) ([]slsa.ResourceDescriptor, error) { - pSpec := pro.Status.PipelineSpec - resolvedDependencies := []slsa.ResourceDescriptor{} - if pSpec != nil { - pipelineTasks := append(pSpec.Tasks, pSpec.Finally...) - for _, t := range pipelineTasks { - tr := pro.GetTaskRunFromTask(t.Name) - // Ignore Tasks that did not execute during the PipelineRun. - if tr == nil || tr.Status.CompletionTime == nil { - logger.Infof("taskrun status not found for task %s", t.Name) - continue - } - rd, err := addTasks(tr) - if err != nil { - logger.Errorf("error storing taskRun %s, error: %s", t.Name, err) - continue - } - - if rd != nil { - resolvedDependencies = append(resolvedDependencies, *rd) - } - - mats := []common.ProvenanceMaterial{} - - // add step images - stepMaterials, err := material.FromStepImages(tr) - if err != nil { - return nil, err - } - mats = append(mats, stepMaterials...) - - // add sidecar images - sidecarMaterials, err := material.FromSidecarImages(tr) - if err != nil { - return nil, err - } - mats = append(mats, sidecarMaterials...) - - // convert materials to resolved dependencies - resolvedDependencies = append(resolvedDependencies, resolveddependencies.ConvertMaterialsToResolvedDependencies(mats, "")...) - } - } - return resolvedDependencies, nil -} - -// taskDependencies gather all dependencies in a task and adds them to resolvedDependencies -func taskDependencies(ctx context.Context, tro *objects.TaskRunObjectV1) ([]slsa.ResourceDescriptor, error) { - var resolvedDependencies []slsa.ResourceDescriptor - var err error - mats := []common.ProvenanceMaterial{} - - // add step and sidecar images - stepMaterials, err := material.FromStepImages(tro) - mats = append(mats, stepMaterials...) - if err != nil { - return nil, err - } - sidecarMaterials, err := material.FromSidecarImages(tro) - if err != nil { - return nil, err - } - mats = append(mats, sidecarMaterials...) - resolvedDependencies = append(resolvedDependencies, resolveddependencies.ConvertMaterialsToResolvedDependencies(mats, "")...) - - mats = material.FromTaskParamsAndResults(ctx, tro) - // convert materials to resolved dependencies - resolvedDependencies = append(resolvedDependencies, resolveddependencies.ConvertMaterialsToResolvedDependencies(mats, resolveddependencies.InputResultName)...) - - // add task resources - // ===== - // convert to v1beta1 and add any task resources - serializedResources := tro.Annotations["tekton.dev/v1beta1-spec-resources"] - var resources v1beta1.TaskRunResources //nolint:staticcheck - shouldReplace := false - if err := json.Unmarshal([]byte(serializedResources), &resources); err == nil { - shouldReplace = true - - } - trV1Beta1 := &v1beta1.TaskRun{} //nolint:staticcheck - fmt.Printf("%v", tro.GetObject().(*v1.TaskRun)) - if err := trV1Beta1.ConvertFrom(ctx, tro.GetObject().(*v1.TaskRun)); err == nil { - if shouldReplace { - trV1Beta1.Spec.Resources = &resources //nolint:staticcheck - } - mats = material.FromTaskResources(ctx, trV1Beta1) - - } - - // convert materials to resolved dependencies - resolvedDependencies = append(resolvedDependencies, - resolveddependencies.ConvertMaterialsToResolvedDependencies(mats, resolveddependencies.PipelineResourceName)...) - - // remove duplicate resolved dependencies - resolvedDependencies, err = resolveddependencies.RemoveDuplicateResolvedDependencies(resolvedDependencies) - if err != nil { - return nil, err - } - - return resolvedDependencies, nil -} - -// TaskRun constructs `predicate.resolvedDependencies` section by collecting all the artifacts that influence a taskrun such as source code repo and step&sidecar base images. -func TaskRun(ctx context.Context, tro *objects.TaskRunObjectV1) ([]slsa.ResourceDescriptor, error) { - var resolvedDependencies []slsa.ResourceDescriptor - var err error - - // add top level task config - if p := tro.Status.Provenance; p != nil && p.RefSource != nil { - rd := slsa.ResourceDescriptor{ - Name: resolveddependencies.TaskConfigName, - URI: p.RefSource.URI, - Digest: p.RefSource.Digest, - } - resolvedDependencies = append(resolvedDependencies, rd) - } - - rds, err := taskDependencies(ctx, tro) - if err != nil { - return nil, err - } - resolvedDependencies = append(resolvedDependencies, rds...) - - return resolvedDependencies, nil -} - -// PipelineRun constructs `predicate.resolvedDependencies` section by collecting all the artifacts that influence a pipeline run such as source code repo and step&sidecar base images. -func PipelineRun(ctx context.Context, pro *objects.PipelineRunObjectV1, slsaconfig *slsaconfig.SlsaConfig, addTasks addTaskDescriptorContent) ([]slsa.ResourceDescriptor, error) { - var err error - var resolvedDependencies []slsa.ResourceDescriptor - logger := logging.FromContext(ctx) - - // add pipeline config to resolved dependencies - if p := pro.Status.Provenance; p != nil && p.RefSource != nil { - rd := slsa.ResourceDescriptor{ - Name: resolveddependencies.PipelineConfigName, - URI: p.RefSource.URI, - Digest: p.RefSource.Digest, - } - resolvedDependencies = append(resolvedDependencies, rd) - } - - // add resolved dependencies from pipeline tasks - rds, err := fromPipelineTask(logger, pro, addTasks) - if err != nil { - return nil, err - } - resolvedDependencies = append(resolvedDependencies, rds...) - - // add resolved dependencies from pipeline results - mats := material.FromPipelineParamsAndResults(ctx, pro, slsaconfig) - // convert materials to resolved dependencies - resolvedDependencies = append(resolvedDependencies, resolveddependencies.ConvertMaterialsToResolvedDependencies(mats, resolveddependencies.InputResultName)...) - - // remove duplicate resolved dependencies - resolvedDependencies, err = resolveddependencies.RemoveDuplicateResolvedDependencies(resolvedDependencies) - if err != nil { - return nil, err - } - return resolvedDependencies, nil -} diff --git a/pkg/chains/formats/slsa/v2alpha3/internal/resolved_dependencies/resolved_dependencies_test.go b/pkg/chains/formats/slsa/v2alpha3/internal/resolved_dependencies/resolved_dependencies_test.go deleted file mode 100644 index 5222280301..0000000000 --- a/pkg/chains/formats/slsa/v2alpha3/internal/resolved_dependencies/resolved_dependencies_test.go +++ /dev/null @@ -1,431 +0,0 @@ -/* -Copyright 2023 The Tekton Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package resolveddependencies - -import ( - "encoding/json" - "strings" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" - v1slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" - "github.com/tektoncd/chains/internal/backport" - "github.com/tektoncd/chains/pkg/artifacts" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/compare" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/slsaconfig" - "github.com/tektoncd/chains/pkg/chains/objects" - "github.com/tektoncd/chains/pkg/internal/objectloader" - v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" - "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" - logtesting "knative.dev/pkg/logging/testing" -) - -const digest = "sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b7" - -var pro *objects.PipelineRunObjectV1 -var proStructuredResults *objects.PipelineRunObjectV1 - -func init() { - pro = createPro("../../../testdata/slsa-v2alpha3/pipelinerun1.json") - proStructuredResults = createPro("../../../testdata/slsa-v2alpha3/pipelinerun_structured_results.json") -} - -func createPro(path string) *objects.PipelineRunObjectV1 { - var err error - 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 tektonTaskRuns() map[string][]byte { - trs := make(map[string][]byte) - 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) - } - - tr1Desc, err := json.Marshal(tr1) - if err != nil { - panic(err) - } - trs[tr1.Name] = tr1Desc - - tr2Desc, err := json.Marshal(tr2) - if err != nil { - panic(err) - } - trs[tr2.Name] = tr2Desc - - return trs -} - -func TestTaskRun(t *testing.T) { - tests := []struct { - name string - obj objects.TektonObject //nolint:staticcheck - want []v1slsa.ResourceDescriptor - }{ - { - name: "resolvedDependencies from pipeline resources", - obj: objects.NewTaskRunObjectV1Beta1(&v1beta1.TaskRun{ //nolint:staticcheck - Spec: v1beta1.TaskRunSpec{ - Resources: &v1beta1.TaskRunResources{ //nolint:all //incompatible with pipelines v0.45 - Inputs: []v1beta1.TaskResourceBinding{ //nolint:all //incompatible with pipelines v0.45 - { - PipelineResourceBinding: v1beta1.PipelineResourceBinding{ //nolint:all //incompatible with pipelines v0.45 - Name: "nil-resource-spec", - }, - }, { - PipelineResourceBinding: v1beta1.PipelineResourceBinding{ //nolint:all //incompatible with pipelines v0.45 - Name: "repo", - ResourceSpec: &v1alpha1.PipelineResourceSpec{ //nolint:all //incompatible with pipelines v0.45 - Params: []v1alpha1.ResourceParam{ //nolint:all //incompatible with pipelines v0.45 - {Name: "url", Value: "https://github.com/GoogleContainerTools/distroless"}, - }, - Type: backport.PipelineResourceTypeGit, - }, - }, - }, - }, - }, - }, - Status: v1beta1.TaskRunStatus{ - TaskRunStatusFields: v1beta1.TaskRunStatusFields{ - TaskRunResults: []v1beta1.TaskRunResult{ - { - Name: "img1_input" + "-" + artifacts.ArtifactsInputsResultName, - Value: *v1beta1.NewObject(map[string]string{ - "uri": "gcr.io/foo/bar", - "digest": digest, - }), - }, - }, - ResourcesResult: []v1beta1.PipelineResourceResult{ - { - ResourceName: "repo", - Key: "commit", - Value: "50c56a48cfb3a5a80fa36ed91c739bdac8381cbe", - }, { - ResourceName: "repo", - Key: "url", - Value: "https://github.com/GoogleContainerTools/distroless", - }, - }, - }, - }, - }), - want: []v1slsa.ResourceDescriptor{ - { - Name: "inputs/result", - URI: "gcr.io/foo/bar", - Digest: common.DigestSet{ - "sha256": strings.TrimPrefix(digest, "sha256:"), - }, - }, - { - Name: "pipelineResource", - URI: "git+https://github.com/GoogleContainerTools/distroless.git", - Digest: common.DigestSet{ - "sha1": "50c56a48cfb3a5a80fa36ed91c739bdac8381cbe", - }, - }, - }, - }, - { - name: "resolvedDependencies from remote task", - obj: objects.NewTaskRunObjectV1(&v1.TaskRun{ //nolint:staticcheck - Status: v1.TaskRunStatus{ - TaskRunStatusFields: v1.TaskRunStatusFields{ - Provenance: &v1.Provenance{ - RefSource: &v1.RefSource{ - URI: "git+github.com/something.git", - Digest: map[string]string{ - "sha1": "abcd1234", - }, - }, - }, - }, - }, - }), - want: []v1slsa.ResourceDescriptor{ - { - Name: "task", - URI: "git+github.com/something.git", - Digest: common.DigestSet{ - "sha1": "abcd1234", - }, - }, - }, - }, - { - name: "git resolvedDependencies from taskrun params", - obj: objects.NewTaskRunObjectV1(&v1.TaskRun{ //nolint:staticcheck - Spec: v1.TaskRunSpec{ - Params: []v1.Param{{ - Name: "CHAINS-GIT_COMMIT", - Value: *v1.NewStructuredValues("my-commit"), - }, { - Name: "CHAINS-GIT_URL", - Value: *v1.NewStructuredValues("github.com/something"), - }}, - }, - }), - want: []v1slsa.ResourceDescriptor{ - { - Name: "inputs/result", - URI: "git+github.com/something.git", - Digest: common.DigestSet{ - "sha1": "my-commit", - }, - }, - }, - }, - { - name: "resolvedDependencies from step images", - obj: objects.NewTaskRunObjectV1(&v1.TaskRun{ //nolint:staticcheck - Status: v1.TaskRunStatus{ - TaskRunStatusFields: v1.TaskRunStatusFields{ - Steps: []v1.StepState{{ - Name: "git-source-repo-jwqcl", - ImageID: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init@sha256:b963f6e7a69617db57b685893256f978436277094c21d43b153994acd8a01247", - }, { - Name: "git-source-repo-repeat-again-jwqcl", - ImageID: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init@sha256:b963f6e7a69617db57b685893256f978436277094c21d43b153994acd8a01247", - }, { - Name: "build", - ImageID: "gcr.io/cloud-marketplace-containers/google/bazel@sha256:010a1ecd1a8c3610f12039a25b823e3a17bd3e8ae455a53e340dcfdd37a49964", - }}, - }, - }, - }), - want: []v1slsa.ResourceDescriptor{ - { - URI: "oci://gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init", - Digest: common.DigestSet{ - "sha256": "b963f6e7a69617db57b685893256f978436277094c21d43b153994acd8a01247", - }, - }, - { - URI: "oci://gcr.io/cloud-marketplace-containers/google/bazel", - Digest: common.DigestSet{ - "sha256": "010a1ecd1a8c3610f12039a25b823e3a17bd3e8ae455a53e340dcfdd37a49964", - }, - }, - }, - }, - { - name: "resolvedDependencies from step and sidecar images", - obj: objects.NewTaskRunObjectV1(&v1.TaskRun{ //nolint:staticcheck - Status: v1.TaskRunStatus{ - TaskRunStatusFields: v1.TaskRunStatusFields{ - Steps: []v1.StepState{{ - Name: "git-source-repo-jwqcl", - ImageID: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init@sha256:b963f6e7a69617db57b685893256f978436277094c21d43b153994acd8a01247", - }, { - Name: "git-source-repo-repeat-again-jwqcl", - ImageID: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init@sha256:b963f6e7a69617db57b685893256f978436277094c21d43b153994acd8a01247", - }, { - Name: "build", - ImageID: "gcr.io/cloud-marketplace-containers/google/bazel@sha256:010a1ecd1a8c3610f12039a25b823e3a17bd3e8ae455a53e340dcfdd37a49964", - }}, - Sidecars: []v1.SidecarState{{ - Name: "sidecar-jwqcl", - ImageID: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/sidecar-git-init@sha256:a1234f6e7a69617db57b685893256f978436277094c21d43b153994acd8a09567", - }}, - }, - }, - }), - want: []v1slsa.ResourceDescriptor{ - { - URI: "oci://gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init", - Digest: common.DigestSet{ - "sha256": "b963f6e7a69617db57b685893256f978436277094c21d43b153994acd8a01247", - }, - }, { - URI: "oci://gcr.io/cloud-marketplace-containers/google/bazel", - Digest: common.DigestSet{ - "sha256": "010a1ecd1a8c3610f12039a25b823e3a17bd3e8ae455a53e340dcfdd37a49964", - }, - }, { - URI: "oci://gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/sidecar-git-init", - Digest: common.DigestSet{ - "sha256": "a1234f6e7a69617db57b685893256f978436277094c21d43b153994acd8a09567", - }, - }, - }, - }} - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - ctx := logtesting.TestContextWithLogger(t) - var input *objects.TaskRunObjectV1 - var err error - if obj, ok := tc.obj.(*objects.TaskRunObjectV1); ok { - input = obj - } - - if trV1Beta1, ok := tc.obj.GetObject().(*v1beta1.TaskRun); ok { //nolint:staticcheck - trV1 := &v1.TaskRun{} - if err := trV1Beta1.ConvertTo(ctx, trV1); err == nil { - if trV1Beta1.Spec.Resources != nil { //nolint:staticcheck - jsonData, err := json.Marshal(trV1Beta1.Spec.Resources) //nolint:staticcheck - if err != nil { - t.Errorf("Error serializing to JSON: %v", err) - } - trV1.Annotations["tekton.dev/v1beta1-spec-resources"] = string(jsonData) - } - input = objects.NewTaskRunObjectV1(trV1) - } - } - - rd, err := TaskRun(ctx, input) - if err != nil { - t.Fatalf("Did not expect an error but got %v", err) - } - if diff := cmp.Diff(tc.want, rd); diff != "" { - t.Errorf("ResolvedDependencies(): -want +got: %s", diff) - } - }) - } -} - -func TestPipelineRun(t *testing.T) { - taskRuns := tektonTaskRuns() - tests := []struct { - name string - taskDescriptor addTaskDescriptorContent - want []v1slsa.ResourceDescriptor - }{ - { - name: "test slsa build type", - taskDescriptor: AddSLSATaskDescriptor, - want: []v1slsa.ResourceDescriptor{ - {Name: "pipeline", URI: "git+https://github.com/test", Digest: common.DigestSet{"sha1": "28b123"}}, - {Name: "pipelineTask", URI: "git+https://github.com/catalog", Digest: common.DigestSet{"sha1": "x123"}}, - { - URI: "oci://gcr.io/test1/test1", - Digest: common.DigestSet{"sha256": "d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"}, - }, - {Name: "pipelineTask", URI: "git+https://github.com/test", Digest: common.DigestSet{"sha1": "ab123"}}, - { - URI: "oci://gcr.io/test2/test2", - Digest: common.DigestSet{"sha256": "4d6dd704ef58cb214dd826519929e92a978a57cdee43693006139c0080fd6fac"}, - }, - { - URI: "oci://gcr.io/test3/test3", - Digest: common.DigestSet{"sha256": "f1a8b8549c179f41e27ff3db0fe1a1793e4b109da46586501a8343637b1d0478"}, - }, - {Name: "inputs/result", URI: "abc", Digest: common.DigestSet{"sha256": "827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7"}}, - {Name: "inputs/result", URI: "git+https://git.test.com.git", Digest: common.DigestSet{"sha1": "abcd"}}, - }, - }, - { - name: "test tekton build type", - taskDescriptor: AddTektonTaskDescriptor, - want: []v1slsa.ResourceDescriptor{ - {Name: "pipeline", URI: "git+https://github.com/test", Digest: common.DigestSet{"sha1": "28b123"}}, - {Name: "pipelineTask", URI: "git+https://github.com/catalog", Digest: common.DigestSet{"sha1": "x123"}, Content: taskRuns["git-clone"]}, - { - URI: "oci://gcr.io/test1/test1", - Digest: common.DigestSet{"sha256": "d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"}, - }, - {Name: "pipelineTask", URI: "git+https://github.com/test", Digest: common.DigestSet{"sha1": "ab123"}, Content: taskRuns["taskrun-build"]}, - { - URI: "oci://gcr.io/test2/test2", - Digest: common.DigestSet{"sha256": "4d6dd704ef58cb214dd826519929e92a978a57cdee43693006139c0080fd6fac"}, - }, - { - URI: "oci://gcr.io/test3/test3", - Digest: common.DigestSet{"sha256": "f1a8b8549c179f41e27ff3db0fe1a1793e4b109da46586501a8343637b1d0478"}, - }, - {Name: "inputs/result", URI: "abc", Digest: common.DigestSet{"sha256": "827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7"}}, - {Name: "inputs/result", URI: "git+https://git.test.com.git", Digest: common.DigestSet{"sha1": "abcd"}}, - }, - }, - } - - ctx := logtesting.TestContextWithLogger(t) - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - got, err := PipelineRun(ctx, pro, &slsaconfig.SlsaConfig{DeepInspectionEnabled: false}, tc.taskDescriptor) - if err != nil { - t.Error(err) - } - if d := cmp.Diff(tc.want, got); d != "" { - t.Errorf("PipelineRunResolvedDependencies(): -want +got: %s", got) - } - }) - } -} - -func TestPipelineRunStructuredResult(t *testing.T) { - want := []v1slsa.ResourceDescriptor{ - {Name: "pipeline", URI: "git+https://github.com/test", Digest: common.DigestSet{"sha1": "28b123"}}, - {Name: "pipelineTask", URI: "git+https://github.com/catalog", Digest: common.DigestSet{"sha1": "x123"}}, - { - URI: "oci://gcr.io/test1/test1", - Digest: common.DigestSet{"sha256": "d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"}, - }, - {Name: "pipelineTask", URI: "git+https://github.com/test", Digest: common.DigestSet{"sha1": "ab123"}}, - { - URI: "oci://gcr.io/test2/test2", - Digest: common.DigestSet{"sha256": "4d6dd704ef58cb214dd826519929e92a978a57cdee43693006139c0080fd6fac"}, - }, - { - URI: "oci://gcr.io/test3/test3", - Digest: common.DigestSet{"sha256": "f1a8b8549c179f41e27ff3db0fe1a1793e4b109da46586501a8343637b1d0478"}, - }, - { - Name: "inputs/result", - URI: "abc", - Digest: common.DigestSet{ - "sha256": "827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7", - }, - }, - { - URI: "git+https://git.test.com.git", - Digest: common.DigestSet{"sha1": "abcd"}, - Name: "inputs/result", - }, - } - ctx := logtesting.TestContextWithLogger(t) - got, err := PipelineRun(ctx, pro, &slsaconfig.SlsaConfig{DeepInspectionEnabled: false}, AddSLSATaskDescriptor) - if err != nil { - t.Errorf("error while extracting resolvedDependencies: %v", err) - } - if diff := cmp.Diff(want, got, compare.SLSAV1CompareOptions()...); diff != "" { - t.Errorf("resolvedDependencies(): -want +got: %s", diff) - } -} diff --git a/pkg/chains/formats/slsa/v2alpha3/internal/taskrun/taskrun.go b/pkg/chains/formats/slsa/v2alpha3/internal/taskrun/taskrun.go index 90d0abc369..793a732db7 100644 --- a/pkg/chains/formats/slsa/v2alpha3/internal/taskrun/taskrun.go +++ b/pkg/chains/formats/slsa/v2alpha3/internal/taskrun/taskrun.go @@ -22,10 +22,10 @@ import ( slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" "github.com/tektoncd/chains/pkg/chains/formats/slsa/extract" buildtypes "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/build_types" + 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" - externalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha3/internal/external_parameters" - resolveddependencies "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha3/internal/resolved_dependencies" "github.com/tektoncd/chains/pkg/chains/objects" ) diff --git a/pkg/chains/formats/slsa/v2alpha3/internal/taskrun/taskrun_test.go b/pkg/chains/formats/slsa/v2alpha3/internal/taskrun/taskrun_test.go index 8d9875a086..1606150399 100644 --- a/pkg/chains/formats/slsa/v2alpha3/internal/taskrun/taskrun_test.go +++ b/pkg/chains/formats/slsa/v2alpha3/internal/taskrun/taskrun_test.go @@ -28,11 +28,11 @@ import ( 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" - externalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha3/internal/external_parameters" "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha3/internal/pipelinerun" - resolveddependencies "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha3/internal/resolved_dependencies" "github.com/tektoncd/chains/pkg/chains/objects" "github.com/tektoncd/chains/pkg/internal/objectloader" "github.com/tektoncd/pipeline/pkg/apis/config"