0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2024-12-16 21:56:37 -05: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:
Ramkumar Chinchani 2024-03-06 12:16:42 -08:00 committed by GitHub
parent 5039128723
commit 18235ca254
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 35 additions and 1687 deletions

1
go.mod
View file

@ -28,7 +28,6 @@ require (
github.com/olekukonko/tablewriter v0.0.5 github.com/olekukonko/tablewriter v0.0.5
github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.1.0 github.com/opencontainers/image-spec v1.1.0
github.com/oras-project/artifacts-spec v1.0.0-rc.2
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5
github.com/prometheus/client_golang v1.19.0 github.com/prometheus/client_golang v1.19.0
github.com/prometheus/client_model v0.6.0 github.com/prometheus/client_model v0.6.0

2
go.sum
View file

@ -1251,8 +1251,6 @@ github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/openvex/go-vex v0.2.5 h1:41utdp2rHgAGCsG+UbjmfMG5CWQxs15nGqir1eRgSrQ= github.com/openvex/go-vex v0.2.5 h1:41utdp2rHgAGCsG+UbjmfMG5CWQxs15nGqir1eRgSrQ=
github.com/openvex/go-vex v0.2.5/go.mod h1:j+oadBxSUELkrKh4NfNb+BPo77U3q7gdKME88IO/0Wo= github.com/openvex/go-vex v0.2.5/go.mod h1:j+oadBxSUELkrKh4NfNb+BPo77U3q7gdKME88IO/0Wo=
github.com/oras-project/artifacts-spec v1.0.0-rc.2 h1:9SMCNSxkJEHqWGDiMCuy6TXHgvjgwXGdXZZGXLKQvVE=
github.com/oras-project/artifacts-spec v1.0.0-rc.2/go.mod h1:Xch2aLzSwtkhbFFN6LUzTfLtukYvMMdXJ4oZ8O7BOdc=
github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU=
github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w=
github.com/owenrumney/go-sarif v1.1.1/go.mod h1:dNDiPlF04ESR/6fHlPyq7gHKmrM0sHUvAGjsoh8ZH0U= github.com/owenrumney/go-sarif v1.1.1/go.mod h1:dNDiPlF04ESR/6fHlPyq7gHKmrM0sHUvAGjsoh8ZH0U=

View file

@ -3,7 +3,6 @@ package constants
import "time" import "time"
const ( const (
ArtifactSpecRoutePrefix = "/oras/artifacts/v1"
RoutePrefix = "/v2" RoutePrefix = "/v2"
Blobs = "blobs" Blobs = "blobs"
Uploads = "uploads" Uploads = "uploads"

View file

@ -36,7 +36,6 @@ import (
distext "github.com/opencontainers/distribution-spec/specs-go/v1/extensions" distext "github.com/opencontainers/distribution-spec/specs-go/v1/extensions"
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1"
"github.com/project-zot/mockoidc" "github.com/project-zot/mockoidc"
"github.com/sigstore/cosign/v2/cmd/cosign/cli/generate" "github.com/sigstore/cosign/v2/cmd/cosign/cli/generate"
"github.com/sigstore/cosign/v2/cmd/cosign/cli/options" "github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
@ -6192,7 +6191,7 @@ func TestImageSignatures(t *testing.T) {
So(resp.StatusCode(), ShouldEqual, http.StatusUnsupportedMediaType) So(resp.StatusCode(), ShouldEqual, http.StatusUnsupportedMediaType)
// check invalid content with artifact media type // check invalid content with artifact media type
resp, err = resty.R().SetHeader("Content-Type", artifactspec.MediaTypeArtifactManifest). resp, err = resty.R().SetHeader("Content-Type", ispec.MediaTypeImageManifest).
SetBody([]byte("bogus")).Put(baseURL + fmt.Sprintf("/v2/%s/manifests/1.0", repoName)) SetBody([]byte("bogus")).Put(baseURL + fmt.Sprintf("/v2/%s/manifests/1.0", repoName))
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusBadRequest) So(resp.StatusCode(), ShouldEqual, http.StatusBadRequest)
@ -6241,34 +6240,6 @@ func TestImageSignatures(t *testing.T) {
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
}) })
}) })
Convey("GetOrasReferrers", func() {
// cover error paths
resp, err := resty.R().Get(
fmt.Sprintf("%s/oras/artifacts/v1/%s/manifests/%s/referrers", baseURL, "badRepo", "badDigest"))
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusNotFound)
resp, err = resty.R().Get(
fmt.Sprintf("%s/oras/artifacts/v1/%s/manifests/%s/referrers", baseURL, repoName, "badDigest"))
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusBadRequest)
resp, err = resty.R().Get(
fmt.Sprintf("%s/oras/artifacts/v1/%s/manifests/%s/referrers", baseURL, repoName, digest.String()))
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusNotFound)
resp, err = resty.R().SetQueryParam("artifactType", "badArtifact").Get(
fmt.Sprintf("%s/oras/artifacts/v1/%s/manifests/%s/referrers", baseURL, repoName, digest.String()))
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusNotFound)
resp, err = resty.R().SetQueryParam("artifactType", notreg.ArtifactTypeNotation).Get(
fmt.Sprintf("%s/oras/artifacts/v1/%s/manifests/%s/referrers", baseURL, "badRepo", digest.String()))
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusNotFound)
})
}) })
} }
@ -7323,30 +7294,6 @@ func TestRouteFailures(t *testing.T) {
So(resp, ShouldNotBeNil) So(resp, ShouldNotBeNil)
So(resp.StatusCode, ShouldEqual, http.StatusNotFound) So(resp.StatusCode, ShouldEqual, http.StatusNotFound)
}) })
Convey("Get referrers", func() {
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodGet, baseURL, nil)
request = mux.SetURLVars(request, map[string]string{})
response := httptest.NewRecorder()
rthdlr.GetOrasReferrers(response, request)
resp := response.Result()
defer resp.Body.Close()
So(resp, ShouldNotBeNil)
So(resp.StatusCode, ShouldEqual, http.StatusNotFound)
request, _ = http.NewRequestWithContext(context.TODO(), http.MethodGet, baseURL, nil)
request = mux.SetURLVars(request, map[string]string{"name": "foo"})
response = httptest.NewRecorder()
rthdlr.GetOrasReferrers(response, request)
resp = response.Result()
defer resp.Body.Close()
So(resp, ShouldNotBeNil)
So(resp.StatusCode, ShouldEqual, http.StatusBadRequest)
})
}) })
} }

View file

