mirror of
https://github.com/project-zot/zot.git
synced 2026-06-16 04:17:55 +08:00
fix(oras)!: remove ORAS artifact references support (#2294)
* fix(oras)!: remove ORAS artifact references support ORAS artifacts/references predated OCI dist-spec 1.1.0 which now has the same functionality and likely to see wider adoption. Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com> * test: update to released official images So that they are unlikely to be deleted. *-rc images may be cleaned up over time. Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com> --------- Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com>
This commit is contained in:
committed by
GitHub
parent
5039128723
commit
18235ca254
@@ -2,7 +2,6 @@ package constants
|
||||
|
||||
// references type.
|
||||
const (
|
||||
Oras = "OrasReference"
|
||||
Cosign = "CosignSignature"
|
||||
OCI = "OCIReference"
|
||||
Tag = "TagReference"
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
//go:build sync
|
||||
// +build sync
|
||||
|
||||
package references
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
godigest "github.com/opencontainers/go-digest"
|
||||
oras "github.com/oras-project/artifacts-spec/specs-go/v1"
|
||||
|
||||
zerr "zotregistry.dev/zot/errors"
|
||||
apiConstants "zotregistry.dev/zot/pkg/api/constants"
|
||||
"zotregistry.dev/zot/pkg/common"
|
||||
"zotregistry.dev/zot/pkg/extensions/sync/constants"
|
||||
client "zotregistry.dev/zot/pkg/extensions/sync/httpclient"
|
||||
"zotregistry.dev/zot/pkg/log"
|
||||
"zotregistry.dev/zot/pkg/meta"
|
||||
mTypes "zotregistry.dev/zot/pkg/meta/types"
|
||||
"zotregistry.dev/zot/pkg/storage"
|
||||
)
|
||||
|
||||
type ReferenceList struct {
|
||||
References []oras.Descriptor `json:"references"`
|
||||
}
|
||||
|
||||
type ORASReferences struct {
|
||||
client *client.Client
|
||||
storeController storage.StoreController
|
||||
metaDB mTypes.MetaDB
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
func NewORASReferences(httpClient *client.Client, storeController storage.StoreController,
|
||||
metaDB mTypes.MetaDB, log log.Logger,
|
||||
) ORASReferences {
|
||||
return ORASReferences{
|
||||
client: httpClient,
|
||||
storeController: storeController,
|
||||
metaDB: metaDB,
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
func (ref ORASReferences) Name() string {
|
||||
return constants.Oras
|
||||
}
|
||||
|
||||
func (ref ORASReferences) IsSigned(ctx context.Context, remoteRepo, subjectDigestStr string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (ref ORASReferences) canSkipReferences(localRepo, subjectDigestStr string, referrers ReferenceList) (bool, error) {
|
||||
imageStore := ref.storeController.GetImageStore(localRepo)
|
||||
digest := godigest.Digest(subjectDigestStr)
|
||||
|
||||
// check oras artifacts already synced
|
||||
if len(referrers.References) > 0 {
|
||||
localRefs, err := imageStore.GetOrasReferrers(localRepo, digest, "")
|
||||
if err != nil {
|
||||
if errors.Is(err, zerr.ErrManifestNotFound) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
ref.log.Error().Str("errorType", common.TypeOf(err)).Str("repository", localRepo).
|
||||
Str("subject", subjectDigestStr).
|
||||
Err(err).Msg("couldn't get local ORAS artifact for image")
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !artifactDescriptorsEqual(localRefs, referrers.References) {
|
||||
ref.log.Info().Str("repository", localRepo).Str("subject", subjectDigestStr).
|
||||
Msg("upstream ORAS artifacts for image changed, syncing again")
|
||||
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
ref.log.Info().Str("repository", localRepo).Str("subject", subjectDigestStr).
|
||||
Msg("skipping ORAS artifact for image, already synced")
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (ref ORASReferences) SyncReferences(ctx context.Context, localRepo, remoteRepo, subjectDigestStr string) (
|
||||
[]godigest.Digest, error,
|
||||
) {
|
||||
refsDigests := make([]godigest.Digest, 0, 10)
|
||||
|
||||
referrers, err := ref.getReferenceList(ctx, remoteRepo, subjectDigestStr)
|
||||
if err != nil {
|
||||
return refsDigests, err
|
||||
}
|
||||
|
||||
skipORASRefs, err := ref.canSkipReferences(localRepo, subjectDigestStr, referrers)
|
||||
if err != nil {
|
||||
ref.log.Error().Err(err).Str("repository", localRepo).Str("subject", subjectDigestStr).
|
||||
Msg("couldn't check if ORAS artifact for image can be skipped")
|
||||
}
|
||||
|
||||
if skipORASRefs {
|
||||
for _, man := range referrers.References {
|
||||
refsDigests = append(refsDigests, man.Digest)
|
||||
}
|
||||
|
||||
return refsDigests, nil
|
||||
}
|
||||
|
||||
imageStore := ref.storeController.GetImageStore(localRepo)
|
||||
|
||||
ref.log.Info().Str("repository", localRepo).Str("subject", subjectDigestStr).
|
||||
Msg("syncing ORAS artifacts for image")
|
||||
|
||||
for _, referrer := range referrers.References {
|
||||
var artifactManifest oras.Manifest
|
||||
|
||||
orasBuf, _, statusCode, err := ref.client.MakeGetRequest(ctx, &artifactManifest, oras.MediaTypeDescriptor,
|
||||
"v2", remoteRepo, "manifests", referrer.Digest.String())
|
||||
if err != nil {
|
||||
if statusCode == http.StatusNotFound {
|
||||
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 refsDigests, err
|
||||
}
|
||||
|
||||
for _, blob := range artifactManifest.Blobs {
|
||||
if err := syncBlob(ctx, ref.client, imageStore, localRepo, remoteRepo, blob.Digest, ref.log); err != nil {
|
||||
return refsDigests, err
|
||||
}
|
||||
}
|
||||
|
||||
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 refsDigests, err
|
||||
}
|
||||
|
||||
refsDigests = append(refsDigests, referenceDigest)
|
||||
|
||||
if ref.metaDB != nil {
|
||||
ref.log.Debug().Str("repository", localRepo).Str("subject", subjectDigestStr).Str("component", "metadb").
|
||||
Msg("trying to sync oras artifact for image")
|
||||
|
||||
err := meta.SetImageMetaFromInput(context.Background(), localRepo, //nolint:contextcheck
|
||||
referenceDigest.String(), referrer.MediaType,
|
||||
referenceDigest, orasBuf, ref.storeController.GetImageStore(localRepo),
|
||||
ref.metaDB, ref.log)
|
||||
if err != nil {
|
||||
return refsDigests, fmt.Errorf("failed to set metadata in db for oras artifact '%s@%s': %w",
|
||||
localRepo, subjectDigestStr, err)
|
||||
}
|
||||
|
||||
ref.log.Info().Str("repository", localRepo).Str("subject", subjectDigestStr).Str("component", "metadb").
|
||||
Msg("successfully added oras artifacts to MetaDB for image")
|
||||
}
|
||||
}
|
||||
|
||||
ref.log.Info().Str("repository", localRepo).Str("subject", subjectDigestStr).
|
||||
Msg("successfully synced oras artifacts for image")
|
||||
|
||||
return refsDigests, nil
|
||||
}
|
||||
|
||||
func (ref ORASReferences) getReferenceList(ctx context.Context, repo, subjectDigestStr string) (ReferenceList, error) {
|
||||
var referrers ReferenceList
|
||||
|
||||
_, _, statusCode, err := ref.client.MakeGetRequest(ctx, &referrers, "application/json",
|
||||
apiConstants.ArtifactSpecRoutePrefix, repo, "manifests", subjectDigestStr, "referrers")
|
||||
if err != nil {
|
||||
if statusCode == http.StatusNotFound || statusCode == http.StatusBadRequest {
|
||||
ref.log.Debug().Str("repository", repo).Str("subject", subjectDigestStr).Err(err).
|
||||
Msg("couldn't find any ORAS artifact for image")
|
||||
|
||||
return referrers, zerr.ErrSyncReferrerNotFound
|
||||
}
|
||||
|
||||
return referrers, err
|
||||
}
|
||||
|
||||
return referrers, nil
|
||||
}
|
||||
@@ -12,7 +12,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/static"
|
||||
|
||||
zerr "zotregistry.dev/zot/errors"
|
||||
@@ -27,7 +26,7 @@ import (
|
||||
)
|
||||
|
||||
type Reference interface {
|
||||
// Returns name of reference (OCIReference/CosignReference/OrasReference)
|
||||
// Returns name of reference (OCIReference/CosignReference)
|
||||
Name() string
|
||||
// Returns whether or not image is signed
|
||||
IsSigned(ctx context.Context, upstreamRepo, subjectDigestStr string) bool
|
||||
@@ -49,7 +48,6 @@ func NewReferences(httpClient *client.Client, storeController storage.StoreContr
|
||||
refs.referenceList = append(refs.referenceList, NewCosignReference(httpClient, storeController, metaDB, log))
|
||||
refs.referenceList = append(refs.referenceList, NewTagReferences(httpClient, storeController, metaDB, log))
|
||||
refs.referenceList = append(refs.referenceList, NewOciReferences(httpClient, storeController, metaDB, log))
|
||||
refs.referenceList = append(refs.referenceList, NewORASReferences(httpClient, storeController, metaDB, log))
|
||||
|
||||
return refs
|
||||
}
|
||||
@@ -81,7 +79,7 @@ func (refs References) syncAll(ctx context.Context, localRepo, upstreamRepo,
|
||||
// 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 each reference type(cosign/oci reference)
|
||||
for _, ref := range refs.referenceList {
|
||||
supported, ok := refs.features.Get(ref.Name(), upstreamRepo)
|
||||
if !supported && ok {
|
||||
@@ -186,23 +184,6 @@ func manifestsEqual(manifest1, manifest2 ispec.Manifest) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func artifactDescriptorsEqual(desc1, desc2 []artifactspec.Descriptor) bool {
|
||||
if len(desc1) != len(desc2) {
|
||||
return false
|
||||
}
|
||||
|
||||
for id, desc := range desc1 {
|
||||
if desc.Digest != desc2[id].Digest ||
|
||||
desc.Size != desc2[id].Size ||
|
||||
desc.MediaType != desc2[id].MediaType ||
|
||||
desc.ArtifactType != desc2[id].ArtifactType {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func descriptorsEqual(desc1, desc2 []ispec.Descriptor) bool {
|
||||
if len(desc1) != len(desc2) {
|
||||
return false
|
||||
|
||||
@@ -10,7 +10,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/smartystreets/goconvey/convey"
|
||||
|
||||
zerr "zotregistry.dev/zot/errors"
|
||||
@@ -134,45 +133,6 @@ func TestReferrersTag(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestORAS(t *testing.T) {
|
||||
Convey("trigger errors", t, func() {
|
||||
cfg := client.Config{
|
||||
URL: "url",
|
||||
TLSVerify: false,
|
||||
}
|
||||
|
||||
client, err := client.New(cfg, log.NewLogger("debug", ""))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
orasRefs := []artifactspec.Descriptor{
|
||||
{
|
||||
MediaType: "oras",
|
||||
ArtifactType: "oras",
|
||||
Digest: "digest1",
|
||||
},
|
||||
}
|
||||
|
||||
oras := NewORASReferences(client, storage.StoreController{DefaultStore: mocks.MockedImageStore{
|
||||
GetOrasReferrersFn: func(repo string, digest godigest.Digest, artifactType string) (
|
||||
[]artifactspec.Descriptor, error,
|
||||
) {
|
||||
return orasRefs, nil
|
||||
},
|
||||
}}, nil, log.NewLogger("debug", ""))
|
||||
|
||||
// trigger artifactDescriptors not equal
|
||||
ok, err := oras.canSkipReferences("repo", "tag", ReferenceList{[]artifactspec.Descriptor{
|
||||
{
|
||||
MediaType: "oras",
|
||||
ArtifactType: "oras",
|
||||
Digest: "digest2",
|
||||
},
|
||||
}})
|
||||
So(err, ShouldBeNil)
|
||||
So(ok, ShouldBeFalse)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSyncManifest(t *testing.T) {
|
||||
Convey("sync manifest not found err", t, func() {
|
||||
cfg := client.Config{
|
||||
@@ -344,99 +304,3 @@ func TestCompareManifest(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestCompareArtifactRefs(t *testing.T) {
|
||||
testCases := []struct {
|
||||
refs1 []artifactspec.Descriptor
|
||||
refs2 []artifactspec.Descriptor
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
refs1: []artifactspec.Descriptor{
|
||||
{
|
||||
Digest: "digest1",
|
||||
},
|
||||
},
|
||||
refs2: []artifactspec.Descriptor{
|
||||
{
|
||||
Digest: "digest2",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
refs1: []artifactspec.Descriptor{
|
||||
{
|
||||
Digest: "digest",
|
||||
},
|
||||
},
|
||||
refs2: []artifactspec.Descriptor{
|
||||
{
|
||||
Digest: "digest",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
refs1: []artifactspec.Descriptor{
|
||||
{
|
||||
Digest: "digest",
|
||||
},
|
||||
{
|
||||
Digest: "digest2",
|
||||
},
|
||||
},
|
||||
refs2: []artifactspec.Descriptor{
|
||||
{
|
||||
Digest: "digest",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
refs1: []artifactspec.Descriptor{
|
||||
{
|
||||
Digest: "digest1",
|
||||
},
|
||||
{
|
||||
Digest: "digest2",
|
||||
},
|
||||
},
|
||||
refs2: []artifactspec.Descriptor{
|
||||
{
|
||||
Digest: "digest1",
|
||||
},
|
||||
{
|
||||
Digest: "digest2",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
refs1: []artifactspec.Descriptor{
|
||||
{
|
||||
Digest: "digest",
|
||||
},
|
||||
{
|
||||
Digest: "digest1",
|
||||
},
|
||||
},
|
||||
refs2: []artifactspec.Descriptor{
|
||||
{
|
||||
Digest: "digest1",
|
||||
},
|
||||
{
|
||||
Digest: "digest2",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
Convey("Test manifestsEqual()", t, func() {
|
||||
for _, test := range testCases {
|
||||
actualResult := artifactDescriptorsEqual(test.refs1, test.refs2)
|
||||
So(actualResult, ShouldEqual, test.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"reflect"
|
||||
"strings"
|
||||
@@ -26,7 +25,6 @@ import (
|
||||
godigest "github.com/opencontainers/go-digest"
|
||||
"github.com/opencontainers/image-spec/specs-go"
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1"
|
||||
"github.com/sigstore/cosign/v2/cmd/cosign/cli/attach"
|
||||
"github.com/sigstore/cosign/v2/cmd/cosign/cli/generate"
|
||||
"github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
|
||||
@@ -229,297 +227,6 @@ func makeDownstreamServer(
|
||||
return dctlr, destBaseURL, destDir, client
|
||||
}
|
||||
|
||||
func TestORAS(t *testing.T) {
|
||||
Convey("Verify sync on demand for oras objects", t, func() {
|
||||
sctlr, srcBaseURL, _, _, srcClient := makeUpstreamServer(t, false, false)
|
||||
|
||||
scm := test.NewControllerManager(sctlr)
|
||||
scm.StartAndWait(sctlr.Config.HTTP.Port)
|
||||
defer scm.StopServer()
|
||||
|
||||
content := []byte("{\"name\":\"foo\",\"value\":\"bar\"}")
|
||||
|
||||
fileDir := t.TempDir()
|
||||
|
||||
err := os.WriteFile(path.Join(fileDir, "config.json"), content, 0o600)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
content = []byte("helloworld")
|
||||
|
||||
err = os.WriteFile(path.Join(fileDir, "artifact.txt"), content, 0o600)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cmd := exec.Command("oras", "version")
|
||||
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
srcURL := strings.Join([]string{sctlr.Server.Addr, "/oras-artifact:v2"}, "")
|
||||
|
||||
cmd = exec.Command("oras", "push", "--plain-http", srcURL, "--config",
|
||||
"config.json:application/vnd.acme.rocket.config.v1+json", "artifact.txt:text/plain", "-d", "-v")
|
||||
cmd.Dir = fileDir
|
||||
|
||||
// Pushing ORAS artifact to upstream
|
||||
err = cmd.Run()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
var tlsVerify bool
|
||||
|
||||
regex := ".*"
|
||||
|
||||
syncRegistryConfig := syncconf.RegistryConfig{
|
||||
Content: []syncconf.Content{
|
||||
{
|
||||
Prefix: "oras-artifact",
|
||||
Tags: &syncconf.Tags{
|
||||
Regex: ®ex,
|
||||
},
|
||||
},
|
||||
},
|
||||
URLs: []string{srcBaseURL},
|
||||
TLSVerify: &tlsVerify,
|
||||
CertDir: "",
|
||||
OnDemand: true,
|
||||
}
|
||||
|
||||
defaultVal := true
|
||||
syncConfig := &syncconf.Config{
|
||||
Enable: &defaultVal,
|
||||
Registries: []syncconf.RegistryConfig{syncRegistryConfig},
|
||||
}
|
||||
|
||||
dctlr, destBaseURL, _, destClient := makeDownstreamServer(t, false, syncConfig)
|
||||
|
||||
dcm := test.NewControllerManager(dctlr)
|
||||
dcm.StartAndWait(dctlr.Config.HTTP.Port)
|
||||
defer dcm.StopServer()
|
||||
|
||||
resp, _ := srcClient.R().Get(srcBaseURL + "/v2/" + "oras-artifact" + "/manifests/v2")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
|
||||
resp, err = destClient.R().Get(destBaseURL + "/v2/" + "oras-artifact" + "/manifests/v2")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
|
||||
destURL := strings.Join([]string{dctlr.Server.Addr, "/oras-artifact:v2"}, "")
|
||||
cmd = exec.Command("oras", "pull", "--plain-http", destURL, "-d", "-v")
|
||||
destDir := t.TempDir()
|
||||
cmd.Dir = destDir
|
||||
// pulling oras artifact from dest server
|
||||
err = cmd.Run()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
cmd = exec.Command("grep", "helloworld", "artifact.txt")
|
||||
cmd.Dir = destDir
|
||||
output, err := cmd.CombinedOutput()
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(string(output), ShouldContainSubstring, "helloworld")
|
||||
})
|
||||
|
||||
Convey("Verify get and sync oras refs", t, func() {
|
||||
updateDuration, _ := time.ParseDuration("30m")
|
||||
|
||||
sctlr, srcBaseURL, srcDir, _, _ := makeUpstreamServer(t, false, false)
|
||||
scm := test.NewControllerManager(sctlr)
|
||||
scm.StartAndWait(sctlr.Config.HTTP.Port)
|
||||
defer scm.StopServer()
|
||||
|
||||
repoName := testImage
|
||||
var digest godigest.Digest
|
||||
So(func() { digest = pushRepo(srcBaseURL, repoName) }, ShouldNotPanic)
|
||||
|
||||
regex := ".*"
|
||||
var semver bool
|
||||
var tlsVerify bool
|
||||
|
||||
syncRegistryConfig := syncconf.RegistryConfig{
|
||||
Content: []syncconf.Content{
|
||||
{
|
||||
Prefix: repoName,
|
||||
Tags: &syncconf.Tags{
|
||||
Regex: ®ex,
|
||||
Semver: &semver,
|
||||
},
|
||||
},
|
||||
},
|
||||
URLs: []string{srcBaseURL},
|
||||
PollInterval: updateDuration,
|
||||
TLSVerify: &tlsVerify,
|
||||
CertDir: "",
|
||||
OnDemand: true,
|
||||
}
|
||||
|
||||
defaultVal := true
|
||||
syncConfig := &syncconf.Config{
|
||||
Enable: &defaultVal,
|
||||
Registries: []syncconf.RegistryConfig{syncRegistryConfig},
|
||||
}
|
||||
|
||||
dctlr, destBaseURL, destDir, destClient := makeDownstreamServer(t, false, syncConfig)
|
||||
|
||||
dcm := test.NewControllerManager(dctlr)
|
||||
dcm.StartAndWait(dctlr.Config.HTTP.Port)
|
||||
defer dcm.StopServer()
|
||||
|
||||
// wait for sync
|
||||
var destTagsList TagsList
|
||||
|
||||
for {
|
||||
resp, err := destClient.R().Get(destBaseURL + "/v2/" + repoName + "/tags/list")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(resp.Body(), &destTagsList)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if len(destTagsList.Tags) > 0 {
|
||||
break
|
||||
}
|
||||
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
// get oras refs from downstream, should be synced
|
||||
getORASReferrersURL := destBaseURL + path.Join("/oras/artifacts/v1/", repoName, "manifests", digest.String(), "referrers") //nolint:lll
|
||||
|
||||
resp, err := resty.R().Get(getORASReferrersURL)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeEmpty)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusNotFound)
|
||||
|
||||
err = os.Chmod(path.Join(destDir, testImage, "index.json"), 0o000)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
resp, err = resty.R().Get(getORASReferrersURL)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeEmpty)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusInternalServerError)
|
||||
|
||||
err = os.Chmod(path.Join(destDir, testImage, "index.json"), 0o755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// get manifest digest from source
|
||||
resp, err = destClient.R().Get(srcBaseURL + "/v2/" + testImage + "/manifests/" + digest.String())
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
|
||||
digest = godigest.FromBytes(resp.Body())
|
||||
|
||||
// layer
|
||||
layer := []byte("blob content")
|
||||
blobDigest := pushBlob(srcBaseURL, repoName, layer)
|
||||
|
||||
// config
|
||||
_ = pushBlob(srcBaseURL, repoName, ispec.DescriptorEmptyJSON.Data)
|
||||
|
||||
artifactManifest := ispec.Manifest{
|
||||
Versioned: specs.Versioned{
|
||||
SchemaVersion: 2,
|
||||
},
|
||||
MediaType: artifactspec.MediaTypeArtifactManifest,
|
||||
ArtifactType: "application/vnd.oras.artifact",
|
||||
Layers: []ispec.Descriptor{
|
||||
{
|
||||
MediaType: "application/octet-stream",
|
||||
Digest: blobDigest,
|
||||
Size: int64(len(layer)),
|
||||
},
|
||||
},
|
||||
Config: ispec.DescriptorEmptyJSON,
|
||||
Subject: &ispec.Descriptor{
|
||||
MediaType: "application/vnd.oci.image.manifest.v1+json",
|
||||
Digest: digest,
|
||||
Size: int64(len(resp.Body())),
|
||||
},
|
||||
}
|
||||
|
||||
artManifestBlob, err := json.Marshal(artifactManifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
artifactDigest := godigest.FromBytes(artManifestBlob)
|
||||
|
||||
// put OCI reference artifact mediaType artifact
|
||||
_, err = resty.R().SetHeader("Content-Type", artifactspec.MediaTypeArtifactManifest).
|
||||
SetBody(artManifestBlob).Put(srcBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", repoName, artifactDigest.String()))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = os.Chmod(path.Join(destDir, testImage, "index.json"), 0o000)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
resp, err = resty.R().Get(getORASReferrersURL)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeEmpty)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusInternalServerError)
|
||||
|
||||
err = os.Chmod(path.Join(destDir, testImage, "index.json"), 0o755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// trigger getORASRefs err
|
||||
err = os.Chmod(path.Join(srcDir, testImage, "blobs/sha256", artifactDigest.Encoded()), 0o000)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = os.RemoveAll(path.Join(destDir, testImage))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
resp, err = resty.R().Get(destBaseURL + "/v2/" + testImage + "/manifests/" + digest.String())
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeEmpty)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
|
||||
err = os.Chmod(path.Join(srcDir, testImage, "blobs/sha256", artifactDigest.Encoded()), 0o755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
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)
|
||||
|
||||
err = os.RemoveAll(path.Join(destDir, repoName))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = os.WriteFile(path.Join(srcDir, repoName, "blobs", "sha256", artifactDigest.Encoded()),
|
||||
[]byte("wrong content"), 0o600)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
_, err = resty.R().SetHeader("Content-Type", artifactspec.MediaTypeArtifactManifest).
|
||||
SetBody(artManifestBlob).Put(srcBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", repoName, artifactDigest.String()))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
resp, err = resty.R().Get(getORASReferrersURL)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeEmpty)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusNotFound)
|
||||
|
||||
waitSyncFinish(dctlr.Config.Log.Output)
|
||||
})
|
||||
}
|
||||
|
||||
func TestOnDemand(t *testing.T) {
|
||||
Convey("Verify sync on demand feature", t, func() {
|
||||
sctlr, srcBaseURL, _, _, srcClient := makeUpstreamServer(t, false, false)
|
||||
@@ -792,27 +499,6 @@ func TestOnDemand(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusCreated)
|
||||
|
||||
// add ORAS Ref
|
||||
ORASRefManifest := artifactspec.Manifest{
|
||||
Subject: &artifactspec.Descriptor{
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Digest: manifestDigest,
|
||||
},
|
||||
Blobs: []artifactspec.Descriptor{},
|
||||
MediaType: artifactspec.MediaTypeArtifactManifest,
|
||||
}
|
||||
|
||||
ORASRefManifestBlob, err := json.Marshal(ORASRefManifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
resp, err = resty.R().
|
||||
SetHeader("Content-type", artifactspec.MediaTypeArtifactManifest).
|
||||
SetBody(ORASRefManifestBlob).
|
||||
Put(srcBaseURL + "/v2/remote-repo/manifests/oras.ref")
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusCreated)
|
||||
|
||||
//------- Start downstream server
|
||||
|
||||
var tlsVerify bool
|
||||
@@ -4463,29 +4149,6 @@ func TestSignatures(t *testing.T) {
|
||||
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
|
||||
@@ -4621,22 +4284,6 @@ func TestSignatures(t *testing.T) {
|
||||
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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user