diff --git a/pkg/api/routes.go b/pkg/api/routes.go index f27aeacbc8..1d3cba0b32 100644 --- a/pkg/api/routes.go +++ b/pkg/api/routes.go @@ -26,7 +26,6 @@ import ( godigest "github.com/opencontainers/go-digest" ispec "github.com/opencontainers/image-spec/specs-go/v1" artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1" - "github.com/sigstore/cosign/v2/pkg/oci/remote" zerr "zotregistry.io/zot/errors" "zotregistry.io/zot/pkg/api/constants" @@ -1734,33 +1733,15 @@ func getImageManifest(routeHandler *RouteHandler, imgStore storageTypes.ImageSto routeHandler.c.Log.Info().Str("repository", name).Str("reference", reference). Msg("trying to get updated image by syncing on demand") - // we use a custom method for syncing cosign signatures for the moment, even though it's also an oci image. - if isCosignTag(reference) { - if errSync := routeHandler.c.SyncOnDemand.SyncReference(name, reference, syncConstants.Cosign); errSync != nil { - routeHandler.c.Log.Err(errSync).Str("repository", name).Str("reference", reference). - Msg("error encounter while syncing cosign signature for image") - } - } else { - if errSync := routeHandler.c.SyncOnDemand.SyncImage(name, reference); errSync != nil { - routeHandler.c.Log.Err(errSync).Str("repository", name).Str("reference", reference). - Msg("error encounter while syncing image") - } + if errSync := routeHandler.c.SyncOnDemand.SyncImage(name, reference); errSync != nil { + routeHandler.c.Log.Err(errSync).Str("repository", name).Str("reference", reference). + Msg("error encounter while syncing image") } } return imgStore.GetImageManifest(name, reference) } -// this function will check if tag is a cosign tag (signature or sbom). -func isCosignTag(tag string) bool { - if strings.HasPrefix(tag, "sha256-") && - (strings.HasSuffix(tag, remote.SignatureTagSuffix) || strings.HasSuffix(tag, remote.SBOMTagSuffix)) { - return true - } - - return false -} - // will sync referrers on demand if they are not found, in case sync extensions is enabled. func getOrasReferrers(routeHandler *RouteHandler, imgStore storageTypes.ImageStore, name string, digest godigest.Digest, diff --git a/pkg/common/common.go b/pkg/common/common.go index 59de175bb2..897ca12b58 100644 --- a/pkg/common/common.go +++ b/pkg/common/common.go @@ -18,7 +18,6 @@ import ( "unicode/utf8" "github.com/gorilla/mux" - "github.com/opencontainers/go-digest" ispec "github.com/opencontainers/image-spec/specs-go/v1" "zotregistry.io/zot/pkg/log" @@ -37,9 +36,9 @@ func AllowedMethods(methods ...string) []string { return append(methods, http.MethodOptions) } -func Contains(slice []string, item string) bool { - for _, v := range slice { - if item == v { +func Contains[T comparable](elems []T, v T) bool { + for _, s := range elems { + if v == s { return true } } @@ -271,16 +270,6 @@ func MarshalThroughStruct(obj interface{}, throughStruct interface{}) ([]byte, e return toJSON, nil } -func DContains(slice []digest.Digest, item digest.Digest) bool { - for _, v := range slice { - if item == v { - return true - } - } - - return false -} - func GetManifestArtifactType(manifestContent ispec.Manifest) string { if manifestContent.ArtifactType != "" { return manifestContent.ArtifactType diff --git a/pkg/extensions/sync/references/cosign.go b/pkg/extensions/sync/references/cosign.go index 9928b2be8f..538029ceae 100644 --- a/pkg/extensions/sync/references/cosign.go +++ b/pkg/extensions/sync/references/cosign.go @@ -4,12 +4,12 @@ package references import ( - "encoding/json" "errors" "fmt" "net/http" "strings" + godigest "github.com/opencontainers/go-digest" ispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/sigstore/cosign/v2/pkg/oci/remote" @@ -46,12 +46,12 @@ func (ref CosignReference) Name() string { func (ref CosignReference) IsSigned(upstreamRepo, subjectDigestStr string) bool { cosignSignatureTag := getCosignSignatureTagFromSubjectDigest(subjectDigestStr) - _, err := ref.getManifest(upstreamRepo, cosignSignatureTag) + _, _, err := ref.getManifest(upstreamRepo, cosignSignatureTag) return err == nil } -func (ref CosignReference) canSkipReferences(localRepo, cosignTag string, manifest *ispec.Manifest) ( +func (ref CosignReference) canSkipReferences(localRepo, digest string, manifest *ispec.Manifest) ( bool, error, ) { if manifest == nil { @@ -59,64 +59,57 @@ func (ref CosignReference) canSkipReferences(localRepo, cosignTag string, manife } imageStore := ref.storeController.GetImageStore(localRepo) - // check cosign signature already synced - - var localManifest ispec.Manifest - - /* we need to use tag (cosign format: sha256-$IMAGE_TAG.sig) instead of digest to get local cosign manifest - because of an issue where cosign digests differs between upstream and downstream */ - localManifestBuf, _, _, err := imageStore.GetImageManifest(localRepo, cosignTag) + // check cosign signature already synced + _, localDigest, _, err := imageStore.GetImageManifest(localRepo, digest) if err != nil { if errors.Is(err, zerr.ErrManifestNotFound) { return false, nil } ref.log.Error().Str("errorType", common.TypeOf(err)).Err(err). - Str("repository", localRepo).Str("reference", cosignTag). + Str("repository", localRepo).Str("reference", digest). Msg("couldn't get local cosign manifest") return false, err } - err = json.Unmarshal(localManifestBuf, &localManifest) - if err != nil { - ref.log.Error().Str("errorType", common.TypeOf(err)). - Str("repository", localRepo).Str("reference", cosignTag). - Err(err).Msg("couldn't unmarshal local cosign signature manifest") - - return false, err - } - - if !manifestsEqual(localManifest, *manifest) { - ref.log.Info().Str("repository", localRepo).Str("reference", cosignTag). - Msg("upstream cosign signatures changed, syncing again") - + if localDigest.String() != digest { return false, nil } - ref.log.Info().Str("repository", localRepo).Str("reference", cosignTag). - Msg("skipping syncing cosign signature, already synced") + ref.log.Info().Str("repository", localRepo).Str("reference", digest). + Msg("skipping syncing cosign reference, already synced") return true, nil } -func (ref CosignReference) SyncReferences(localRepo, remoteRepo, subjectDigestStr string) error { +func (ref CosignReference) SyncReferences(localRepo, remoteRepo, subjectDigestStr string) ([]godigest.Digest, error) { cosignTags := getCosignTagsFromSubjectDigest(subjectDigestStr) + refsDigests := make([]godigest.Digest, 0, len(cosignTags)) + for _, cosignTag := range cosignTags { - manifest, err := ref.getManifest(remoteRepo, cosignTag) - if err != nil && errors.Is(err, zerr.ErrSyncReferrerNotFound) { - return err + manifest, manifestBuf, err := ref.getManifest(remoteRepo, cosignTag) + if err != nil { + if errors.Is(err, zerr.ErrSyncReferrerNotFound) { + continue + } + + return refsDigests, err } - skip, err := ref.canSkipReferences(localRepo, cosignTag, manifest) + digest := godigest.FromBytes(manifestBuf) + + skip, err := ref.canSkipReferences(localRepo, digest.String(), manifest) if err != nil { ref.log.Error().Err(err).Str("repository", localRepo).Str("subject", subjectDigestStr). Msg("couldn't check if the remote image cosign reference can be skipped") } if skip { + refsDigests = append(refsDigests, digest) + continue } @@ -127,22 +120,13 @@ func (ref CosignReference) SyncReferences(localRepo, remoteRepo, subjectDigestSt for _, blob := range manifest.Layers { if err := syncBlob(ref.client, imageStore, localRepo, remoteRepo, blob.Digest, ref.log); err != nil { - return err + return refsDigests, err } } // sync config blob if err := syncBlob(ref.client, imageStore, localRepo, remoteRepo, manifest.Config.Digest, ref.log); err != nil { - return err - } - - manifestBuf, err := json.Marshal(manifest) - if err != nil { - ref.log.Error().Str("errorType", common.TypeOf(err)). - Str("repository", localRepo).Str("subject", subjectDigestStr). - Err(err).Msg("couldn't marshal cosign reference manifest") - - return err + return refsDigests, err } // push manifest @@ -153,9 +137,11 @@ func (ref CosignReference) SyncReferences(localRepo, remoteRepo, subjectDigestSt Str("repository", localRepo).Str("subject", subjectDigestStr). Err(err).Msg("couldn't upload cosign reference manifest for image") - return err + return refsDigests, err } + refsDigests = append(refsDigests, digest) + ref.log.Info().Str("repository", localRepo).Str("subject", subjectDigestStr). Msg("successfully synced cosign reference for image") @@ -166,7 +152,7 @@ func (ref CosignReference) SyncReferences(localRepo, remoteRepo, subjectDigestSt isSig, sigType, signedManifestDig, err := storage.CheckIsImageSignature(localRepo, manifestBuf, cosignTag) if err != nil { - return fmt.Errorf("failed to check if cosign reference '%s@%s' is a signature: %w", localRepo, + return refsDigests, fmt.Errorf("failed to check if cosign reference '%s@%s' is a signature: %w", localRepo, cosignTag, err) } @@ -176,13 +162,14 @@ func (ref CosignReference) SyncReferences(localRepo, remoteRepo, subjectDigestSt SignatureDigest: referenceDigest.String(), }) } else { - err = repodb.SetImageMetaFromInput(localRepo, cosignTag, manifest.MediaType, + err = repodb.SetImageMetaFromInput(localRepo, cosignTag, ispec.MediaTypeImageManifest, referenceDigest, manifestBuf, ref.storeController.GetImageStore(localRepo), ref.repoDB, ref.log) } if err != nil { - return fmt.Errorf("failed to set metadata for cosign reference in '%s@%s': %w", localRepo, subjectDigestStr, err) + return refsDigests, fmt.Errorf("failed to set metadata for cosign reference in '%s@%s': %w", + localRepo, subjectDigestStr, err) } ref.log.Info().Str("repository", localRepo).Str("subject", subjectDigestStr). @@ -190,13 +177,13 @@ func (ref CosignReference) SyncReferences(localRepo, remoteRepo, subjectDigestSt } } - return nil + return refsDigests, nil } -func (ref CosignReference) getManifest(repo, cosignTag string) (*ispec.Manifest, error) { +func (ref CosignReference) getManifest(repo, cosignTag string) (*ispec.Manifest, []byte, error) { var cosignManifest ispec.Manifest - _, _, statusCode, err := ref.client.MakeGetRequest(&cosignManifest, ispec.MediaTypeImageManifest, + body, _, statusCode, err := ref.client.MakeGetRequest(&cosignManifest, ispec.MediaTypeImageManifest, "v2", repo, "manifests", cosignTag) if err != nil { if statusCode == http.StatusNotFound { @@ -204,17 +191,17 @@ func (ref CosignReference) getManifest(repo, cosignTag string) (*ispec.Manifest, Str("repository", repo).Str("tag", cosignTag). Err(err).Msg("couldn't find any cosign manifest for image") - return nil, zerr.ErrSyncReferrerNotFound + return nil, nil, zerr.ErrSyncReferrerNotFound } ref.log.Error().Str("errorType", common.TypeOf(err)). Str("repository", repo).Str("tag", cosignTag).Int("statusCode", statusCode). Err(err).Msg("couldn't get cosign manifest for image") - return nil, err + return nil, nil, err } - return &cosignManifest, nil + return &cosignManifest, body, nil } func getCosignSignatureTagFromSubjectDigest(digestStr string) string { diff --git a/pkg/extensions/sync/references/oci.go b/pkg/extensions/sync/references/oci.go index df4964fc05..8bbedc6604 100644 --- a/pkg/extensions/sync/references/oci.go +++ b/pkg/extensions/sync/references/oci.go @@ -90,10 +90,12 @@ func (ref OciReferences) canSkipReferences(localRepo, subjectDigestStr string, i return true, nil } -func (ref OciReferences) SyncReferences(localRepo, remoteRepo, subjectDigestStr string) error { +func (ref OciReferences) SyncReferences(localRepo, remoteRepo, subjectDigestStr string) ([]godigest.Digest, error) { + refsDigests := make([]godigest.Digest, 0, 10) + index, err := ref.getIndex(remoteRepo, subjectDigestStr) if err != nil { - return err + return refsDigests, err } skipOCIRefs, err := ref.canSkipReferences(localRepo, subjectDigestStr, index) @@ -103,7 +105,13 @@ func (ref OciReferences) SyncReferences(localRepo, remoteRepo, subjectDigestStr } if skipOCIRefs { - return nil + /* even if it's skip we need to return the digests, + because maybe in the meantime a reference pointing to this one was pushed */ + for _, man := range index.Manifests { + refsDigests = append(refsDigests, man.Digest) + } + + return refsDigests, nil } imageStore := ref.storeController.GetImageStore(localRepo) @@ -118,14 +126,14 @@ func (ref OciReferences) SyncReferences(localRepo, remoteRepo, subjectDigestStr "v2", remoteRepo, "manifests", referrer.Digest.String()) if err != nil { if statusCode == http.StatusNotFound { - return zerr.ErrSyncReferrerNotFound + return refsDigests, zerr.ErrSyncReferrerNotFound } ref.log.Error().Str("errorType", common.TypeOf(err)). Str("repository", localRepo).Str("subject", subjectDigestStr). Err(err).Msg("couldn't get oci reference manifest for image") - return err + return refsDigests, err } if referrer.MediaType == ispec.MediaTypeImageManifest { @@ -138,33 +146,35 @@ func (ref OciReferences) SyncReferences(localRepo, remoteRepo, subjectDigestStr Str("repository", localRepo).Str("subject", subjectDigestStr). Err(err).Msg("couldn't unmarshal oci reference manifest for image") - return err + return refsDigests, err } for _, layer := range manifest.Layers { if err := syncBlob(ref.client, imageStore, localRepo, remoteRepo, layer.Digest, ref.log); err != nil { - return err + return refsDigests, err } } // sync config blob if err := syncBlob(ref.client, imageStore, localRepo, remoteRepo, manifest.Config.Digest, ref.log); err != nil { - return err + return refsDigests, err } } else { continue } - digest, _, err := imageStore.PutImageManifest(localRepo, referrer.Digest.String(), + referenceDigest, _, err := imageStore.PutImageManifest(localRepo, referrer.Digest.String(), referrer.MediaType, OCIRefBuf) if err != nil { ref.log.Error().Str("errorType", common.TypeOf(err)). Str("repository", localRepo).Str("subject", subjectDigestStr). Err(err).Msg("couldn't upload oci reference for image") - return err + return refsDigests, err } + refsDigests = append(refsDigests, referenceDigest) + if ref.repoDB != nil { ref.log.Debug().Str("repository", localRepo).Str("subject", subjectDigestStr). Msg("repoDB: trying to add oci references for image") @@ -172,23 +182,24 @@ func (ref OciReferences) SyncReferences(localRepo, remoteRepo, subjectDigestStr isSig, sigType, signedManifestDig, err := storage.CheckIsImageSignature(localRepo, OCIRefBuf, referrer.Digest.String()) if err != nil { - return fmt.Errorf("failed to check if oci reference '%s@%s' is a signature: %w", localRepo, + return refsDigests, fmt.Errorf("failed to check if oci reference '%s@%s' is a signature: %w", localRepo, referrer.Digest.String(), err) } if isSig { err = ref.repoDB.AddManifestSignature(localRepo, signedManifestDig, repodb.SignatureMetadata{ SignatureType: sigType, - SignatureDigest: digest.String(), + SignatureDigest: referenceDigest.String(), }) } else { - err = repodb.SetImageMetaFromInput(localRepo, digest.String(), referrer.MediaType, - digest, OCIRefBuf, ref.storeController.GetImageStore(localRepo), + err = repodb.SetImageMetaFromInput(localRepo, referenceDigest.String(), referrer.MediaType, + referenceDigest, OCIRefBuf, ref.storeController.GetImageStore(localRepo), ref.repoDB, ref.log) } if err != nil { - return fmt.Errorf("failed to set metadata for oci reference in '%s@%s': %w", localRepo, subjectDigestStr, err) + return refsDigests, fmt.Errorf("failed to set metadata for oci reference in '%s@%s': %w", + localRepo, subjectDigestStr, err) } ref.log.Info().Str("repository", localRepo).Str("subject", subjectDigestStr). @@ -199,7 +210,7 @@ func (ref OciReferences) SyncReferences(localRepo, remoteRepo, subjectDigestStr ref.log.Info().Str("repository", localRepo).Str("subject", subjectDigestStr). Msg("successfully synced oci references for image") - return nil + return refsDigests, nil } func (ref OciReferences) getIndex(repo, subjectDigestStr string) (ispec.Index, error) { diff --git a/pkg/extensions/sync/references/oras.go b/pkg/extensions/sync/references/oras.go index 712e698a47..8c49c0d64f 100644 --- a/pkg/extensions/sync/references/oras.go +++ b/pkg/extensions/sync/references/oras.go @@ -84,10 +84,12 @@ func (ref ORASReferences) canSkipReferences(localRepo, subjectDigestStr string, return true, nil } -func (ref ORASReferences) SyncReferences(localRepo, remoteRepo, subjectDigestStr string) error { +func (ref ORASReferences) SyncReferences(localRepo, remoteRepo, subjectDigestStr string) ([]godigest.Digest, error) { + refsDigests := make([]godigest.Digest, 0, 10) + referrers, err := ref.getReferenceList(remoteRepo, subjectDigestStr) if err != nil { - return err + return refsDigests, err } skipORASRefs, err := ref.canSkipReferences(localRepo, subjectDigestStr, referrers) @@ -97,7 +99,11 @@ func (ref ORASReferences) SyncReferences(localRepo, remoteRepo, subjectDigestStr } if skipORASRefs { - return nil + for _, man := range referrers.References { + refsDigests = append(refsDigests, man.Digest) + } + + return refsDigests, nil } imageStore := ref.storeController.GetImageStore(localRepo) @@ -112,41 +118,44 @@ func (ref ORASReferences) SyncReferences(localRepo, remoteRepo, subjectDigestStr "v2", remoteRepo, "manifests", referrer.Digest.String()) if err != nil { if statusCode == http.StatusNotFound { - return zerr.ErrSyncReferrerNotFound + return refsDigests, zerr.ErrSyncReferrerNotFound } ref.log.Error().Str("errorType", common.TypeOf(err)). Str("repository", localRepo).Str("subject", subjectDigestStr). Err(err).Msg("couldn't get ORAS artifact for image") - return err + return refsDigests, err } for _, blob := range artifactManifest.Blobs { if err := syncBlob(ref.client, imageStore, localRepo, remoteRepo, blob.Digest, ref.log); err != nil { - return err + return refsDigests, err } } - digest, _, err := imageStore.PutImageManifest(localRepo, referrer.Digest.String(), + referenceDigest, _, err := imageStore.PutImageManifest(localRepo, referrer.Digest.String(), oras.MediaTypeArtifactManifest, orasBuf) if err != nil { ref.log.Error().Str("errorType", common.TypeOf(err)). Str("repository", localRepo).Str("subject", subjectDigestStr). Err(err).Msg("couldn't upload ORAS artifact for image") - return err + return refsDigests, err } + refsDigests = append(refsDigests, referenceDigest) + if ref.repoDB != nil { ref.log.Debug().Str("repository", localRepo).Str("subject", subjectDigestStr). Msg("repoDB: trying to sync oras artifact for image") - err := repodb.SetImageMetaFromInput(localRepo, digest.String(), referrer.MediaType, - digest, orasBuf, ref.storeController.GetImageStore(localRepo), + err := repodb.SetImageMetaFromInput(localRepo, referenceDigest.String(), referrer.MediaType, + referenceDigest, orasBuf, ref.storeController.GetImageStore(localRepo), ref.repoDB, ref.log) if err != nil { - return fmt.Errorf("repoDB: failed to set metadata for oras artifact '%s@%s': %w", localRepo, subjectDigestStr, err) + return refsDigests, fmt.Errorf("repoDB: failed to set metadata for oras artifact '%s@%s': %w", + localRepo, subjectDigestStr, err) } ref.log.Info().Str("repository", localRepo).Str("subject", subjectDigestStr). @@ -157,7 +166,7 @@ func (ref ORASReferences) SyncReferences(localRepo, remoteRepo, subjectDigestStr ref.log.Info().Str("repository", localRepo).Str("subject", subjectDigestStr). Msg("successfully synced oras artifacts for image") - return nil + return refsDigests, nil } func (ref ORASReferences) getReferenceList(repo, subjectDigestStr string) (ReferenceList, error) { diff --git a/pkg/extensions/sync/references/references.go b/pkg/extensions/sync/references/references.go index 3145b016ac..59aee5e0e1 100644 --- a/pkg/extensions/sync/references/references.go +++ b/pkg/extensions/sync/references/references.go @@ -9,7 +9,7 @@ import ( "net/http" notreg "github.com/notaryproject/notation-go/registry" - "github.com/opencontainers/go-digest" + godigest "github.com/opencontainers/go-digest" ispec "github.com/opencontainers/image-spec/specs-go/v1" artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1" "github.com/sigstore/cosign/v2/pkg/oci/static" @@ -23,14 +23,17 @@ import ( ) type Reference interface { + // Returns name of reference (OCIReference/CosignReference/OrasReference) Name() string + // Returns whether or not image is signed IsSigned(upstreamRepo, subjectDigestStr string) bool - SyncReferences(localRepo, upstreamRepo, subjectDigestStr string) error + // Sync recursively all references for a subject digest (can be image/artifacts/signatures) + SyncReferences(localRepo, upstreamRepo, subjectDigestStr string) ([]godigest.Digest, error) } type References struct { - refernceList []Reference - log log.Logger + referenceList []Reference + log log.Logger } func NewReferences(httpClient *client.Client, storeController storage.StoreController, @@ -38,15 +41,15 @@ func NewReferences(httpClient *client.Client, storeController storage.StoreContr ) References { refs := References{log: log} - refs.refernceList = append(refs.refernceList, NewCosignReference(httpClient, storeController, repoDB, log)) - refs.refernceList = append(refs.refernceList, NewOciReferences(httpClient, storeController, repoDB, log)) - refs.refernceList = append(refs.refernceList, NewORASReferences(httpClient, storeController, repoDB, log)) + refs.referenceList = append(refs.referenceList, NewCosignReference(httpClient, storeController, repoDB, log)) + refs.referenceList = append(refs.referenceList, NewOciReferences(httpClient, storeController, repoDB, log)) + refs.referenceList = append(refs.referenceList, NewORASReferences(httpClient, storeController, repoDB, log)) return refs } func (refs References) IsSigned(upstreamRepo, subjectDigestStr string) bool { - for _, ref := range refs.refernceList { + for _, ref := range refs.referenceList { ok := ref.IsSigned(upstreamRepo, subjectDigestStr) if ok { return true @@ -57,25 +60,50 @@ func (refs References) IsSigned(upstreamRepo, subjectDigestStr string) bool { } func (refs References) SyncAll(localRepo, upstreamRepo, subjectDigestStr string) error { + seen := &[]godigest.Digest{} + + return refs.syncAll(localRepo, upstreamRepo, subjectDigestStr, seen) +} + +func (refs References) syncAll(localRepo, upstreamRepo, subjectDigestStr string, seen *[]godigest.Digest) error { var err error - for _, ref := range refs.refernceList { - err = ref.SyncReferences(localRepo, upstreamRepo, subjectDigestStr) + var syncedRefsDigests []godigest.Digest + + // mark subject digest as seen as soon as it comes in + *seen = append(*seen, godigest.Digest(subjectDigestStr)) + + // for each reference type(cosign/oci/oras reference) + for _, ref := range refs.referenceList { + syncedRefsDigests, err = ref.SyncReferences(localRepo, upstreamRepo, subjectDigestStr) if err != nil { - refs.log.Error().Err(err). + refs.log.Debug().Err(err). Str("reference type", ref.Name()). Str("image", fmt.Sprintf("%s:%s", upstreamRepo, subjectDigestStr)). Msg("couldn't sync image referrer") } + + // for each synced references + for _, refDigest := range syncedRefsDigests { + if !common.Contains(*seen, refDigest) { + // sync all references pointing to this one + err = refs.syncAll(localRepo, upstreamRepo, refDigest.String(), seen) + } + } } return err } func (refs References) SyncReference(localRepo, upstreamRepo, subjectDigestStr, referenceType string) error { - for _, ref := range refs.refernceList { + var err error + + var syncedRefsDigests []godigest.Digest + + for _, ref := range refs.referenceList { if ref.Name() == referenceType { - if err := ref.SyncReferences(localRepo, upstreamRepo, subjectDigestStr); err != nil { + syncedRefsDigests, err = ref.SyncReferences(localRepo, upstreamRepo, subjectDigestStr) + if err != nil { refs.log.Error().Err(err). Str("reference type", ref.Name()). Str("image", fmt.Sprintf("%s:%s", upstreamRepo, subjectDigestStr)). @@ -83,14 +111,18 @@ func (refs References) SyncReference(localRepo, upstreamRepo, subjectDigestStr, return err } + + for _, refDigest := range syncedRefsDigests { + err = refs.SyncAll(localRepo, upstreamRepo, refDigest.String()) + } } } - return nil + return err } func syncBlob(client *client.Client, imageStore storageTypes.ImageStore, localRepo, remoteRepo string, - digest digest.Digest, log log.Logger, + digest godigest.Digest, log log.Logger, ) error { var resultPtr interface{} diff --git a/pkg/extensions/sync/references/references_internal_test.go b/pkg/extensions/sync/references/references_internal_test.go index d3264f8640..c82329b40e 100644 --- a/pkg/extensions/sync/references/references_internal_test.go +++ b/pkg/extensions/sync/references/references_internal_test.go @@ -48,13 +48,13 @@ func TestCosign(t *testing.T) { cosign = NewCosignReference(client, storage.StoreController{DefaultStore: mocks.MockedImageStore{ GetImageManifestFn: func(repo, reference string) ([]byte, godigest.Digest, string, error) { - return []byte{}, "", "", nil + return []byte{}, "digest", "", nil }, }}, nil, log.NewLogger("debug", "")) - // trigger unmarshal err + // different digest ok, err = cosign.canSkipReferences("repo", "tag", &ispec.Manifest{MediaType: ispec.MediaTypeImageManifest}) - So(err, ShouldNotBeNil) + So(err, ShouldBeNil) So(ok, ShouldBeFalse) }) } diff --git a/pkg/extensions/sync/service.go b/pkg/extensions/sync/service.go index 5db78d7ec6..5477c55fb4 100644 --- a/pkg/extensions/sync/service.go +++ b/pkg/extensions/sync/service.go @@ -367,7 +367,7 @@ func (service *BaseService) syncTag(localRepo, remoteRepo, tag string) (digest.D return "", zerr.ErrMediaTypeNotSupported } - if service.config.OnlySigned != nil && *service.config.OnlySigned { + if service.config.OnlySigned != nil && *service.config.OnlySigned && !references.IsCosignTag(tag) { signed := service.references.IsSigned(remoteRepo, manifestDigest.String()) if !signed { // skip unsigned images diff --git a/pkg/extensions/sync/sync_test.go b/pkg/extensions/sync/sync_test.go index 97004a1dbe..43054db65c 100644 --- a/pkg/extensions/sync/sync_test.go +++ b/pkg/extensions/sync/sync_test.go @@ -743,6 +743,7 @@ func TestOnDemand(t *testing.T) { Subject: &ispec.Descriptor{ MediaType: ispec.MediaTypeImageManifest, Digest: manifestDigest, + Size: int64(len(manifestBlob)), }, Config: ispec.Descriptor{ MediaType: ispec.MediaTypeEmptyJSON, @@ -876,6 +877,147 @@ func TestOnDemand(t *testing.T) { }) } +func TestSyncReferenceInLoop(t *testing.T) { + Convey("Verify sync doesn't end up in an infinite loop when syncing image references", t, func() { + sctlr, srcBaseURL, srcDir, _, _ := makeUpstreamServer(t, false, false) + + scm := test.NewControllerManager(sctlr) + scm.StartAndWait(sctlr.Config.HTTP.Port) + defer scm.StopServer() + + var tlsVerify bool + + maxRetries := 1 + delay := 1 * time.Second + + syncRegistryConfig := syncconf.RegistryConfig{ + Content: []syncconf.Content{ + { + Prefix: testImage, + }, + }, + URLs: []string{srcBaseURL}, + TLSVerify: &tlsVerify, + OnDemand: true, + MaxRetries: &maxRetries, + RetryDelay: &delay, + } + + defaultVal := true + syncConfig := &syncconf.Config{ + Enable: &defaultVal, + Registries: []syncconf.RegistryConfig{syncRegistryConfig}, + } + + dctlr, destBaseURL, _, _ := makeDownstreamServer(t, false, syncConfig) + + dcm := test.NewControllerManager(dctlr) + dcm.StartAndWait(dctlr.Config.HTTP.Port) + defer dcm.StopServer() + + // we will push references in loop: image A -> sbom A -> oci artifact A -> sbom A (same sbom as before) + // recursive syncing it should not get in an infinite loop + // sync testImage and get its digest + resp, err := resty.R().Get(destBaseURL + "/v2/" + testImage + "/manifests/" + testImageTag) + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusOK) + + imageDigest := godigest.FromBytes(resp.Body()) + + // attach sbom + attachSBOM(srcDir, sctlr.Config.HTTP.Port, testImage, imageDigest) + + // sbom tag + sbomTag := strings.Replace(imageDigest.String(), ":", "-", 1) + "." + remote.SBOMTagSuffix + + // sync sbom and get its digest + resp, err = resty.R(). + SetHeader("Content-type", ispec.MediaTypeImageManifest). + Get(destBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", testImage, sbomTag)) + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusOK) + + sbomManifestBuf := resp.Body() + sbomDigest := godigest.FromBytes(sbomManifestBuf) + + // push oci ref referencing sbom + _ = pushBlob(srcBaseURL, testImage, ispec.DescriptorEmptyJSON.Data) + + OCIRefManifest := ispec.Manifest{ + Subject: &ispec.Descriptor{ + MediaType: ispec.MediaTypeImageManifest, + Digest: sbomDigest, + Size: int64(len(sbomManifestBuf)), + }, + Config: ispec.Descriptor{ + MediaType: ispec.MediaTypeEmptyJSON, + Digest: ispec.DescriptorEmptyJSON.Digest, + Size: 2, + }, + Layers: []ispec.Descriptor{ + { + MediaType: ispec.MediaTypeEmptyJSON, + Digest: ispec.DescriptorEmptyJSON.Digest, + Size: 2, + }, + }, + MediaType: ispec.MediaTypeImageManifest, + } + + OCIRefManifestBlob, err := json.Marshal(OCIRefManifest) + So(err, ShouldBeNil) + + OCIRefDigest := godigest.FromBytes(OCIRefManifestBlob) + + resp, err = resty.R(). + SetHeader("Content-type", ispec.MediaTypeImageManifest). + SetBody(OCIRefManifestBlob). + Put(srcBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", testImage, OCIRefDigest)) + + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusCreated) + + // attach same sbom we attached to image + // can not use same function attachSBOM because its digest will differ + sbomTag2 := strings.Replace(OCIRefDigest.String(), ":", "-", 1) + "." + remote.SBOMTagSuffix + + resp, err = resty.R(). + SetHeader("Content-type", ispec.MediaTypeImageManifest). + SetBody(sbomManifestBuf). + Put(srcBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", testImage, sbomTag2)) + + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusCreated) + + // sync image + resp, err = resty.R().Get(destBaseURL + "/v2/" + testImage + "/manifests/" + testImageTag) + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusOK) + + // check all references are synced + // first sbom + resp, err = resty.R(). + SetHeader("Content-type", ispec.MediaTypeImageManifest). + Get(destBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", testImage, sbomTag)) + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusOK) + + // oci ref + resp, err = resty.R(). + SetHeader("Content-type", ispec.MediaTypeImageManifest). + Get(destBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", testImage, OCIRefDigest)) + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusOK) + + // second sbom + resp, err = resty.R(). + SetHeader("Content-type", ispec.MediaTypeImageManifest). + Get(destBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", testImage, sbomTag2)) + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusOK) + }) +} + func TestSyncWithNonDistributableBlob(t *testing.T) { Convey("Verify sync doesn't copy non distributable blobs", t, func() { sctlr, srcBaseURL, srcDir, _, _ := makeUpstreamServer(t, false, false) @@ -3339,7 +3481,7 @@ func TestSignatures(t *testing.T) { splittedURL := strings.SplitAfter(srcBaseURL, ":") srcPort := splittedURL[len(splittedURL)-1] - + t.Logf(srcPort) cwd, err := os.Getwd() So(err, ShouldBeNil) @@ -3354,6 +3496,82 @@ func TestSignatures(t *testing.T) { // attach sbom attachSBOM(srcDir, sctlr.Config.HTTP.Port, repoName, digest) + // sbom tag + sbomTag := strings.Replace(digest.String(), ":", "-", 1) + "." + remote.SBOMTagSuffix + + // get sbom digest + resp, err := resty.R(). + SetHeader("Content-type", ispec.MediaTypeImageManifest). + Get(srcBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", repoName, sbomTag)) + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusOK) + + sbomDigest := godigest.FromBytes(resp.Body()) + + // sign sbom + So(func() { signImage(tdir, srcPort, repoName, sbomDigest) }, ShouldNotPanic) + + // attach oci ref to sbom + // add OCI Ref + _ = pushBlob(srcBaseURL, repoName, ispec.DescriptorEmptyJSON.Data) + + OCIRefManifest := ispec.Manifest{ + Subject: &ispec.Descriptor{ + MediaType: ispec.MediaTypeImageManifest, + Digest: sbomDigest, + Size: int64(len(resp.Body())), + }, + Config: ispec.Descriptor{ + MediaType: ispec.MediaTypeEmptyJSON, + Digest: ispec.DescriptorEmptyJSON.Digest, + Size: 2, + }, + Layers: []ispec.Descriptor{ + { + MediaType: ispec.MediaTypeEmptyJSON, + Digest: ispec.DescriptorEmptyJSON.Digest, + Size: 2, + }, + }, + MediaType: ispec.MediaTypeImageManifest, + } + + OCIRefManifestBlob, err := json.Marshal(OCIRefManifest) + So(err, ShouldBeNil) + + ociRefDigest := godigest.FromBytes(OCIRefManifestBlob) + + resp, err = resty.R(). + SetHeader("Content-type", ispec.MediaTypeImageManifest). + SetBody(OCIRefManifestBlob). + Put(srcBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", repoName, ociRefDigest.String())) + + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusCreated) + + // add ORAS Ref to oci ref which points to sbom which points to image + ORASRefManifest := artifactspec.Manifest{ + Subject: &artifactspec.Descriptor{ + MediaType: ispec.MediaTypeImageManifest, + Digest: ociRefDigest, + Size: int64(len(OCIRefManifestBlob)), + }, + Blobs: []artifactspec.Descriptor{}, + MediaType: artifactspec.MediaTypeArtifactManifest, + } + + ORASRefManifestBlob, err := json.Marshal(ORASRefManifest) + So(err, ShouldBeNil) + + ORASRefManifestDigest := godigest.FromBytes(ORASRefManifestBlob) + + resp, err = resty.R(). + SetHeader("Content-type", artifactspec.MediaTypeArtifactManifest). + SetBody(ORASRefManifestBlob). + Put(srcBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", repoName, ORASRefManifestDigest)) + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusCreated) + regex := ".*" var semver bool var tlsVerify bool @@ -3413,36 +3631,30 @@ func TestSignatures(t *testing.T) { splittedURL = strings.SplitAfter(destBaseURL, ":") destPort := splittedURL[len(splittedURL)-1] - a := &options.AnnotationOptions{Annotations: []string{fmt.Sprintf("tag=%s", testImageTag)}} - amap, err := a.AnnotationsMap() - if err != nil { - panic(err) - } - time.Sleep(1 * time.Second) // notation verify the image - image := fmt.Sprintf("localhost:%s/%s:%s", destPort, repoName, testImageTag) + image := fmt.Sprintf("localhost:%s/%s@%s", destPort, repoName, digest) vrfy := verify.VerifyCommand{ RegistryOptions: options.RegistryOptions{AllowInsecure: true}, CheckClaims: true, KeyRef: path.Join(tdir, "cosign.pub"), - Annotations: amap, IgnoreTlog: true, } + test.LoadNotationPath(tdir) // notation verify signed image err = test.VerifyWithNotation(image, tdir) So(err, ShouldBeNil) // cosign verify signed image - err = vrfy.Exec(context.TODO(), []string{fmt.Sprintf("localhost:%s/%s:%s", destPort, repoName, testImageTag)}) + err = vrfy.Exec(context.TODO(), []string{image}) So(err, ShouldBeNil) // get oci references from downstream, should be synced getOCIReferrersURL := destBaseURL + path.Join("/v2", repoName, "referrers", digest.String()) - resp, err := resty.R().Get(getOCIReferrersURL) + resp, err = resty.R().Get(getOCIReferrersURL) So(err, ShouldBeNil) So(resp, ShouldNotBeEmpty) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -3461,6 +3673,55 @@ func TestSignatures(t *testing.T) { So(err, ShouldBeNil) So(resp, ShouldNotBeEmpty) So(resp.StatusCode(), ShouldEqual, http.StatusOK) + So(godigest.FromBytes(resp.Body()), ShouldEqual, sbomDigest) + + // verify sbom signature + sbom := fmt.Sprintf("localhost:%s/%s@%s", destPort, repoName, sbomDigest) + + test.LoadNotationPath(tdir) + // notation verify signed sbom + err = test.VerifyWithNotation(sbom, tdir) + So(err, ShouldBeNil) + + vrfy = verify.VerifyCommand{ + RegistryOptions: options.RegistryOptions{AllowInsecure: true}, + CheckClaims: true, + KeyRef: path.Join(tdir, "cosign.pub"), + IgnoreTlog: true, + } + + // cosign verify signed sbom + err = vrfy.Exec(context.TODO(), []string{sbom}) + So(err, ShouldBeNil) + + // get oci ref pointing to sbom + getOCIReferrersURL = destBaseURL + path.Join("/v2", repoName, "referrers", sbomDigest.String()) + resp, err = resty.R().Get(getOCIReferrersURL) + So(err, ShouldBeNil) + So(resp, ShouldNotBeEmpty) + So(resp.StatusCode(), ShouldEqual, http.StatusOK) + + err = json.Unmarshal(resp.Body(), &index) + So(err, ShouldBeNil) + + So(len(index.Manifests), ShouldEqual, 2) + So(index.Manifests[1].Digest, ShouldEqual, ociRefDigest) + + // get oras ref pointing to oci ref + + getORASReferrersURL := destBaseURL + path.Join("/oras/artifacts/v1/", repoName, "manifests", ociRefDigest.String(), "referrers") //nolint:lll + resp, err = resty.R().Get(getORASReferrersURL) + So(err, ShouldBeNil) + So(resp, ShouldNotBeEmpty) + So(resp.StatusCode(), ShouldEqual, http.StatusOK) + + var refs ReferenceList + + err = json.Unmarshal(resp.Body(), &refs) + So(err, ShouldBeNil) + + So(len(refs.References), ShouldEqual, 1) + So(refs.References[0].Digest, ShouldEqual, ORASRefManifestDigest) // test negative cases (trigger errors) // test notary signatures errors @@ -3527,6 +3788,10 @@ func TestSignatures(t *testing.T) { So(err, ShouldBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) + // remove already synced image + err = os.RemoveAll(path.Join(destDir, repoName)) + So(err, ShouldBeNil) + // triggers perm denied on sig blobs for _, blob := range artifactManifest.Layers { blobPath := path.Join(srcDir, repoName, "blobs", string(blob.Digest.Algorithm()), blob.Digest.Encoded()) @@ -3534,15 +3799,15 @@ func TestSignatures(t *testing.T) { So(err, ShouldBeNil) } - // remove already synced image - err = os.RemoveAll(path.Join(destDir, repoName)) - So(err, ShouldBeNil) - // sync on demand resp, err = resty.R().Get(destBaseURL + "/v2/" + repoName + "/manifests/" + testImageTag) So(err, ShouldBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) + // remove already synced image + err = os.RemoveAll(path.Join(destDir, repoName)) + So(err, ShouldBeNil) + // test cosign signatures errors // based on manifest digest get cosign manifest cosignEncodedDigest := strings.Replace(digest.String(), ":", "-", 1) + ".sig" @@ -3550,28 +3815,14 @@ func TestSignatures(t *testing.T) { mResp, err := resty.R().Get(getCosignManifestURL) So(err, ShouldBeNil) + So(mResp.StatusCode(), ShouldEqual, http.StatusOK) var imageManifest ispec.Manifest err = json.Unmarshal(mResp.Body(), &imageManifest) So(err, ShouldBeNil) - downstreaamCosignManifest := ispec.Manifest{ - MediaType: imageManifest.MediaType, - Config: ispec.Descriptor{ - MediaType: imageManifest.Config.MediaType, - Size: imageManifest.Config.Size, - Digest: imageManifest.Config.Digest, - Annotations: imageManifest.Config.Annotations, - }, - Layers: imageManifest.Layers, - Versioned: imageManifest.Versioned, - Annotations: imageManifest.Annotations, - } - - buf, err := json.Marshal(downstreaamCosignManifest) - So(err, ShouldBeNil) - cosignManifestDigest := godigest.FromBytes(buf) + cosignManifestDigest := godigest.FromBytes(mResp.Body()) for _, blob := range imageManifest.Layers { blobPath := path.Join(srcDir, repoName, "blobs", string(blob.Digest.Algorithm()), blob.Digest.Encoded()) @@ -3755,6 +4006,20 @@ func TestSignatures(t *testing.T) { resp, err = resty.R().Get(destBaseURL + "/v2/" + repoName + "/manifests/" + testImageTag) So(err, ShouldBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) + + // remove already synced image + err = os.RemoveAll(path.Join(destDir, repoName)) + So(err, ShouldBeNil) + + // sync on demand + resp, err = resty.R().Get(destBaseURL + "/v2/" + repoName + "/manifests/" + testImageTag) + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusOK) + + // sync on demand again for coverage + resp, err = resty.R().Get(destBaseURL + "/v2/" + repoName + "/manifests/" + testImageTag) + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusOK) }) } @@ -4383,12 +4648,6 @@ func TestSignaturesOnDemand(t *testing.T) { splittedURL = strings.SplitAfter(destBaseURL, ":") destPort := splittedURL[len(splittedURL)-1] - a := &options.AnnotationOptions{Annotations: []string{fmt.Sprintf("tag=%s", testImageTag)}} - amap, err := a.AnnotationsMap() - if err != nil { - panic(err) - } - // notation verify the synced image image := fmt.Sprintf("localhost:%s/%s:%s", destPort, repoName, testImageTag) err = test.VerifyWithNotation(image, tdir) @@ -4399,7 +4658,6 @@ func TestSignaturesOnDemand(t *testing.T) { RegistryOptions: options.RegistryOptions{AllowInsecure: true}, CheckClaims: true, KeyRef: path.Join(tdir, "cosign.pub"), - Annotations: amap, IgnoreTlog: true, } err = vrfy.Exec(context.TODO(), []string{fmt.Sprintf("localhost:%s/%s:%s", destPort, repoName, testImageTag)}) @@ -4625,12 +4883,6 @@ func TestOnlySignaturesOnDemand(t *testing.T) { splittedURL = strings.SplitAfter(destBaseURL, ":") destPort := splittedURL[len(splittedURL)-1] - a := &options.AnnotationOptions{Annotations: []string{fmt.Sprintf("tag=%s", testImageTag)}} - amap, err := a.AnnotationsMap() - if err != nil { - panic(err) - } - generateKeyPairs(tdir) // sync signature on demand when upstream doesn't have the signature @@ -4643,7 +4895,6 @@ func TestOnlySignaturesOnDemand(t *testing.T) { RegistryOptions: options.RegistryOptions{AllowInsecure: true}, CheckClaims: true, KeyRef: path.Join(tdir, "cosign.pub"), - Annotations: amap, IgnoreTlog: true, } @@ -4663,7 +4914,6 @@ func TestOnlySignaturesOnDemand(t *testing.T) { RegistryOptions: options.RegistryOptions{AllowInsecure: true}, CheckClaims: true, KeyRef: path.Join(tdir, "cosign.pub"), - Annotations: amap, IgnoreTlog: true, } @@ -4995,12 +5245,6 @@ func TestSyncSignaturesDiff(t *testing.T) { splittedURL = strings.SplitAfter(destBaseURL, ":") destPort := splittedURL[len(splittedURL)-1] - a := &options.AnnotationOptions{Annotations: []string{fmt.Sprintf("tag=%s", testImageTag)}} - amap, err := a.AnnotationsMap() - if err != nil { - panic(err) - } - // notation verify the image image := fmt.Sprintf("localhost:%s/%s:%s", destPort, repoName, testImageTag) err = test.VerifyWithNotation(image, tdir) @@ -5011,7 +5255,6 @@ func TestSyncSignaturesDiff(t *testing.T) { RegistryOptions: options.RegistryOptions{AllowInsecure: true}, CheckClaims: true, KeyRef: path.Join(tdir, "cosign.pub"), - Annotations: amap, IgnoreTlog: true, } err = vrfy.Exec(context.TODO(), []string{fmt.Sprintf("localhost:%s/%s:%s", destPort, repoName, testImageTag)}) @@ -5038,7 +5281,6 @@ func TestSyncSignaturesDiff(t *testing.T) { RegistryOptions: options.RegistryOptions{AllowInsecure: true}, CheckClaims: true, KeyRef: path.Join(tdir, "cosign.pub"), - Annotations: amap, IgnoreTlog: true, } err = vrfy.Exec(context.TODO(), []string{fmt.Sprintf("localhost:%s/%s:%s", destPort, repoName, testImageTag)}) @@ -5359,12 +5601,6 @@ func TestSyncWithDestination(t *testing.T) { splittedURL = strings.SplitAfter(destBaseURL, ":") destPort := splittedURL[len(splittedURL)-1] - a := &options.AnnotationOptions{Annotations: []string{fmt.Sprintf("tag=%s", testImageTag)}} - amap, err := a.AnnotationsMap() - if err != nil { - panic(err) - } - // notation verify the synced image image := fmt.Sprintf("localhost:%s/%s:%s", destPort, testCase.expected, testImageTag) err = test.VerifyWithNotation(image, tdir) @@ -5375,7 +5611,6 @@ func TestSyncWithDestination(t *testing.T) { RegistryOptions: options.RegistryOptions{AllowInsecure: true}, CheckClaims: true, KeyRef: path.Join(tdir, "cosign.pub"), - Annotations: amap, IgnoreTlog: true, } err = vrfy.Exec(context.TODO(), []string{fmt.Sprintf("localhost:%s/%s:%s", destPort, @@ -5416,12 +5651,6 @@ func TestSyncWithDestination(t *testing.T) { splittedURL = strings.SplitAfter(destBaseURL, ":") destPort := splittedURL[len(splittedURL)-1] - a := &options.AnnotationOptions{Annotations: []string{fmt.Sprintf("tag=%s", testImageTag)}} - amap, err := a.AnnotationsMap() - if err != nil { - panic(err) - } - // notation verify the synced image image := fmt.Sprintf("localhost:%s/%s:%s", destPort, testCase.expected, testImageTag) err = test.VerifyWithNotation(image, tdir) @@ -5432,7 +5661,6 @@ func TestSyncWithDestination(t *testing.T) { RegistryOptions: options.RegistryOptions{AllowInsecure: true}, CheckClaims: true, KeyRef: path.Join(tdir, "cosign.pub"), - Annotations: amap, IgnoreTlog: true, } err = vrfy.Exec(context.TODO(), []string{fmt.Sprintf("localhost:%s/%s:%s", destPort, @@ -5622,39 +5850,27 @@ func attachSBOM(tdir, port, repoName string, digest godigest.Digest) { } func signImage(tdir, port, repoName string, digest godigest.Digest) { - annotations := []string{fmt.Sprintf("tag=%s", testImageTag)} - // push signatures to upstream server so that we can sync them later // sign the image err := sign.SignCmd(&options.RootOptions{Verbose: true, Timeout: 1 * time.Minute}, options.KeyOpts{KeyRef: path.Join(tdir, "cosign.key"), PassFunc: generate.GetPass}, options.SignOptions{ - Registry: options.RegistryOptions{AllowInsecure: true}, - AnnotationOptions: options.AnnotationOptions{Annotations: annotations}, - Upload: true, + Registry: options.RegistryOptions{AllowInsecure: true}, + Upload: true, }, []string{fmt.Sprintf("localhost:%s/%s@%s", port, repoName, digest.String())}) if err != nil { panic(err) } - // verify the image - a := &options.AnnotationOptions{Annotations: annotations} - - amap, err := a.AnnotationsMap() - if err != nil { - panic(err) - } - vrfy := verify.VerifyCommand{ RegistryOptions: options.RegistryOptions{AllowInsecure: true}, CheckClaims: true, KeyRef: path.Join(tdir, "cosign.pub"), - Annotations: amap, IgnoreTlog: true, } - err = vrfy.Exec(context.TODO(), []string{fmt.Sprintf("localhost:%s/%s:%s", port, repoName, testImageTag)}) + err = vrfy.Exec(context.TODO(), []string{fmt.Sprintf("localhost:%s/%s@%s", port, repoName, digest.String())}) if err != nil { panic(err) } @@ -5665,7 +5881,7 @@ func signImage(tdir, port, repoName string, digest godigest.Digest) { test.LoadNotationPath(tdir) // sign the image - image := fmt.Sprintf("localhost:%s/%s:%s", port, repoName, testImageTag) + image := fmt.Sprintf("localhost:%s/%s@%s", port, repoName, digest.String()) err = test.SignWithNotation("good", image, tdir) if err != nil { diff --git a/pkg/storage/local/local.go b/pkg/storage/local/local.go index 7788a6977b..b1e773c19c 100644 --- a/pkg/storage/local/local.go +++ b/pkg/storage/local/local.go @@ -1838,7 +1838,7 @@ func (is *ImageStoreLocal) GetNextDigestWithBlobPaths(lastDigests []godigest.Dig return nil //nolint:nilerr // ignore files which are not blobs } - if digest == "" && !zcommon.DContains(lastDigests, blobDigest) { + if digest == "" && !zcommon.Contains(lastDigests, blobDigest) { digest = blobDigest } diff --git a/pkg/storage/s3/s3.go b/pkg/storage/s3/s3.go index 4e47752da5..04a60252f5 100644 --- a/pkg/storage/s3/s3.go +++ b/pkg/storage/s3/s3.go @@ -1442,7 +1442,7 @@ func (is *ObjectStorage) GetNextDigestWithBlobPaths(lastDigests []godigest.Diges return nil //nolint:nilerr // ignore files which are not blobs } - if digest == "" && !zcommon.DContains(lastDigests, blobDigest) { + if digest == "" && !zcommon.Contains(lastDigests, blobDigest) { digest = blobDigest }