@ -29,7 +29,6 @@ import (
"github.com/opencontainers/distribution-spec/specs-go/v1/extensions" "github.com/opencontainers/distribution-spec/specs-go/v1/extensions"
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1"
"github.com/zitadel/oidc/pkg/client/rp" "github.com/zitadel/oidc/pkg/client/rp"
"github.com/zitadel/oidc/pkg/oidc" "github.com/zitadel/oidc/pkg/oidc"
@ -173,10 +172,6 @@ func (rh *RouteHandler) SetupRoutes() {
applyCORSHeaders(rh.CheckVersionSupport))).Methods(http.MethodGet, http.MethodOptions) applyCORSHeaders(rh.CheckVersionSupport))).Methods(http.MethodGet, http.MethodOptions)
} }
// support for ORAS artifact reference types (alpha 1) - image signature use case
rh.c.Router.HandleFunc(fmt.Sprintf("%s/{name:%s}/manifests/{digest}/referrers",
constants.ArtifactSpecRoutePrefix, zreg.NameRegexp.String()), rh.GetOrasReferrers).Methods("GET")
// swagger // swagger
debug.SetupSwaggerRoutes(rh.c.Config, rh.c.Router, authHandler, rh.c.Log) debug.SetupSwaggerRoutes(rh.c.Config, rh.c.Router, authHandler, rh.c.Log)
// gql playground // gql playground
@ -1926,104 +1921,6 @@ func getImageManifest(ctx context.Context, routeHandler *RouteHandler, imgStore
return imgStore.GetImageManifest(name, reference) return imgStore.GetImageManifest(name, reference)
} }
// will sync referrers on demand if they are not found, in case sync extensions is enabled.
func getOrasReferrers(ctx context.Context, routeHandler *RouteHandler,
imgStore storageTypes.ImageStore, name string, digest godigest.Digest,
artifactType string,
) ([]artifactspec.Descriptor, error) {
refs, err := imgStore.GetOrasReferrers(name, digest, artifactType)
if err != nil {
if isSyncOnDemandEnabled(*routeHandler.c) {
routeHandler.c.Log.Info().Str("repository", name).Str("reference", digest.String()).
Msg("artifact not found, trying to get artifact by syncing on demand")
if errSync := routeHandler.c.SyncOnDemand.SyncReference(ctx, name, digest.String(),
syncConstants.Oras); errSync != nil {
routeHandler.c.Log.Error().Err(err).Str("name", name).Str("digest", digest.String()).
Msg("failed to get references")
}
refs, err = imgStore.GetOrasReferrers(name, digest, artifactType)
}
}
return refs, err
}
type ReferenceList struct {
References []artifactspec.Descriptor `json:"references"`
}
// GetOrasReferrers godoc
// @Summary Get references for an image
// @Description Get references for an image given a digest and artifact type
// @Accept json
// @Produce json
// @Param name path string true "repository name"
// @Param digest path string true "image digest"
// @Param artifactType query string true "artifact type"
// @Success 200 {string} string "ok"
// @Failure 404 {string} string "not found"
// @Failure 500 {string} string "internal server error"
// @Router /oras/artifacts/v1/{name}/manifests/{digest}/referrers [get].
func (rh *RouteHandler) GetOrasReferrers(response http.ResponseWriter, request *http.Request) {
vars := mux.Vars(request)
name, ok := vars["name"]
if !ok || name == "" {
response.WriteHeader(http.StatusNotFound)
return
}
digestStr, ok := vars["digest"]
digest, err := godigest.Parse(digestStr)
if !ok || digestStr == "" || err != nil {
response.WriteHeader(http.StatusBadRequest)
return
}
// filter by artifact type
artifactType := ""
artifactTypes, ok := request.URL.Query()["artifactType"]
if ok {
if len(artifactTypes) != 1 {
rh.c.Log.Error().Msg("invalid artifact types")
response.WriteHeader(http.StatusBadRequest)
return
}
artifactType = artifactTypes[0]
}
imgStore := rh.getImageStore(name)
rh.c.Log.Info().Str("digest", digest.String()).Str("artifactType", artifactType).Msg("getting manifest")
refs, err := getOrasReferrers(request.Context(), rh, imgStore, name, digest, artifactType) //nolint:contextcheck
if err != nil {
if errors.Is(err, zerr.ErrManifestNotFound) || errors.Is(err, zerr.ErrRepoNotFound) {
rh.c.Log.Error().Err(err).Str("name", name).Str("digest", digest.String()).
Msg("failed to get manifest")
response.WriteHeader(http.StatusNotFound)
} else {
rh.c.Log.Error().Err(err).Str("name", name).Str("digest", digest.String()).
Msg("failed to get references")
response.WriteHeader(http.StatusInternalServerError)
}
return
}
rs := ReferenceList{References: refs}
zcommon.WriteJSON(response, http.StatusOK, rs)
}
type APIKeyPayload struct { //nolint:revive type APIKeyPayload struct { //nolint:revive
Label string `json:"label"` Label string `json:"label"`
Scopes []string `json:"scopes"` Scopes []string `json:"scopes"`

View file

@ -2,7 +2,6 @@ package constants
// references type. // references type.
const ( const (
Oras = "OrasReference"
Cosign = "CosignSignature" Cosign = "CosignSignature"
OCI = "OCIReference" OCI = "OCIReference"
Tag = "TagReference" Tag = "TagReference"

View file

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

View file

@ -12,7 +12,6 @@ import (
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1" 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" "github.com/sigstore/cosign/v2/pkg/oci/static"
zerr "zotregistry.dev/zot/errors" zerr "zotregistry.dev/zot/errors"
@ -27,7 +26,7 @@ import (
) )
type Reference interface { type Reference interface {
// Returns name of reference (OCIReference/CosignReference/OrasReference) // Returns name of reference (OCIReference/CosignReference)
Name() string Name() string
// Returns whether or not image is signed // Returns whether or not image is signed
IsSigned(ctx context.Context, upstreamRepo, subjectDigestStr string) bool 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, NewCosignReference(httpClient, storeController, metaDB, log))
refs.referenceList = append(refs.referenceList, NewTagReferences(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, NewOciReferences(httpClient, storeController, metaDB, log))
refs.referenceList = append(refs.referenceList, NewORASReferences(httpClient, storeController, metaDB, log))
return refs 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 // mark subject digest as seen as soon as it comes in
*seen = append(*seen, godigest.Digest(subjectDigestStr)) *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 { for _, ref := range refs.referenceList {
supported, ok := refs.features.Get(ref.Name(), upstreamRepo) supported, ok := refs.features.Get(ref.Name(), upstreamRepo)
if !supported && ok { if !supported && ok {
@ -186,23 +184,6 @@ func manifestsEqual(manifest1, manifest2 ispec.Manifest) bool {
return false 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 { func descriptorsEqual(desc1, desc2 []ispec.Descriptor) bool {
if len(desc1) != len(desc2) { if len(desc1) != len(desc2) {
return false return false

View file

@ -10,7 +10,6 @@ import (
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
zerr "zotregistry.dev/zot/errors" 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) { func TestSyncManifest(t *testing.T) {
Convey("sync manifest not found err", t, func() { Convey("sync manifest not found err", t, func() {
cfg := client.Config{ 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)
}
})
}

View file

@ -13,7 +13,6 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
"os/exec"
"path" "path"
"reflect" "reflect"
"strings" "strings"
@ -26,7 +25,6 @@ import (
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
"github.com/opencontainers/image-spec/specs-go" "github.com/opencontainers/image-spec/specs-go"
ispec "github.com/opencontainers/image-spec/specs-go/v1" 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/attach"
"github.com/sigstore/cosign/v2/cmd/cosign/cli/generate" "github.com/sigstore/cosign/v2/cmd/cosign/cli/generate"
"github.com/sigstore/cosign/v2/cmd/cosign/cli/options" "github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
@ -229,297 +227,6 @@ func makeDownstreamServer(
return dctlr, destBaseURL, destDir, client 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: &regex,
},
},
},
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: &regex,
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) { func TestOnDemand(t *testing.T) {
Convey("Verify sync on demand feature", t, func() { Convey("Verify sync on demand feature", t, func() {
sctlr, srcBaseURL, _, _, srcClient := makeUpstreamServer(t, false, false) sctlr, srcBaseURL, _, _, srcClient := makeUpstreamServer(t, false, false)
@ -792,27 +499,6 @@ func TestOnDemand(t *testing.T) {
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusCreated) 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 //------- Start downstream server
var tlsVerify bool var tlsVerify bool
@ -4463,29 +4149,6 @@ func TestSignatures(t *testing.T) {
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusCreated) 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 := ".*" regex := ".*"
var semver bool var semver bool
var tlsVerify bool var tlsVerify bool
@ -4621,22 +4284,6 @@ func TestSignatures(t *testing.T) {
So(len(index.Manifests), ShouldEqual, 2) So(len(index.Manifests), ShouldEqual, 2)
So(index.Manifests[1].Digest, ShouldEqual, ociRefDigest) 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 negative cases (trigger errors)
// test notary signatures errors // test notary signatures errors

View file

@ -16,7 +16,6 @@ import (
"github.com/opencontainers/image-spec/schema" "github.com/opencontainers/image-spec/schema"
imeta "github.com/opencontainers/image-spec/specs-go" imeta "github.com/opencontainers/image-spec/specs-go"
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
oras "github.com/oras-project/artifacts-spec/specs-go/v1"
zerr "zotregistry.dev/zot/errors" zerr "zotregistry.dev/zot/errors"
zcommon "zotregistry.dev/zot/pkg/common" zcommon "zotregistry.dev/zot/pkg/common"
@ -126,13 +125,6 @@ func ValidateManifest(imgStore storageTypes.ImageStore, repo, reference, mediaTy
} }
} }
} }
case oras.MediaTypeArtifactManifest:
var m oras.Descriptor
if err := json.Unmarshal(body, &m); err != nil {
log.Error().Err(err).Msg("failed to unmarshal JSON")
return "", zerr.ErrBadManifest
}
case ispec.MediaTypeImageIndex: case ispec.MediaTypeImageIndex:
// validate manifest // validate manifest
if err := ValidateImageIndexSchema(body); err != nil { if err := ValidateImageIndexSchema(body); err != nil {
@ -505,30 +497,6 @@ func isBlobReferencedInImageManifest(imgStore storageTypes.ImageStore, repo stri
return false, nil return false, nil
} }
func isBlobReferencedInORASManifest(imgStore storageTypes.ImageStore, repo string,
bdigest, mdigest godigest.Digest, log zlog.Logger,
) (bool, error) {
if bdigest == mdigest {
return true, nil
}
manifestContent, err := GetOrasManifestByDigest(imgStore, repo, mdigest, log)
if err != nil {
log.Error().Err(err).Str("repo", repo).Str("digest", mdigest.String()).Str("component", "gc").
Msg("failed to read manifest image")
return false, err
}
for _, blob := range manifestContent.Blobs {
if bdigest == blob.Digest {
return true, nil
}
}
return false, nil
}
func IsBlobReferencedInImageIndex(imgStore storageTypes.ImageStore, repo string, func IsBlobReferencedInImageIndex(imgStore storageTypes.ImageStore, repo string,
digest godigest.Digest, index ispec.Index, log zlog.Logger, digest godigest.Digest, index ispec.Index, log zlog.Logger,
) (bool, error) { ) (bool, error) {
@ -548,8 +516,6 @@ func IsBlobReferencedInImageIndex(imgStore storageTypes.ImageStore, repo string,
found, _ = IsBlobReferencedInImageIndex(imgStore, repo, digest, indexImage, log) found, _ = IsBlobReferencedInImageIndex(imgStore, repo, digest, indexImage, log)
case ispec.MediaTypeImageManifest: case ispec.MediaTypeImageManifest:
found, _ = isBlobReferencedInImageManifest(imgStore, repo, digest, desc.Digest, log) found, _ = isBlobReferencedInImageManifest(imgStore, repo, digest, desc.Digest, log)
case oras.MediaTypeArtifactManifest:
found, _ = isBlobReferencedInORASManifest(imgStore, repo, digest, desc.Digest, log)
default: default:
log.Warn().Str("mediatype", desc.MediaType).Msg("unknown media-type") log.Warn().Str("mediatype", desc.MediaType).Msg("unknown media-type")
// should return true for digests found in index.json even if we don't know it's mediatype // should return true for digests found in index.json even if we don't know it's mediatype
@ -632,64 +598,6 @@ func IsSignature(descriptor ispec.Descriptor) bool {
return false return false
} }
func GetOrasReferrers(imgStore storageTypes.ImageStore, repo string, gdigest godigest.Digest, artifactType string,
log zlog.Logger,
) ([]oras.Descriptor, error) {
if err := gdigest.Validate(); err != nil {
return nil, err
}
dir := path.Join(imgStore.RootDir(), repo)
if !imgStore.DirExists(dir) {
return nil, zerr.ErrRepoNotFound
}
index, err := GetIndex(imgStore, repo, log)
if err != nil {
return nil, err
}
found := false
result := []oras.Descriptor{}
for _, manifest := range index.Manifests {
if manifest.MediaType != oras.MediaTypeArtifactManifest {
continue
}
artManifest, err := GetOrasManifestByDigest(imgStore, repo, manifest.Digest, log)
if err != nil {
return nil, err
}
if artManifest.Subject.Digest != gdigest {
continue
}
// filter by artifact type
if artifactType != "" && artManifest.ArtifactType != artifactType {
continue
}
result = append(result, oras.Descriptor{
MediaType: manifest.MediaType,
ArtifactType: artManifest.ArtifactType,
Digest: manifest.Digest,
Size: manifest.Size,
Annotations: manifest.Annotations,
})
found = true
}
if !found {
return nil, zerr.ErrManifestNotFound
}
return result, nil
}
func GetReferrers(imgStore storageTypes.ImageStore, repo string, gdigest godigest.Digest, artifactTypes []string, func GetReferrers(imgStore storageTypes.ImageStore, repo string, gdigest godigest.Digest, artifactTypes []string,
log zlog.Logger, log zlog.Logger,
) (ispec.Index, error) { ) (ispec.Index, error) {
@ -794,32 +702,6 @@ func GetReferrers(imgStore storageTypes.ImageStore, repo string, gdigest godiges
return index, nil return index, nil
} }
func GetOrasManifestByDigest(imgStore storageTypes.ImageStore, repo string, digest godigest.Digest, log zlog.Logger,
) (oras.Manifest, error) {
var artManifest oras.Manifest
blobPath := imgStore.BlobPath(repo, digest)
buf, err := imgStore.GetBlobContent(repo, digest)
if err != nil {
log.Error().Err(err).Str("blob", blobPath).Msg("failed to read manifest")
if errors.Is(err, zerr.ErrBlobNotFound) {
return artManifest, zerr.ErrManifestNotFound
}
return artManifest, err
}
if err := json.Unmarshal(buf, &artManifest); err != nil {
log.Error().Err(err).Str("blob", blobPath).Msg("invalid JSON")
return artManifest, err
}
return artManifest, nil
}
// Get blob descriptor from it's manifest contents, if blob can not be found it will return error. // Get blob descriptor from it's manifest contents, if blob can not be found it will return error.
func GetBlobDescriptorFromRepo(imgStore storageTypes.ImageStore, repo string, blobDigest godigest.Digest, func GetBlobDescriptorFromRepo(imgStore storageTypes.ImageStore, repo string, blobDigest godigest.Digest,
log zlog.Logger, log zlog.Logger,
@ -854,10 +736,6 @@ func GetBlobDescriptorFromIndex(imgStore storageTypes.ImageStore, index ispec.In
if foundDescriptor, err := GetBlobDescriptorFromIndex(imgStore, indexImage, repo, blobDigest, log); err == nil { if foundDescriptor, err := GetBlobDescriptorFromIndex(imgStore, indexImage, repo, blobDigest, log); err == nil {
return foundDescriptor, nil return foundDescriptor, nil
} }
case oras.MediaTypeArtifactManifest:
if foundDescriptor, err := getBlobDescriptorFromORASManifest(imgStore, repo, blobDigest, desc, log); err == nil {
return foundDescriptor, nil
}
} }
} }
@ -885,33 +763,9 @@ func getBlobDescriptorFromManifest(imgStore storageTypes.ImageStore, repo string
return ispec.Descriptor{}, zerr.ErrBlobNotFound return ispec.Descriptor{}, zerr.ErrBlobNotFound
} }
func getBlobDescriptorFromORASManifest(imgStore storageTypes.ImageStore, repo string, blobDigest godigest.Digest,
desc ispec.Descriptor, log zlog.Logger,
) (ispec.Descriptor, error) {
manifest, err := GetOrasManifestByDigest(imgStore, repo, desc.Digest, log)
if err != nil {
return ispec.Descriptor{}, err
}
for _, layer := range manifest.Blobs {
if layer.Digest == blobDigest {
return ispec.Descriptor{
MediaType: layer.MediaType,
Size: layer.Size,
Digest: layer.Digest,
ArtifactType: layer.ArtifactType,
Annotations: layer.Annotations,
}, nil
}
}
return ispec.Descriptor{}, zerr.ErrBlobNotFound
}
func IsSupportedMediaType(mediaType string) bool { func IsSupportedMediaType(mediaType string) bool {
return mediaType == ispec.MediaTypeImageIndex || return mediaType == ispec.MediaTypeImageIndex ||
mediaType == ispec.MediaTypeImageManifest || mediaType == ispec.MediaTypeImageManifest
mediaType == oras.MediaTypeArtifactManifest
} }
func IsNonDistributable(mediaType string) bool { func IsNonDistributable(mediaType string) bool {

View file

@ -9,7 +9,6 @@ import (
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1"
"github.com/rs/zerolog" "github.com/rs/zerolog"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
@ -165,20 +164,12 @@ func TestGetReferrersErrors(t *testing.T) {
_, err := common.GetReferrers(imgStore, "zot-test", "invalidDigest", _, err := common.GetReferrers(imgStore, "zot-test", "invalidDigest",
[]string{artifactType}, log) []string{artifactType}, log)
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
_, err = common.GetOrasReferrers(imgStore, "zot-test", "invalidDigest",
artifactType, log)
So(err, ShouldNotBeNil)
}) })
Convey("Trigger repo not found error", func(c C) { Convey("Trigger repo not found error", func(c C) {
_, err := common.GetReferrers(imgStore, "zot-test", validDigest, _, err := common.GetReferrers(imgStore, "zot-test", validDigest,
[]string{artifactType}, log) []string{artifactType}, log)
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
_, err = common.GetOrasReferrers(imgStore, "zot-test", validDigest,
artifactType, log)
So(err, ShouldNotBeNil)
}) })
storageCtlr := storage.StoreController{DefaultStore: imgStore} storageCtlr := storage.StoreController{DefaultStore: imgStore}
@ -190,7 +181,7 @@ func TestGetReferrersErrors(t *testing.T) {
index := ispec.Index{ index := ispec.Index{
Manifests: []ispec.Descriptor{ Manifests: []ispec.Descriptor{
{ {
MediaType: artifactspec.MediaTypeArtifactManifest, MediaType: "application/vnd.example.invalid.v1",
Digest: digest, Digest: digest,
}, },
}, },
@ -212,10 +203,6 @@ func TestGetReferrersErrors(t *testing.T) {
_, err = common.GetReferrers(imgStore, "zot-test", validDigest, _, err = common.GetReferrers(imgStore, "zot-test", validDigest,
[]string{artifactType}, log) []string{artifactType}, log)
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
_, err = common.GetOrasReferrers(imgStore, "zot-test", validDigest,
artifactType, log)
So(err, ShouldNotBeNil)
}) })
Convey("Trigger GetBlobContent() generic error", func(c C) { Convey("Trigger GetBlobContent() generic error", func(c C) {
@ -231,53 +218,6 @@ func TestGetReferrersErrors(t *testing.T) {
_, err = common.GetReferrers(imgStore, "zot-test", validDigest, _, err = common.GetReferrers(imgStore, "zot-test", validDigest,
[]string{artifactType}, log) []string{artifactType}, log)
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
_, err = common.GetOrasReferrers(imgStore, "zot-test", validDigest,
artifactType, log)
So(err, ShouldNotBeNil)
})
Convey("Trigger continue on different artifactType", func(c C) {
orasManifest := artifactspec.Manifest{
Subject: &artifactspec.Descriptor{
Digest: digest,
ArtifactType: "unknown",
},
}
orasBuf, err := json.Marshal(orasManifest)
So(err, ShouldBeNil)
imgStore = &mocks.MockedImageStore{
GetIndexContentFn: func(repo string) ([]byte, error) {
return indexBuf, nil
},
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
return orasBuf, nil
},
}
_, err = common.GetOrasReferrers(imgStore, "zot-test", validDigest,
artifactType, log)
So(err, ShouldNotBeNil)
_, err = common.GetOrasReferrers(imgStore, "zot-test", digest,
artifactType, log)
So(err, ShouldNotBeNil)
})
Convey("Unmarshal oras artifact error", func(c C) {
imgStore = &mocks.MockedImageStore{
GetIndexContentFn: func(repo string) ([]byte, error) {
return indexBuf, nil
},
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
return []byte("wrong content"), nil
},
}
_, err = common.GetOrasReferrers(imgStore, "zot-test", validDigest, artifactType, log)
So(err, ShouldNotBeNil)
}) })
Convey("Trigger unmarshal error on manifest image mediaType", func(c C) { Convey("Trigger unmarshal error on manifest image mediaType", func(c C) {

View file

@ -12,7 +12,6 @@ import (
"github.com/docker/distribution/registry/storage/driver" "github.com/docker/distribution/registry/storage/driver"
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
oras "github.com/oras-project/artifacts-spec/specs-go/v1"
zerr "zotregistry.dev/zot/errors" zerr "zotregistry.dev/zot/errors"
"zotregistry.dev/zot/pkg/api/config" "zotregistry.dev/zot/pkg/api/config"
@ -244,7 +243,7 @@ func (gc GarbageCollect) removeIndexReferrers(repo string, rootIndex *ispec.Inde
if gced { if gced {
count++ count++
} }
case ispec.MediaTypeImageManifest, oras.MediaTypeArtifactManifest: case ispec.MediaTypeImageManifest:
image, err := common.GetImageManifest(gc.imgStore, repo, desc.Digest, gc.log) image, err := common.GetImageManifest(gc.imgStore, repo, desc.Digest, gc.log)
if err != nil { if err != nil {
gc.log.Error().Err(err).Str("module", "gc").Str("repo", repo).Str("digest", desc.Digest.String()). gc.log.Error().Err(err).Str("module", "gc").Str("repo", repo).Str("digest", desc.Digest.String()).
@ -529,7 +528,7 @@ func (gc GarbageCollect) identifyManifestsReferencedInIndex(index ispec.Index, r
if err := gc.identifyManifestsReferencedInIndex(indexImage, repo, referenced); err != nil { if err := gc.identifyManifestsReferencedInIndex(indexImage, repo, referenced); err != nil {
return err return err
} }
case ispec.MediaTypeImageManifest, oras.MediaTypeArtifactManifest: case ispec.MediaTypeImageManifest:
image, err := common.GetImageManifest(gc.imgStore, repo, desc.Digest, gc.log) image, err := common.GetImageManifest(gc.imgStore, repo, desc.Digest, gc.log)
if err != nil { if err != nil {
gc.log.Error().Err(err).Str("module", "gc").Str("repo", repo). gc.log.Error().Err(err).Str("module", "gc").Str("repo", repo).
@ -638,13 +637,6 @@ func (gc GarbageCollect) addIndexBlobsToReferences(repo string, index ispec.Inde
gc.log.Error().Err(err).Str("module", "gc").Str("repository", repo). gc.log.Error().Err(err).Str("module", "gc").Str("repository", repo).
Str("digest", desc.Digest.String()).Msg("failed to read blobs in image manifest") Str("digest", desc.Digest.String()).Msg("failed to read blobs in image manifest")
return err
}
case oras.MediaTypeArtifactManifest:
if err := gc.addORASImageManifestBlobsToReferences(repo, desc.Digest, refBlobs); err != nil {
gc.log.Error().Err(err).Str("module", "gc").Str("repository", repo).
Str("digest", desc.Digest.String()).Msg("failed to read blobs in ORAS image manifest")
return err return err
} }
} }
@ -703,31 +695,6 @@ func (gc GarbageCollect) addImageManifestBlobsToReferences(repo string, mdigest
return nil return nil
} }
func (gc GarbageCollect) addORASImageManifestBlobsToReferences(repo string, mdigest godigest.Digest,
refBlobs map[string]bool,
) error {
manifestContent, err := common.GetOrasManifestByDigest(gc.imgStore, repo, mdigest, gc.log)
if err != nil {
gc.log.Error().Err(err).Str("module", "gc").Str("repository", repo).
Str("digest", mdigest.String()).Msg("failed to read manifest image")
return err
}
refBlobs[mdigest.String()] = true
// if there is a Subject, it may not exist yet and that is ok
if manifestContent.Subject != nil {
refBlobs[manifestContent.Subject.Digest.String()] = true
}
for _, blob := range manifestContent.Blobs {
refBlobs[blob.Digest.String()] = true
}
return nil
}
func isManifestReferencedInIndex(index *ispec.Index, digest godigest.Digest) bool { func isManifestReferencedInIndex(index *ispec.Index, digest godigest.Digest) bool {
for _, manifest := range index.Manifests { for _, manifest := range index.Manifests {
if manifest.Digest == digest { if manifest.Digest == digest {

View file

@ -12,7 +12,6 @@ import (
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
"zotregistry.dev/zot/pkg/api/config" "zotregistry.dev/zot/pkg/api/config"
@ -87,18 +86,6 @@ func TestGarbageCollectManifestErrors(t *testing.T) {
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
}) })
Convey("trigger repo not found in addORASImageManifestBlobsToReferences()", func() {
err := gc.addIndexBlobsToReferences(repoName, ispec.Index{
Manifests: []ispec.Descriptor{
{
Digest: godigest.FromString("miss"),
MediaType: artifactspec.MediaTypeArtifactManifest,
},
},
}, map[string]bool{})
So(err, ShouldNotBeNil)
})
content := []byte("this is a blob") content := []byte("this is a blob")
digest := godigest.FromBytes(content) digest := godigest.FromBytes(content)
So(digest, ShouldNotBeNil) So(digest, ShouldNotBeNil)

View file

@ -18,7 +18,6 @@ import (
guuid "github.com/gofrs/uuid" guuid "github.com/gofrs/uuid"
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1"
zerr "zotregistry.dev/zot/errors" zerr "zotregistry.dev/zot/errors"
zcommon "zotregistry.dev/zot/pkg/common" zcommon "zotregistry.dev/zot/pkg/common"
@ -1450,16 +1449,6 @@ func (is *ImageStore) GetReferrers(repo string, gdigest godigest.Digest, artifac
return common.GetReferrers(is, repo, gdigest, artifactTypes, is.log) return common.GetReferrers(is, repo, gdigest, artifactTypes, is.log)
} }
func (is *ImageStore) GetOrasReferrers(repo string, gdigest godigest.Digest, artifactType string,
) ([]artifactspec.Descriptor, error) {
var lockLatency time.Time
is.RLock(&lockLatency)
defer is.RUnlock(&lockLatency)
return common.GetOrasReferrers(is, repo, gdigest, artifactType, is.log)
}
// GetIndexContent returns index.json contents, the caller function MUST lock from outside. // GetIndexContent returns index.json contents, the caller function MUST lock from outside.
func (is *ImageStore) GetIndexContent(repo string) ([]byte, error) { func (is *ImageStore) GetIndexContent(repo string) ([]byte, error) {
dir := path.Join(is.rootDir, repo) dir := path.Join(is.rootDir, repo)

View file

@ -21,7 +21,6 @@ import (
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
imeta "github.com/opencontainers/image-spec/specs-go" imeta "github.com/opencontainers/image-spec/specs-go"
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1"
"github.com/rs/zerolog" "github.com/rs/zerolog"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
@ -182,16 +181,6 @@ func TestStorageFSAPIs(t *testing.T) {
panic(err) panic(err)
} }
// invalid GetOrasReferrers
_, err = imgStore.GetOrasReferrers("invalid", "invalid", "invalid")
So(err, ShouldNotBeNil)
_, err = imgStore.GetOrasReferrers(repoName, "invalid", "invalid")
So(err, ShouldNotBeNil)
_, err = imgStore.GetOrasReferrers(repoName, digest, "invalid")
So(err, ShouldNotBeNil)
// invalid DeleteImageManifest // invalid DeleteImageManifest
indexPath := path.Join(imgStore.RootDir(), repoName, "index.json") indexPath := path.Join(imgStore.RootDir(), repoName, "index.json")
err = os.Chmod(indexPath, 0o000) err = os.Chmod(indexPath, 0o000)
@ -210,63 +199,6 @@ func TestStorageFSAPIs(t *testing.T) {
}) })
} }
func TestGetOrasReferrers(t *testing.T) {
dir := t.TempDir()
log := zlog.Logger{Logger: zerolog.New(os.Stdout)}
metrics := monitoring.NewMetricsServer(false, log)
cacheDriver, _ := storage.Create("boltdb", cache.BoltDBDriverParameters{
RootDir: dir,
Name: "cache",
UseRelPaths: true,
}, log)
imgStore := local.NewImageStore(dir, true, true, log, metrics, nil, cacheDriver)
Convey("Get referrers", t, func(c C) {
err := WriteImageToFileSystem(CreateDefaultVulnerableImage(), "zot-test", "0.0.1", storage.StoreController{
DefaultStore: imgStore,
})
So(err, ShouldBeNil)
body := []byte("this is a blob")
digest := godigest.FromBytes(body)
buf := bytes.NewBuffer(body)
buflen := buf.Len()
err = os.WriteFile(path.Join(imgStore.RootDir(), //nolint: gosec
"zot-test", "blobs", digest.Algorithm().String(), digest.Encoded()),
buf.Bytes(), 0o644)
So(err, ShouldBeNil)
_, n, err := imgStore.FullBlobUpload("zot-test", buf, digest)
So(err, ShouldBeNil)
So(n, ShouldEqual, buflen)
artifactManifest := artifactspec.Manifest{}
artifactManifest.ArtifactType = "signature-example"
artifactManifest.Subject = &artifactspec.Descriptor{
MediaType: ispec.MediaTypeImageManifest,
Digest: digest,
Size: int64(buflen),
}
artifactManifest.Blobs = []artifactspec.Descriptor{}
manBuf, err := json.Marshal(artifactManifest)
manBufLen := len(manBuf)
So(err, ShouldBeNil)
manDigest := godigest.FromBytes(manBuf)
_, _, err = imgStore.PutImageManifest("zot-test", manDigest.Encoded(), artifactspec.MediaTypeArtifactManifest, manBuf)
So(err, ShouldBeNil)
So(err, ShouldBeNil)
descriptors, err := imgStore.GetOrasReferrers("zot-test", digest, "signature-example")
So(err, ShouldBeNil)
So(descriptors, ShouldNotBeEmpty)
So(descriptors[0].ArtifactType, ShouldEqual, "signature-example")
So(descriptors[0].MediaType, ShouldEqual, artifactspec.MediaTypeArtifactManifest)
So(descriptors[0].Size, ShouldEqual, manBufLen)
So(descriptors[0].Digest, ShouldEqual, manDigest)
})
}
func FuzzNewBlobUpload(f *testing.F) { func FuzzNewBlobUpload(f *testing.F) {
f.Fuzz(func(t *testing.T, data string) { f.Fuzz(func(t *testing.T, data string) {
dir := t.TempDir() dir := t.TempDir()
@ -1066,69 +998,6 @@ func FuzzGetBlobContent(f *testing.F) {
}) })
} }
func FuzzGetOrasReferrers(f *testing.F) {
f.Fuzz(func(t *testing.T, data string) {
log := &zlog.Logger{Logger: zerolog.New(os.Stdout)}
metrics := monitoring.NewMetricsServer(false, *log)
dir := t.TempDir()
defer os.RemoveAll(dir)
cacheDriver, _ := storage.Create("boltdb", cache.BoltDBDriverParameters{
RootDir: dir,
Name: "cache",
UseRelPaths: true,
}, *log)
imgStore := local.NewImageStore(dir, true, true, *log, metrics, nil, cacheDriver)
storageCtlr := storage.StoreController{DefaultStore: imgStore}
err := WriteImageToFileSystem(CreateDefaultVulnerableImage(), "zot-test", "0.0.1", storageCtlr)
if err != nil {
t.Error(err)
}
digest := godigest.FromBytes([]byte(data))
buf := bytes.NewBufferString(data)
buflen := buf.Len()
err = os.WriteFile(path.Join(imgStore.RootDir(), //nolint: gosec
"zot-test", "blobs", digest.Algorithm().String(), digest.Encoded()),
buf.Bytes(), 0o644)
if err != nil {
t.Error(err)
}
_, _, err = imgStore.FullBlobUpload("zot-test", buf, digest)
if err != nil {
t.Error(err)
}
artifactManifest := artifactspec.Manifest{}
artifactManifest.ArtifactType = data
artifactManifest.Subject = &artifactspec.Descriptor{
MediaType: ispec.MediaTypeImageManifest,
Digest: digest,
Size: int64(buflen),
}
artifactManifest.Blobs = []artifactspec.Descriptor{}
manBuf, err := json.Marshal(artifactManifest)
if err != nil {
t.Error(err)
}
manDigest := godigest.FromBytes(manBuf)
_, _, err = imgStore.PutImageManifest("zot-test", manDigest.Encoded(), artifactspec.MediaTypeArtifactManifest, manBuf)
if err != nil {
t.Error(err)
}
_, err = imgStore.GetOrasReferrers("zot-test", digest, data)
if err != nil {
if errors.Is(err, zerr.ErrManifestNotFound) || isKnownErr(err) {
return
}
t.Error(err)
}
})
}
func FuzzRunGCRepo(f *testing.F) { func FuzzRunGCRepo(f *testing.F) {
f.Fuzz(func(t *testing.T, data string) { f.Fuzz(func(t *testing.T, data string) {
log := zlog.NewLogger("debug", "") log := zlog.NewLogger("debug", "")

View file

@ -20,7 +20,6 @@ import (
guuid "github.com/gofrs/uuid" guuid "github.com/gofrs/uuid"
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1"
"github.com/rs/zerolog" "github.com/rs/zerolog"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
"gopkg.in/resty.v1" "gopkg.in/resty.v1"
@ -450,7 +449,7 @@ func TestStorageDriverStatFunction(t *testing.T) {
}) })
} }
func TestGetOrasAndOCIReferrers(t *testing.T) { func TestGetOCIReferrers(t *testing.T) {
tskip.SkipS3(t) tskip.SkipS3(t)
repo := "zot-test" repo := "zot-test"
@ -577,40 +576,6 @@ func TestGetOrasAndOCIReferrers(t *testing.T) {
So(index.Manifests[0].Size, ShouldEqual, manBufLen) So(index.Manifests[0].Size, ShouldEqual, manBufLen)
So(index.Manifests[0].Digest, ShouldEqual, manDigest) So(index.Manifests[0].Digest, ShouldEqual, manDigest)
}) })
Convey("Get oras referrers", func(c C) {
artifactManifest := artifactspec.Manifest{}
artifactManifest.ArtifactType = "signature-example"
artifactManifest.Subject = &artifactspec.Descriptor{
MediaType: ispec.MediaTypeImageManifest,
Digest: mdigest,
Size: int64(mbuflen),
}
artifactManifest.Blobs = []artifactspec.Descriptor{
{
Size: int64(buflen),
Digest: digest,
MediaType: "application/octet-stream",
},
}
manBuf, err := json.Marshal(artifactManifest)
So(err, ShouldBeNil)
manBufLen := len(manBuf)
manDigest := godigest.FromBytes(manBuf)
_, _, err = imgStore.PutImageManifest(repo, manDigest.Encoded(), artifactspec.MediaTypeArtifactManifest, manBuf)
So(err, ShouldBeNil)
descriptors, err := imgStore.GetOrasReferrers(repo, mdigest, "signature-example")
So(err, ShouldBeNil)
So(descriptors, ShouldNotBeEmpty)
So(descriptors[0].ArtifactType, ShouldEqual, "signature-example")
So(descriptors[0].MediaType, ShouldEqual, artifactspec.MediaTypeArtifactManifest)
So(descriptors[0].Size, ShouldEqual, manBufLen)
So(descriptors[0].Digest, ShouldEqual, manDigest)
})
}) })
} }
@ -1219,14 +1184,6 @@ func TestNegativeCasesObjectsStorage(t *testing.T) {
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
So(err, ShouldEqual, zerr.ErrRepoBadVersion) So(err, ShouldEqual, zerr.ErrRepoBadVersion)
}) })
Convey("Test GetOrasReferrers", func(c C) {
imgStore = createMockStorage(testDir, tdir, false, &StorageDriverMock{})
d := godigest.FromBytes([]byte(""))
_, err := imgStore.GetOrasReferrers(testImage, d, "application/image")
So(err, ShouldNotBeNil)
So(err, ShouldEqual, zerr.ErrRepoBadVersion)
})
}) })
} }

View file

@ -296,7 +296,6 @@ func scrubManifest(
func CheckManifestAndConfig( func CheckManifestAndConfig(
imageName string, manifestDesc ispec.Descriptor, manifestContent []byte, imgStore storageTypes.ImageStore, imageName string, manifestDesc ispec.Descriptor, manifestContent []byte, imgStore storageTypes.ImageStore,
) (godigest.Digest, ispec.Manifest, error) { ) (godigest.Digest, ispec.Manifest, error) {
// Q oras artifacts?
if manifestDesc.MediaType != ispec.MediaTypeImageManifest { if manifestDesc.MediaType != ispec.MediaTypeImageManifest {
return manifestDesc.Digest, ispec.Manifest{}, zerr.ErrBadManifest return manifestDesc.Digest, ispec.Manifest{}, zerr.ErrBadManifest
} }

View file

@ -22,7 +22,6 @@ import (
guuid "github.com/gofrs/uuid" guuid "github.com/gofrs/uuid"
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1"
"github.com/rs/zerolog" "github.com/rs/zerolog"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
"gopkg.in/resty.v1" "gopkg.in/resty.v1"
@ -1389,87 +1388,6 @@ func TestReuploadCorruptedBlob(t *testing.T) {
So(size, ShouldEqual, blobSize) So(size, ShouldEqual, blobSize)
So(err, ShouldBeNil) So(err, ShouldBeNil)
}) })
Convey("Test reupload repair corrupted oras artifact", t, func() {
storeController := storage.StoreController{DefaultStore: imgStore}
image := CreateRandomImage()
tag := "oras-artifact"
err := WriteImageToFileSystem(image, repoName, tag, storeController)
So(err, ShouldBeNil)
body := []byte("this is a blob")
blobDigest := godigest.FromBytes(body)
blobPath := imgStore.BlobPath(repoName, blobDigest)
buf := bytes.NewBuffer(body)
blobSize := int64(buf.Len())
_, size, err := imgStore.FullBlobUpload(repoName, buf, blobDigest)
So(err, ShouldBeNil)
So(size, ShouldEqual, blobSize)
artifactManifest := artifactspec.Manifest{}
artifactType := "signature"
artifactManifest.ArtifactType = artifactType
artifactManifest.Subject = &artifactspec.Descriptor{
MediaType: ispec.MediaTypeImageManifest,
Digest: image.Digest(),
Size: image.ManifestDescriptor.Size,
}
artifactManifest.Blobs = []artifactspec.Descriptor{
{
Digest: blobDigest,
Size: blobSize,
},
}
manBuf, err := json.Marshal(artifactManifest)
So(err, ShouldBeNil)
manBufLen := len(manBuf)
manDigest := godigest.FromBytes(manBuf)
_, _, err = imgStore.PutImageManifest(repoName, manDigest.String(), artifactspec.MediaTypeArtifactManifest, manBuf)
So(err, ShouldBeNil)
descriptors, err := imgStore.GetOrasReferrers(repoName, image.Digest(), artifactType)
So(err, ShouldBeNil)
So(descriptors, ShouldNotBeEmpty)
So(descriptors[0].ArtifactType, ShouldEqual, artifactType)
So(descriptors[0].MediaType, ShouldEqual, artifactspec.MediaTypeArtifactManifest)
So(descriptors[0].Size, ShouldEqual, manBufLen)
So(descriptors[0].Digest, ShouldEqual, manDigest)
ok, size, err := imgStore.CheckBlob(repoName, blobDigest)
So(ok, ShouldBeTrue)
So(size, ShouldEqual, blobSize)
So(err, ShouldBeNil)
_, err = driver.WriteFile(blobPath, []byte("corrupted"))
So(err, ShouldBeNil)
ok, size, err = imgStore.CheckBlob(repoName, blobDigest)
So(ok, ShouldBeFalse)
So(size, ShouldNotEqual, blobSize)
So(err, ShouldEqual, zerr.ErrBlobNotFound)
buf = bytes.NewBuffer(body)
_, size, err = imgStore.FullBlobUpload(repoName, buf, blobDigest)
So(err, ShouldBeNil)
So(size, ShouldEqual, blobSize)
ok, size, _, err = imgStore.StatBlob(repoName, blobDigest)
So(ok, ShouldBeTrue)
So(blobSize, ShouldEqual, size)
So(err, ShouldBeNil)
ok, size, err = imgStore.CheckBlob(repoName, blobDigest)
So(ok, ShouldBeTrue)
So(size, ShouldEqual, blobSize)
So(err, ShouldBeNil)
})
}) })
} }
} }
@ -1937,35 +1855,6 @@ func TestGarbageCollectImageManifest(t *testing.T) {
ispec.MediaTypeImageManifest, artifactManifestBuf) ispec.MediaTypeImageManifest, artifactManifestBuf)
So(err, ShouldBeNil) So(err, ShouldBeNil)
// push oras manifest pointing to manifest
orasArtifactManifest := artifactspec.Manifest{}
orasArtifactManifest.ArtifactType = "signature-example" //nolint: goconst
orasArtifactManifest.Subject = &artifactspec.Descriptor{
MediaType: ispec.MediaTypeImageManifest,
Digest: digest,
Size: int64(len(manifestBuf)),
}
orasArtifactManifest.Blobs = []artifactspec.Descriptor{
{
Digest: artifactBlobDigest,
MediaType: "application/vnd.oci.image.layer.v1.tar",
Size: int64(len(artifactBlob)),
},
}
orasArtifactManifestBuf, err := json.Marshal(orasArtifactManifest)
So(err, ShouldBeNil)
orasDigest := godigest.FromBytes(orasArtifactManifestBuf)
// push oras manifest
_, _, err = imgStore.PutImageManifest(repoName, orasDigest.Encoded(),
artifactspec.MediaTypeArtifactManifest, orasArtifactManifestBuf)
So(err, ShouldBeNil)
_, _, _, err = imgStore.GetImageManifest(repoName, orasDigest.String())
So(err, ShouldBeNil)
err = gc.CleanRepo(ctx, repoName) err = gc.CleanRepo(ctx, repoName)
So(err, ShouldBeNil) So(err, ShouldBeNil)
@ -2007,9 +1896,6 @@ func TestGarbageCollectImageManifest(t *testing.T) {
_, _, _, err := imgStore.GetImageManifest(repoName, artifactDigest.String()) _, _, _, err := imgStore.GetImageManifest(repoName, artifactDigest.String())
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
_, _, _, err = imgStore.GetImageManifest(repoName, orasDigest.String())
So(err, ShouldNotBeNil)
_, _, _, err = imgStore.GetImageManifest(repoName, artifactOfArtifactManifestDigest.String()) _, _, _, err = imgStore.GetImageManifest(repoName, artifactOfArtifactManifestDigest.String())
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
@ -2052,9 +1938,6 @@ func TestGarbageCollectImageManifest(t *testing.T) {
_, _, _, err := imgStore.GetImageManifest(repoName, artifactDigest.String()) _, _, _, err := imgStore.GetImageManifest(repoName, artifactDigest.String())
So(err, ShouldBeNil) So(err, ShouldBeNil)
_, _, _, err = imgStore.GetImageManifest(repoName, orasDigest.String())
So(err, ShouldBeNil)
_, _, _, err = imgStore.GetImageManifest(repoName, artifactOfArtifactManifestDigest.String()) _, _, _, err = imgStore.GetImageManifest(repoName, artifactOfArtifactManifestDigest.String())
So(err, ShouldBeNil) So(err, ShouldBeNil)
}) })
@ -2590,35 +2473,6 @@ func TestGarbageCollectImageIndex(t *testing.T) {
ispec.MediaTypeImageManifest, artifactManifestBuf) ispec.MediaTypeImageManifest, artifactManifestBuf)
So(err, ShouldBeNil) So(err, ShouldBeNil)
// push oras manifest pointing to index image
orasArtifactManifest := artifactspec.Manifest{}
orasArtifactManifest.ArtifactType = "signature-example"
orasArtifactManifest.Subject = &artifactspec.Descriptor{
MediaType: ispec.MediaTypeImageIndex,
Digest: indexDigest,
Size: indexSize,
}
orasArtifactManifest.Blobs = []artifactspec.Descriptor{}
orasArtifactManifestBuf, err := json.Marshal(orasArtifactManifest)
So(err, ShouldBeNil)
orasDigest := godigest.FromBytes(orasArtifactManifestBuf)
// push oras manifest
_, _, err = imgStore.PutImageManifest(repoName, orasDigest.Encoded(),
artifactspec.MediaTypeArtifactManifest, orasArtifactManifestBuf)
So(err, ShouldBeNil)
_, _, _, err = imgStore.GetImageManifest(repoName, orasDigest.String())
So(err, ShouldBeNil)
err = gc.CleanRepo(ctx, repoName)
So(err, ShouldBeNil)
_, _, _, err = imgStore.GetImageManifest(repoName, orasDigest.String())
So(err, ShouldBeNil)
hasBlob, _, err := imgStore.CheckBlob(repoName, bdgst) hasBlob, _, err := imgStore.CheckBlob(repoName, bdgst)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(hasBlob, ShouldEqual, true) So(hasBlob, ShouldEqual, true)
@ -2659,9 +2513,6 @@ func TestGarbageCollectImageIndex(t *testing.T) {
_, _, _, err = imgStore.GetImageManifest(repoName, artifactOfArtifactManifestDigest.String()) _, _, _, err = imgStore.GetImageManifest(repoName, artifactOfArtifactManifestDigest.String())
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
_, _, _, err = imgStore.GetImageManifest(repoName, orasDigest.String())
So(err, ShouldBeNil)
_, _, _, err = imgStore.GetImageManifest(repoName, artifactManifestIndexDigest.String()) _, _, _, err = imgStore.GetImageManifest(repoName, artifactManifestIndexDigest.String())
So(err, ShouldBeNil) So(err, ShouldBeNil)
}) })
@ -2692,9 +2543,6 @@ func TestGarbageCollectImageIndex(t *testing.T) {
_, _, _, err = imgStore.GetImageManifest(repoName, artifactDigest.String()) _, _, _, err = imgStore.GetImageManifest(repoName, artifactDigest.String())
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
_, _, _, err = imgStore.GetImageManifest(repoName, orasDigest.String())
So(err, ShouldNotBeNil)
_, _, _, err = imgStore.GetImageManifest(repoName, artifactOfArtifactManifestDigest.String()) _, _, _, err = imgStore.GetImageManifest(repoName, artifactOfArtifactManifestDigest.String())
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
@ -3096,35 +2944,6 @@ func TestGarbageCollectChainedImageIndexes(t *testing.T) {
ispec.MediaTypeImageManifest, artifactManifestBuf) ispec.MediaTypeImageManifest, artifactManifestBuf)
So(err, ShouldBeNil) So(err, ShouldBeNil)
// push oras manifest pointing to index image
orasArtifactManifest := artifactspec.Manifest{}
orasArtifactManifest.ArtifactType = "signature-example"
orasArtifactManifest.Subject = &artifactspec.Descriptor{
MediaType: ispec.MediaTypeImageIndex,
Digest: indexDigest,
Size: int64(len(indexContent)),
}
orasArtifactManifest.Blobs = []artifactspec.Descriptor{}
orasArtifactManifestBuf, err := json.Marshal(orasArtifactManifest)
So(err, ShouldBeNil)
orasDigest := godigest.FromBytes(orasArtifactManifestBuf)
// push oras manifest
_, _, err = imgStore.PutImageManifest(repoName, orasDigest.Encoded(),
artifactspec.MediaTypeArtifactManifest, orasArtifactManifestBuf)
So(err, ShouldBeNil)
_, _, _, err = imgStore.GetImageManifest(repoName, orasDigest.String())
So(err, ShouldBeNil)
err = gc.CleanRepo(ctx, repoName)
So(err, ShouldBeNil)
_, _, _, err = imgStore.GetImageManifest(repoName, orasDigest.String())
So(err, ShouldBeNil)
hasBlob, _, err := imgStore.CheckBlob(repoName, bdgst) hasBlob, _, err := imgStore.CheckBlob(repoName, bdgst)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(hasBlob, ShouldEqual, true) So(hasBlob, ShouldEqual, true)
@ -3165,9 +2984,6 @@ func TestGarbageCollectChainedImageIndexes(t *testing.T) {
_, _, _, err = imgStore.GetImageManifest(repoName, artifactOfArtifactManifestDigest.String()) _, _, _, err = imgStore.GetImageManifest(repoName, artifactOfArtifactManifestDigest.String())
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
_, _, _, err = imgStore.GetImageManifest(repoName, orasDigest.String())
So(err, ShouldBeNil)
_, _, _, err = imgStore.GetImageManifest(repoName, artifactManifestIndexDigest.String()) _, _, _, err = imgStore.GetImageManifest(repoName, artifactManifestIndexDigest.String())
So(err, ShouldBeNil) So(err, ShouldBeNil)
}) })
@ -3198,9 +3014,6 @@ func TestGarbageCollectChainedImageIndexes(t *testing.T) {
_, _, _, err = imgStore.GetImageManifest(repoName, artifactDigest.String()) _, _, _, err = imgStore.GetImageManifest(repoName, artifactDigest.String())
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
_, _, _, err = imgStore.GetImageManifest(repoName, orasDigest.String())
So(err, ShouldNotBeNil)
_, _, _, err = imgStore.GetImageManifest(repoName, artifactOfArtifactManifestDigest.String()) _, _, _, err = imgStore.GetImageManifest(repoName, artifactOfArtifactManifestDigest.String())
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)

