From 945c0a42774cbfd211418a287222a8903797c809 Mon Sep 17 00:00:00 2001 From: Renzo Rojas Silva Date: Tue, 4 Jun 2024 17:39:34 -0400 Subject: [PATCH 1/2] Calculate subjects per formatter --- pkg/chains/formats/format.go | 1 + pkg/chains/formats/simple/simple.go | 4 ++++ pkg/chains/formats/slsa/v1/intotoite6.go | 9 ++++++++ pkg/chains/formats/slsa/v2alpha3/slsav2.go | 9 ++++++++ .../internal/pipelinerun/pipelinerun.go | 4 ++-- pkg/chains/formats/slsa/v2alpha4/slsav2.go | 22 +++++++++++++++++++ pkg/chains/storage/grafeas/grafeas.go | 15 ++++++++++++- 7 files changed, 61 insertions(+), 3 deletions(-) diff --git a/pkg/chains/formats/format.go b/pkg/chains/formats/format.go index 797240f999..4caabbc88b 100644 --- a/pkg/chains/formats/format.go +++ b/pkg/chains/formats/format.go @@ -25,6 +25,7 @@ type Payloader interface { CreatePayload(ctx context.Context, obj interface{}) (interface{}, error) Type() config.PayloadType Wrap() bool + RetrieveAllArtifactURIs(ctx context.Context, obj interface{}) ([]string, error) } const ( diff --git a/pkg/chains/formats/simple/simple.go b/pkg/chains/formats/simple/simple.go index 10c464f96a..93a19f8fd2 100644 --- a/pkg/chains/formats/simple/simple.go +++ b/pkg/chains/formats/simple/simple.go @@ -69,3 +69,7 @@ func (i SimpleContainerImage) ImageName() string { func (i *SimpleSigning) Type() config.PayloadType { return formats.PayloadTypeSimpleSigning } + +func (i *SimpleSigning) RetrieveAllArtifactURIs(ctx context.Context, obj interface{}) ([]string, error) { + return nil, fmt.Errorf("RetrieveAllArtifactURIs not supported for simeplesining formatter") +} diff --git a/pkg/chains/formats/slsa/v1/intotoite6.go b/pkg/chains/formats/slsa/v1/intotoite6.go index f4c3bc8d8f..689a702770 100644 --- a/pkg/chains/formats/slsa/v1/intotoite6.go +++ b/pkg/chains/formats/slsa/v1/intotoite6.go @@ -21,6 +21,7 @@ import ( "fmt" "github.com/tektoncd/chains/pkg/chains/formats" + "github.com/tektoncd/chains/pkg/chains/formats/slsa/extract" "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/slsaconfig" "github.com/tektoncd/chains/pkg/chains/formats/slsa/v1/pipelinerun" "github.com/tektoncd/chains/pkg/chains/formats/slsa/v1/taskrun" @@ -94,3 +95,11 @@ func (i *InTotoIte6) CreatePayload(ctx context.Context, obj interface{}) (interf func (i *InTotoIte6) Type() config.PayloadType { return formats.PayloadTypeSlsav1 } + +func (i *InTotoIte6) RetrieveAllArtifactURIs(ctx context.Context, obj interface{}) ([]string, error) { + tkObj, ok := obj.(objects.TektonObject) + if !ok { + return nil, fmt.Errorf("intoto does not support type") + } + return extract.RetrieveAllArtifactURIs(ctx, tkObj, i.slsaConfig.DeepInspectionEnabled), nil +} diff --git a/pkg/chains/formats/slsa/v2alpha3/slsav2.go b/pkg/chains/formats/slsa/v2alpha3/slsav2.go index d86dd01802..63237907af 100644 --- a/pkg/chains/formats/slsa/v2alpha3/slsav2.go +++ b/pkg/chains/formats/slsa/v2alpha3/slsav2.go @@ -21,6 +21,7 @@ import ( "fmt" "github.com/tektoncd/chains/pkg/chains/formats" + "github.com/tektoncd/chains/pkg/chains/formats/slsa/extract" "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/slsaconfig" "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha3/internal/pipelinerun" "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha3/internal/taskrun" @@ -68,3 +69,11 @@ func (s *Slsa) CreatePayload(ctx context.Context, obj interface{}) (interface{}, func (s *Slsa) Type() config.PayloadType { return formats.PayloadTypeSlsav2alpha3 } + +func (s *Slsa) RetrieveAllArtifactURIs(ctx context.Context, obj interface{}) ([]string, error) { + tkObj, ok := obj.(objects.TektonObject) + if !ok { + return nil, fmt.Errorf("intoto does not support type") + } + return extract.RetrieveAllArtifactURIs(ctx, tkObj, s.slsaConfig.DeepInspectionEnabled), nil +} diff --git a/pkg/chains/formats/slsa/v2alpha4/internal/pipelinerun/pipelinerun.go b/pkg/chains/formats/slsa/v2alpha4/internal/pipelinerun/pipelinerun.go index 8864923a74..ace3c92419 100644 --- a/pkg/chains/formats/slsa/v2alpha4/internal/pipelinerun/pipelinerun.go +++ b/pkg/chains/formats/slsa/v2alpha4/internal/pipelinerun/pipelinerun.go @@ -47,7 +47,7 @@ func GenerateAttestation(ctx context.Context, pro *objects.PipelineRunObjectV1, return nil, err } - sub := subjectDigests(ctx, pro, slsaconfig) + sub := SubjectDigests(ctx, pro, slsaconfig) return provenance.GetSLSA1Statement(pro, sub, &bd, bp, slsaconfig) } @@ -74,7 +74,7 @@ func byproducts(pro *objects.PipelineRunObjectV1, slsaconfig *slsaconfig.SlsaCon return byProd, nil } -func subjectDigests(ctx context.Context, pro *objects.PipelineRunObjectV1, slsaconfig *slsaconfig.SlsaConfig) []*intoto.ResourceDescriptor { +func SubjectDigests(ctx context.Context, pro *objects.PipelineRunObjectV1, slsaconfig *slsaconfig.SlsaConfig) []*intoto.ResourceDescriptor { subjects := extract.SubjectsFromBuildArtifact(ctx, pro.GetResults()) if !slsaconfig.DeepInspectionEnabled { diff --git a/pkg/chains/formats/slsa/v2alpha4/slsav2.go b/pkg/chains/formats/slsa/v2alpha4/slsav2.go index d756cac477..b406488cb4 100644 --- a/pkg/chains/formats/slsa/v2alpha4/slsav2.go +++ b/pkg/chains/formats/slsa/v2alpha4/slsav2.go @@ -20,6 +20,7 @@ import ( "context" "fmt" + intoto "github.com/in-toto/attestation/go/v1" "github.com/tektoncd/chains/pkg/chains/formats" "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/slsaconfig" "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha4/internal/pipelinerun" @@ -74,3 +75,24 @@ func (s *Slsa) CreatePayload(ctx context.Context, obj interface{}) (interface{}, func (s *Slsa) Type() config.PayloadType { return payloadTypeSlsav2alpha4 } + +func (s *Slsa) RetrieveAllArtifactURIs(ctx context.Context, obj interface{}) ([]string, error) { + var subjects []*intoto.ResourceDescriptor + var fullURIs []string + + switch v := obj.(type) { + case *objects.TaskRunObjectV1: + subjects = taskrun.SubjectDigests(ctx, v) + case *objects.PipelineRunObjectV1: + subjects = pipelinerun.SubjectDigests(ctx, v, s.slsaConfig) + default: + return nil, fmt.Errorf("intoto does not support type: %s", v) + } + + for _, s := range subjects { + for algo, digest := range s.Digest { + fullURIs = append(fullURIs, fmt.Sprintf("%s@%s:%s", s.Name, algo, digest)) + } + } + return fullURIs, nil +} diff --git a/pkg/chains/storage/grafeas/grafeas.go b/pkg/chains/storage/grafeas/grafeas.go index 7f04f3e86e..acb5f9ed6c 100644 --- a/pkg/chains/storage/grafeas/grafeas.go +++ b/pkg/chains/storage/grafeas/grafeas.go @@ -253,7 +253,7 @@ func (b *Backend) createOccurrence(ctx context.Context, obj objects.TektonObject } // create Occurrence_Build for TaskRun - allURIs := extract.RetrieveAllArtifactURIs(ctx, obj, b.cfg.Artifacts.PipelineRuns.DeepInspectionEnabled) + allURIs := b.getAllArtifactURIs(ctx, opts.PayloadFormat, obj) for _, uri := range allURIs { occ, err := b.createBuildOccurrence(ctx, obj, payload, signature, uri) if err != nil { @@ -264,6 +264,19 @@ func (b *Backend) createOccurrence(ctx context.Context, obj objects.TektonObject return occs, nil } +func (b *Backend) getAllArtifactURIs(ctx context.Context, payloadFormat config.PayloadType, obj objects.TektonObject) []string { + payloader, err := formats.GetPayloader(payloadFormat, b.cfg) + if err != nil { + return extract.RetrieveAllArtifactURIs(ctx, obj, b.cfg.Artifacts.PipelineRuns.DeepInspectionEnabled) + } + + if uris, err := payloader.RetrieveAllArtifactURIs(ctx, obj); err == nil { + return uris + } + + return extract.RetrieveAllArtifactURIs(ctx, obj, b.cfg.Artifacts.PipelineRuns.DeepInspectionEnabled) +} + func (b *Backend) createAttestationOccurrence(ctx context.Context, payload []byte, signature string, uri string) (*pb.Occurrence, error) { occurrenceDetails := &pb.Occurrence_Attestation{ Attestation: &pb.AttestationOccurrence{ From 47c808b2f354252d086287cdfb2ef348ad4028d2 Mon Sep 17 00:00:00 2001 From: Renzo Rojas Silva Date: Thu, 6 Jun 2024 00:32:55 -0400 Subject: [PATCH 2/2] Tests for new retrieve full uris in grafeas --- pkg/chains/formats/simple/simple.go | 3 +- pkg/chains/formats/slsa/v1/intotoite6.go | 1 + pkg/chains/formats/slsa/v2alpha3/slsav2.go | 1 + .../internal/pipelinerun/pipelinerun.go | 1 + pkg/chains/formats/slsa/v2alpha4/slsav2.go | 1 + pkg/chains/storage/grafeas/grafeas.go | 5 +- pkg/chains/storage/grafeas/grafeas_test.go | 291 +++++++++++++++++- 7 files changed, 293 insertions(+), 10 deletions(-) diff --git a/pkg/chains/formats/simple/simple.go b/pkg/chains/formats/simple/simple.go index 93a19f8fd2..1089574774 100644 --- a/pkg/chains/formats/simple/simple.go +++ b/pkg/chains/formats/simple/simple.go @@ -70,6 +70,7 @@ func (i *SimpleSigning) Type() config.PayloadType { return formats.PayloadTypeSimpleSigning } -func (i *SimpleSigning) RetrieveAllArtifactURIs(ctx context.Context, obj interface{}) ([]string, error) { +// RetrieveAllArtifactURIs returns always an error, feature not available for simplesigning formatter. +func (i *SimpleSigning) RetrieveAllArtifactURIs(_ context.Context, _ interface{}) ([]string, error) { return nil, fmt.Errorf("RetrieveAllArtifactURIs not supported for simeplesining formatter") } diff --git a/pkg/chains/formats/slsa/v1/intotoite6.go b/pkg/chains/formats/slsa/v1/intotoite6.go index 689a702770..d6a9c8abf9 100644 --- a/pkg/chains/formats/slsa/v1/intotoite6.go +++ b/pkg/chains/formats/slsa/v1/intotoite6.go @@ -96,6 +96,7 @@ func (i *InTotoIte6) Type() config.PayloadType { return formats.PayloadTypeSlsav1 } +// RetrieveAllArtifactURIs returns the full URI of all artifacts detected as subjects. func (i *InTotoIte6) RetrieveAllArtifactURIs(ctx context.Context, obj interface{}) ([]string, error) { tkObj, ok := obj.(objects.TektonObject) if !ok { diff --git a/pkg/chains/formats/slsa/v2alpha3/slsav2.go b/pkg/chains/formats/slsa/v2alpha3/slsav2.go index 63237907af..3b8c241462 100644 --- a/pkg/chains/formats/slsa/v2alpha3/slsav2.go +++ b/pkg/chains/formats/slsa/v2alpha3/slsav2.go @@ -70,6 +70,7 @@ func (s *Slsa) Type() config.PayloadType { return formats.PayloadTypeSlsav2alpha3 } +// RetrieveAllArtifactURIs returns the full URI of all artifacts detected as subjects. func (s *Slsa) RetrieveAllArtifactURIs(ctx context.Context, obj interface{}) ([]string, error) { tkObj, ok := obj.(objects.TektonObject) if !ok { diff --git a/pkg/chains/formats/slsa/v2alpha4/internal/pipelinerun/pipelinerun.go b/pkg/chains/formats/slsa/v2alpha4/internal/pipelinerun/pipelinerun.go index ace3c92419..4ccf941a89 100644 --- a/pkg/chains/formats/slsa/v2alpha4/internal/pipelinerun/pipelinerun.go +++ b/pkg/chains/formats/slsa/v2alpha4/internal/pipelinerun/pipelinerun.go @@ -74,6 +74,7 @@ func byproducts(pro *objects.PipelineRunObjectV1, slsaconfig *slsaconfig.SlsaCon return byProd, nil } +// SubjectDigests calculates the subjects associated with the given PipelineRun. func SubjectDigests(ctx context.Context, pro *objects.PipelineRunObjectV1, slsaconfig *slsaconfig.SlsaConfig) []*intoto.ResourceDescriptor { subjects := extract.SubjectsFromBuildArtifact(ctx, pro.GetResults()) diff --git a/pkg/chains/formats/slsa/v2alpha4/slsav2.go b/pkg/chains/formats/slsa/v2alpha4/slsav2.go index b406488cb4..c5e6cb5273 100644 --- a/pkg/chains/formats/slsa/v2alpha4/slsav2.go +++ b/pkg/chains/formats/slsa/v2alpha4/slsav2.go @@ -76,6 +76,7 @@ func (s *Slsa) Type() config.PayloadType { return payloadTypeSlsav2alpha4 } +// RetrieveAllArtifactURIs returns the full URI of all artifacts detected as subjects. func (s *Slsa) RetrieveAllArtifactURIs(ctx context.Context, obj interface{}) ([]string, error) { var subjects []*intoto.ResourceDescriptor var fullURIs []string diff --git a/pkg/chains/storage/grafeas/grafeas.go b/pkg/chains/storage/grafeas/grafeas.go index acb5f9ed6c..ef86b87acc 100644 --- a/pkg/chains/storage/grafeas/grafeas.go +++ b/pkg/chains/storage/grafeas/grafeas.go @@ -265,8 +265,10 @@ func (b *Backend) createOccurrence(ctx context.Context, obj objects.TektonObject } func (b *Backend) getAllArtifactURIs(ctx context.Context, payloadFormat config.PayloadType, obj objects.TektonObject) []string { + logger := logging.FromContext(ctx) payloader, err := formats.GetPayloader(payloadFormat, b.cfg) if err != nil { + logger.Infof("couldn't get payloader for %v format, will use extract.RetrieveAllArtifactURIs method instead", payloadFormat) return extract.RetrieveAllArtifactURIs(ctx, obj, b.cfg.Artifacts.PipelineRuns.DeepInspectionEnabled) } @@ -274,6 +276,7 @@ func (b *Backend) getAllArtifactURIs(ctx context.Context, payloadFormat config.P return uris } + logger.Infof("couldn't get URIs from payloader %v, will use extract.RetrieveAllArtifactURIs method instead", payloadFormat) return extract.RetrieveAllArtifactURIs(ctx, obj, b.cfg.Artifacts.PipelineRuns.DeepInspectionEnabled) } @@ -377,7 +380,7 @@ func (b *Backend) getBuildNotePath(obj objects.TektonObject) string { func (b *Backend) getAllOccurrences(ctx context.Context, obj objects.TektonObject, opts config.StorageOpts) ([]*pb.Occurrence, error) { result := []*pb.Occurrence{} // step 1: get all resource URIs created under the taskrun - uriFilters := extract.RetrieveAllArtifactURIs(ctx, obj, b.cfg.Artifacts.PipelineRuns.DeepInspectionEnabled) + uriFilters := b.getAllArtifactURIs(ctx, opts.PayloadFormat, obj) // step 2: find all build occurrences if _, ok := formats.IntotoAttestationSet[opts.PayloadFormat]; ok { diff --git a/pkg/chains/storage/grafeas/grafeas_test.go b/pkg/chains/storage/grafeas/grafeas_test.go index 57809aee31..398c7a8eee 100644 --- a/pkg/chains/storage/grafeas/grafeas_test.go +++ b/pkg/chains/storage/grafeas/grafeas_test.go @@ -21,14 +21,15 @@ import ( "sort" "strings" "testing" + "time" "github.com/google/go-cmp/cmp" intoto "github.com/in-toto/attestation/go/v1" "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" "github.com/tektoncd/chains/pkg/chains/formats" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/extract" "github.com/tektoncd/chains/pkg/chains/objects" + v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" "google.golang.org/grpc" "google.golang.org/grpc/codes" @@ -46,6 +47,8 @@ import ( "knative.dev/pkg/logging" logtesting "knative.dev/pkg/logging/testing" rtesting "knative.dev/pkg/reconciler/testing" + + _ "github.com/tektoncd/chains/pkg/chains/formats/all" ) const ( @@ -159,6 +162,125 @@ var ( }, } + // TaskRun with step results. + taskRunWithStepResults = &v1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "taskrun-with-steps", + UID: types.UID("uid-pipeline"), + Labels: map[string]string{ + "tekton.dev/pipelineTask": "taskrun-with-steps", + }, + }, + Status: v1.TaskRunStatus{ + TaskRunStatusFields: v1.TaskRunStatusFields{ + CompletionTime: &metav1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 12, time.UTC)}, + Results: []v1.TaskRunResult{ + { + Name: "art1-ARTIFACT_OUTPUTS", + Value: *v1.NewObject(map[string]string{ + "uri": "gcr.io/img1", + "digest": "sha256:52e18b100a8da6e191a1955913ba127b75a8b38146cd9b0f573ec1d8e8ecd135", + "isBuildArtifact": "true", + }), + }, + { + Name: "art2-ARTIFACT_OUTPUTS", + Value: *v1.NewObject(map[string]string{ + "uri": "gcr.io/img2", + "digest": "sha256:2996854378975c2f8011ddf0526975d1aaf1790b404da7aad4bf25293055bc8b", + "isBuildArtifact": "false", + }), + }, + {Name: "IMAGE_URL", Value: *v1.NewStructuredValues("gcr.io/img3")}, + {Name: "IMAGE_DIGEST", Value: *v1.NewStructuredValues("sha256:ef334b5d9704da9b325ed6d4e3e5327863847e2da6d43f81831fd1decbdb2213")}, + }, + Steps: []v1.StepState{ + { + Name: "step1", + Results: []v1.TaskRunStepResult{ + { + Name: "art3-repeated-ARTIFACT_OUTPUTS", + Value: *v1.NewObject(map[string]string{ + "uri": "gcr.io/img1", + "digest": "sha256:52e18b100a8da6e191a1955913ba127b75a8b38146cd9b0f573ec1d8e8ecd135", + "isBuildArtifact": "true", + }), + }, + { + Name: "art4-ARTIFACT_OUTPUTS", + Value: *v1.NewObject(map[string]string{ + "uri": "gcr.io/img4", + "digest": "sha256:910700c5ace59f70588c4e2a38ed131146c9f65c94379dfe12376075fc2f338f", + "isBuildArtifact": "true", + }), + }, + { + Name: "art5-ARTIFACT_OUTPUTS", + Value: *v1.NewObject(map[string]string{ + "uri": "gcr.io/img5", + "digest": "sha256:7492314e32aa75ff1f2cfea35b7dda85d8831929d076aab52420c3400c8c65d8", + }), + }, + }, + }, + }, + }, + }, + } + + taskRunWithStepResultsProvenancev2alpha4 = intoto.Statement{ + Subject: []*intoto.ResourceDescriptor{ + { + Name: "gcr.io/img1", + Digest: common.DigestSet{ + "sha256": "52e18b100a8da6e191a1955913ba127b75a8b38146cd9b0f573ec1d8e8ecd135", + }, + }, + { + Name: "gcr.io/img4", + Digest: common.DigestSet{ + "sha256": "910700c5ace59f70588c4e2a38ed131146c9f65c94379dfe12376075fc2f338f", + }, + }, + { + Name: "gcr.io/img3", + Digest: common.DigestSet{ + "sha256": "ef334b5d9704da9b325ed6d4e3e5327863847e2da6d43f81831fd1decbdb2213", + }, + }, + }, + } + + pipelineRunWithStepResultsProvenancev2alpha4 = intoto.Statement{ + Subject: []*intoto.ResourceDescriptor{ + { + Name: "gcr.io/img1", + Digest: common.DigestSet{ + "sha256": "52e18b100a8da6e191a1955913ba127b75a8b38146cd9b0f573ec1d8e8ecd135", + }, + }, + { + Name: "gcr.io/img0", + Digest: common.DigestSet{ + "sha256": "e82e58757ff417de62d35689a6ff58f4a3975c331595ceda979d900d4f5de465", + }, + }, + { + Name: "gcr.io/img4", + Digest: common.DigestSet{ + "sha256": "910700c5ace59f70588c4e2a38ed131146c9f65c94379dfe12376075fc2f338f", + }, + }, + { + Name: "gcr.io/img3", + Digest: common.DigestSet{ + "sha256": "ef334b5d9704da9b325ed6d4e3e5327863847e2da6d43f81831fd1decbdb2213", + }, + }, + }, + } + // ci pipelinerun provenance ciPipelineRunPredicate = slsa.ProvenancePredicate{ Materials: cloneTaskRunPredicate.Materials, @@ -173,10 +295,11 @@ type args struct { } type testConfig struct { - name string - args args - wantOccurrences []*pb.Occurrence - wantErr bool + name string + args args + withDeepInspection bool + wantOccurrences []*pb.Occurrence + wantErr bool } // This function is to test the implementation of the fake server's ListOccurrences function. @@ -327,6 +450,29 @@ func TestGrafeasBackend_StoreAndRetrieve(t *testing.T) { wantOccurrences: nil, wantErr: true, }, + { + name: "slsav1/v2alpha4 taskrun format, no error", + args: args{ + runObject: &objects.TaskRunObjectV1{ + TaskRun: taskRunWithStepResults, + }, + payload: getRawFromProto(t, &taskRunWithStepResultsProvenancev2alpha4), + signature: "bar", + opts: config.StorageOpts{PayloadFormat: formats.PayloadTypeSlsav2alpha4}, + }, + wantOccurrences: getOccFromProvenance(t, &taskRunWithStepResultsProvenancev2alpha4, "taskrun"), + }, + { + name: "slsav1/v2alpha4 pipelinerun format, no error", + withDeepInspection: true, + args: args{ + runObject: getPipelineRunWithSteps(t), + payload: getRawFromProto(t, &pipelineRunWithStepResultsProvenancev2alpha4), + signature: "bar", + opts: config.StorageOpts{PayloadFormat: formats.PayloadTypeSlsav2alpha4}, + }, + wantOccurrences: getOccFromProvenance(t, &pipelineRunWithStepResultsProvenancev2alpha4, "pipelinerun"), + }, } // setup connection @@ -354,7 +500,7 @@ func TestGrafeasBackend_StoreAndRetrieve(t *testing.T) { }, Artifacts: config.ArtifactConfigs{ PipelineRuns: config.Artifact{ - DeepInspectionEnabled: false, + DeepInspectionEnabled: test.withDeepInspection, }, }, }, @@ -388,6 +534,112 @@ func TestGrafeasBackend_StoreAndRetrieve(t *testing.T) { } } +func getPipelineRunWithSteps(t *testing.T) *objects.PipelineRunObjectV1 { + t.Helper() + pr := &v1.PipelineRun{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "pipeline-with-steps", + UID: types.UID("uid-pipeline"), + }, + Status: v1.PipelineRunStatus{ + PipelineRunStatusFields: v1.PipelineRunStatusFields{ + Results: []v1.PipelineRunResult{ + { + Name: "art1-ARTIFACT_OUTPUTS", + Value: *v1.NewObject(map[string]string{ + "uri": "gcr.io/img1", + "digest": "sha256:52e18b100a8da6e191a1955913ba127b75a8b38146cd9b0f573ec1d8e8ecd135", + "isBuildArtifact": "true", + }), + }, + { + Name: "art0-ARTIFACT_OUTPUTS", + Value: *v1.NewObject(map[string]string{ + "uri": "gcr.io/img0", + "digest": "sha256:e82e58757ff417de62d35689a6ff58f4a3975c331595ceda979d900d4f5de465", + "isBuildArtifact": "true", + }), + }, + { + Name: "art0-ARTIFACT_OUTPUTS", + Value: *v1.NewObject(map[string]string{ + "uri": "gcr.io/img7", + "digest": "sha256:dc9c5a6b73b21dbc5c49254907fafead52ce59604e073c200c2c38002a9102e7", + "isBuildArtifact": "false", + }), + }, + }, + PipelineSpec: &v1.PipelineSpec{ + Tasks: []v1.PipelineTask{ + { + Name: "taskrun-with-steps", + }, + }, + }, + }, + }, + } + + prObj := &objects.PipelineRunObjectV1{ + PipelineRun: pr, + } + + prObj.AppendTaskRun(taskRunWithStepResults) + + return prObj +} + +func getOccFromProvenance(t *testing.T, provenance *intoto.Statement, noteType string) []*pb.Occurrence { + t.Helper() + var intotoSubjects []*pb.Subject + var occurs []*pb.Occurrence + subjects := provenance.Subject + noteName := fmt.Sprintf("projects/%s/notes/%s-%s-intoto", ProjectID, NoteID, noteType) + + for _, subject := range subjects { + intotoSubjects = append(intotoSubjects, &pb.Subject{ + Name: subject.Name, + Digest: subject.Digest, + }) + } + + for _, subject := range subjects { + identifier := fmt.Sprintf("%v@sha256:%v", subject.Name, subject.Digest["sha256"]) + occ := &pb.Occurrence{ + Name: identifier, + ResourceUri: identifier, + NoteName: noteName, + Details: &pb.Occurrence_Build{ + Build: &pb.BuildOccurrence{ + IntotoStatement: &pb.InTotoStatement{ + Subject: intotoSubjects, + Predicate: &pb.InTotoStatement_SlsaProvenanceZeroTwo{ + SlsaProvenanceZeroTwo: &pb.SlsaProvenanceZeroTwo{ + Builder: &pb.SlsaProvenanceZeroTwo_SlsaBuilder{}, + Invocation: &pb.SlsaProvenanceZeroTwo_SlsaInvocation{ + ConfigSource: &pb.SlsaProvenanceZeroTwo_SlsaConfigSource{}, + }, + }, + }, + }, + }, + }, + Envelope: &pb.Envelope{ + Payload: getRawFromProto(t, provenance), + PayloadType: "application/vnd.in-toto+json", + Signatures: []*pb.EnvelopeSignature{ + {Sig: []byte("bar")}, + }, + }, + } + + occurs = append(occurs, occ) + } + + return occurs +} + // test attestation storage and retrieval func testStoreAndRetrieveHelper(ctx context.Context, t *testing.T, test testConfig, backend Backend) { t.Helper() @@ -407,7 +659,7 @@ func testStoreAndRetrieveHelper(ctx context.Context, t *testing.T, test testConf expectSignature[test.args.opts.FullKey] = []string{test.args.signature} } if _, ok := formats.IntotoAttestationSet[test.args.opts.PayloadFormat]; ok { - allURIs := extract.RetrieveAllArtifactURIs(ctx, test.args.runObject, false) + allURIs := retrieveAllArtifactURIs(ctx, t, test, backend) for _, u := range allURIs { expectSignature[u] = []string{test.args.signature} } @@ -429,7 +681,7 @@ func testStoreAndRetrieveHelper(ctx context.Context, t *testing.T, test testConf expectPayload[test.args.opts.FullKey] = string(test.args.payload) } if _, ok := formats.IntotoAttestationSet[test.args.opts.PayloadFormat]; ok { - allURIs := extract.RetrieveAllArtifactURIs(ctx, test.args.runObject, false) + allURIs := retrieveAllArtifactURIs(ctx, t, test, backend) for _, u := range allURIs { expectPayload[u] = string(test.args.payload) } @@ -445,6 +697,20 @@ func testStoreAndRetrieveHelper(ctx context.Context, t *testing.T, test testConf } } +func retrieveAllArtifactURIs(ctx context.Context, t *testing.T, test testConfig, backend Backend) []string { + t.Helper() + payloader, err := formats.GetPayloader(test.args.opts.PayloadFormat, backend.cfg) + if err != nil { + t.Fatalf("error getting payloader: %v", err) + } + allURIs, err := payloader.RetrieveAllArtifactURIs(ctx, test.args.runObject) + if err != nil { + t.Fatalf("error getting artifacts URIs: %v", err) + } + + return allURIs +} + // ------------------ occurrences for taskruns and pipelineruns -------------- // BUILD Occurrence for the build taskrun that stores the slsa provenance func getTaskRunBuildOcc(t *testing.T, identifier string) *pb.Occurrence { @@ -570,6 +836,15 @@ func getRawPayload(t *testing.T, in interface{}) []byte { return rawPayload } +func getRawFromProto(t *testing.T, in *intoto.Statement) []byte { + t.Helper() + raw, err := protojson.Marshal(in) + if err != nil { + t.Errorf("Unable to marshal the proto provenance: %v", in) + } + return raw +} + // set up the connection between grafeas server and client // and return the client object to the caller func setupConnection() (*grpc.ClientConn, pb.GrafeasClient, error) { //nolint:ireturn