From 06e45a45e43b83e36a84d75933bc64bea0c4e95a Mon Sep 17 00:00:00 2001 From: PuneetPunamiya Date: Fri, 27 Oct 2023 22:26:51 +0530 Subject: [PATCH] Fixes value for storage.oci.repository Previously while providing repo url value for storage oci repository, chains controller was giving an error as `a digest must contain exactly one '@' separator (e.g. registry/repository@digest)` because, it was not able to add digest Hence this patch fixes it, by formatting the value provided by the user and thus storing the attestations/signatures in the provided location Signed-off-by: PuneetPunamiya --- pkg/chains/storage/oci/legacy.go | 33 +++++++++------ pkg/chains/storage/oci/legacy_test.go | 61 +++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 12 deletions(-) create mode 100644 pkg/chains/storage/oci/legacy_test.go diff --git a/pkg/chains/storage/oci/legacy.go b/pkg/chains/storage/oci/legacy.go index 1994a62694..70aa04d02f 100644 --- a/pkg/chains/storage/oci/legacy.go +++ b/pkg/chains/storage/oci/legacy.go @@ -54,7 +54,8 @@ type Backend struct { // NewStorageBackend returns a new OCI StorageBackend that stores signatures in an OCI registry func NewStorageBackend(ctx context.Context, client kubernetes.Interface, cfg config.Config) *Backend { return &Backend{ - cfg: cfg, + cfg: cfg, + client: client, getAuthenticator: func(ctx context.Context, obj objects.TektonObject, client kubernetes.Interface) (remote.Option, error) { kc, err := k8schain.New(ctx, client, @@ -119,12 +120,17 @@ func (b *Backend) uploadSignature(ctx context.Context, format simple.SimpleConta imageName := format.ImageName() logger.Infof("Uploading %s signature", imageName) - ref, err := newDigest(b.cfg, imageName) + ref, err := name.NewDigest(imageName) if err != nil { return errors.Wrap(err, "getting digest") } - store, err := NewSimpleStorerFromConfig(WithTargetRepository(ref.Repository)) + repo, err := newRepo(b.cfg, ref) + if err != nil { + return errors.Wrapf(err, "getting storage repo for sub %s", imageName) + } + + store, err := NewSimpleStorerFromConfig(WithTargetRepository(repo)) if err != nil { return err } @@ -154,12 +160,17 @@ func (b *Backend) uploadAttestation(ctx context.Context, attestation in_toto.Sta imageName := fmt.Sprintf("%s@sha256:%s", subj.Name, subj.Digest["sha256"]) logger.Infof("Starting attestation upload to OCI for %s...", imageName) - ref, err := newDigest(b.cfg, imageName) + ref, err := name.NewDigest(imageName) if err != nil { return errors.Wrapf(err, "getting digest for subj %s", imageName) } - store, err := NewAttestationStorer(WithTargetRepository(ref.Repository)) + repo, err := newRepo(b.cfg, ref) + if err != nil { + return errors.Wrapf(err, "getting storage repo for sub %s", imageName) + } + + store, err := NewAttestationStorer(WithTargetRepository(repo)) if err != nil { return err } @@ -278,16 +289,14 @@ func (b *Backend) RetrieveArtifact(ctx context.Context, obj objects.TektonObject return m, nil } -func newDigest(cfg config.Config, imageName string) (name.Digest, error) { - // Override image name from config if set. - if r := cfg.Storage.OCI.Repository; r != "" { - imageName = r - } - +func newRepo(cfg config.Config, imageName name.Digest) (name.Repository, error) { var opts []name.Option if cfg.Storage.OCI.Insecure { opts = append(opts, name.Insecure) } + if storageOCIRepository := cfg.Storage.OCI.Repository; storageOCIRepository != "" { + return name.NewRepository(storageOCIRepository, opts...) + } - return name.NewDigest(imageName, opts...) + return name.NewRepository(imageName.RepositoryStr(), opts...) } diff --git a/pkg/chains/storage/oci/legacy_test.go b/pkg/chains/storage/oci/legacy_test.go new file mode 100644 index 0000000000..6170ca778f --- /dev/null +++ b/pkg/chains/storage/oci/legacy_test.go @@ -0,0 +1,61 @@ +/* +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 oci + +import ( + "github.com/google/go-containerregistry/pkg/name" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/tektoncd/chains/pkg/config" +) + +func TestNewRepo(t *testing.T) { + t.Run("Use any registry in storage oci repository", func(t *testing.T) { + cfg := config.Config{} + cfg.Storage.OCI.Repository = "example.com/foo" + tests := []struct { + testImageName string + expectedImageName string + expectedRepo *name.Repository + }{ + { + testImageName: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init@sha256:bc4f7468f87486e3835b09098c74cd7f54db2cf697cbb9b824271b95a2d0871e", + expectedImageName: "example.com/foo", + expectedRepo: &name.Repository{}, + }, + { + testImageName: "foo.io/bar/kaniko-chains@sha256:bc4f7468f87486e3835b09098c74cd7f54db2cf697cbb9b824271b95a2d0871e", + expectedImageName: "example.com/foo", + }, + { + testImageName: "registry.com/spam/spam/spam/spam/spam/spam@sha256:bc4f7468f87486e3835b09098c74cd7f54db2cf697cbb9b824271b95a2d0871e", + expectedImageName: "example.com/foo", + }, + } + + for _, test := range tests { + ref, err := name.NewDigest(test.testImageName) + if err != nil { + t.Error(err, "getting digest for subj %s", test.testImageName) + } + + repo, err := newRepo(cfg, ref) + if err != nil { + t.Error(err) + } + assert.Equal(t, repo.Name(), test.expectedImageName) + } + }) +}