View file

@ -8,7 +8,6 @@ import (
storagedriver "github.com/docker/distribution/registry/storage/driver" storagedriver "github.com/docker/distribution/registry/storage/driver"
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1"
"zotregistry.dev/zot/pkg/scheduler" "zotregistry.dev/zot/pkg/scheduler"
) )
@ -58,7 +57,6 @@ type ImageStore interface { //nolint:interfacebloat
StatIndex(repo string) (bool, int64, time.Time, error) StatIndex(repo string) (bool, int64, time.Time, error)
GetBlobContent(repo string, digest godigest.Digest) ([]byte, error) GetBlobContent(repo string, digest godigest.Digest) ([]byte, error)
GetReferrers(repo string, digest godigest.Digest, artifactTypes []string) (ispec.Index, error) GetReferrers(repo string, digest godigest.Digest, artifactTypes []string) (ispec.Index, error)
GetOrasReferrers(repo string, digest godigest.Digest, artifactType string) ([]artifactspec.Descriptor, error)
RunDedupeBlobs(interval time.Duration, sch *scheduler.Scheduler) RunDedupeBlobs(interval time.Duration, sch *scheduler.Scheduler)
RunDedupeForDigest(ctx context.Context, digest godigest.Digest, dedupe bool, duplicateBlobs []string) error RunDedupeForDigest(ctx context.Context, digest godigest.Digest, dedupe bool, duplicateBlobs []string) error
GetNextDigestWithBlobPaths(repos []string, lastDigests []godigest.Digest) (godigest.Digest, []string, error) GetNextDigestWithBlobPaths(repos []string, lastDigests []godigest.Digest) (godigest.Digest, []string, error)

View file

@ -7,7 +7,6 @@ import (
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1"
"zotregistry.dev/zot/pkg/scheduler" "zotregistry.dev/zot/pkg/scheduler"
) )
@ -40,13 +39,11 @@ type MockedImageStore struct {
StatBlobFn func(repo string, digest godigest.Digest) (bool, int64, time.Time, error) StatBlobFn func(repo string, digest godigest.Digest) (bool, int64, time.Time, error)
GetBlobPartialFn func(repo string, digest godigest.Digest, mediaType string, from, to int64, GetBlobPartialFn func(repo string, digest godigest.Digest, mediaType string, from, to int64,
) (io.ReadCloser, int64, int64, error) ) (io.ReadCloser, int64, int64, error)
GetBlobFn func(repo string, digest godigest.Digest, mediaType string) (io.ReadCloser, int64, error) GetBlobFn func(repo string, digest godigest.Digest, mediaType string) (io.ReadCloser, int64, error)
DeleteBlobFn func(repo string, digest godigest.Digest) error DeleteBlobFn func(repo string, digest godigest.Digest) error
GetIndexContentFn func(repo string) ([]byte, error) GetIndexContentFn func(repo string) ([]byte, error)
GetBlobContentFn func(repo string, digest godigest.Digest) ([]byte, error) GetBlobContentFn func(repo string, digest godigest.Digest) ([]byte, error)
GetReferrersFn func(repo string, digest godigest.Digest, artifactTypes []string) (ispec.Index, error) GetReferrersFn func(repo string, digest godigest.Digest, artifactTypes []string) (ispec.Index, error)
GetOrasReferrersFn func(repo string, digest godigest.Digest, artifactType string,
) ([]artifactspec.Descriptor, error)
URLForPathFn func(path string) (string, error) URLForPathFn func(path string) (string, error)
RunGCRepoFn func(repo string) error RunGCRepoFn func(repo string) error
RunGCPeriodicallyFn func(interval time.Duration, sch *scheduler.Scheduler) RunGCPeriodicallyFn func(interval time.Duration, sch *scheduler.Scheduler)
@ -346,18 +343,6 @@ func (is MockedImageStore) GetReferrers(
return ispec.Index{}, nil return ispec.Index{}, nil
} }
func (is MockedImageStore) GetOrasReferrers(
repo string,
digest godigest.Digest,
artifactType string,
) ([]artifactspec.Descriptor, error) {
if is.GetOrasReferrersFn != nil {
return is.GetOrasReferrersFn(repo, digest, artifactType)
}
return []artifactspec.Descriptor{}, nil
}
func (is MockedImageStore) URLForPath(path string) (string, error) { func (is MockedImageStore) URLForPath(path string) (string, error) {
if is.URLForPathFn != nil { if is.URLForPathFn != nil {
return is.URLForPathFn(path) return is.URLForPathFn(path)

View file

@ -19,61 +19,6 @@ const docTemplate = `{
"host": "{{.Host}}", "host": "{{.Host}}",
"basePath": "{{.BasePath}}", "basePath": "{{.BasePath}}",
"paths": { "paths": {
"/oras/artifacts/v1/{name}/manifests/{digest}/referrers": {
"get": {
"description": "Get references for an image given a digest and artifact type",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "Get references for an image",
"parameters": [
{
"type": "string",
"description": "repository name",
"name": "name",
"in": "path",
"required": true
},
{
"type": "string",
"description": "image digest",
"name": "digest",
"in": "path",
"required": true
},
{
"type": "string",
"description": "artifact type",
"name": "artifactType",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "ok",
"schema": {
"type": "string"
}
},
"404": {
"description": "not found",
"schema": {
"type": "string"
}
},
"500": {
"description": "internal server error",
"schema": {
"type": "string"
}
}
}
}
},
"/v2/": { "/v2/": {
"get": { "get": {
"description": "Check if this API version is supported", "description": "Check if this API version is supported",
@ -1211,7 +1156,7 @@ const docTemplate = `{
"description": "Manifests references platform specific manifests.", "description": "Manifests references platform specific manifests.",
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/github_com_opencontainers_image-spec_specs-go_v1.Descriptor" "$ref": "#/definitions/v1.Descriptor"
} }
}, },
"mediaType": { "mediaType": {
@ -1226,7 +1171,7 @@ const docTemplate = `{
"description": "Subject is an optional link from the image manifest to another manifest forming an association between the image manifest and the other manifest.", "description": "Subject is an optional link from the image manifest to another manifest forming an association between the image manifest and the other manifest.",
"allOf": [ "allOf": [
{ {
"$ref": "#/definitions/github_com_opencontainers_image-spec_specs-go_v1.Descriptor" "$ref": "#/definitions/v1.Descriptor"
} }
] ]
} }
@ -1250,7 +1195,7 @@ const docTemplate = `{
"description": "Config references a configuration object for a container, by digest.\nThe referenced configuration object is a JSON blob that the runtime uses to set up the container.", "description": "Config references a configuration object for a container, by digest.\nThe referenced configuration object is a JSON blob that the runtime uses to set up the container.",
"allOf": [ "allOf": [
{ {
"$ref": "#/definitions/github_com_opencontainers_image-spec_specs-go_v1.Descriptor" "$ref": "#/definitions/v1.Descriptor"
} }
] ]
}, },
@ -1258,7 +1203,7 @@ const docTemplate = `{
"description": "Layers is an indexed list of layers referenced by the manifest.", "description": "Layers is an indexed list of layers referenced by the manifest.",
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/github_com_opencontainers_image-spec_specs-go_v1.Descriptor" "$ref": "#/definitions/v1.Descriptor"
} }
}, },
"mediaType": { "mediaType": {
@ -1273,7 +1218,7 @@ const docTemplate = `{
"description": "Subject is an optional link from the image manifest to another manifest forming an association between the image manifest and the other manifest.", "description": "Subject is an optional link from the image manifest to another manifest forming an association between the image manifest and the other manifest.",
"allOf": [ "allOf": [
{ {
"$ref": "#/definitions/github_com_opencontainers_image-spec_specs-go_v1.Descriptor" "$ref": "#/definitions/v1.Descriptor"
} }
] ]
} }
@ -1412,7 +1357,7 @@ const docTemplate = `{
} }
} }
}, },
"github_com_opencontainers_image-spec_specs-go_v1.Descriptor": { "v1.Descriptor": {
"type": "object", "type": "object",
"properties": { "properties": {
"annotations": { "annotations": {

View file

@ -11,61 +11,6 @@
"version": "v1.1.0" "version": "v1.1.0"
}, },
"paths": { "paths": {
"/oras/artifacts/v1/{name}/manifests/{digest}/referrers": {
"get": {
"description": "Get references for an image given a digest and artifact type",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "Get references for an image",
"parameters": [
{
"type": "string",
"description": "repository name",
"name": "name",
"in": "path",
"required": true
},
{
"type": "string",
"description": "image digest",
"name": "digest",
"in": "path",
"required": true
},
{
"type": "string",
"description": "artifact type",
"name": "artifactType",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "ok",
"schema": {
"type": "string"
}
},
"404": {
"description": "not found",
"schema": {
"type": "string"
}
},
"500": {
"description": "internal server error",
"schema": {
"type": "string"
}
}
}
}
},
"/v2/": { "/v2/": {
"get": { "get": {
"description": "Check if this API version is supported", "description": "Check if this API version is supported",
@ -1203,7 +1148,7 @@
"description": "Manifests references platform specific manifests.", "description": "Manifests references platform specific manifests.",
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/github_com_opencontainers_image-spec_specs-go_v1.Descriptor" "$ref": "#/definitions/v1.Descriptor"
} }
}, },
"mediaType": { "mediaType": {
@ -1218,7 +1163,7 @@
"description": "Subject is an optional link from the image manifest to another manifest forming an association between the image manifest and the other manifest.", "description": "Subject is an optional link from the image manifest to another manifest forming an association between the image manifest and the other manifest.",
"allOf": [ "allOf": [
{ {
"$ref": "#/definitions/github_com_opencontainers_image-spec_specs-go_v1.Descriptor" "$ref": "#/definitions/v1.Descriptor"
} }
] ]
} }
@ -1242,7 +1187,7 @@
"description": "Config references a configuration object for a container, by digest.\nThe referenced configuration object is a JSON blob that the runtime uses to set up the container.", "description": "Config references a configuration object for a container, by digest.\nThe referenced configuration object is a JSON blob that the runtime uses to set up the container.",
"allOf": [ "allOf": [
{ {
"$ref": "#/definitions/github_com_opencontainers_image-spec_specs-go_v1.Descriptor" "$ref": "#/definitions/v1.Descriptor"
} }
] ]
}, },
@ -1250,7 +1195,7 @@
"description": "Layers is an indexed list of layers referenced by the manifest.", "description": "Layers is an indexed list of layers referenced by the manifest.",
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/github_com_opencontainers_image-spec_specs-go_v1.Descriptor" "$ref": "#/definitions/v1.Descriptor"
} }
}, },
"mediaType": { "mediaType": {
@ -1265,7 +1210,7 @@
"description": "Subject is an optional link from the image manifest to another manifest forming an association between the image manifest and the other manifest.", "description": "Subject is an optional link from the image manifest to another manifest forming an association between the image manifest and the other manifest.",
"allOf": [ "allOf": [
{ {
"$ref": "#/definitions/github_com_opencontainers_image-spec_specs-go_v1.Descriptor" "$ref": "#/definitions/v1.Descriptor"
} }
] ]
} }
@ -1404,7 +1349,7 @@
} }
} }
}, },
"github_com_opencontainers_image-spec_specs-go_v1.Descriptor": { "v1.Descriptor": {
"type": "object", "type": "object",
"properties": { "properties": {
"annotations": { "annotations": {

View file

@ -31,7 +31,7 @@ definitions:
manifests: manifests:
description: Manifests references platform specific manifests. description: Manifests references platform specific manifests.
items: items:
$ref: '#/definitions/github_com_opencontainers_image-spec_specs-go_v1.Descriptor' $ref: '#/definitions/v1.Descriptor'
type: array type: array
mediaType: mediaType:
description: MediaType specifies the type of this document data structure description: MediaType specifies the type of this document data structure
@ -42,7 +42,7 @@ definitions:
type: integer type: integer
subject: subject:
allOf: allOf:
- $ref: '#/definitions/github_com_opencontainers_image-spec_specs-go_v1.Descriptor' - $ref: '#/definitions/v1.Descriptor'
description: Subject is an optional link from the image manifest to another description: Subject is an optional link from the image manifest to another
manifest forming an association between the image manifest and the other manifest forming an association between the image manifest and the other
manifest. manifest.
@ -60,14 +60,14 @@ definitions:
type: string type: string
config: config:
allOf: allOf:
- $ref: '#/definitions/github_com_opencontainers_image-spec_specs-go_v1.Descriptor' - $ref: '#/definitions/v1.Descriptor'
description: |- description: |-
Config references a configuration object for a container, by digest. Config references a configuration object for a container, by digest.
The referenced configuration object is a JSON blob that the runtime uses to set up the container. The referenced configuration object is a JSON blob that the runtime uses to set up the container.
layers: layers:
description: Layers is an indexed list of layers referenced by the manifest. description: Layers is an indexed list of layers referenced by the manifest.
items: items:
$ref: '#/definitions/github_com_opencontainers_image-spec_specs-go_v1.Descriptor' $ref: '#/definitions/v1.Descriptor'
type: array type: array
mediaType: mediaType:
description: MediaType specifies the type of this document data structure description: MediaType specifies the type of this document data structure
@ -78,7 +78,7 @@ definitions:
type: integer type: integer
subject: subject:
allOf: allOf:
- $ref: '#/definitions/github_com_opencontainers_image-spec_specs-go_v1.Descriptor' - $ref: '#/definitions/v1.Descriptor'
description: Subject is an optional link from the image manifest to another description: Subject is an optional link from the image manifest to another
manifest forming an association between the image manifest and the other manifest forming an association between the image manifest and the other
manifest. manifest.
@ -168,7 +168,7 @@ definitions:
releaseTag: releaseTag:
type: string type: string
type: object type: object
github_com_opencontainers_image-spec_specs-go_v1.Descriptor: v1.Descriptor:
properties: properties:
annotations: annotations:
additionalProperties: additionalProperties:
@ -247,43 +247,6 @@ info:
title: Open Container Initiative Distribution Specification title: Open Container Initiative Distribution Specification
version: v1.1.0 version: v1.1.0
paths: paths:
/oras/artifacts/v1/{name}/manifests/{digest}/referrers:
get:
consumes:
- application/json
description: Get references for an image given a digest and artifact type
parameters:
- description: repository name
in: path
name: name
required: true
type: string
- description: image digest
in: path
name: digest
required: true
type: string
- description: artifact type
in: query
name: artifactType
required: true
type: string
produces:
- application/json
responses:
"200":
description: ok
schema:
type: string
"404":
description: not found
schema:
type: string
"500":
description: internal server error
schema:
type: string
summary: Get references for an image
/v2/: /v2/:
get: get:
consumes: consumes:

View file

@ -332,7 +332,7 @@ function teardown_file() {
@test "sync image on demand from ghcr.io" { @test "sync image on demand from ghcr.io" {
zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port` zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port`
run skopeo copy docker://127.0.0.1:${zot_port}/project-zot/zot-linux-amd64:v2.0.0-rc5 oci:${TEST_DATA_DIR} --src-tls-verify=false run skopeo copy docker://127.0.0.1:${zot_port}/project-zot/zot-linux-amd64:v2.0.1 oci:${TEST_DATA_DIR} --src-tls-verify=false
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
run curl http://127.0.0.1:${zot_port}/v2/_catalog run curl http://127.0.0.1:${zot_port}/v2/_catalog
@ -340,7 +340,7 @@ function teardown_file() {
[ $(echo "${lines[-1]}"| jq '.repositories | map(select(. == "project-zot/zot-linux-amd64"))' | jq '.[]') = '"project-zot/zot-linux-amd64"' ] [ $(echo "${lines[-1]}"| jq '.repositories | map(select(. == "project-zot/zot-linux-amd64"))' | jq '.[]') = '"project-zot/zot-linux-amd64"' ]
run curl http://127.0.0.1:${zot_port}/v2/project-zot/zot-linux-amd64/tags/list run curl http://127.0.0.1:${zot_port}/v2/project-zot/zot-linux-amd64/tags/list
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
[ $(echo "${lines[-1]}" | jq '.tags[]') = '"v2.0.0-rc5"' ] [ $(echo "${lines[-1]}" | jq '.tags[]') = '"v2.0.1"' ]
} }
@test "run docker with image synced from docker.io" { @test "run docker with image synced from docker.io" {
@ -450,7 +450,7 @@ function teardown_file() {
@test "run docker with image synced from ghcr.io" { @test "run docker with image synced from ghcr.io" {
zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port` zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port`
run docker run -d 127.0.0.1:${zot_port}/project-zot/zot-linux-amd64:v2.0.0-rc5 run docker run -d 127.0.0.1:${zot_port}/project-zot/zot-linux-amd64:v2.0.1
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
run curl http://127.0.0.1:${zot_port}/v2/_catalog run curl http://127.0.0.1:${zot_port}/v2/_catalog
@ -458,5 +458,5 @@ function teardown_file() {
[ $(echo "${lines[-1]}"| jq '.repositories | map(select(. == "project-zot/zot-linux-amd64"))' | jq '.[]') = '"project-zot/zot-linux-amd64"' ] [ $(echo "${lines[-1]}"| jq '.repositories | map(select(. == "project-zot/zot-linux-amd64"))' | jq '.[]') = '"project-zot/zot-linux-amd64"' ]
run curl http://127.0.0.1:${zot_port}/v2/project-zot/zot-linux-amd64/tags/list run curl http://127.0.0.1:${zot_port}/v2/project-zot/zot-linux-amd64/tags/list
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
[ $(echo "${lines[-1]}" | jq '.tags[]') = '"v2.0.0-rc5"' ] [ $(echo "${lines[-1]}" | jq '.tags[]') = '"v2.0.1"' ]
} }