0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2024-12-30 22:34:13 -05:00

feat(sync): sync references(signatures/artifacts) recursively (#1500)

sync now also pulls chained artifacts recursively
eg:
 image->sbom->sbom signature
 image->artifact->artifact

Signed-off-by: Petu Eusebiu <peusebiu@cisco.com>
This commit is contained in:
peusebiu 2023-06-16 20:27:33 +03:00 committed by GitHub
parent c41bf02240
commit fc6d6356fb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 447 additions and 222 deletions

View file

@ -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,

View file

@ -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

View file

@ -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)
_, 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 {

View file

@ -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) {

View file

@ -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) {

View file

@ -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{}

View file

@ -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)
})
}

View file

@ -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

View file

@ -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)})
@ -5114,7 +5356,7 @@ func TestSyncSignaturesDiff(t *testing.T) {
So(reflect.DeepEqual(cosignManifest, syncedCosignManifest), ShouldEqual, true)
found, err := test.ReadLogFileAndSearchString(dctlr.Config.Log.Output,
"skipping syncing cosign signature", 15*time.Second)
"skipping syncing cosign reference", 15*time.Second)
if err != nil {
panic(err)
}
@ -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 {

View file

@ -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
}

View file

@ -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
}