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:
parent
5039128723
commit
18235ca254
25 changed files with 35 additions and 1687 deletions
1
go.mod
1
go.mod
|
@ -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
2
go.sum
|
@ -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=
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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"`
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
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
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -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: ®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) {
|
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
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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", "")
|
||||||
|
|
|
@ -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)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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": {
|
||||||
|
|
|
@ -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": {
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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"' ]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue