From e658c154b77630d9a0a02bddc880ab07eaaa6b6a Mon Sep 17 00:00:00 2001 From: Chuang Wang Date: Fri, 21 Oct 2022 16:03:57 -0700 Subject: [PATCH] Revert "Remove unsupported tekton-provenance storage in config (#594) (#590)" This reverts commit 83af00211046c47baeda591627c01294888dd789. --- .../formats/intotoite6/extract/extract.go | 26 +- .../intotoite6/extract/extract_test.go | 165 ----- .../intotoite6/pipelinerun/pipelinerun.go | 3 +- .../formats/intotoite6/taskrun/taskrun.go | 6 +- pkg/chains/objects/objects.go | 25 +- pkg/chains/signing.go | 4 +- pkg/chains/storage/grafeas/grafeas.go | 161 ++--- pkg/chains/storage/grafeas/grafeas_test.go | 681 ++++++------------ pkg/chains/storage/oci/oci.go | 4 +- pkg/chains/storage/tekton/tekton.go | 8 +- pkg/config/config.go | 2 +- test/test_utils.go | 8 +- 12 files changed, 329 insertions(+), 764 deletions(-) delete mode 100644 pkg/chains/formats/intotoite6/extract/extract_test.go diff --git a/pkg/chains/formats/intotoite6/extract/extract.go b/pkg/chains/formats/intotoite6/extract/extract.go index 366a336f32..bdf8e1901c 100644 --- a/pkg/chains/formats/intotoite6/extract/extract.go +++ b/pkg/chains/formats/intotoite6/extract/extract.go @@ -17,7 +17,6 @@ limitations under the License. package extract import ( - "fmt" "sort" "strings" @@ -31,13 +30,8 @@ import ( "go.uber.org/zap" ) -// SubjectDigests returns software artifacts produced from the TaskRun/PipelineRun object -// in the form of standard subject field of intoto statement. -// The type hinting fields expected in results help identify the generated software artifacts. -// Valid type hinting fields must: -// - have suffix `IMAGE_URL` & `IMAGE_DIGEST` or `ARTIFACT_URI` & `ARTIFACT_DIGEST` pair. -// - the `*_DIGEST` field must be in the format of ":" where the algorithm must be "sha256" and actual sha must be valid per https://github.com/opencontainers/image-spec/blob/main/descriptor.md#sha-256. -// - the `*_URL` or `*_URI` fields cannot be empty. +// SubjectDigests extracts OCI images and other structured results from the TaskRun and PipelineRun based on standard hinting set up +// It also goes through looking for any PipelineResources of Image type func SubjectDigests(obj objects.TektonObject, logger *zap.SugaredLogger) []intoto.Subject { var subjects []intoto.Subject @@ -124,19 +118,3 @@ func SubjectDigests(obj objects.TektonObject, logger *zap.SugaredLogger) []intot }) return subjects } - -// RetrieveAllArtifactURIs returns all the URIs of the software artifacts produced from the run object. -// - It first extracts intoto subjects from run object results and converts the subjects -// to a slice of string URIs in the format of "NAME" + "@" + "ALGORITHM" + ":" + "DIGEST". -// - If no subjects could be extracted from results, then an empty slice is returned. -func RetrieveAllArtifactURIs(obj objects.TektonObject, logger *zap.SugaredLogger) []string { - result := []string{} - subjects := SubjectDigests(obj, logger) - - for _, s := range subjects { - for algo, digest := range s.Digest { - result = append(result, fmt.Sprintf("%s@%s:%s", s.Name, algo, digest)) - } - } - return result -} diff --git a/pkg/chains/formats/intotoite6/extract/extract_test.go b/pkg/chains/formats/intotoite6/extract/extract_test.go deleted file mode 100644 index 2c72d9d6fb..0000000000 --- a/pkg/chains/formats/intotoite6/extract/extract_test.go +++ /dev/null @@ -1,165 +0,0 @@ -/* -Copyright 2022 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 extract_test - -import ( - "fmt" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - intoto "github.com/in-toto/in-toto-golang/in_toto" - "github.com/tektoncd/chains/pkg/chains/formats/intotoite6/extract" - "github.com/tektoncd/chains/pkg/chains/objects" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" - logtesting "knative.dev/pkg/logging/testing" -) - -const ( - artifactURL1 = "gcr.io/test/kaniko-chains1" - artifactDigest1 = "a2e500bebfe16cf12fc56316ba72c645e1d29054541dc1ab6c286197434170a9" - artifactURL2 = "us-central1-maven.pkg.dev/test/java" - artifactDigest2 = "b2e500bebfe16cf12fc56316ba72c645e1d29054541dc1ab6c286197434170a9" -) - -func TestSubjectDigestsAndRetrieveAllArtifactURIs(t *testing.T) { - var tests = []struct { - name string - // a map of url:digest pairs for type hinting results - results map[string]string - wantSubjects []intoto.Subject - wantFullURLs []string - }{ - { - name: "valid type hinting result fields", - results: map[string]string{ - artifactURL1: "sha256:" + artifactDigest1, - artifactURL2: "sha256:" + artifactDigest2, - }, - wantSubjects: []intoto.Subject{ - { - Name: artifactURL1, - Digest: map[string]string{ - "sha256": artifactDigest1, - }, - }, - { - Name: artifactURL2, - Digest: map[string]string{ - "sha256": artifactDigest2, - }, - }, - }, - wantFullURLs: []string{ - fmt.Sprintf("%s@sha256:%s", artifactURL1, artifactDigest1), - fmt.Sprintf("%s@sha256:%s", artifactURL2, artifactDigest2), - }, - }, - { - name: "invalid/missing digest algorithm name", - results: map[string]string{ - artifactURL1: "sha1:" + artifactDigest1, - artifactURL2: artifactDigest2, - }, - wantSubjects: nil, - wantFullURLs: []string{}, - }, - { - name: "invalid digest sha", - results: map[string]string{ - artifactURL1: "sha256:a123", - }, - wantSubjects: nil, - wantFullURLs: []string{}, - }, - { - name: "invalid url value", - results: map[string]string{ - "": "sha256:" + artifactDigest1, - }, - wantSubjects: nil, - wantFullURLs: []string{}, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - // test both taskrun object and pipelinerun object - runObjects := []objects.TektonObject{ - createTaskRunObjectWithResults(tc.results), - createPipelineRunObjectWithResults(tc.results), - } - - for _, o := range runObjects { - gotSubjects := extract.SubjectDigests(o, logtesting.TestLogger(t)) - if diff := cmp.Diff(tc.wantSubjects, gotSubjects, cmpopts.SortSlices(func(x, y intoto.Subject) bool { return x.Name < y.Name })); diff != "" { - t.Errorf("Wrong subjects extracted, diff=%s", diff) - } - - gotURIs := extract.RetrieveAllArtifactURIs(o, logtesting.TestLogger(t)) - if diff := cmp.Diff(tc.wantFullURLs, gotURIs, cmpopts.SortSlices(func(x, y string) bool { return x < y })); diff != "" { - t.Errorf("Wrong URIs extracted, diff=%s", diff) - } - } - - }) - } -} - -func createTaskRunObjectWithResults(results map[string]string) objects.TektonObject { - trResults := []v1beta1.TaskRunResult{} - prefix := 0 - for url, digest := range results { - trResults = append(trResults, - v1beta1.TaskRunResult{Name: fmt.Sprintf("%v_IMAGE_DIGEST", prefix), Value: *v1beta1.NewStructuredValues(digest)}, - v1beta1.TaskRunResult{Name: fmt.Sprintf("%v_IMAGE_URL", prefix), Value: *v1beta1.NewStructuredValues(url)}, - ) - prefix++ - } - - return objects.NewTaskRunObject( - &v1beta1.TaskRun{ - Status: v1beta1.TaskRunStatus{ - TaskRunStatusFields: v1beta1.TaskRunStatusFields{ - TaskRunResults: trResults, - }, - }, - }, - ) -} - -func createPipelineRunObjectWithResults(results map[string]string) objects.TektonObject { - prResults := []v1beta1.PipelineRunResult{} - prefix := 0 - for url, digest := range results { - prResults = append(prResults, - v1beta1.PipelineRunResult{Name: fmt.Sprintf("%v_IMAGE_DIGEST", prefix), Value: *v1beta1.NewStructuredValues(digest)}, - v1beta1.PipelineRunResult{Name: fmt.Sprintf("%v_IMAGE_URL", prefix), Value: *v1beta1.NewStructuredValues(url)}, - ) - prefix++ - } - - return objects.NewPipelineRunObject( - &v1beta1.PipelineRun{ - Status: v1beta1.PipelineRunStatus{ - PipelineRunStatusFields: v1beta1.PipelineRunStatusFields{ - PipelineResults: prResults, - }, - }, - }, - ) -} diff --git a/pkg/chains/formats/intotoite6/pipelinerun/pipelinerun.go b/pkg/chains/formats/intotoite6/pipelinerun/pipelinerun.go index 7e8b5b8c40..f9f97207f9 100644 --- a/pkg/chains/formats/intotoite6/pipelinerun/pipelinerun.go +++ b/pkg/chains/formats/intotoite6/pipelinerun/pipelinerun.go @@ -14,6 +14,7 @@ limitations under the License. package pipelinerun import ( + "fmt" "time" intoto "github.com/in-toto/in-toto-golang/in_toto" @@ -57,7 +58,7 @@ func GenerateAttestation(builderID string, pro *objects.PipelineRunObject, logge Builder: slsa.ProvenanceBuilder{ ID: builderID, }, - BuildType: pro.GetGVK(), + BuildType: fmt.Sprintf("%s/%s", pro.GetGroupVersionKind().GroupVersion().String(), pro.GetGroupVersionKind().Kind), Invocation: invocation(pro), BuildConfig: buildConfig(pro, logger), Metadata: metadata(pro), diff --git a/pkg/chains/formats/intotoite6/taskrun/taskrun.go b/pkg/chains/formats/intotoite6/taskrun/taskrun.go index 0c7639f6ed..1a52749c95 100644 --- a/pkg/chains/formats/intotoite6/taskrun/taskrun.go +++ b/pkg/chains/formats/intotoite6/taskrun/taskrun.go @@ -14,6 +14,8 @@ limitations under the License. package taskrun import ( + "fmt" + intoto "github.com/in-toto/in-toto-golang/in_toto" slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" "github.com/tektoncd/chains/pkg/artifacts" @@ -28,6 +30,8 @@ import ( func GenerateAttestation(builderID string, tro *objects.TaskRunObject, logger *zap.SugaredLogger) (interface{}, error) { subjects := extract.SubjectDigests(tro, logger) + tr := tro.GetObject().(*v1beta1.TaskRun) + att := intoto.ProvenanceStatement{ StatementHeader: intoto.StatementHeader{ Type: intoto.StatementInTotoV01, @@ -38,7 +42,7 @@ func GenerateAttestation(builderID string, tro *objects.TaskRunObject, logger *z Builder: slsa.ProvenanceBuilder{ ID: builderID, }, - BuildType: tro.GetGVK(), + BuildType: fmt.Sprintf("%s/%s", tr.GetGroupVersionKind().GroupVersion().String(), tr.GetGroupVersionKind().Kind), Invocation: invocation(tro), BuildConfig: buildConfig(tro), Metadata: metadata(tro), diff --git a/pkg/chains/objects/objects.go b/pkg/chains/objects/objects.go index 9e9828d434..0217fce0ff 100644 --- a/pkg/chains/objects/objects.go +++ b/pkg/chains/objects/objects.go @@ -16,7 +16,6 @@ package objects import ( "context" "errors" - "fmt" "github.com/tektoncd/pipeline/pkg/apis/pipeline/pod" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" @@ -52,7 +51,7 @@ type Result struct { // to Tekton objects. type TektonObject interface { Object - GetGVK() string + GetKind() string GetObject() interface{} GetLatestAnnotations(ctx context.Context, clientSet versioned.Interface) (map[string]string, error) Patch(ctx context.Context, clientSet versioned.Interface, patchBytes []byte) error @@ -79,17 +78,17 @@ type TaskRunObject struct { *v1beta1.TaskRun } -var _ TektonObject = &TaskRunObject{} - func NewTaskRunObject(tr *v1beta1.TaskRun) *TaskRunObject { return &TaskRunObject{ tr, } } -// Get the TaskRun GroupVersionKind -func (tro *TaskRunObject) GetGVK() string { - return fmt.Sprintf("%s/%s", tro.GetGroupVersionKind().GroupVersion().String(), tro.GetGroupVersionKind().Kind) +// Get the TaskRun kind +func (tro *TaskRunObject) GetKind() string { + // TODO: Want to use tro.GetObjectKind().GroupVersionKind().Kind but + // never seems to be populated + return "taskrun" } // Get the latest annotations on the TaskRun @@ -136,21 +135,21 @@ func (tro *TaskRunObject) GetPullSecrets() []string { type PipelineRunObject struct { // The base PipelineRun *v1beta1.PipelineRun - // taskRuns that were apart of this PipelineRun + // TaskRuns that were apart of this PipelineRun taskRuns []*v1beta1.TaskRun } -var _ TektonObject = &PipelineRunObject{} - func NewPipelineRunObject(pr *v1beta1.PipelineRun) *PipelineRunObject { return &PipelineRunObject{ PipelineRun: pr, } } -// Get the PipelineRun GroupVersionKind -func (pro *PipelineRunObject) GetGVK() string { - return fmt.Sprintf("%s/%s", pro.GetGroupVersionKind().GroupVersion().String(), pro.GetGroupVersionKind().Kind) +// Get the PipelineRun kind +func (pro *PipelineRunObject) GetKind() string { + // TODO: Want to use tro.GetObjectKind().GroupVersionKind().Kind but + // never seems to be populated + return "pipelinerun" } // Request the current annotations on the PipelineRun object diff --git a/pkg/chains/signing.go b/pkg/chains/signing.go index 53daa3a465..dfb54f12e2 100644 --- a/pkg/chains/signing.go +++ b/pkg/chains/signing.go @@ -165,7 +165,7 @@ func (o *ObjectSigner) Sign(ctx context.Context, tektonObj objects.TektonObject) payloader, ok := o.Formatters[payloadFormat] if !ok { - logger.Warnf("Format %s configured for %s: %v was not found", payloadFormat, tektonObj.GetGVK(), signableType.Type()) + logger.Warnf("Format %s configured for %s: %v was not found", payloadFormat, tektonObj.GetKind(), signableType.Type()) continue } @@ -181,7 +181,7 @@ func (o *ObjectSigner) Sign(ctx context.Context, tektonObj objects.TektonObject) logger.Error(err) continue } - logger.Infof("Created payload of type %s for %s %s/%s", string(payloadFormat), tektonObj.GetGVK(), tektonObj.GetNamespace(), tektonObj.GetName()) + logger.Infof("Created payload of type %s for %s %s/%s", string(payloadFormat), tektonObj.GetKind(), tektonObj.GetNamespace(), tektonObj.GetName()) // Sign it! signerType := signableType.Signer(cfg) diff --git a/pkg/chains/storage/grafeas/grafeas.go b/pkg/chains/storage/grafeas/grafeas.go index e317590776..4f9469c4b8 100644 --- a/pkg/chains/storage/grafeas/grafeas.go +++ b/pkg/chains/storage/grafeas/grafeas.go @@ -20,13 +20,14 @@ import ( "fmt" "strings" + "github.com/google/go-containerregistry/pkg/name" grafeasutil "github.com/grafeas/grafeas/go/utils/intoto" pb "github.com/grafeas/grafeas/proto/v1/grafeas_go_proto" intoto "github.com/in-toto/in-toto-golang/in_toto" "github.com/pkg/errors" "github.com/sigstore/cosign/pkg/types" + "github.com/tektoncd/chains/pkg/artifacts" "github.com/tektoncd/chains/pkg/chains/formats" - "github.com/tektoncd/chains/pkg/chains/formats/intotoite6/extract" "github.com/tektoncd/chains/pkg/chains/objects" "github.com/tektoncd/chains/pkg/config" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" @@ -39,12 +40,11 @@ import ( ) const ( - StorageBackendGrafeas = "grafeas" - projectPathFormat = "projects/%s" - notePathFormat = "projects/%s/notes/%s" - attestationNoteNameFormat = "%s-simplesigning" - pipelinerunBuildNoteNameFormat = "%s-pipelinerun-intoto" - taskrunBuildNoteNameFormat = "%s-taskrun-intoto" + StorageBackendGrafeas = "grafeas" + projectPath = "projects/%s" + notePath = "projects/%s/notes/%s" + attestationNoteNameFormat = "%s-simplesigning" + buildNoteNameFormat = "%s-intoto" ) // Backend is a storage backend that stores signed payloads in the storage that @@ -89,7 +89,9 @@ func NewStorageBackend(ctx context.Context, logger *zap.SugaredLogger, cfg confi // StorePayload implements the storage.Backend interface. func (b *Backend) StorePayload(ctx context.Context, obj objects.TektonObject, rawPayload []byte, signature string, opts config.StorageOpts) error { - // We only support simplesigning for OCI images, and in-toto for taskrun & pipelinerun. + // TODO: Gracefully handle unexpected type + tr := obj.GetObject().(*v1beta1.TaskRun) + // We only support simplesigning for OCI images, and in-toto for taskrun. if opts.PayloadFormat != formats.PayloadTypeInTotoIte6 && opts.PayloadFormat != formats.PayloadTypeSimpleSigning { return errors.New("Grafeas storage backend only supports simplesigning and intoto payload format.") } @@ -101,43 +103,40 @@ func (b *Backend) StorePayload(ctx context.Context, obj objects.TektonObject, ra // check if noteID is configured. If not, we give it a name as `tekton-` if b.cfg.Storage.Grafeas.NoteID == "" { - generatedNoteID := fmt.Sprintf("tekton-%s", obj.GetNamespace()) + generatedNoteID := fmt.Sprintf("tekton-%s", tr.GetNamespace()) b.cfg.Storage.Grafeas.NoteID = generatedNoteID } // step1: create note // If the note already exists, just move to the next step of creating occurrence. - if _, err := b.createNote(ctx, obj, opts); err != nil && status.Code(err) != codes.AlreadyExists { + if _, err := b.createNote(ctx, tr, opts); err != nil && status.Code(err) != codes.AlreadyExists { return err } // step2: create occurrences - occurrences, err := b.createOccurrence(ctx, obj, rawPayload, signature, opts) + occurrences, err := b.createOccurrence(ctx, tr, rawPayload, signature, opts) if err != nil { return err } - occNames := []string{} + names := []string{} for _, occ := range occurrences { - occNames = append(occNames, occ.GetName()) - } - - if len(occNames) == 0 { - b.logger.Infof("No occurrences created for payload of type %s for %s %s/%s", string(opts.PayloadFormat), obj.GetGVK(), obj.GetNamespace(), obj.GetName()) - } else { - b.logger.Infof("Successfully created grafeas occurrences %v for %s %s/%s", occNames, obj.GetGVK(), obj.GetNamespace(), obj.GetName()) + names = append(names, occ.GetName()) } + b.logger.Infof("Successfully stored signature in the grafeas occurrences %s.", names) return nil } // Retrieve payloads from grafeas server and store it in a map func (b *Backend) RetrievePayloads(ctx context.Context, obj objects.TektonObject, opts config.StorageOpts) (map[string]string, error) { + // TODO: Gracefully handle unexpected type + tr := obj.GetObject().(*v1beta1.TaskRun) // initialize an empty map for result result := make(map[string]string) // get all occurrences created using this backend - occurrences, err := b.getAllOccurrences(ctx, obj, opts) + occurrences, err := b.getAllOccurrences(ctx, tr, opts) if err != nil { return nil, err } @@ -157,11 +156,13 @@ func (b *Backend) RetrievePayloads(ctx context.Context, obj objects.TektonObject // Retrieve signatures from grafeas server and store it in a map func (b *Backend) RetrieveSignatures(ctx context.Context, obj objects.TektonObject, opts config.StorageOpts) (map[string][]string, error) { + // TODO: Gracefully handle unexpected type + tr := obj.GetObject().(*v1beta1.TaskRun) // initialize an empty map for result result := make(map[string][]string) // get all occurrences created using this backend - occurrences, err := b.getAllOccurrences(ctx, obj, opts) + occurrences, err := b.getAllOccurrences(ctx, tr, opts) if err != nil { return nil, err } @@ -190,15 +191,15 @@ func (b *Backend) Type() string { // ----------------------------- Helper Functions ---------------------------- // createNote creates grafeas note that will be linked to grafeas occurrences -func (b *Backend) createNote(ctx context.Context, obj objects.TektonObject, opts config.StorageOpts) (*pb.Note, error) { - notePrefix := b.cfg.Storage.Grafeas.NoteID +func (b *Backend) createNote(ctx context.Context, tr *v1beta1.TaskRun, opts config.StorageOpts) (*pb.Note, error) { + noteID := b.cfg.Storage.Grafeas.NoteID // for oci image: AttestationNote if opts.PayloadFormat == formats.PayloadTypeSimpleSigning { return b.client.CreateNote(ctx, &pb.CreateNoteRequest{ Parent: b.getProjectPath(), - NoteId: fmt.Sprintf(attestationNoteNameFormat, b.cfg.Storage.Grafeas.NoteID), + NoteId: fmt.Sprintf(attestationNoteNameFormat, noteID), Note: &pb.Note{ ShortDescription: "OCI Artifact Attestation Note", Type: &pb.Note_Attestation{ @@ -213,28 +214,16 @@ func (b *Backend) createNote(ctx context.Context, obj objects.TektonObject, opts ) } - switch obj.GetObject().(type) { - case *v1beta1.PipelineRun: - // create the build note for pipelinerun attestations - return b.createBuildNote(ctx, fmt.Sprintf(pipelinerunBuildNoteNameFormat, notePrefix), obj) - case *v1beta1.TaskRun: - // create the build note for taskrun attestations - return b.createBuildNote(ctx, fmt.Sprintf(taskrunBuildNoteNameFormat, notePrefix), obj) - default: - return nil, errors.New("Tried to create build note for unsupported type of object") - } -} - -func (b *Backend) createBuildNote(ctx context.Context, noteid string, obj objects.TektonObject) (*pb.Note, error) { + // for taskrun: BuildNote return b.client.CreateNote(ctx, &pb.CreateNoteRequest{ Parent: b.getProjectPath(), - NoteId: noteid, + NoteId: fmt.Sprintf(buildNoteNameFormat, noteID), Note: &pb.Note{ - ShortDescription: "Build Provenance Note for TaskRun", + ShortDescription: "Build Provenance Note", Type: &pb.Note_Build{ Build: &pb.BuildNote{ - BuilderVersion: obj.GetGVK(), + BuilderVersion: tr.GetGroupVersionKind().GroupVersion().String(), }, }, }, @@ -247,16 +236,16 @@ func (b *Backend) createBuildNote(ctx context.Context, noteid string, obj object // - its simplesigning payload and signature will be stored in ATTESTATION occurrence // - the identifier/ResourceUri is IMAGE_URL@IMAGE_DIGEST // -// for a taskrun/pipelinerun object -// - its intoto payload and signature will be stored in a BUILD occurrences for each image artifact generated from the taskrun/pipelinerun +// for a taskrun object +// - its intoto payload and signature will be stored in a BUILD occurrences for each image artifact generated from the taskrun // - each BUILD occurrence will have the same data but differ in the ResourceUri field // - the identifier/ResourceUri is IMAGE_URL@IMAGE_DIGEST -func (b *Backend) createOccurrence(ctx context.Context, obj objects.TektonObject, payload []byte, signature string, opts config.StorageOpts) ([]*pb.Occurrence, error) { +func (b *Backend) createOccurrence(ctx context.Context, tr *v1beta1.TaskRun, payload []byte, signature string, opts config.StorageOpts) ([]*pb.Occurrence, error) { occs := []*pb.Occurrence{} // create Occurrence_Attestation for OCI if opts.PayloadFormat == formats.PayloadTypeSimpleSigning { - occ, err := b.createAttestationOccurrence(ctx, payload, signature, opts.FullKey) + occ, err := b.createAttestationOccurrence(ctx, tr, payload, signature, opts.FullKey) if err != nil { return nil, err } @@ -265,9 +254,9 @@ func (b *Backend) createOccurrence(ctx context.Context, obj objects.TektonObject } // create Occurrence_Build for TaskRun - allURIs := extract.RetrieveAllArtifactURIs(obj, b.logger) + allURIs := b.retrieveAllArtifactIdentifiers(tr) for _, uri := range allURIs { - occ, err := b.createBuildOccurrence(ctx, obj, payload, signature, uri) + occ, err := b.createBuildOccurrence(ctx, tr, payload, signature, uri) if err != nil { return nil, err } @@ -276,7 +265,7 @@ func (b *Backend) createOccurrence(ctx context.Context, obj objects.TektonObject return occs, nil } -func (b *Backend) createAttestationOccurrence(ctx context.Context, payload []byte, signature string, uri string) (*pb.Occurrence, error) { +func (b *Backend) createAttestationOccurrence(ctx context.Context, tr *v1beta1.TaskRun, payload []byte, signature string, uri string) (*pb.Occurrence, error) { occurrenceDetails := &pb.Occurrence_Attestation{ Attestation: &pb.AttestationOccurrence{ SerializedPayload: payload, @@ -314,7 +303,7 @@ func (b *Backend) createAttestationOccurrence(ctx context.Context, payload []byt ) } -func (b *Backend) createBuildOccurrence(ctx context.Context, obj objects.TektonObject, payload []byte, signature string, uri string) (*pb.Occurrence, error) { +func (b *Backend) createBuildOccurrence(ctx context.Context, tr *v1beta1.TaskRun, payload []byte, signature string, uri string) (*pb.Occurrence, error) { in := intoto.ProvenanceStatement{} if err := json.Unmarshal(payload, &in); err != nil { return nil, err @@ -347,7 +336,7 @@ func (b *Backend) createBuildOccurrence(ctx context.Context, obj objects.TektonO Parent: b.getProjectPath(), Occurrence: &pb.Occurrence{ ResourceUri: uri, - NoteName: b.getBuildNotePath(obj), + NoteName: b.getBuildNotePath(), Details: occurrenceDetails, Envelope: envelope, }, @@ -357,66 +346,44 @@ func (b *Backend) createBuildOccurrence(ctx context.Context, obj objects.TektonO func (b *Backend) getProjectPath() string { projectID := b.cfg.Storage.Grafeas.ProjectID - return fmt.Sprintf(projectPathFormat, projectID) + return fmt.Sprintf(projectPath, projectID) } func (b *Backend) getAttestationNotePath() string { projectID := b.cfg.Storage.Grafeas.ProjectID noteID := b.cfg.Storage.Grafeas.NoteID - return fmt.Sprintf(notePathFormat, projectID, fmt.Sprintf(attestationNoteNameFormat, noteID)) + return fmt.Sprintf(notePath, projectID, fmt.Sprintf(attestationNoteNameFormat, noteID)) } -func (b *Backend) getBuildNotePath(obj objects.TektonObject) string { +func (b *Backend) getBuildNotePath() string { projectID := b.cfg.Storage.Grafeas.ProjectID noteID := b.cfg.Storage.Grafeas.NoteID - - switch obj.GetObject().(type) { - case *v1beta1.PipelineRun: - return fmt.Sprintf(notePathFormat, projectID, fmt.Sprintf(pipelinerunBuildNoteNameFormat, noteID)) - case *v1beta1.TaskRun: - return fmt.Sprintf(notePathFormat, projectID, fmt.Sprintf(taskrunBuildNoteNameFormat, noteID)) - } - return "" + return fmt.Sprintf(notePath, projectID, fmt.Sprintf(buildNoteNameFormat, noteID)) } // getAllOccurrences retrieves back all occurrences created for a taskrun -func (b *Backend) getAllOccurrences(ctx context.Context, obj objects.TektonObject, opts config.StorageOpts) ([]*pb.Occurrence, error) { - result := []*pb.Occurrence{} +func (b *Backend) getAllOccurrences(ctx context.Context, tr *v1beta1.TaskRun, opts config.StorageOpts) ([]*pb.Occurrence, error) { // step 1: get all resource URIs created under the taskrun - uriFilters := extract.RetrieveAllArtifactURIs(obj, b.logger) + uriFilters := b.retrieveAllArtifactIdentifiers(tr) - // step 2: find all build occurrences - if opts.PayloadFormat == formats.PayloadTypeInTotoIte6 { - occs, err := b.findOccurrencesForCriteria(ctx, b.getBuildNotePath(obj), uriFilters) - if err != nil { - return nil, err - } - result = append(result, occs...) - } - - // step 3: find all attestation occurrences - if opts.PayloadFormat == formats.PayloadTypeSimpleSigning { - occs, err := b.findOccurrencesForCriteria(ctx, b.getAttestationNotePath(), uriFilters) - if err != nil { - return nil, err - } - result = append(result, occs...) + // step 2: find all occurrences by using ListOccurrences filters + occs, err := b.findOccurrencesForCriteria(ctx, b.getProjectPath(), uriFilters) + if err != nil { + return nil, err } - - return result, nil + return occs, nil } // findOccurrencesForCriteria lookups a project's occurrences by the resource uri -func (b *Backend) findOccurrencesForCriteria(ctx context.Context, noteName string, resourceURIs []string) ([]*pb.Occurrence, error) { - +func (b *Backend) findOccurrencesForCriteria(ctx context.Context, projectPath string, resourceURIs []string) ([]*pb.Occurrence, error) { var uriFilters []string for _, url := range resourceURIs { uriFilters = append(uriFilters, fmt.Sprintf("resourceUrl=%q", url)) } - occurences, err := b.client.ListNoteOccurrences(ctx, - &pb.ListNoteOccurrencesRequest{ - Name: noteName, + occurences, err := b.client.ListOccurrences(ctx, + &pb.ListOccurrencesRequest{ + Parent: projectPath, Filter: strings.Join(uriFilters, " OR "), }, ) @@ -426,3 +393,25 @@ func (b *Backend) findOccurrencesForCriteria(ctx context.Context, noteName strin } return occurences.GetOccurrences(), nil } + +// retrieve the uri of all images generated from a specific taskrun in the format of `IMAGE_URL@IMAGE_DIGEST` +func (b *Backend) retrieveAllArtifactIdentifiers(tr *v1beta1.TaskRun) []string { + result := []string{} + // for image artifacts + trObj := objects.NewTaskRunObject(tr) + images := artifacts.ExtractOCIImagesFromResults(trObj, b.logger) + for _, image := range images { + ref, ok := image.(name.Digest) + if !ok { + continue + } + result = append(result, ref.Name()) + } + + // for other signable artifacts + artifacts := artifacts.ExtractSignableTargetFromResults(trObj, b.logger) + for _, a := range artifacts { + result = append(result, a.FullRef()) + } + return result +} diff --git a/pkg/chains/storage/grafeas/grafeas_test.go b/pkg/chains/storage/grafeas/grafeas_test.go index 1ce8a60333..f085320ff9 100644 --- a/pkg/chains/storage/grafeas/grafeas_test.go +++ b/pkg/chains/storage/grafeas/grafeas_test.go @@ -1,5 +1,5 @@ /* -Copyright 2022 The Tekton Authors +Copyright 2020 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 @@ -15,7 +15,6 @@ package grafeas import ( "context" - "encoding/json" "fmt" "net" "sort" @@ -23,190 +22,40 @@ import ( "testing" "github.com/google/go-cmp/cmp" - intoto "github.com/in-toto/in-toto-golang/in_toto" - 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/intotoite6/extract" "github.com/tektoncd/chains/pkg/chains/objects" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/status" "google.golang.org/protobuf/testing/protocmp" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" pb "github.com/grafeas/grafeas/proto/v1/grafeas_go_proto" "github.com/tektoncd/chains/pkg/config" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" gstatus "google.golang.org/grpc/status" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" logtesting "knative.dev/pkg/logging/testing" rtesting "knative.dev/pkg/reconciler/testing" ) -const ( - ProjectID = "test-project" - NoteID = "test-note" - // repo information for clone taskrun - repoURL = "https://github.com/test/tekton-test.git" - commitSHA = "e02ae3576b4e621bd6798ccbfb89358121d896d7" - // image information for artifact build task - artifactURL1 = "gcr.io/test/kaniko-chains1" - artifactDigest1 = "a2e500bebfe16cf12fc56316ba72c645e1d29054541dc1ab6c286197434170a9" - artifactURL2 = "us-central1-maven.pkg.dev/test/java" - artifactDigest2 = "b2e500bebfe16cf12fc56316ba72c645e1d29054541dc1ab6c286197434170a9" -) - -// Those variables are -// - the clone taskrun and its provenance -// - the artifact build taskrun and its provenance -// - the CI pipelinerun that mocks as the owner of the two taskruns, and its provenance -var ( - // clone taskrun - // -------------- - cloneTaskRun = &v1beta1.TaskRun{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - Name: "git-clone", - UID: types.UID("uid-task1"), - }, - Status: v1beta1.TaskRunStatus{ - TaskRunStatusFields: v1beta1.TaskRunStatusFields{ - TaskRunResults: []v1beta1.TaskRunResult{ - {Name: "CHAINS-GIT_COMMIT", Value: *v1beta1.NewStructuredValues(commitSHA)}, - {Name: "CHAINS-GIT_URL", Value: *v1beta1.NewStructuredValues(repoURL)}, - }, - }, - }, - } - - // clone taskrun provenance - cloneTaskRunProvenance = intoto.ProvenanceStatement{ - Predicate: slsa.ProvenancePredicate{ - Materials: []slsa.ProvenanceMaterial{ - { - URI: repoURL, - Digest: slsa.DigestSet{ - "sha1": commitSHA, - }, - }, - }, - }, - } - - artifactIdentifier1 = fmt.Sprintf("%s@sha256:%s", artifactURL1, artifactDigest1) - artifactIdentifier2 = fmt.Sprintf("%s@sha256:%s", artifactURL2, artifactDigest2) - - // artifact build taskrun - buildTaskRun = &v1beta1.TaskRun{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - Name: "artifact-build", - UID: types.UID("uid-task2"), - }, - Status: v1beta1.TaskRunStatus{ - TaskRunStatusFields: v1beta1.TaskRunStatusFields{ - TaskRunResults: []v1beta1.TaskRunResult{ - {Name: "IMAGE_DIGEST", Value: *v1beta1.NewStructuredValues("sha256:" + artifactDigest1)}, - {Name: "IMAGE_URL", Value: *v1beta1.NewStructuredValues(artifactURL1)}, - {Name: "x_ARTIFACT_DIGEST", Value: *v1beta1.NewStructuredValues("sha256:" + artifactDigest2)}, - {Name: "x_ARTIFACT_URI", Value: *v1beta1.NewStructuredValues(artifactURL2)}, - }, - }, - }, - } - - // artifact built taskrun provenance - buildTaskRunProvenance = intoto.ProvenanceStatement{ - StatementHeader: intoto.StatementHeader{ - Subject: []intoto.Subject{ - { - Name: artifactURL1, - Digest: slsa.DigestSet{ - "sha256": artifactDigest1, - }, - }, - { - Name: artifactURL2, - Digest: slsa.DigestSet{ - "sha256": artifactDigest2, - }, - }, - }, - }, - } - - // ci pipelinerun - ciPipeline = &v1beta1.PipelineRun{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - Name: "ci-pipeline", - UID: types.UID("uid-pipeline"), - }, - Status: v1beta1.PipelineRunStatus{ - PipelineRunStatusFields: v1beta1.PipelineRunStatusFields{ - PipelineResults: []v1beta1.PipelineRunResult{ - // the results from task 1 - clone - {Name: "CHAINS-GIT_COMMIT", Value: *v1beta1.NewStructuredValues(commitSHA)}, - {Name: "CHAINS-GIT_URL", Value: *v1beta1.NewStructuredValues(repoURL)}, - // the results from task 2 - build - {Name: "IMAGE_DIGEST", Value: *v1beta1.NewStructuredValues("sha256:" + artifactDigest1)}, - {Name: "IMAGE_URL", Value: *v1beta1.NewStructuredValues(artifactURL1)}, - {Name: "x_ARTIFACT_DIGEST", Value: *v1beta1.NewStructuredValues("sha256:" + artifactDigest2)}, - {Name: "x_ARTIFACT_URI", Value: *v1beta1.NewStructuredValues(artifactURL2)}, - }, - }, - }, - } - - // ci pipelinerun provenance - ciPipelineRunProvenance = intoto.ProvenanceStatement{ - StatementHeader: buildTaskRunProvenance.StatementHeader, - Predicate: slsa.ProvenancePredicate{ - Materials: cloneTaskRunProvenance.Predicate.Materials, - }, - } -) - type args struct { - runObject objects.TektonObject + tr *v1beta1.TaskRun payload []byte signature string opts config.StorageOpts } type testConfig struct { - name string - args args - wantOccurrences []*pb.Occurrence - wantErr bool + name string + args args + wantErr bool } // This function is to test the implementation of the fake server's ListOccurrences function. // As the filter logic is implemented, we want to make sure it can be trusted before testing store & retrieve. func TestBackend_ListOccurrences(t *testing.T) { - var tests = []struct { - name string - filter string - wantOccurrences []*pb.Occurrence - }{ - { - name: "empty filter", - wantOccurrences: []*pb.Occurrence{getPipelineRunBuildOcc(t, artifactIdentifier1), getPipelineRunBuildOcc(t, artifactIdentifier2)}, - }, - { - name: "multiple filters", - filter: fmt.Sprintf(`resourceUrl="%s" OR resourceUrl="%s"`, artifactIdentifier1, artifactIdentifier2), - wantOccurrences: []*pb.Occurrence{getPipelineRunBuildOcc(t, artifactIdentifier1), getPipelineRunBuildOcc(t, artifactIdentifier2)}, - }, - { - name: "a single filter", - filter: fmt.Sprintf(`resourceUrl="%s"`, artifactIdentifier1), - wantOccurrences: []*pb.Occurrence{getPipelineRunBuildOcc(t, artifactIdentifier1)}, - }, - } - - // setup + // get grafeas client ctx, _ := rtesting.SetupFakeContext(t) conn, client, err := setupConnection() @@ -215,115 +64,136 @@ func TestBackend_ListOccurrences(t *testing.T) { } defer conn.Close() - // store two sample occurrences into the fake server - occs := []*pb.Occurrence{getPipelineRunBuildOcc(t, artifactIdentifier1), getPipelineRunBuildOcc(t, artifactIdentifier2)} + // two sample occurrences used for testing + occs := getExpectedOccurrences() + // store occurrences into the fake server for _, occ := range occs { - // create note - _, err := client.CreateNote(ctx, &pb.CreateNoteRequest{ - Parent: "projects/" + ProjectID, - NoteId: fmt.Sprintf("%s-pipelinerun-intoto", NoteID), - Note: &pb.Note{ - Name: occ.NoteName, - }, - }) - if err != nil && status.Code(err) != codes.AlreadyExists { - t.Fatal("Failed to create notes in the server, err:", err) - } - - // create occurrence - _, err = client.CreateOccurrence(ctx, &pb.CreateOccurrenceRequest{Occurrence: occ}) + _, err := client.CreateOccurrence(ctx, &pb.CreateOccurrenceRequest{Occurrence: occ}) if err != nil { - t.Fatal("Failed to create occurrence in the server, err:", err) + t.Fatal("Failed to create occurrence in the server") } } - for _, tc := range tests { - got, err := client.ListOccurrences(ctx, &pb.ListOccurrencesRequest{Filter: tc.filter}) - if err != nil { - t.Fatalf("Failed to call ListOccurrences: %v", err) - } + // construct expected ListOccurrencesResponse + wantedResponse := &pb.ListOccurrencesResponse{Occurrences: occs} - want := &pb.ListOccurrencesResponse{Occurrences: tc.wantOccurrences} - if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { - t.Errorf("Wrong list of occurrences received, diff=%s", diff) - } + // 1. test empty filter string - return all occurrences + got, err := client.ListOccurrences(ctx, &pb.ListOccurrencesRequest{}) + if err != nil { + t.Fatalf("Failed to call ListOccurrences: %v", err) + } + if diff := cmp.Diff(got, wantedResponse, protocmp.Transform()); diff != "" { + t.Errorf("Wrong list of occurrences received for empty filter, diff=%s", diff) + } + + // 2. test multiple chained filter - return multiple occurrences + got, err = client.ListOccurrences(ctx, &pb.ListOccurrencesRequest{ + Filter: `resourceUrl="gcr.io/test/kaniko-chains1@sha256:cfe4f0bf41c80609214f9b8ec0408b1afb28b3ced343b944aaa05d47caba3e00" OR resourceUrl="gcr.io/test/kaniko-chains1@sha256:a2e500bebfe16cf12fc56316ba72c645e1d29054541dc1ab6c286197434170a9"`, + }) + if err != nil { + t.Fatalf("Failed to call ListOccurrences: %v", err) + } + + wantedResponse = &pb.ListOccurrencesResponse{Occurrences: occs[:2]} + if diff := cmp.Diff(got, wantedResponse, protocmp.Transform()); diff != "" { + t.Errorf("Wrong list of occurrences received for multiple filters, diff=%s", diff) + } + + // 3. test a single filter - return one occurrence + got, err = client.ListOccurrences(ctx, &pb.ListOccurrencesRequest{ + Filter: `resourceUrl="gcr.io/test/kaniko-chains1@sha256:cfe4f0bf41c80609214f9b8ec0408b1afb28b3ced343b944aaa05d47caba3e00"`, + }) + if err != nil { + t.Fatalf("Failed to call ListOccurrences: %v", err) + } + + wantedResponse = &pb.ListOccurrencesResponse{Occurrences: occs[1:2]} + if diff := cmp.Diff(got, wantedResponse, protocmp.Transform()); diff != "" { + t.Errorf("Wrong list of occurrences received for a single filter, diff=%s", diff) } } -// This function is to test -// - if the StorePayload function can create correct occurrences and store them into grafeas server -// - if the RetrievePayloads and RetrieveSignatures functions work properly to fetch correct payloads and signatures +/* + This function is to test + +- if the StorePayload function can create correct occurrences and store them into grafeas server +- if the RetrievePayloads and RetrieveSignatures functions work properly to fetch correct payloads and signatures +*/ func TestGrafeasBackend_StoreAndRetrieve(t *testing.T) { tests := []testConfig{ { - name: "intoto for clone taskrun, no error, no occurrences created because no artifacts were built.", + name: "intoto for taskrun, no error", args: args{ - runObject: &objects.TaskRunObject{ - TaskRun: cloneTaskRun, - }, - payload: getRawPayload(t, cloneTaskRunProvenance), - signature: "clone taskrun signatures", - opts: config.StorageOpts{PayloadFormat: formats.PayloadTypeInTotoIte6}, - }, - wantOccurrences: nil, - wantErr: false, - }, - { - name: "intoto for build taskrun, no error, 2 BUILD occurrences should be created for the 2 artifacts generated.", - args: args{ - runObject: &objects.TaskRunObject{ - TaskRun: buildTaskRun, - }, - payload: getRawPayload(t, buildTaskRunProvenance), - signature: "build taskrun signature", - opts: config.StorageOpts{PayloadFormat: formats.PayloadTypeInTotoIte6}, - }, - wantOccurrences: []*pb.Occurrence{getTaskRunBuildOcc(t, artifactIdentifier1), getTaskRunBuildOcc(t, artifactIdentifier2)}, - wantErr: false, - }, - { - name: "simplesigning for the build taskrun, no error, 1 ATTESTATION occurrence should be created for the artifact specified in storageopts.key", - args: args{ - runObject: &objects.TaskRunObject{ - TaskRun: buildTaskRun, + tr: &v1beta1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "foo1", + Name: "bar1", + UID: types.UID("uid1"), + }, + Status: v1beta1.TaskRunStatus{ + TaskRunStatusFields: v1beta1.TaskRunStatusFields{ + TaskRunResults: []v1beta1.TaskRunResult{ + // the image digest for test purpose also needs to follow image digest protocol to pass the check. + // i.e. only contain chars in "sh:0123456789abcdef", and the lenth is 7+64. See more details here: + // https://github.com/google/go-containerregistry/blob/d9bfbcb99e526b2a9417160e209b816e1b1fb6bd/pkg/name/digest.go#L63 + {Name: "IMAGE_DIGEST", Value: *v1beta1.NewArrayOrString("sha256:a2e500bebfe16cf12fc56316ba72c645e1d29054541dc1ab6c286197434170a9")}, + {Name: "IMAGE_URL", Value: *v1beta1.NewArrayOrString("gcr.io/test/kaniko-chains1")}, + {Name: "x_ARTIFACT_DIGEST", Value: *v1beta1.NewArrayOrString("sha256:b2e500bebfe16cf12fc56316ba72c645e1d29054541dc1ab6c286197434170a9")}, + {Name: "x_ARTIFACT_URI", Value: *v1beta1.NewArrayOrString("us-central1-maven.pkg.dev/test/java")}, + }, + }, + }, }, - payload: []byte("attestation payload"), - signature: "build taskrun image signature", - opts: config.StorageOpts{FullKey: artifactIdentifier1, PayloadFormat: formats.PayloadTypeSimpleSigning}, + payload: []byte("{}"), + signature: "taskrun signature", + opts: config.StorageOpts{FullKey: "tekton.dev-v1beta1-taskrun-uuid", PayloadFormat: formats.PayloadTypeInTotoIte6}, }, - wantOccurrences: []*pb.Occurrence{getTaskRunAttestationOcc(t, artifactIdentifier1)}, - wantErr: false, + wantErr: false, }, { - name: "intoto for the ci pipeline, no error, 2 occurences should be created for the pipelinerun for the 2 artifact generated.", + name: "simplesigning for oci, no error", args: args{ - runObject: &objects.PipelineRunObject{ - PipelineRun: ciPipeline, + tr: &v1beta1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "foo2", + Name: "bar2", + UID: types.UID("uid2"), + }, + Status: v1beta1.TaskRunStatus{ + TaskRunStatusFields: v1beta1.TaskRunStatusFields{ + TaskRunResults: []v1beta1.TaskRunResult{ + // the image digest for test purpose also needs to follow image digest protocol to pass the check. + // i.e. only contain chars in "sh:0123456789abcdef", and the lenth is 7+64. See more details here: + // https://github.com/google/go-containerregistry/blob/d9bfbcb99e526b2a9417160e209b816e1b1fb6bd/pkg/name/digest.go#L63 + {Name: "IMAGE_DIGEST", Value: *v1beta1.NewArrayOrString("sha256:cfe4f0bf41c80609214f9b8ec0408b1afb28b3ced343b944aaa05d47caba3e00")}, + {Name: "IMAGE_URL", Value: *v1beta1.NewArrayOrString("gcr.io/test/kaniko-chains1")}, + }, + }, + }, }, - payload: getRawPayload(t, ciPipelineRunProvenance), - signature: "ci pipelinerun signature", - opts: config.StorageOpts{PayloadFormat: formats.PayloadTypeInTotoIte6}, + payload: []byte("oci payload"), + signature: "oci signature", + opts: config.StorageOpts{FullKey: "gcr.io/test/kaniko-chains1@sha256:cfe4f0bf41c80609214f9b8ec0408b1afb28b3ced343b944aaa05d47caba3e00", PayloadFormat: formats.PayloadTypeSimpleSigning}, }, - wantOccurrences: []*pb.Occurrence{getPipelineRunBuildOcc(t, artifactIdentifier1), getPipelineRunBuildOcc(t, artifactIdentifier2)}, - wantErr: false, + wantErr: false, }, { - name: "tekton format for a taskrun, error, only simplesigning and intoto are supported", + name: "tekton format for taskrun, error", args: args{ - runObject: &objects.TaskRunObject{ - TaskRun: buildTaskRun, + tr: &v1beta1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "foo3", + Name: "bar3", + UID: types.UID("uid3"), + }, }, - payload: []byte("foo"), - signature: "bar", - opts: config.StorageOpts{PayloadFormat: formats.PayloadTypeTekton}, + opts: config.StorageOpts{FullKey: "tekton.dev-v1beta1-taskrun2-uuid", PayloadFormat: formats.PayloadTypeTekton}, }, - wantOccurrences: nil, - wantErr: true, + wantErr: true, }, } - // setup connection ctx, _ := rtesting.SetupFakeContext(t) conn, client, err := setupConnection() if err != nil { @@ -332,12 +202,7 @@ func TestGrafeasBackend_StoreAndRetrieve(t *testing.T) { defer conn.Close() - // collect all the occurences expected to be created in the server - allOccurrencesInServer := []*pb.Occurrence{} - for _, test := range tests { - - // run the test t.Run(test.name, func(t *testing.T) { backend := Backend{ logger: logtesting.TestLogger(t), @@ -345,52 +210,38 @@ func TestGrafeasBackend_StoreAndRetrieve(t *testing.T) { cfg: config.Config{ Storage: config.StorageConfigs{ Grafeas: config.GrafeasConfig{ - ProjectID: ProjectID, - NoteID: NoteID, + ProjectID: "test-project", + NoteID: "test-note", }, }, }, } // test if the attestation of the taskrun/oci artifact can be successfully stored into grafeas server // and test if payloads and signatures inside the attestation can be retrieved. - testStoreAndRetrieveHelper(ctx, t, test, backend) - - // accumulate the expected occurrences from each call. - allOccurrencesInServer = append(allOccurrencesInServer, test.wantOccurrences...) + testStoreAndRetrieve(ctx, t, test, backend) }) } - // test if all occurrences are created correctly from multiple requests + // test if occurrences are created correctly from the StorePayload function // - ProjectID field in ListOccurrencesRequest doesn't matter here because we assume there is only one project in the mocked server. // - ListOccurrencesRequest with empty filter should be able to fetch all occurrences. got, err := client.ListOccurrences(ctx, &pb.ListOccurrencesRequest{}) if err != nil { t.Fatal("Failed to call ListOccurrences. error ", err) } - - sort.Slice(allOccurrencesInServer, func(i, j int) bool { - return allOccurrencesInServer[i].ResourceUri+allOccurrencesInServer[i].NoteName < allOccurrencesInServer[j].ResourceUri+allOccurrencesInServer[j].NoteName - }) - want := &pb.ListOccurrencesResponse{ - Occurrences: allOccurrencesInServer, - } - - if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { + wantedResponse := &pb.ListOccurrencesResponse{Occurrences: getExpectedOccurrences()} + if diff := cmp.Diff(got, wantedResponse, protocmp.Transform()); diff != "" { t.Errorf("Wrong list of occurrences received for empty filter, diff=%s", diff) } } // test attestation storage and retrieval -func testStoreAndRetrieveHelper(ctx context.Context, t *testing.T, test testConfig, backend Backend) { - if err := backend.StorePayload(ctx, test.args.runObject, test.args.payload, test.args.signature, test.args.opts); (err != nil) != test.wantErr { +func testStoreAndRetrieve(ctx context.Context, t *testing.T, test testConfig, backend Backend) { + trObj := objects.NewTaskRunObject(test.args.tr) + if err := backend.StorePayload(ctx, trObj, test.args.payload, test.args.signature, test.args.opts); (err != nil) != test.wantErr { t.Fatalf("Backend.StorePayload() failed. error:%v, wantErr:%v", err, test.wantErr) } - // if occurrence is not expected to be created, then stop and no point to retrieve sig & payload - if len(test.wantOccurrences) == 0 { - return - } - // check signature // ---------------- expectSignature := map[string][]string{} @@ -398,13 +249,13 @@ func testStoreAndRetrieveHelper(ctx context.Context, t *testing.T, test testConf expectSignature[test.args.opts.FullKey] = []string{test.args.signature} } if test.args.opts.PayloadFormat == formats.PayloadTypeInTotoIte6 { - allURIs := extract.RetrieveAllArtifactURIs(test.args.runObject, backend.logger) + allURIs := backend.retrieveAllArtifactIdentifiers(test.args.tr) for _, u := range allURIs { expectSignature[u] = []string{test.args.signature} } } - gotSignature, err := backend.RetrieveSignatures(ctx, test.args.runObject, test.args.opts) + gotSignature, err := backend.RetrieveSignatures(ctx, trObj, test.args.opts) if err != nil { t.Fatal("Backend.RetrieveSignatures() failed: ", err) } @@ -420,13 +271,13 @@ func testStoreAndRetrieveHelper(ctx context.Context, t *testing.T, test testConf expectPayload[test.args.opts.FullKey] = string(test.args.payload) } if test.args.opts.PayloadFormat == formats.PayloadTypeInTotoIte6 { - allURIs := extract.RetrieveAllArtifactURIs(test.args.runObject, backend.logger) + allURIs := backend.retrieveAllArtifactIdentifiers(test.args.tr) for _, u := range allURIs { expectPayload[u] = string(test.args.payload) } } - gotPayload, err := backend.RetrievePayloads(ctx, test.args.runObject, test.args.opts) + gotPayload, err := backend.RetrievePayloads(ctx, trObj, test.args.opts) if err != nil { t.Fatal("RetrievePayloads.RetrievePayloads() failed: ", err) } @@ -436,122 +287,87 @@ func testStoreAndRetrieveHelper(ctx context.Context, t *testing.T, test testConf } } -// ------------------ 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 { - return &pb.Occurrence{ - Name: identifier, - ResourceUri: identifier, - NoteName: fmt.Sprintf("projects/%s/notes/%s-taskrun-intoto", ProjectID, NoteID), - Details: &pb.Occurrence_Build{ - Build: &pb.BuildOccurrence{ - IntotoStatement: &pb.InTotoStatement{ - Subject: []*pb.Subject{ - { - Name: artifactURL1, - Digest: map[string]string{"sha256": artifactDigest1}, - }, - { - Name: artifactURL2, - Digest: map[string]string{"sha256": artifactDigest2}, - }, - }, - Predicate: &pb.InTotoStatement_SlsaProvenanceZeroTwo{ - SlsaProvenanceZeroTwo: &pb.SlsaProvenanceZeroTwo{ - Builder: &pb.SlsaProvenanceZeroTwo_SlsaBuilder{}, - Invocation: &pb.SlsaProvenanceZeroTwo_SlsaInvocation{ - ConfigSource: &pb.SlsaProvenanceZeroTwo_SlsaConfigSource{}, +// Two occurrences that will be used for testing ListOccurrences +func getExpectedOccurrences() []*pb.Occurrence { + return []*pb.Occurrence{ + // build occurrence for taskrun that is associated with image artifact + { + // Occurrence ID will be randomly generated by grafeas server. + // In this fake grafeas server, we mock this behaviour by just using resource URI as the auto-generated occurrence name. + Name: "gcr.io/test/kaniko-chains1@sha256:a2e500bebfe16cf12fc56316ba72c645e1d29054541dc1ab6c286197434170a9", + ResourceUri: "gcr.io/test/kaniko-chains1@sha256:a2e500bebfe16cf12fc56316ba72c645e1d29054541dc1ab6c286197434170a9", + NoteName: "projects/test-project/notes/test-note-intoto", + Details: &pb.Occurrence_Build{ + Build: &pb.BuildOccurrence{ + IntotoStatement: &pb.InTotoStatement{ + Predicate: &pb.InTotoStatement_SlsaProvenanceZeroTwo{ + SlsaProvenanceZeroTwo: &pb.SlsaProvenanceZeroTwo{ + Builder: &pb.SlsaProvenanceZeroTwo_SlsaBuilder{}, + Invocation: &pb.SlsaProvenanceZeroTwo_SlsaInvocation{ + ConfigSource: &pb.SlsaProvenanceZeroTwo_SlsaConfigSource{}, + }, }, - }, - }}, + }}, + }, }, - }, - Envelope: &pb.Envelope{ - Payload: getRawPayload(t, buildTaskRunProvenance), - PayloadType: "application/vnd.in-toto+json", - Signatures: []*pb.EnvelopeSignature{ - {Sig: []byte("build taskrun signature")}, + Envelope: &pb.Envelope{ + Payload: []byte("{}"), + PayloadType: "application/vnd.in-toto+json", + Signatures: []*pb.EnvelopeSignature{ + {Sig: []byte("taskrun signature")}, + }, }, }, - } -} - -// ATTESTATION Occurrence for the build taskrun that stores the image attestation -func getTaskRunAttestationOcc(t *testing.T, identifier string) *pb.Occurrence { - return &pb.Occurrence{ - Name: identifier, - ResourceUri: identifier, - NoteName: fmt.Sprintf("projects/%s/notes/%s-simplesigning", ProjectID, NoteID), - Details: &pb.Occurrence_Attestation{ - Attestation: &pb.AttestationOccurrence{ - SerializedPayload: []byte("attestation payload"), - Signatures: []*pb.Signature{ - {Signature: []byte("build taskrun image signature")}, + // attestation occurrence for OCI image + { + Name: "gcr.io/test/kaniko-chains1@sha256:cfe4f0bf41c80609214f9b8ec0408b1afb28b3ced343b944aaa05d47caba3e00", + ResourceUri: "gcr.io/test/kaniko-chains1@sha256:cfe4f0bf41c80609214f9b8ec0408b1afb28b3ced343b944aaa05d47caba3e00", + NoteName: "projects/test-project/notes/test-note-simplesigning", + Details: &pb.Occurrence_Attestation{ + Attestation: &pb.AttestationOccurrence{ + SerializedPayload: []byte("oci payload"), + Signatures: []*pb.Signature{ + {Signature: []byte("oci signature")}, + }, }, }, - }, - Envelope: &pb.Envelope{ - Payload: []byte("attestation payload"), - PayloadType: "application/vnd.dev.cosign.simplesigning.v1+json", - Signatures: []*pb.EnvelopeSignature{ - {Sig: []byte("build taskrun image signature")}, + Envelope: &pb.Envelope{ + Payload: []byte("oci payload"), + PayloadType: "application/vnd.dev.cosign.simplesigning.v1+json", + Signatures: []*pb.EnvelopeSignature{ + {Sig: []byte("oci signature")}, + }, }, }, - } -} - -func getPipelineRunBuildOcc(t *testing.T, identifier string) *pb.Occurrence { - return &pb.Occurrence{ - Name: identifier, - ResourceUri: identifier, - NoteName: fmt.Sprintf("projects/%s/notes/%s-pipelinerun-intoto", ProjectID, NoteID), - Details: &pb.Occurrence_Build{ - Build: &pb.BuildOccurrence{ - IntotoStatement: &pb.InTotoStatement{ - Subject: []*pb.Subject{ - { - Name: artifactURL1, - Digest: map[string]string{"sha256": artifactDigest1}, - }, - { - Name: artifactURL2, - Digest: map[string]string{"sha256": artifactDigest2}, - }, - }, - Predicate: &pb.InTotoStatement_SlsaProvenanceZeroTwo{ - SlsaProvenanceZeroTwo: &pb.SlsaProvenanceZeroTwo{ - Builder: &pb.SlsaProvenanceZeroTwo_SlsaBuilder{}, - Invocation: &pb.SlsaProvenanceZeroTwo_SlsaInvocation{ - ConfigSource: &pb.SlsaProvenanceZeroTwo_SlsaConfigSource{}, - }, - Materials: []*pb.SlsaProvenanceZeroTwo_SlsaMaterial{ - { - Uri: repoURL, - Digest: map[string]string{"sha1": commitSHA}, + // build occurrence for taskrun that is associated with maven artifact + { + Name: "us-central1-maven.pkg.dev/test/java@sha256:b2e500bebfe16cf12fc56316ba72c645e1d29054541dc1ab6c286197434170a9", + ResourceUri: "us-central1-maven.pkg.dev/test/java@sha256:b2e500bebfe16cf12fc56316ba72c645e1d29054541dc1ab6c286197434170a9", + NoteName: "projects/test-project/notes/test-note-intoto", + Details: &pb.Occurrence_Build{ + Build: &pb.BuildOccurrence{ + IntotoStatement: &pb.InTotoStatement{ + Predicate: &pb.InTotoStatement_SlsaProvenanceZeroTwo{ + SlsaProvenanceZeroTwo: &pb.SlsaProvenanceZeroTwo{ + Builder: &pb.SlsaProvenanceZeroTwo_SlsaBuilder{}, + Invocation: &pb.SlsaProvenanceZeroTwo_SlsaInvocation{ + ConfigSource: &pb.SlsaProvenanceZeroTwo_SlsaConfigSource{}, }, }, - }, - }}, + }}, + }, }, - }, - Envelope: &pb.Envelope{ - Payload: getRawPayload(t, ciPipelineRunProvenance), - PayloadType: "application/vnd.in-toto+json", - Signatures: []*pb.EnvelopeSignature{ - {Sig: []byte("ci pipelinerun signature")}, + Envelope: &pb.Envelope{ + Payload: []byte("{}"), + PayloadType: "application/vnd.in-toto+json", + Signatures: []*pb.EnvelopeSignature{ + {Sig: []byte("taskrun signature")}, + }, }, }, } } -func getRawPayload(t *testing.T, in interface{}) []byte { - rawPayload, err := json.Marshal(in) - if err != nil { - t.Errorf("Unable to marshal the provenance: %v", in) - } - return rawPayload -} - // set up the connection between grafeas server and client // and return the client object to the caller func setupConnection() (*grpc.ClientConn, pb.GrafeasClient, error) { @@ -585,128 +401,71 @@ type mockGrafeasServer struct { // Tests will keep working if more methods are added in the future. pb.UnimplementedGrafeasServer - // entries mocks the storage of notes and occurrences. - // Assume there is only one grafeas project - entries map[string]*noteOccurrences -} - -// noteOccurrences mocks that the behaviour of one note linking multiple occurrences -type noteOccurrences struct { - // mocks a grafeas note instance - note *pb.Note - // mocks occurrences under a note - // - key is artifact uri (ResourceUri) that represents the occurrence. - // - value is the actual occurrence instance - occurrences map[string]*pb.Occurrence + // Assume there is only one project for storing notes and occurences + occurences map[string]*pb.Occurrence + notes map[string]*pb.Note } func (s *mockGrafeasServer) CreateOccurrence(ctx context.Context, req *pb.CreateOccurrenceRequest) (*pb.Occurrence, error) { - if s.entries == nil { - s.entries = make(map[string]*noteOccurrences) + if s.occurences == nil { + s.occurences = make(map[string]*pb.Occurrence) } - occ := req.GetOccurrence() - noteName := req.GetOccurrence().NoteName - resourceUri := req.GetOccurrence().ResourceUri - occ.Name = resourceUri // mock how the occurrence ID (name) is outputed. - - if note, ok := s.entries[noteName]; ok { - if _, ok := note.occurrences[resourceUri]; ok { - return nil, gstatus.Error(codes.AlreadyExists, "Occurrence ID already exists") - } - if note.occurrences == nil { - note.occurrences = make(map[string]*pb.Occurrence) - } - note.occurrences[resourceUri] = occ - return occ, nil - } + occID := req.GetOccurrence().GetResourceUri() + expectedResponse := req.GetOccurrence() + expectedResponse.Name = occID // mock auto-generated id - return nil, gstatus.Error(codes.FailedPrecondition, "The note for that occurrences does not exist.") + s.occurences[occID] = expectedResponse + return expectedResponse, nil } func (s *mockGrafeasServer) CreateNote(ctx context.Context, req *pb.CreateNoteRequest) (*pb.Note, error) { - notePath := fmt.Sprintf("%s/notes/%s", req.GetParent(), req.GetNoteId()) - noteRequested := req.GetNote() - - if s.entries == nil { - s.entries = make(map[string]*noteOccurrences) + noteID := fmt.Sprintf("%s/notes/%s", req.GetParent(), req.GetNoteId()) + expectedResponse := req.GetNote() + if s.notes == nil { + s.notes = make(map[string]*pb.Note) } - if _, ok := s.entries[notePath]; ok { + if _, exists := s.notes[noteID]; exists { return nil, gstatus.Error(codes.AlreadyExists, "note ID already exists") } - - s.entries[notePath] = ¬eOccurrences{ - note: noteRequested, - } - return noteRequested, nil -} - -func (s *mockGrafeasServer) ListNotes(ctx context.Context, req *pb.ListNotesRequest) (*pb.ListNotesResponse, error) { - notes := []*pb.Note{} - for _, n := range s.entries { - notes = append(notes, n.note) - } - return &pb.ListNotesResponse{Notes: notes}, nil + s.notes[noteID] = expectedResponse + return expectedResponse, nil } func (s *mockGrafeasServer) ListOccurrences(ctx context.Context, req *pb.ListOccurrencesRequest) (*pb.ListOccurrencesResponse, error) { // to make sure the occurrences we get are in order. - allOccurrencesInServer := []*pb.Occurrence{} - for _, note := range s.entries { - for _, occ := range note.occurrences { - allOccurrencesInServer = append(allOccurrencesInServer, occ) - } + sortedOccurrencesInServer := []*pb.Occurrence{} + keys := []string{} + for k := range s.occurences { + keys = append(keys, k) } - - filteredOccs := s.getOccurrencesByFilter(req.GetFilter(), allOccurrencesInServer) - sort.Slice(filteredOccs, func(i, j int) bool { - return filteredOccs[i].ResourceUri+filteredOccs[i].NoteName < filteredOccs[j].ResourceUri+filteredOccs[j].NoteName - }) - - return &pb.ListOccurrencesResponse{Occurrences: filteredOccs}, nil -} - -func (s *mockGrafeasServer) ListNoteOccurrences(ctx context.Context, req *pb.ListNoteOccurrencesRequest) (*pb.ListNoteOccurrencesResponse, error) { - noteName := req.Name - if _, ok := s.entries[noteName]; !ok { - return nil, nil + sort.Strings(keys) + for _, k := range keys { + sortedOccurrencesInServer = append(sortedOccurrencesInServer, s.occurences[k]) } - allOccurrences := []*pb.Occurrence{} - for _, o := range s.entries[noteName].occurrences { - allOccurrences = append(allOccurrences, o) - } - - filteredOccs := s.getOccurrencesByFilter(req.GetFilter(), allOccurrences) - sort.Slice(filteredOccs, func(i, j int) bool { - return filteredOccs[i].ResourceUri+filteredOccs[i].NoteName < filteredOccs[j].ResourceUri+filteredOccs[j].NoteName - }) - return &pb.ListNoteOccurrencesResponse{Occurrences: filteredOccs}, nil -} - -func (s *mockGrafeasServer) getOccurrencesByFilter(filter string, occurrences []*pb.Occurrence) []*pb.Occurrence { // if filter string is empty, the expected behaviour will be to return all. - if len(filter) == 0 { - return occurrences + if len(req.GetFilter()) == 0 { + return &pb.ListOccurrencesResponse{Occurrences: sortedOccurrencesInServer}, nil } // if the filter string is not empty, do the filtering. // mock how uri filter works - uris := parseURIFilterString(filter) + uris := parseURIFilterString(req.GetFilter()) - // result result - result := []*pb.Occurrence{} + // result occurrences + occurrences := []*pb.Occurrence{} - for _, occ := range occurrences { + for _, occ := range sortedOccurrencesInServer { for _, uri := range uris { if uri == occ.GetResourceUri() { - result = append(result, occ) + occurrences = append(occurrences, occ) } } } - return result + return &pb.ListOccurrencesResponse{Occurrences: occurrences}, nil } // parse a chained uri filter string to a list of uris diff --git a/pkg/chains/storage/oci/oci.go b/pkg/chains/storage/oci/oci.go index e11517f31a..723bde8a3a 100644 --- a/pkg/chains/storage/oci/oci.go +++ b/pkg/chains/storage/oci/oci.go @@ -80,7 +80,7 @@ func (b *Backend) StorePayload(ctx context.Context, obj objects.TektonObject, ra return err } - b.logger.Infof("Storing payload on %s/%s/%s", obj.GetGVK(), obj.GetNamespace(), obj.GetName()) + b.logger.Infof("Storing payload on %s/%s/%s", obj.GetKind(), obj.GetNamespace(), obj.GetName()) if storageOpts.PayloadFormat == formats.PayloadTypeSimpleSigning { format := simple.SimpleContainerImage{} @@ -101,7 +101,7 @@ func (b *Backend) StorePayload(ctx context.Context, obj objects.TektonObject, ra // that is not intended to produce an image, e.g. git-clone. if len(attestation.Subject) == 0 { b.logger.Infof( - "No image subject to attest for %s/%s/%s. Skipping upload to registry", obj.GetGVK(), obj.GetNamespace(), obj.GetName()) + "No image subject to attest for %s/%s/%s. Skipping upload to registry", obj.GetKind(), obj.GetNamespace(), obj.GetName()) return nil } diff --git a/pkg/chains/storage/tekton/tekton.go b/pkg/chains/storage/tekton/tekton.go index 938ffb195b..aa1d254572 100644 --- a/pkg/chains/storage/tekton/tekton.go +++ b/pkg/chains/storage/tekton/tekton.go @@ -51,7 +51,7 @@ func NewStorageBackend(ps versioned.Interface, logger *zap.SugaredLogger) *Backe // StorePayload implements the Payloader interface. func (b *Backend) StorePayload(ctx context.Context, obj objects.TektonObject, rawPayload []byte, signature string, opts config.StorageOpts) error { - b.logger.Infof("Storing payload on %s/%s/%s", obj.GetGVK(), obj.GetNamespace(), obj.GetName()) + b.logger.Infof("Storing payload on %s/%s/%s", obj.GetKind(), obj.GetNamespace(), obj.GetName()) // Use patch instead of update to prevent race conditions. patchBytes, err := patch.GetAnnotationsPatch(map[string]string{ @@ -78,7 +78,7 @@ func (b *Backend) Type() string { // retrieveAnnotationValue retrieve the value of an annotation and base64 decode it if needed. func (b *Backend) retrieveAnnotationValue(ctx context.Context, obj objects.TektonObject, annotationKey string, decode bool) (string, error) { - b.logger.Infof("Retrieving annotation %q on %s/%s/%s", annotationKey, obj.GetGVK(), obj.GetNamespace(), obj.GetName()) + b.logger.Infof("Retrieving annotation %q on %s/%s/%s", annotationKey, obj.GetKind(), obj.GetNamespace(), obj.GetName()) var annotationValue string annotations, err := obj.GetLatestAnnotations(ctx, b.pipelineclientset) @@ -106,7 +106,7 @@ func (b *Backend) retrieveAnnotationValue(ctx context.Context, obj objects.Tekto // RetrieveSignature retrieve the signature stored in the taskrun. func (b *Backend) RetrieveSignatures(ctx context.Context, obj objects.TektonObject, opts config.StorageOpts) (map[string][]string, error) { - b.logger.Infof("Retrieving signature on %s/%s/%s", obj.GetGVK(), obj.GetNamespace(), obj.GetName()) + b.logger.Infof("Retrieving signature on %s/%s/%s", obj.GetKind(), obj.GetNamespace(), obj.GetName()) signatureAnnotation := sigName(opts) signature, err := b.retrieveAnnotationValue(ctx, obj, signatureAnnotation, true) if err != nil { @@ -119,7 +119,7 @@ func (b *Backend) RetrieveSignatures(ctx context.Context, obj objects.TektonObje // RetrievePayload retrieve the payload stored in the taskrun. func (b *Backend) RetrievePayloads(ctx context.Context, obj objects.TektonObject, opts config.StorageOpts) (map[string]string, error) { - b.logger.Infof("Retrieving payload on %s/%s/%s", obj.GetGVK(), obj.GetNamespace(), obj.GetName()) + b.logger.Infof("Retrieving payload on %s/%s/%s", obj.GetKind(), obj.GetNamespace(), obj.GetName()) payloadAnnotation := payloadName(opts) payload, err := b.retrieveAnnotationValue(ctx, obj, payloadAnnotation, true) if err != nil { diff --git a/pkg/config/config.go b/pkg/config/config.go index b6351f4ae4..5246519ff9 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -256,7 +256,7 @@ func NewConfigFromMap(data map[string]string) (*Config, error) { // PipelineRuns asString(pipelinerunFormatKey, &cfg.Artifacts.PipelineRuns.Format, "tekton", "in-toto"), - asStringSet(pipelinerunStorageKey, &cfg.Artifacts.PipelineRuns.StorageBackend, sets.NewString("tekton", "oci", "grafeas")), + asStringSet(pipelinerunStorageKey, &cfg.Artifacts.PipelineRuns.StorageBackend, sets.NewString("tekton", "oci")), asString(pipelinerunSignerKey, &cfg.Artifacts.PipelineRuns.Signer, "x509", "kms"), // OCI diff --git a/test/test_utils.go b/test/test_utils.go index 3fe54b8d16..1a1b68346e 100644 --- a/test/test_utils.go +++ b/test/test_utils.go @@ -213,12 +213,12 @@ func setConfigMap(ctx context.Context, t *testing.T, c *clients, data map[string } func printDebugging(t *testing.T, obj objects.TektonObject) { - t.Logf("============================== %s logs ==============================", obj.GetGVK()) - output, _ := exec.Command("tkn", obj.GetGVK(), "logs", "-n", obj.GetNamespace(), obj.GetName()).CombinedOutput() + t.Logf("============================== %s logs ==============================", obj.GetKind()) + output, _ := exec.Command("tkn", obj.GetKind(), "logs", "-n", obj.GetNamespace(), obj.GetName()).CombinedOutput() t.Log(string(output)) - t.Logf("============================== %s describe ==============================", obj.GetGVK()) - output, _ = exec.Command("tkn", obj.GetGVK(), "describe", "-n", obj.GetNamespace(), obj.GetName()).CombinedOutput() + t.Logf("============================== %s describe ==============================", obj.GetKind()) + output, _ = exec.Command("tkn", obj.GetKind(), "describe", "-n", obj.GetNamespace(), obj.GetName()).CombinedOutput() t.Log(string(output)) t.Log("============================== chains controller logs ==============================")