2022-03-07 03:45:10 -05:00
|
|
|
package sync
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"path"
|
|
|
|
"strings"
|
|
|
|
|
2022-08-20 20:18:50 -05:00
|
|
|
notreg "github.com/notaryproject/notation-go/registry"
|
2022-10-22 15:46:13 -05:00
|
|
|
godigest "github.com/opencontainers/go-digest"
|
2022-03-07 03:45:10 -05:00
|
|
|
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
|
|
artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1"
|
2022-04-14 05:57:09 -05:00
|
|
|
"github.com/sigstore/cosign/pkg/oci/remote"
|
2022-03-07 03:45:10 -05:00
|
|
|
"gopkg.in/resty.v1"
|
2022-10-20 11:39:20 -05:00
|
|
|
|
2022-03-07 03:45:10 -05:00
|
|
|
zerr "zotregistry.io/zot/errors"
|
2022-03-24 07:25:14 -05:00
|
|
|
"zotregistry.io/zot/pkg/api/constants"
|
2022-03-07 03:45:10 -05:00
|
|
|
"zotregistry.io/zot/pkg/log"
|
|
|
|
"zotregistry.io/zot/pkg/storage"
|
|
|
|
)
|
|
|
|
|
2022-10-22 02:26:14 -05:00
|
|
|
type signaturesCopier struct {
|
|
|
|
client *resty.Client
|
|
|
|
upstreamURL url.URL
|
|
|
|
storeController storage.StoreController
|
|
|
|
log log.Logger
|
|
|
|
}
|
|
|
|
|
|
|
|
func newSignaturesCopier(httpClient *resty.Client, upstreamURL url.URL,
|
|
|
|
storeController storage.StoreController, log log.Logger,
|
|
|
|
) *signaturesCopier {
|
|
|
|
return &signaturesCopier{
|
|
|
|
client: httpClient,
|
|
|
|
upstreamURL: upstreamURL,
|
|
|
|
storeController: storeController,
|
|
|
|
log: log,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-22 15:46:13 -05:00
|
|
|
func (sig *signaturesCopier) getCosignManifest(repo, digestStr string) (*ispec.Manifest, error) {
|
2022-03-21 12:37:23 -05:00
|
|
|
var cosignManifest ispec.Manifest
|
2022-03-07 03:45:10 -05:00
|
|
|
|
2022-10-22 15:46:13 -05:00
|
|
|
cosignTag := getCosignTagFromImageDigest(digestStr)
|
2022-03-07 03:45:10 -05:00
|
|
|
|
2022-10-22 02:26:14 -05:00
|
|
|
getCosignManifestURL := sig.upstreamURL
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
getCosignManifestURL.Path = path.Join(getCosignManifestURL.Path, "v2", repo, "manifests", cosignTag)
|
|
|
|
|
|
|
|
getCosignManifestURL.RawQuery = getCosignManifestURL.Query().Encode()
|
|
|
|
|
2022-10-22 02:26:14 -05:00
|
|
|
resp, err := sig.client.R().
|
2022-05-25 05:22:16 -05:00
|
|
|
SetHeader("Content-Type", "application/vnd.oci.image.manifest.v1+json").
|
|
|
|
Get(getCosignManifestURL.String())
|
2022-03-07 03:45:10 -05:00
|
|
|
if err != nil {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Error().Str("errorType", TypeOf(err)).
|
2022-04-21 03:09:08 -05:00
|
|
|
Err(err).Str("url", getCosignManifestURL.String()).
|
2022-03-07 03:45:10 -05:00
|
|
|
Msgf("couldn't get cosign manifest: %s", cosignTag)
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp.StatusCode() == http.StatusNotFound {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Info().Msgf("couldn't find any cosign signature from %s, status code: %d skipping",
|
2022-03-07 03:45:10 -05:00
|
|
|
getCosignManifestURL.String(), resp.StatusCode())
|
|
|
|
|
|
|
|
return nil, zerr.ErrSyncSignatureNotFound
|
|
|
|
} else if resp.IsError() {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Error().Str("errorType", TypeOf(zerr.ErrSyncSignature)).
|
2022-04-21 03:09:08 -05:00
|
|
|
Err(zerr.ErrSyncSignature).Msgf("couldn't get cosign signature from %s, status code: %d skipping",
|
2022-03-07 03:45:10 -05:00
|
|
|
getCosignManifestURL.String(), resp.StatusCode())
|
|
|
|
|
|
|
|
return nil, zerr.ErrSyncSignature
|
|
|
|
}
|
|
|
|
|
2022-03-21 12:37:23 -05:00
|
|
|
err = json.Unmarshal(resp.Body(), &cosignManifest)
|
2022-03-07 03:45:10 -05:00
|
|
|
if err != nil {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Error().Str("errorType", TypeOf(err)).
|
2022-04-21 03:09:08 -05:00
|
|
|
Err(err).Str("url", getCosignManifestURL.String()).
|
2022-03-07 03:45:10 -05:00
|
|
|
Msgf("couldn't unmarshal cosign manifest %s", cosignTag)
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-03-21 12:37:23 -05:00
|
|
|
return &cosignManifest, nil
|
2022-03-07 03:45:10 -05:00
|
|
|
}
|
|
|
|
|
2022-10-22 15:46:13 -05:00
|
|
|
func (sig *signaturesCopier) getNotaryRefs(repo, digestStr string) (ReferenceList, error) {
|
2022-03-07 03:45:10 -05:00
|
|
|
var referrers ReferenceList
|
|
|
|
|
2022-10-22 02:26:14 -05:00
|
|
|
getReferrersURL := sig.upstreamURL
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
// based on manifest digest get referrers
|
2022-03-24 07:25:14 -05:00
|
|
|
getReferrersURL.Path = path.Join(getReferrersURL.Path, constants.ArtifactSpecRoutePrefix,
|
2022-10-22 15:46:13 -05:00
|
|
|
repo, "manifests", digestStr, "referrers")
|
2022-03-24 07:25:14 -05:00
|
|
|
|
2022-03-07 03:45:10 -05:00
|
|
|
getReferrersURL.RawQuery = getReferrersURL.Query().Encode()
|
|
|
|
|
2022-10-22 02:26:14 -05:00
|
|
|
resp, err := sig.client.R().
|
2022-03-07 03:45:10 -05:00
|
|
|
SetHeader("Content-Type", "application/json").
|
|
|
|
SetQueryParam("artifactType", notreg.ArtifactTypeNotation).
|
|
|
|
Get(getReferrersURL.String())
|
|
|
|
if err != nil {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Error().Str("errorType", TypeOf(err)).
|
2022-04-21 03:09:08 -05:00
|
|
|
Err(err).Str("url", getReferrersURL.String()).Msg("couldn't get referrers")
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return referrers, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp.StatusCode() == http.StatusNotFound || resp.StatusCode() == http.StatusBadRequest {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Info().Msgf("couldn't find any notary signature from %s, status code: %d, skipping",
|
2022-03-07 03:45:10 -05:00
|
|
|
getReferrersURL.String(), resp.StatusCode())
|
|
|
|
|
|
|
|
return ReferenceList{}, zerr.ErrSyncSignatureNotFound
|
|
|
|
} else if resp.IsError() {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Error().Str("errorType", TypeOf(zerr.ErrSyncSignature)).
|
2022-04-21 03:09:08 -05:00
|
|
|
Err(zerr.ErrSyncSignature).Msgf("couldn't get notary signature from %s, status code: %d skipping",
|
2022-03-07 03:45:10 -05:00
|
|
|
getReferrersURL.String(), resp.StatusCode())
|
|
|
|
|
|
|
|
return ReferenceList{}, zerr.ErrSyncSignature
|
|
|
|
}
|
|
|
|
|
|
|
|
err = json.Unmarshal(resp.Body(), &referrers)
|
|
|
|
if err != nil {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Error().Str("errorType", TypeOf(err)).
|
2022-04-21 03:09:08 -05:00
|
|
|
Err(err).Str("url", getReferrersURL.String()).
|
2022-03-07 03:45:10 -05:00
|
|
|
Msgf("couldn't unmarshal notary signature")
|
|
|
|
|
|
|
|
return referrers, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return referrers, nil
|
|
|
|
}
|
|
|
|
|
2022-10-22 15:46:13 -05:00
|
|
|
func (sig *signaturesCopier) syncCosignSignature(localRepo, remoteRepo, digestStr string,
|
|
|
|
cosignManifest *ispec.Manifest,
|
2022-03-07 03:45:10 -05:00
|
|
|
) error {
|
2022-10-22 15:46:13 -05:00
|
|
|
cosignTag := getCosignTagFromImageDigest(digestStr)
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
// if no manifest found
|
|
|
|
if cosignManifest == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-10-22 15:46:13 -05:00
|
|
|
skipCosignSig, err := sig.canSkipCosignSignature(localRepo, digestStr, cosignManifest)
|
2022-10-22 02:26:14 -05:00
|
|
|
if err != nil {
|
|
|
|
sig.log.Error().Err(err).Msgf("couldn't check if the upstream image %s:%s cosign signature can be skipped",
|
2022-10-22 15:46:13 -05:00
|
|
|
remoteRepo, digestStr)
|
2022-10-22 02:26:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if skipCosignSig {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
imageStore := sig.storeController.GetImageStore(localRepo)
|
|
|
|
|
|
|
|
sig.log.Info().Msg("syncing cosign signatures")
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
for _, blob := range cosignManifest.Layers {
|
|
|
|
// get blob
|
2022-10-22 02:26:14 -05:00
|
|
|
getBlobURL := sig.upstreamURL
|
2022-03-07 03:45:10 -05:00
|
|
|
getBlobURL.Path = path.Join(getBlobURL.Path, "v2", remoteRepo, "blobs", blob.Digest.String())
|
|
|
|
getBlobURL.RawQuery = getBlobURL.Query().Encode()
|
|
|
|
|
2022-10-22 02:26:14 -05:00
|
|
|
resp, err := sig.client.R().SetDoNotParseResponse(true).Get(getBlobURL.String())
|
2022-03-07 03:45:10 -05:00
|
|
|
if err != nil {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Error().Str("errorType", TypeOf(err)).
|
2022-04-21 03:09:08 -05:00
|
|
|
Err(err).Msgf("couldn't get cosign blob: %s", blob.Digest.String())
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp.IsError() {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Info().Msgf("couldn't find cosign blob from %s, status code: %d", getBlobURL.String(), resp.StatusCode())
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return zerr.ErrSyncSignature
|
|
|
|
}
|
|
|
|
|
|
|
|
defer resp.RawBody().Close()
|
|
|
|
|
|
|
|
// push blob
|
2022-10-22 15:46:13 -05:00
|
|
|
_, _, err = imageStore.FullBlobUpload(localRepo, resp.RawBody(), blob.Digest)
|
2022-03-07 03:45:10 -05:00
|
|
|
if err != nil {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Error().Str("errorType", TypeOf(err)).
|
2022-04-21 03:09:08 -05:00
|
|
|
Err(err).Msg("couldn't upload cosign blob")
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// get config blob
|
2022-10-22 02:26:14 -05:00
|
|
|
getBlobURL := sig.upstreamURL
|
2022-03-07 03:45:10 -05:00
|
|
|
getBlobURL.Path = path.Join(getBlobURL.Path, "v2", remoteRepo, "blobs", cosignManifest.Config.Digest.String())
|
|
|
|
getBlobURL.RawQuery = getBlobURL.Query().Encode()
|
|
|
|
|
2022-10-22 02:26:14 -05:00
|
|
|
resp, err := sig.client.R().SetDoNotParseResponse(true).Get(getBlobURL.String())
|
2022-03-07 03:45:10 -05:00
|
|
|
if err != nil {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Error().Str("errorType", TypeOf(err)).
|
2022-04-21 03:09:08 -05:00
|
|
|
Err(err).Msgf("couldn't get cosign config blob: %s", getBlobURL.String())
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp.IsError() {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Info().Msgf("couldn't find cosign config blob from %s, status code: %d",
|
|
|
|
getBlobURL.String(), resp.StatusCode())
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return zerr.ErrSyncSignature
|
|
|
|
}
|
|
|
|
|
|
|
|
defer resp.RawBody().Close()
|
|
|
|
|
|
|
|
// push config blob
|
2022-10-22 15:46:13 -05:00
|
|
|
_, _, err = imageStore.FullBlobUpload(localRepo, resp.RawBody(), cosignManifest.Config.Digest)
|
2022-03-07 03:45:10 -05:00
|
|
|
if err != nil {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Error().Str("errorType", TypeOf(err)).
|
2022-04-21 03:09:08 -05:00
|
|
|
Err(err).Msg("couldn't upload cosign config blob")
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
cosignManifestBuf, err := json.Marshal(cosignManifest)
|
|
|
|
if err != nil {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Error().Str("errorType", TypeOf(err)).
|
2022-04-21 03:09:08 -05:00
|
|
|
Err(err).Msg("couldn't marshal cosign manifest")
|
2022-03-07 03:45:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// push manifest
|
2022-06-24 08:08:47 -05:00
|
|
|
_, err = imageStore.PutImageManifest(localRepo, cosignTag,
|
|
|
|
ispec.MediaTypeImageManifest, cosignManifestBuf)
|
2022-03-07 03:45:10 -05:00
|
|
|
if err != nil {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Error().Str("errorType", TypeOf(err)).
|
2022-04-21 03:09:08 -05:00
|
|
|
Err(err).Msg("couldn't upload cosign manifest")
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-10-22 15:46:13 -05:00
|
|
|
sig.log.Info().Msgf("successfully synced cosign signature for repo %s digest %s", localRepo, digestStr)
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-10-22 15:46:13 -05:00
|
|
|
func (sig *signaturesCopier) syncNotarySignature(localRepo, remoteRepo, digestStr string, referrers ReferenceList,
|
2022-03-21 12:37:23 -05:00
|
|
|
) error {
|
2022-03-07 03:45:10 -05:00
|
|
|
if len(referrers.References) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-10-22 15:46:13 -05:00
|
|
|
skipNotarySig, err := sig.canSkipNotarySignature(localRepo, digestStr, referrers)
|
2022-10-22 02:26:14 -05:00
|
|
|
if skipNotarySig || err != nil {
|
|
|
|
sig.log.Error().Err(err).Msgf("couldn't check if the upstream image %s:%s notary signature can be skipped",
|
2022-10-22 15:46:13 -05:00
|
|
|
remoteRepo, digestStr)
|
2022-10-22 02:26:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if skipNotarySig {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
imageStore := sig.storeController.GetImageStore(localRepo)
|
|
|
|
|
|
|
|
sig.log.Info().Msg("syncing notary signatures")
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
for _, ref := range referrers.References {
|
|
|
|
// get referrer manifest
|
2022-10-22 02:26:14 -05:00
|
|
|
getRefManifestURL := sig.upstreamURL
|
2022-03-07 03:45:10 -05:00
|
|
|
getRefManifestURL.Path = path.Join(getRefManifestURL.Path, "v2", remoteRepo, "manifests", ref.Digest.String())
|
|
|
|
getRefManifestURL.RawQuery = getRefManifestURL.Query().Encode()
|
|
|
|
|
2022-10-22 02:26:14 -05:00
|
|
|
resp, err := sig.client.R().
|
2022-03-07 03:45:10 -05:00
|
|
|
Get(getRefManifestURL.String())
|
|
|
|
if err != nil {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Error().Str("errorType", TypeOf(err)).
|
2022-04-21 03:09:08 -05:00
|
|
|
Err(err).Msgf("couldn't get notary manifest: %s", getRefManifestURL.String())
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// read manifest
|
2022-03-21 12:37:23 -05:00
|
|
|
var artifactManifest artifactspec.Manifest
|
2022-03-07 03:45:10 -05:00
|
|
|
|
2022-03-21 12:37:23 -05:00
|
|
|
err = json.Unmarshal(resp.Body(), &artifactManifest)
|
2022-03-07 03:45:10 -05:00
|
|
|
if err != nil {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Error().Str("errorType", TypeOf(err)).
|
2022-04-21 03:09:08 -05:00
|
|
|
Err(err).Msgf("couldn't unmarshal notary manifest: %s", getRefManifestURL.String())
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-03-21 12:37:23 -05:00
|
|
|
for _, blob := range artifactManifest.Blobs {
|
2022-10-22 02:26:14 -05:00
|
|
|
getBlobURL := sig.upstreamURL
|
2022-03-07 03:45:10 -05:00
|
|
|
getBlobURL.Path = path.Join(getBlobURL.Path, "v2", remoteRepo, "blobs", blob.Digest.String())
|
|
|
|
getBlobURL.RawQuery = getBlobURL.Query().Encode()
|
|
|
|
|
2022-10-22 02:26:14 -05:00
|
|
|
resp, err := sig.client.R().SetDoNotParseResponse(true).Get(getBlobURL.String())
|
2022-03-07 03:45:10 -05:00
|
|
|
if err != nil {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Error().Str("errorType", TypeOf(err)).
|
2022-04-21 03:09:08 -05:00
|
|
|
Err(err).Msgf("couldn't get notary blob: %s", getBlobURL.String())
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
defer resp.RawBody().Close()
|
|
|
|
|
|
|
|
if resp.IsError() {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Info().Msgf("couldn't find notary blob from %s, status code: %d",
|
2022-03-07 03:45:10 -05:00
|
|
|
getBlobURL.String(), resp.StatusCode())
|
|
|
|
|
|
|
|
return zerr.ErrSyncSignature
|
|
|
|
}
|
|
|
|
|
2022-10-22 15:46:13 -05:00
|
|
|
_, _, err = imageStore.FullBlobUpload(localRepo, resp.RawBody(), blob.Digest)
|
2022-03-07 03:45:10 -05:00
|
|
|
if err != nil {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Error().Str("errorType", TypeOf(err)).
|
2022-04-21 03:09:08 -05:00
|
|
|
Err(err).Msg("couldn't upload notary sig blob")
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = imageStore.PutImageManifest(localRepo, ref.Digest.String(),
|
|
|
|
artifactspec.MediaTypeArtifactManifest, resp.Body())
|
|
|
|
if err != nil {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Error().Str("errorType", TypeOf(err)).
|
2022-04-21 03:09:08 -05:00
|
|
|
Err(err).Msg("couldn't upload notary sig manifest")
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-22 15:46:13 -05:00
|
|
|
sig.log.Info().Msgf("successfully synced notary signature for repo %s digest %s", localRepo, digestStr)
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-10-22 15:46:13 -05:00
|
|
|
func (sig *signaturesCopier) canSkipNotarySignature(localRepo, digestStr string, refs ReferenceList,
|
2022-03-21 12:37:23 -05:00
|
|
|
) (bool, error) {
|
2022-10-22 02:26:14 -05:00
|
|
|
imageStore := sig.storeController.GetImageStore(localRepo)
|
2022-10-22 15:46:13 -05:00
|
|
|
digest := godigest.Digest(digestStr)
|
2022-10-22 02:26:14 -05:00
|
|
|
|
2022-03-07 03:45:10 -05:00
|
|
|
// check notary signature already synced
|
|
|
|
if len(refs.References) > 0 {
|
2022-11-08 03:38:16 -05:00
|
|
|
localRefs, err := imageStore.GetOrasReferrers(localRepo, digest, notreg.ArtifactTypeNotation)
|
2022-03-07 03:45:10 -05:00
|
|
|
if err != nil {
|
|
|
|
if errors.Is(err, zerr.ErrManifestNotFound) {
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Error().Str("errorType", TypeOf(err)).
|
2022-10-22 15:46:13 -05:00
|
|
|
Err(err).Msgf("couldn't get local notary signature %s:%s manifest", localRepo, digestStr)
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if !artifactDescriptorsEqual(localRefs, refs.References) {
|
2022-10-22 15:46:13 -05:00
|
|
|
sig.log.Info().Msgf("upstream notary signatures %s:%s changed, syncing again", localRepo, digestStr)
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-22 15:46:13 -05:00
|
|
|
sig.log.Info().Msgf("skipping notary signature %s:%s, already synced", localRepo, digestStr)
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
2022-10-22 15:46:13 -05:00
|
|
|
func (sig *signaturesCopier) canSkipCosignSignature(localRepo, digestStr string, cosignManifest *ispec.Manifest,
|
2022-03-21 12:37:23 -05:00
|
|
|
) (bool, error) {
|
2022-10-22 02:26:14 -05:00
|
|
|
imageStore := sig.storeController.GetImageStore(localRepo)
|
2022-03-07 03:45:10 -05:00
|
|
|
// check cosign signature already synced
|
|
|
|
if cosignManifest != nil {
|
|
|
|
var localCosignManifest 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 */
|
2022-10-22 15:46:13 -05:00
|
|
|
cosignManifestTag := getCosignTagFromImageDigest(digestStr)
|
2022-03-07 03:45:10 -05:00
|
|
|
|
2022-10-22 02:26:14 -05:00
|
|
|
localCosignManifestBuf, _, _, err := imageStore.GetImageManifest(localRepo, cosignManifestTag)
|
2022-03-07 03:45:10 -05:00
|
|
|
if err != nil {
|
|
|
|
if errors.Is(err, zerr.ErrManifestNotFound) {
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Error().Str("errorType", TypeOf(err)).
|
2022-10-22 15:46:13 -05:00
|
|
|
Err(err).Msgf("couldn't get local cosign %s:%s manifest", localRepo, digestStr)
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = json.Unmarshal(localCosignManifestBuf, &localCosignManifest)
|
|
|
|
if err != nil {
|
2022-10-22 02:26:14 -05:00
|
|
|
sig.log.Error().Str("errorType", TypeOf(err)).
|
2022-10-22 15:46:13 -05:00
|
|
|
Err(err).Msgf("couldn't unmarshal local cosign signature %s:%s manifest", localRepo, digestStr)
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if !manifestsEqual(localCosignManifest, *cosignManifest) {
|
2022-10-22 15:46:13 -05:00
|
|
|
sig.log.Info().Msgf("upstream cosign signatures %s:%s changed, syncing again", localRepo, digestStr)
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-22 15:46:13 -05:00
|
|
|
sig.log.Info().Msgf("skipping cosign signature %s:%s, already synced", localRepo, digestStr)
|
2022-03-07 03:45:10 -05:00
|
|
|
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// sync feature will try to pull cosign signature because for sync cosign signature is just an image
|
|
|
|
// this function will check if tag is a cosign tag.
|
|
|
|
func isCosignTag(tag string) bool {
|
2022-04-14 05:57:09 -05:00
|
|
|
if strings.HasPrefix(tag, "sha256-") && strings.HasSuffix(tag, remote.SignatureTagSuffix) {
|
2022-03-07 03:45:10 -05:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2022-10-22 15:46:13 -05:00
|
|
|
func getCosignTagFromImageDigest(digestStr string) string {
|
|
|
|
if !isCosignTag(digestStr) {
|
|
|
|
return strings.Replace(digestStr, ":", "-", 1) + "." + remote.SignatureTagSuffix
|
2022-03-07 03:45:10 -05:00
|
|
|
}
|
|
|
|
|
2022-10-22 15:46:13 -05:00
|
|
|
return digestStr
|
2022-03-07 03:45:10 -05:00
|
|
|
}
|