mirror of
https://github.com/project-zot/zot.git
synced 2026-06-17 21:09:23 +08:00
refactor(artifact): remove oci artifact support (#1359)
* refactor(artifact): remove oci artifact support - add header to referrers call to indicated applied artifact type filters Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com> * feat(gc): simplify gc logic to increase coverage Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com> --------- Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com>
This commit is contained in:
+5
-135
@@ -51,7 +51,6 @@ import (
|
||||
"zotregistry.io/zot/pkg/log"
|
||||
"zotregistry.io/zot/pkg/meta/repodb/repodbfactory"
|
||||
"zotregistry.io/zot/pkg/storage"
|
||||
storageConstants "zotregistry.io/zot/pkg/storage/constants"
|
||||
"zotregistry.io/zot/pkg/storage/local"
|
||||
"zotregistry.io/zot/pkg/test"
|
||||
)
|
||||
@@ -157,7 +156,6 @@ func TestCreateCacheDatabaseDriver(t *testing.T) {
|
||||
"cacheTablename": "BlobTable",
|
||||
"repoMetaTablename": "RepoMetadataTable",
|
||||
"manifestDataTablename": "ManifestDataTable",
|
||||
"artifactDataTablename": "ArtifactDataTable",
|
||||
"userDataTablename": "ZotUserDataTable",
|
||||
"versionTablename": "Version",
|
||||
}
|
||||
@@ -173,7 +171,6 @@ func TestCreateCacheDatabaseDriver(t *testing.T) {
|
||||
"cacheTablename": "BlobTable",
|
||||
"repoMetaTablename": "RepoMetadataTable",
|
||||
"manifestDataTablename": "ManifestDataTable",
|
||||
"artifactDataTablename": "ArtifactDataTable",
|
||||
"userDataTablename": "ZotUserDataTable",
|
||||
"versionTablename": "Version",
|
||||
}
|
||||
@@ -188,7 +185,6 @@ func TestCreateCacheDatabaseDriver(t *testing.T) {
|
||||
"cacheTablename": "BlobTable",
|
||||
"repoMetaTablename": "RepoMetadataTable",
|
||||
"manifestDataTablename": "ManifestDataTable",
|
||||
"artifactDataTablename": "ArtifactDataTable",
|
||||
"userDataTablename": "ZotUserDataTable",
|
||||
"versionTablename": "Version",
|
||||
}
|
||||
@@ -222,7 +218,6 @@ func TestCreateRepoDBDriver(t *testing.T) {
|
||||
"cachetablename": "BlobTable",
|
||||
"repometatablename": "RepoMetadataTable",
|
||||
"manifestdatatablename": "ManifestDataTable",
|
||||
"artifactDataTablename": "ArtifactDataTable",
|
||||
"userdatatablename": "UserDatatable",
|
||||
}
|
||||
|
||||
@@ -236,7 +231,6 @@ func TestCreateRepoDBDriver(t *testing.T) {
|
||||
"cachetablename": "",
|
||||
"repometatablename": "RepoMetadataTable",
|
||||
"manifestdatatablename": "ManifestDataTable",
|
||||
"artifactDataTablename": "ArtifactDataTable",
|
||||
"userDataTablename": "ZotUserDataTable",
|
||||
"versiontablename": 1,
|
||||
}
|
||||
@@ -252,7 +246,6 @@ func TestCreateRepoDBDriver(t *testing.T) {
|
||||
"repometatablename": "RepoMetadataTable",
|
||||
"manifestdatatablename": "ManifestDataTable",
|
||||
"indexdatatablename": "IndexDataTable",
|
||||
"artifactdatatablename": "ArtifactDataTable",
|
||||
"userdatatablename": "ZotUserDataTable",
|
||||
"versiontablename": "1",
|
||||
}
|
||||
@@ -4395,138 +4388,15 @@ func TestArtifactReferences(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
So(resp.Header().Get("Content-Type"), ShouldEqual, ispec.MediaTypeImageIndex)
|
||||
})
|
||||
})
|
||||
So(resp.Header().Get("OCI-Filters-Applied"), ShouldEqual, artifactType)
|
||||
|
||||
Convey("Validate Artifact Manifest Reference", func() {
|
||||
resp, err := resty.R().Get(baseURL + fmt.Sprintf("/v2/%s/referrers/%s", repoName, digest.String()))
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
|
||||
var referrers ispec.Index
|
||||
err = json.Unmarshal(resp.Body(), &referrers)
|
||||
So(err, ShouldBeNil)
|
||||
So(referrers.Manifests, ShouldBeEmpty)
|
||||
|
||||
// now upload a reference
|
||||
|
||||
// upload image config blob
|
||||
resp, err = resty.R().Post(baseURL + fmt.Sprintf("/v2/%s/blobs/uploads/", repoName))
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusAccepted)
|
||||
loc := test.Location(baseURL, resp)
|
||||
cblob, cdigest := test.GetEmptyImageConfig()
|
||||
|
||||
resp, err = resty.R().
|
||||
SetContentLength(true).
|
||||
SetHeader("Content-Length", fmt.Sprintf("%d", len(cblob))).
|
||||
SetHeader("Content-Type", "application/octet-stream").
|
||||
SetQueryParam("digest", cdigest.String()).
|
||||
SetBody(cblob).
|
||||
Put(loc)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusCreated)
|
||||
|
||||
// create a artifact
|
||||
manifest := ispec.Artifact{
|
||||
MediaType: ispec.MediaTypeArtifactManifest,
|
||||
ArtifactType: artifactType,
|
||||
Blobs: []ispec.Descriptor{
|
||||
{
|
||||
MediaType: "application/vnd.oci.image.layer.v1.tar",
|
||||
Digest: digest,
|
||||
Size: int64(len(content)),
|
||||
},
|
||||
},
|
||||
Subject: &ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Digest: digest,
|
||||
Size: int64(len(content)),
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
"key": "val",
|
||||
},
|
||||
}
|
||||
Convey("Using invalid content", func() {
|
||||
content := []byte("invalid data")
|
||||
So(err, ShouldBeNil)
|
||||
mdigest := godigest.FromBytes(content)
|
||||
So(mdigest, ShouldNotBeNil)
|
||||
resp, err = resty.R().SetHeader("Content-Type", ispec.MediaTypeArtifactManifest).
|
||||
SetBody(content).Put(baseURL + fmt.Sprintf("/v2/%s/manifests/%s", repoName, mdigest.String()))
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusBadRequest)
|
||||
|
||||
// unknown repo will return status not found
|
||||
resp, err = resty.R().Get(baseURL + fmt.Sprintf("/v2/%s/referrers/%s", "unknown", digest.String()))
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusNotFound)
|
||||
|
||||
resp, err = resty.R().Get(baseURL + fmt.Sprintf("/v2/%s/referrers/%s", repoName, digest.String()))
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
|
||||
resp, err = resty.R().SetQueryParams(map[string]string{"artifactType": artifactType}).
|
||||
Get(baseURL + fmt.Sprintf("/v2/%s/referrers/%s", repoName, digest.String()))
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
})
|
||||
Convey("Using valid content", func() {
|
||||
content, err = json.Marshal(manifest)
|
||||
So(err, ShouldBeNil)
|
||||
mdigest := godigest.FromBytes(content)
|
||||
So(mdigest, ShouldNotBeNil)
|
||||
resp, err = resty.R().SetHeader("Content-Type", ispec.MediaTypeArtifactManifest).
|
||||
SetBody(content).Put(baseURL + fmt.Sprintf("/v2/%s/manifests/%s", repoName, mdigest.String()))
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusCreated)
|
||||
|
||||
resp, err = resty.R().Get(baseURL + fmt.Sprintf("/v2/%s/referrers/%s", repoName, digest.String()))
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
|
||||
resp, err = resty.R().SetQueryParams(map[string]string{"artifact": "invalid"}).
|
||||
Get(baseURL + fmt.Sprintf("/v2/%s/referrers/%s", repoName, digest.String()))
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
|
||||
resp, err = resty.R().SetQueryParams(map[string]string{"artifactType": "invalid"}).
|
||||
Get(baseURL + fmt.Sprintf("/v2/%s/referrers/%s", repoName, digest.String()))
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
|
||||
resp, err = resty.R().SetQueryParams(map[string]string{"artifactType": artifactType}).
|
||||
Get(baseURL + fmt.Sprintf("/v2/%s/referrers/%s", repoName, digest.String()))
|
||||
resp, err = resty.R().SetQueryParams(map[string]string{"artifactType": artifactType +
|
||||
",otherArtType"}).Get(baseURL + fmt.Sprintf("/v2/%s/referrers/%s", repoName,
|
||||
digest.String()))
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
So(resp.Header().Get("Content-Type"), ShouldEqual, ispec.MediaTypeImageIndex)
|
||||
|
||||
var index ispec.Index
|
||||
err = json.Unmarshal(resp.Body(), &index)
|
||||
So(err, ShouldBeNil)
|
||||
So(index.Manifests, ShouldNotBeEmpty)
|
||||
So(index.Annotations[storageConstants.ReferrerFilterAnnotation], ShouldNotBeEmpty)
|
||||
|
||||
// filter by multiple artifactTypes
|
||||
req, err := http.NewRequestWithContext(context.TODO(), http.MethodGet,
|
||||
baseURL+fmt.Sprintf("/v2/%s/referrers/%s", repoName, digest.String()), nil)
|
||||
So(err, ShouldBeNil)
|
||||
values := url.Values{}
|
||||
values.Add("artifactType", artifactType)
|
||||
values.Add("artifactType", "foobar")
|
||||
req.URL.RawQuery = values.Encode()
|
||||
rsp, err := http.DefaultClient.Do(req)
|
||||
So(err, ShouldBeNil)
|
||||
defer rsp.Body.Close()
|
||||
So(rsp.StatusCode, ShouldEqual, http.StatusOK)
|
||||
So(rsp.Header.Get("Content-Type"), ShouldEqual, ispec.MediaTypeImageIndex)
|
||||
body, err := io.ReadAll(rsp.Body)
|
||||
So(err, ShouldBeNil)
|
||||
err = json.Unmarshal(body, &index)
|
||||
So(err, ShouldBeNil)
|
||||
So(index.Manifests, ShouldNotBeEmpty)
|
||||
So(index.Annotations[storageConstants.ReferrerFilterAnnotation], ShouldNotBeEmpty)
|
||||
So(len(strings.Split(index.Annotations[storageConstants.ReferrerFilterAnnotation], ",")), ShouldEqual, 2)
|
||||
So(resp.Header().Get("OCI-Filters-Applied"), ShouldEqual, artifactType+",otherArtType")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
+5
-1
@@ -433,7 +433,7 @@ func (rh *RouteHandler) GetManifest(response http.ResponseWriter, request *http.
|
||||
}
|
||||
|
||||
if rh.c.RepoDB != nil {
|
||||
err := meta.OnGetManifest(name, reference, digest, content, rh.c.StoreController, rh.c.RepoDB, rh.c.Log)
|
||||
err := meta.OnGetManifest(name, reference, content, rh.c.StoreController, rh.c.RepoDB, rh.c.Log)
|
||||
|
||||
if errors.Is(err, zerr.ErrOrphanSignature) {
|
||||
rh.c.Log.Error().Err(err).Msg("image is an orphan signature")
|
||||
@@ -546,6 +546,10 @@ func (rh *RouteHandler) GetReferrers(response http.ResponseWriter, request *http
|
||||
return
|
||||
}
|
||||
|
||||
if len(artifactTypes) > 0 {
|
||||
response.Header().Set("OCI-Filters-Applied", strings.Join(artifactTypes, ","))
|
||||
}
|
||||
|
||||
WriteData(response, http.StatusOK, ispec.MediaTypeImageIndex, out)
|
||||
}
|
||||
|
||||
|
||||
+2
-4
@@ -490,10 +490,8 @@ func isNotationSigned(ctx context.Context, repo, digestStr string, searchConf se
|
||||
return false
|
||||
}
|
||||
|
||||
for _, reference := range referrers.Manifests {
|
||||
if reference.ArtifactType == notreg.ArtifactTypeNotation {
|
||||
return true
|
||||
}
|
||||
if len(referrers.Manifests) > 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
@@ -5,7 +5,6 @@ package cli //nolint:testpackage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -20,48 +19,6 @@ import (
|
||||
"zotregistry.io/zot/pkg/test"
|
||||
)
|
||||
|
||||
type RouteHandler struct {
|
||||
Route string
|
||||
// HandlerFunc is the HTTP handler function that receives a writer for output and an HTTP request as input.
|
||||
HandlerFunc http.HandlerFunc
|
||||
// AllowedMethods specifies the HTTP methods allowed for the current route.
|
||||
AllowedMethods []string
|
||||
}
|
||||
|
||||
// Routes is a map that associates HTTP paths to their corresponding HTTP handlers.
|
||||
type HTTPRoutes []RouteHandler
|
||||
|
||||
func StartTestHTTPServer(routes HTTPRoutes, port string) *http.Server {
|
||||
baseURL := test.GetBaseURL(port)
|
||||
mux := mux.NewRouter()
|
||||
|
||||
mux.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
|
||||
_, err := w.Write([]byte("{}"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}).Methods(http.MethodGet)
|
||||
|
||||
for _, routeHandler := range routes {
|
||||
mux.HandleFunc(routeHandler.Route, routeHandler.HandlerFunc).Methods(routeHandler.AllowedMethods...)
|
||||
}
|
||||
|
||||
server := &http.Server{ //nolint:gosec
|
||||
Addr: fmt.Sprintf(":%s", port),
|
||||
Handler: mux,
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
test.WaitTillServerReady(baseURL + "/test")
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
func getDefaultSearchConf(baseURL string) searchConfig {
|
||||
verifyTLS := false
|
||||
debug := false
|
||||
@@ -81,7 +38,7 @@ func getDefaultSearchConf(baseURL string) searchConfig {
|
||||
func TestDoHTTPRequest(t *testing.T) {
|
||||
Convey("doHTTPRequest nil result pointer", t, func() {
|
||||
port := test.GetFreePort()
|
||||
server := StartTestHTTPServer(nil, port)
|
||||
server := test.StartTestHTTPServer(nil, port)
|
||||
defer server.Close()
|
||||
|
||||
url := fmt.Sprintf("http://127.0.0.1:%s/asd", port)
|
||||
@@ -93,7 +50,7 @@ func TestDoHTTPRequest(t *testing.T) {
|
||||
|
||||
Convey("doHTTPRequest bad return json", t, func() {
|
||||
port := test.GetFreePort()
|
||||
server := StartTestHTTPServer(HTTPRoutes{
|
||||
server := test.StartTestHTTPServer(test.HTTPRoutes{
|
||||
{
|
||||
Route: "/test",
|
||||
HandlerFunc: func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -135,7 +92,7 @@ func TestDoHTTPRequest(t *testing.T) {
|
||||
searchConf := getDefaultSearchConf(baseURL)
|
||||
|
||||
// 404 erorr will appear
|
||||
server := StartTestHTTPServer(HTTPRoutes{}, port)
|
||||
server := test.StartTestHTTPServer(test.HTTPRoutes{}, port)
|
||||
defer server.Close()
|
||||
|
||||
URL := baseURL + "/v2/repo/manifests/tag"
|
||||
@@ -158,7 +115,7 @@ func TestDoHTTPRequest(t *testing.T) {
|
||||
searchConf := getDefaultSearchConf(baseURL)
|
||||
|
||||
Convey("makeGETRequest manifest error, context is done", func() {
|
||||
server := StartTestHTTPServer(HTTPRoutes{}, port)
|
||||
server := test.StartTestHTTPServer(test.HTTPRoutes{}, port)
|
||||
defer server.Close()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
@@ -172,7 +129,7 @@ func TestDoHTTPRequest(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("makeGETRequest manifest error, context is not done", func() {
|
||||
server := StartTestHTTPServer(HTTPRoutes{}, port)
|
||||
server := test.StartTestHTTPServer(test.HTTPRoutes{}, port)
|
||||
defer server.Close()
|
||||
|
||||
_, err := fetchManifestStruct(context.Background(), "repo", "tag", searchConf,
|
||||
@@ -182,7 +139,7 @@ func TestDoHTTPRequest(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("makeGETRequest config error, context is not done", func() {
|
||||
server := StartTestHTTPServer(HTTPRoutes{
|
||||
server := test.StartTestHTTPServer(test.HTTPRoutes{
|
||||
{
|
||||
Route: "/v2/{name}/manifests/{reference}",
|
||||
HandlerFunc: func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -203,7 +160,7 @@ func TestDoHTTPRequest(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Platforms on config", func() {
|
||||
server := StartTestHTTPServer(HTTPRoutes{
|
||||
server := test.StartTestHTTPServer(test.HTTPRoutes{
|
||||
{
|
||||
Route: "/v2/{name}/manifests/{reference}",
|
||||
HandlerFunc: func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -258,7 +215,7 @@ func TestDoHTTPRequest(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("fetchImageIndexStruct no errors", func() {
|
||||
server := StartTestHTTPServer(HTTPRoutes{
|
||||
server := test.StartTestHTTPServer(test.HTTPRoutes{
|
||||
{
|
||||
Route: "/v2/{name}/manifests/{reference}",
|
||||
HandlerFunc: func(writer http.ResponseWriter, req *http.Request) {
|
||||
@@ -327,7 +284,7 @@ func TestDoHTTPRequest(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("fetchImageIndexStruct makeGETRequest errors context done", func() {
|
||||
server := StartTestHTTPServer(HTTPRoutes{}, port)
|
||||
server := test.StartTestHTTPServer(test.HTTPRoutes{}, port)
|
||||
defer server.Close()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
@@ -349,7 +306,7 @@ func TestDoHTTPRequest(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("fetchImageIndexStruct makeGETRequest errors context not done", func() {
|
||||
server := StartTestHTTPServer(HTTPRoutes{}, port)
|
||||
server := test.StartTestHTTPServer(test.HTTPRoutes{}, port)
|
||||
defer server.Close()
|
||||
|
||||
URL := baseURL + "/v2/repo/manifests/indexRef"
|
||||
@@ -384,7 +341,7 @@ func TestDoJobErrors(t *testing.T) {
|
||||
reqPool.wtgrp.Add(1)
|
||||
|
||||
Convey("Do Job makeHEADRequest error context done", func() {
|
||||
server := StartTestHTTPServer(HTTPRoutes{}, port)
|
||||
server := test.StartTestHTTPServer(test.HTTPRoutes{}, port)
|
||||
defer server.Close()
|
||||
|
||||
URL := baseURL + "/v2/repo/manifests/manifestRef"
|
||||
@@ -404,7 +361,7 @@ func TestDoJobErrors(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Do Job makeHEADRequest error context not done", func() {
|
||||
server := StartTestHTTPServer(HTTPRoutes{}, port)
|
||||
server := test.StartTestHTTPServer(test.HTTPRoutes{}, port)
|
||||
defer server.Close()
|
||||
|
||||
URL := baseURL + "/v2/repo/manifests/manifestRef"
|
||||
@@ -426,7 +383,7 @@ func TestDoJobErrors(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Do Job fetchManifestStruct errors context canceled", func() {
|
||||
server := StartTestHTTPServer(HTTPRoutes{
|
||||
server := test.StartTestHTTPServer(test.HTTPRoutes{
|
||||
{
|
||||
Route: "/v2/{name}/manifests/{reference}",
|
||||
HandlerFunc: func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -459,7 +416,7 @@ func TestDoJobErrors(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Do Job fetchManifestStruct errors context not canceled", func() {
|
||||
server := StartTestHTTPServer(HTTPRoutes{
|
||||
server := test.StartTestHTTPServer(test.HTTPRoutes{
|
||||
{
|
||||
Route: "/v2/{name}/manifests/{reference}",
|
||||
HandlerFunc: func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -493,7 +450,7 @@ func TestDoJobErrors(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Do Job fetchIndexStruct errors context canceled", func() {
|
||||
server := StartTestHTTPServer(HTTPRoutes{
|
||||
server := test.StartTestHTTPServer(test.HTTPRoutes{
|
||||
{
|
||||
Route: "/v2/{name}/manifests/{reference}",
|
||||
HandlerFunc: func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -526,7 +483,7 @@ func TestDoJobErrors(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Do Job fetchIndexStruct errors context not canceled", func() {
|
||||
server := StartTestHTTPServer(HTTPRoutes{
|
||||
server := test.StartTestHTTPServer(test.HTTPRoutes{
|
||||
{
|
||||
Route: "/v2/{name}/manifests/{reference}",
|
||||
HandlerFunc: func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -559,7 +516,7 @@ func TestDoJobErrors(t *testing.T) {
|
||||
So(result.StrValue, ShouldResemble, "")
|
||||
})
|
||||
Convey("Do Job fetchIndexStruct not supported content type", func() {
|
||||
server := StartTestHTTPServer(HTTPRoutes{
|
||||
server := test.StartTestHTTPServer(test.HTTPRoutes{
|
||||
{
|
||||
Route: "/v2/{name}/manifests/{reference}",
|
||||
HandlerFunc: func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -589,7 +546,7 @@ func TestDoJobErrors(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Media type is MediaTypeImageIndex image.string erorrs", func() {
|
||||
server := StartTestHTTPServer(HTTPRoutes{
|
||||
server := test.StartTestHTTPServer(test.HTTPRoutes{
|
||||
{
|
||||
Route: "/v2/{name}/manifests/{reference}",
|
||||
HandlerFunc: func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -713,7 +713,7 @@ func TestServerCVEResponse(t *testing.T) {
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
str = strings.TrimSpace(str)
|
||||
So(err, ShouldBeNil)
|
||||
So(str, ShouldEqual, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE zot-cve-test 0.0.1 82836dd7 false 548B")
|
||||
So(str, ShouldEqual, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE zot-cve-test 0.0.1 40d1f749 false 605B")
|
||||
})
|
||||
|
||||
Convey("Test images by CVE ID - GQL - invalid CVE ID", t, func() {
|
||||
@@ -829,7 +829,7 @@ func TestServerCVEResponse(t *testing.T) {
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
So(err, ShouldBeNil)
|
||||
So(strings.TrimSpace(str), ShouldEqual,
|
||||
"IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE zot-cve-test 0.0.1 82836dd7 false 548B")
|
||||
"IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE zot-cve-test 0.0.1 40d1f749 false 605B")
|
||||
})
|
||||
|
||||
Convey("Test CVE by name and CVE ID - GQL - invalid name and CVE ID", t, func() {
|
||||
@@ -907,7 +907,7 @@ func TestServerCVEResponse(t *testing.T) {
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
str = strings.TrimSpace(str)
|
||||
So(err, ShouldBeNil)
|
||||
So(str, ShouldEqual, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE zot-cve-test 0.0.1 linux/amd64 82836dd7 false 548B")
|
||||
So(str, ShouldEqual, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE zot-cve-test 0.0.1 linux/amd64 40d1f749 false 605B")
|
||||
})
|
||||
|
||||
Convey("Test images by CVE ID - invalid CVE ID", t, func() {
|
||||
@@ -992,7 +992,7 @@ func TestServerCVEResponse(t *testing.T) {
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
So(err, ShouldBeNil)
|
||||
So(strings.TrimSpace(str), ShouldEqual,
|
||||
"IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE zot-cve-test 0.0.1 linux/amd64 82836dd7 false 548B")
|
||||
"IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE zot-cve-test 0.0.1 linux/amd64 40d1f749 false 605B")
|
||||
})
|
||||
|
||||
Convey("Test CVE by name and CVE ID - invalid name and CVE ID", t, func() {
|
||||
|
||||
+15
-15
@@ -333,7 +333,7 @@ func TestSignature(t *testing.T) {
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
actual := strings.TrimSpace(str)
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 linux/amd64 6742241d true 447B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 linux/amd64 8e59ed3b true 504B")
|
||||
|
||||
t.Log("Test getting all images using rest calls to get catalog and individual manifests")
|
||||
cmd = MockNewImageCommand(new(searchService))
|
||||
@@ -346,7 +346,7 @@ func TestSignature(t *testing.T) {
|
||||
str = space.ReplaceAllString(buff.String(), " ")
|
||||
actual = strings.TrimSpace(str)
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 linux/amd64 6742241d true 447B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 linux/amd64 8e59ed3b true 504B")
|
||||
|
||||
err = os.Chdir(currentWorkingDir)
|
||||
So(err, ShouldBeNil)
|
||||
@@ -410,7 +410,7 @@ func TestSignature(t *testing.T) {
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
actual := strings.TrimSpace(str)
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 0.0.1 linux/amd64 6742241d true 447B")
|
||||
So(actual, ShouldContainSubstring, "repo7 0.0.1 linux/amd64 8e59ed3b true 504B")
|
||||
|
||||
t.Log("Test getting all images using rest calls to get catalog and individual manifests")
|
||||
cmd = MockNewImageCommand(new(searchService))
|
||||
@@ -423,7 +423,7 @@ func TestSignature(t *testing.T) {
|
||||
str = space.ReplaceAllString(buff.String(), " ")
|
||||
actual = strings.TrimSpace(str)
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 0.0.1 linux/amd64 6742241d true 447B")
|
||||
So(actual, ShouldContainSubstring, "repo7 0.0.1 linux/amd64 8e59ed3b true 504B")
|
||||
|
||||
err = os.Chdir(currentWorkingDir)
|
||||
So(err, ShouldBeNil)
|
||||
@@ -1333,13 +1333,13 @@ func runDisplayIndexTests(baseURL string) {
|
||||
actual := strings.TrimSpace(str)
|
||||
// Actual cli output should be something similar to (order of images may differ):
|
||||
// IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE
|
||||
// repo multi-arch * 46b78b06 false 1.4kB
|
||||
// linux/amd64 97b0d65c false 577B
|
||||
// repo multi-arch * 59b25ae4 false 1.5kB
|
||||
// linux/amd64 97b0d65c false 634B
|
||||
// windows/arm64/v6 dcfa3a9c false 444B
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo multi-arch * 46b78b06 false 1.4kB ")
|
||||
So(actual, ShouldContainSubstring, "linux/amd64 97b0d65c false 577B ")
|
||||
So(actual, ShouldContainSubstring, "windows/arm64/v6 dcfa3a9c false 444B")
|
||||
So(actual, ShouldContainSubstring, "repo multi-arch * 59b25ae4 false 1.5kB ")
|
||||
So(actual, ShouldContainSubstring, "linux/amd64 2ab1a275 false 634B ")
|
||||
So(actual, ShouldContainSubstring, "windows/arm64/v6 55fdd23a false 501B")
|
||||
})
|
||||
|
||||
Convey("Test Image Index Verbose", func() {
|
||||
@@ -1361,18 +1361,18 @@ func runDisplayIndexTests(baseURL string) {
|
||||
actual := strings.TrimSpace(str)
|
||||
// Actual cli output should be something similar to (order of images may differ):
|
||||
// IMAGE NAME TAG OS/ARCH DIGEST CONFIG SIGNED LAYERS SIZE
|
||||
// repo multi-arch * 46b78b06 false 1.4kB
|
||||
// linux/amd64 97b0d65c 58cc9abe false 577B
|
||||
// repo multi-arch * 59b25ae4 false 1.5kB
|
||||
// linux/amd64 2ab1a275 58cc9abe false 634B
|
||||
// cbb5b121 4B
|
||||
// a00291e8 4B
|
||||
// windows/arm64/v6 dcfa3a9c 5132a1cd false 444B
|
||||
// windows/arm64/v6 55fdd23a 5132a1cd false 501B
|
||||
// 7d08ce29 4B
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST CONFIG SIGNED LAYERS SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo multi-arch * 46b78b06 false 1.4kB")
|
||||
So(actual, ShouldContainSubstring, "linux/amd64 97b0d65c 58cc9abe false 577B")
|
||||
So(actual, ShouldContainSubstring, "repo multi-arch * 59b25ae4 false 1.5kB")
|
||||
So(actual, ShouldContainSubstring, "linux/amd64 2ab1a275 58cc9abe false 634B")
|
||||
So(actual, ShouldContainSubstring, "cbb5b121 4B")
|
||||
So(actual, ShouldContainSubstring, "a00291e8 4B")
|
||||
So(actual, ShouldContainSubstring, "windows/arm64/v6 dcfa3a9c 5132a1cd false 444B")
|
||||
So(actual, ShouldContainSubstring, "windows/arm64/v6 55fdd23a 5132a1cd false 501B")
|
||||
So(actual, ShouldContainSubstring, "7d08ce29 4B")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/opencontainers/go-digest"
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
|
||||
"zotregistry.io/zot/pkg/log"
|
||||
)
|
||||
@@ -274,3 +275,11 @@ func DContains(slice []digest.Digest, item digest.Digest) bool {
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func GetManifestArtifactType(manifestContent ispec.Manifest) string {
|
||||
if manifestContent.ArtifactType != "" {
|
||||
return manifestContent.ArtifactType
|
||||
}
|
||||
|
||||
return manifestContent.Config.MediaType
|
||||
}
|
||||
|
||||
@@ -78,7 +78,8 @@ func (linter *Linter) CheckMandatoryAnnotations(repo string, manifestDigest godi
|
||||
|
||||
content, err = imgStore.GetBlobContent(repo, configDigest)
|
||||
if err != nil {
|
||||
linter.log.Error().Err(err).Msg("linter: couldn't get config JSON " + configDigest.String())
|
||||
linter.log.Error().Err(err).Msg("linter: couldn't get config JSON " +
|
||||
configDigest.String())
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ func TestConvertErrors(t *testing.T) {
|
||||
Referrers: map[string][]repodb.ReferrerInfo{},
|
||||
},
|
||||
repodb.ManifestMetadata{
|
||||
ManifestBlob: []byte("{}"),
|
||||
ManifestBlob: []byte(`{}`),
|
||||
ConfigBlob: []byte("bad json"),
|
||||
},
|
||||
nil,
|
||||
|
||||
@@ -923,7 +923,7 @@ func TestCVEStruct(t *testing.T) {
|
||||
},
|
||||
Layers: []ispec.Descriptor{
|
||||
{
|
||||
MediaType: ispec.MediaTypeImageLayerNonDistributableGzip,
|
||||
MediaType: ispec.MediaTypeImageLayerNonDistributableGzip, //nolint:staticcheck
|
||||
Size: 0,
|
||||
Digest: godigest.NewDigestFromEncoded(godigest.SHA256, "digest"),
|
||||
},
|
||||
|
||||
@@ -1449,7 +1449,7 @@ func TestGetReferrers(t *testing.T) {
|
||||
Convey("GetReferrers return index of descriptors", func() {
|
||||
testLogger := log.NewLogger("debug", "")
|
||||
referrerDescriptor := ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeArtifactManifest,
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
ArtifactType: "com.artifact.test",
|
||||
Size: 403,
|
||||
Digest: godigest.FromString("test"),
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/gobwas/glob"
|
||||
regTypes "github.com/google/go-containerregistry/pkg/v1/types"
|
||||
notreg "github.com/notaryproject/notation-go/registry"
|
||||
godigest "github.com/opencontainers/go-digest"
|
||||
"github.com/opencontainers/image-spec/specs-go"
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
@@ -31,7 +32,7 @@ import (
|
||||
"zotregistry.io/zot/pkg/api"
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
"zotregistry.io/zot/pkg/api/constants"
|
||||
"zotregistry.io/zot/pkg/common"
|
||||
zcommon "zotregistry.io/zot/pkg/common"
|
||||
extconf "zotregistry.io/zot/pkg/extensions/config"
|
||||
"zotregistry.io/zot/pkg/extensions/monitoring"
|
||||
cveinfo "zotregistry.io/zot/pkg/extensions/search/cve"
|
||||
@@ -97,7 +98,7 @@ type ReferrersResp struct {
|
||||
}
|
||||
|
||||
type ReferrersResult struct {
|
||||
Referrers []common.Referrer `json:"referrers"`
|
||||
Referrers []zcommon.Referrer `json:"referrers"`
|
||||
}
|
||||
type GlobalSearchResultResp struct {
|
||||
GlobalSearchResult GlobalSearchResult `json:"data"`
|
||||
@@ -109,24 +110,24 @@ type GlobalSearchResult struct {
|
||||
}
|
||||
|
||||
type GlobalSearch struct {
|
||||
Images []common.ImageSummary `json:"images"`
|
||||
Repos []common.RepoSummary `json:"repos"`
|
||||
Layers []common.LayerSummary `json:"layers"`
|
||||
Page repodb.PageInfo `json:"page"`
|
||||
Images []zcommon.ImageSummary `json:"images"`
|
||||
Repos []zcommon.RepoSummary `json:"repos"`
|
||||
Layers []zcommon.LayerSummary `json:"layers"`
|
||||
Page repodb.PageInfo `json:"page"`
|
||||
}
|
||||
|
||||
type ExpandedRepoInfo struct {
|
||||
RepoInfo common.RepoInfo `json:"expandedRepoInfo"`
|
||||
RepoInfo zcommon.RepoInfo `json:"expandedRepoInfo"`
|
||||
}
|
||||
|
||||
type PaginatedReposResult struct {
|
||||
Results []common.RepoSummary `json:"results"`
|
||||
Page repodb.PageInfo `json:"page"`
|
||||
Results []zcommon.RepoSummary `json:"results"`
|
||||
Page repodb.PageInfo `json:"page"`
|
||||
}
|
||||
|
||||
type PaginatedImagesResult struct {
|
||||
Results []common.ImageSummary `json:"results"`
|
||||
Page repodb.PageInfo `json:"page"`
|
||||
Results []zcommon.ImageSummary `json:"results"`
|
||||
Page repodb.PageInfo `json:"page"`
|
||||
}
|
||||
|
||||
//nolint:tagliatelle // graphQL schema
|
||||
@@ -140,7 +141,7 @@ type ErrorGQL struct {
|
||||
}
|
||||
|
||||
type SingleImageSummary struct {
|
||||
ImageSummary common.ImageSummary `json:"Image"` //nolint:tagliatelle
|
||||
ImageSummary zcommon.ImageSummary `json:"Image"` //nolint:tagliatelle
|
||||
}
|
||||
type ImageSummaryResult struct {
|
||||
SingleImageSummary SingleImageSummary `json:"data"`
|
||||
@@ -189,7 +190,7 @@ func readFileAndSearchString(filePath string, stringToMatch string, timeout time
|
||||
}
|
||||
|
||||
func verifyRepoSummaryFields(t *testing.T,
|
||||
actualRepoSummary, expectedRepoSummary *common.RepoSummary,
|
||||
actualRepoSummary, expectedRepoSummary *zcommon.RepoSummary,
|
||||
) {
|
||||
t.Helper()
|
||||
|
||||
@@ -218,7 +219,7 @@ func verifyRepoSummaryFields(t *testing.T,
|
||||
}
|
||||
|
||||
func verifyImageSummaryFields(t *testing.T,
|
||||
actualImageSummary, expectedImageSummary *common.ImageSummary,
|
||||
actualImageSummary, expectedImageSummary *zcommon.ImageSummary,
|
||||
) {
|
||||
t.Helper()
|
||||
|
||||
@@ -972,30 +973,37 @@ func TestGetReferrersGQL(t *testing.T) {
|
||||
artifactContentBlobDigest := godigest.FromBytes(artifactContentBlob)
|
||||
artifactType := "com.artifact.test"
|
||||
|
||||
err = UploadBlob(baseURL, repo, artifactContentBlob, artifactContentType)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
artifact := &ispec.Artifact{
|
||||
Blobs: []ispec.Descriptor{
|
||||
{
|
||||
MediaType: artifactContentType,
|
||||
Digest: artifactContentBlobDigest,
|
||||
Size: artifactContentBlobSize,
|
||||
artifactImg := Image{
|
||||
Manifest: ispec.Manifest{
|
||||
Layers: []ispec.Descriptor{
|
||||
{
|
||||
MediaType: artifactContentType,
|
||||
Digest: artifactContentBlobDigest,
|
||||
Size: artifactContentBlobSize,
|
||||
},
|
||||
},
|
||||
Subject: subjectDescriptor,
|
||||
ArtifactType: artifactType,
|
||||
Config: ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeScratch,
|
||||
Digest: ispec.ScratchDescriptor.Digest,
|
||||
Data: ispec.ScratchDescriptor.Data,
|
||||
},
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Annotations: map[string]string{
|
||||
"com.artifact.format": "test",
|
||||
},
|
||||
},
|
||||
Subject: subjectDescriptor,
|
||||
ArtifactType: artifactType,
|
||||
MediaType: ispec.MediaTypeArtifactManifest,
|
||||
Annotations: map[string]string{
|
||||
"com.artifact.format": "test",
|
||||
},
|
||||
Config: ispec.Image{},
|
||||
Layers: [][]byte{artifactContentBlob},
|
||||
}
|
||||
|
||||
artifactManifestBlob, err := json.Marshal(artifact)
|
||||
artifactManifestBlob, err := json.Marshal(artifactImg.Manifest)
|
||||
So(err, ShouldBeNil)
|
||||
artifactManifestDigest := godigest.FromBytes(artifactManifestBlob)
|
||||
artifactImg.Reference = artifactManifestDigest.String()
|
||||
|
||||
err = UploadArtifactManifest(artifact, nil, baseURL, repo)
|
||||
err = UploadImage(artifactImg, baseURL, repo)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
gqlQuery := `
|
||||
@@ -1029,7 +1037,7 @@ func TestGetReferrersGQL(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
So(referrersResp.Errors, ShouldBeNil)
|
||||
So(referrersResp.ReferrersResult.Referrers[0].ArtifactType, ShouldEqual, artifactType)
|
||||
So(referrersResp.ReferrersResult.Referrers[0].MediaType, ShouldEqual, ispec.MediaTypeArtifactManifest)
|
||||
So(referrersResp.ReferrersResult.Referrers[0].MediaType, ShouldEqual, ispec.MediaTypeImageManifest)
|
||||
|
||||
So(referrersResp.ReferrersResult.Referrers[0].Annotations[0].Key, ShouldEqual, "com.artifact.format")
|
||||
So(referrersResp.ReferrersResult.Referrers[0].Annotations[0].Value, ShouldEqual, "test")
|
||||
@@ -1505,6 +1513,7 @@ func TestExpandedRepoInfo(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Test expanded repo info with tagged referrers", t, func() {
|
||||
const test = "test"
|
||||
rootDir := t.TempDir()
|
||||
port := GetFreePort()
|
||||
baseURL := GetBaseURL(port)
|
||||
@@ -1524,7 +1533,7 @@ func TestExpandedRepoInfo(t *testing.T) {
|
||||
ctlrManager.StartAndWait(port)
|
||||
defer ctlrManager.StopServer()
|
||||
|
||||
image, err := GetRandomImage("test")
|
||||
image, err := GetRandomImage(test)
|
||||
So(err, ShouldBeNil)
|
||||
manifestDigest, err := image.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
@@ -1532,17 +1541,15 @@ func TestExpandedRepoInfo(t *testing.T) {
|
||||
err = UploadImage(image, baseURL, "repo")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
referrer, err := GetRandomArtifact(&ispec.Descriptor{
|
||||
Digest: manifestDigest,
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
})
|
||||
referrer, err := GetImageWithSubject(manifestDigest, ispec.MediaTypeImageManifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
tag := "test-ref-tag"
|
||||
err = UploadArtifactManifest(&referrer.Manifest, &tag, baseURL, "repo")
|
||||
referrer.Reference = tag
|
||||
err = UploadImage(referrer, baseURL, "repo")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// ------- Make the call to GQL and see that it doesn't crash and that the referrer isn't in the list of tags
|
||||
// ------- Make the call to GQL and see that it doesn't crash
|
||||
responseStruct := &ExpandedRepoInfoResp{}
|
||||
query := `
|
||||
{
|
||||
@@ -1564,10 +1571,23 @@ func TestExpandedRepoInfo(t *testing.T) {
|
||||
|
||||
err = json.Unmarshal(resp.Body(), responseStruct)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(responseStruct.ExpandedRepoInfo.RepoInfo.ImageSummaries), ShouldEqual, 1)
|
||||
So(len(responseStruct.ExpandedRepoInfo.RepoInfo.ImageSummaries), ShouldEqual, 2)
|
||||
|
||||
repoInfo := responseStruct.ExpandedRepoInfo.RepoInfo
|
||||
So(repoInfo.ImageSummaries[0].Tag, ShouldEqual, "test")
|
||||
|
||||
foundTagTest := false
|
||||
foundTagRefTag := false
|
||||
|
||||
for _, imgSum := range repoInfo.ImageSummaries {
|
||||
switch imgSum.Tag {
|
||||
case test:
|
||||
foundTagTest = true
|
||||
case "test-ref-tag":
|
||||
foundTagRefTag = true
|
||||
}
|
||||
}
|
||||
|
||||
So(foundTagTest || foundTagRefTag, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("Test image tags order", t, func() {
|
||||
@@ -3241,8 +3261,8 @@ func TestGlobalSearch(t *testing.T) {
|
||||
repos, err := olu.GetRepositories()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
allExpectedRepoInfoMap := make(map[string]common.RepoInfo)
|
||||
allExpectedImageSummaryMap := make(map[string]common.ImageSummary)
|
||||
allExpectedRepoInfoMap := make(map[string]zcommon.RepoInfo)
|
||||
allExpectedImageSummaryMap := make(map[string]zcommon.ImageSummary)
|
||||
for _, repo := range repos {
|
||||
repoInfo, err := olu.GetExpandedRepoInfo(repo)
|
||||
So(err, ShouldBeNil)
|
||||
@@ -3310,8 +3330,8 @@ func TestGlobalSearch(t *testing.T) {
|
||||
t.Logf("returned layers: %v", responseStruct.GlobalSearchResult.GlobalSearch.Layers)
|
||||
So(responseStruct.GlobalSearchResult.GlobalSearch.Layers, ShouldBeEmpty)
|
||||
|
||||
newestImageMap := make(map[string]common.ImageSummary)
|
||||
actualRepoMap := make(map[string]common.RepoSummary)
|
||||
newestImageMap := make(map[string]zcommon.ImageSummary)
|
||||
actualRepoMap := make(map[string]zcommon.RepoSummary)
|
||||
for _, repo := range responseStruct.GlobalSearchResult.GlobalSearch.Repos {
|
||||
newestImageMap[repo.Name] = repo.NewestImage
|
||||
actualRepoMap[repo.Name] = repo
|
||||
@@ -3570,8 +3590,8 @@ func TestGlobalSearch(t *testing.T) {
|
||||
repos, err := olu.GetRepositories()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
allExpectedRepoInfoMap := make(map[string]common.RepoInfo)
|
||||
allExpectedImageSummaryMap := make(map[string]common.ImageSummary)
|
||||
allExpectedRepoInfoMap := make(map[string]zcommon.RepoInfo)
|
||||
allExpectedImageSummaryMap := make(map[string]zcommon.ImageSummary)
|
||||
for _, repo := range repos {
|
||||
repoInfo, err := olu.GetExpandedRepoInfo(repo)
|
||||
So(err, ShouldBeNil)
|
||||
@@ -3637,8 +3657,8 @@ func TestGlobalSearch(t *testing.T) {
|
||||
t.Logf("returned layers: %v", responseStruct.GlobalSearchResult.GlobalSearch.Layers)
|
||||
So(responseStruct.GlobalSearchResult.GlobalSearch.Layers, ShouldBeEmpty)
|
||||
|
||||
newestImageMap := make(map[string]common.ImageSummary)
|
||||
actualRepoMap := make(map[string]common.RepoSummary)
|
||||
newestImageMap := make(map[string]zcommon.ImageSummary)
|
||||
actualRepoMap := make(map[string]zcommon.RepoSummary)
|
||||
for _, repo := range responseStruct.GlobalSearchResult.GlobalSearch.Repos {
|
||||
newestImageMap[repo.Name] = repo.NewestImage
|
||||
actualRepoMap[repo.Name] = repo
|
||||
@@ -5626,10 +5646,17 @@ func TestRepoDBWhenDeletingImages(t *testing.T) {
|
||||
|
||||
signatureReference := ""
|
||||
|
||||
var sigManifestContent ispec.Artifact
|
||||
var sigManifestContent ispec.Manifest
|
||||
|
||||
for _, manifest := range indexContent.Manifests {
|
||||
if manifest.MediaType == ispec.MediaTypeArtifactManifest {
|
||||
manifestBlob, _, _, err := storage.GetImageManifest(repo, manifest.Digest.String())
|
||||
So(err, ShouldBeNil)
|
||||
var manifestContent ispec.Manifest
|
||||
|
||||
err = json.Unmarshal(manifestBlob, &manifestContent)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
if zcommon.GetManifestArtifactType(manifestContent) == notreg.ArtifactTypeNotation {
|
||||
signatureReference = manifest.Digest.String()
|
||||
manifestBlob, _, _, err := storage.GetImageManifest(repo, signatureReference)
|
||||
So(err, ShouldBeNil)
|
||||
@@ -6233,11 +6260,11 @@ func TestImageSummary(t *testing.T) {
|
||||
So(imgSummary.Vulnerabilities.Count, ShouldEqual, 0)
|
||||
So(imgSummary.Vulnerabilities.MaxSeverity, ShouldEqual, "")
|
||||
So(len(imgSummary.Referrers), ShouldEqual, 1)
|
||||
So(imgSummary.Referrers[0], ShouldResemble, common.Referrer{
|
||||
So(imgSummary.Referrers[0], ShouldResemble, zcommon.Referrer{
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
ArtifactType: "test.artifact.type",
|
||||
Digest: referrerManifestDigest.String(),
|
||||
Annotations: []common.Annotation{{Key: "testAnnotationKey", Value: "testAnnotationValue"}},
|
||||
Annotations: []zcommon.Annotation{{Key: "testAnnotationKey", Value: "testAnnotationValue"}},
|
||||
})
|
||||
|
||||
t.Log("starting Test retrieve duplicated image same layers based on image identifier")
|
||||
|
||||
@@ -355,23 +355,8 @@ func (sig *signaturesCopier) syncOCIRefs(localRepo, remoteRepo, digestStr string
|
||||
if err := syncBlob(sig, imageStore, localRepo, remoteRepo, manifest.Config.Digest); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if ref.MediaType == ispec.MediaTypeArtifactManifest {
|
||||
// read manifest
|
||||
var manifest ispec.Artifact
|
||||
|
||||
err = json.Unmarshal(OCIRefBody, &manifest)
|
||||
if err != nil {
|
||||
sig.log.Error().Str("errorType", common.TypeOf(err)).Err(err).
|
||||
Str("manifest", getRefManifestURL.String()).Msg("couldn't unmarshal oci reference manifest")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
for _, layer := range manifest.Blobs {
|
||||
if err := syncBlob(sig, imageStore, localRepo, remoteRepo, layer.Digest); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
|
||||
digest, err := imageStore.PutImageManifest(localRepo, ref.Digest.String(),
|
||||
@@ -404,78 +389,6 @@ func (sig *signaturesCopier) syncOCIRefs(localRepo, remoteRepo, digestStr string
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sig *signaturesCopier) syncOCIArtifact(localRepo, remoteRepo, reference string,
|
||||
ociArtifactBuf []byte,
|
||||
) error {
|
||||
var ociArtifact ispec.Artifact
|
||||
|
||||
err := json.Unmarshal(ociArtifactBuf, &ociArtifact)
|
||||
if err != nil {
|
||||
sig.log.Error().Err(err).Str("repository", remoteRepo).Str("reference", reference).
|
||||
Msg("couldn't unmarshal OCI artifact")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
canSkipOCIArtifact, err := sig.canSkipOCIArtifact(localRepo, reference, ociArtifact)
|
||||
if err != nil {
|
||||
sig.log.Error().Err(err).Str("repository", remoteRepo).Str("reference", reference).
|
||||
Msg("couldn't check if OCI artifact can be skipped")
|
||||
}
|
||||
|
||||
if canSkipOCIArtifact {
|
||||
return nil
|
||||
}
|
||||
|
||||
imageStore := sig.storeController.GetImageStore(localRepo)
|
||||
|
||||
sig.log.Info().Msg("syncing OCI artifacts")
|
||||
|
||||
for _, blob := range ociArtifact.Blobs {
|
||||
if err := syncBlob(sig, imageStore, localRepo, remoteRepo, blob.Digest); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
artifactManifestBuf, err := json.Marshal(ociArtifact)
|
||||
if err != nil {
|
||||
sig.log.Error().Str("errorType", common.TypeOf(err)).
|
||||
Err(err).Msg("couldn't marshal OCI artifact")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// push manifest
|
||||
digest, err := imageStore.PutImageManifest(localRepo, reference,
|
||||
ispec.MediaTypeArtifactManifest, artifactManifestBuf)
|
||||
if err != nil {
|
||||
sig.log.Error().Str("errorType", common.TypeOf(err)).
|
||||
Err(err).Msg("couldn't upload OCI artifact manifest")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if sig.repoDB != nil {
|
||||
sig.log.Debug().Str("repository", localRepo).Str("digest", digest.String()).
|
||||
Msg("trying to OCI refs for repo digest")
|
||||
|
||||
err = repodb.SetMetadataFromInput(localRepo, reference, ispec.MediaTypeArtifactManifest,
|
||||
digest, artifactManifestBuf, sig.storeController.GetImageStore(localRepo),
|
||||
sig.repoDB, sig.log)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set metadata for OCI Artifact '%s@%s': %w", localRepo, digest.String(), err)
|
||||
}
|
||||
|
||||
sig.log.Info().Str("repository", localRepo).Str("digest", digest.String()).
|
||||
Msg("successfully added oci artifacts to RepoDB for repo digest")
|
||||
}
|
||||
|
||||
sig.log.Info().Str("repository", localRepo).Str("tag", reference).
|
||||
Msg("successfully synced OCI artifact for repo tag")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sig *signaturesCopier) canSkipORASRefs(localRepo, digestStr string, refs ReferenceList,
|
||||
) (bool, error) {
|
||||
imageStore := sig.storeController.GetImageStore(localRepo)
|
||||
@@ -509,47 +422,6 @@ func (sig *signaturesCopier) canSkipORASRefs(localRepo, digestStr string, refs R
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (sig *signaturesCopier) canSkipOCIArtifact(localRepo, reference string, artifact ispec.Artifact,
|
||||
) (bool, error) {
|
||||
imageStore := sig.storeController.GetImageStore(localRepo)
|
||||
|
||||
var localArtifactManifest ispec.Artifact
|
||||
|
||||
localArtifactBuf, _, _, err := imageStore.GetImageManifest(localRepo, reference)
|
||||
if err != nil {
|
||||
if errors.Is(err, zerr.ErrManifestNotFound) || errors.Is(err, zerr.ErrRepoNotFound) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
sig.log.Error().Str("errorType", common.TypeOf(err)).Err(err).
|
||||
Str("repository", localRepo).Str("reference", reference).
|
||||
Msg("couldn't get local OCI artifact manifest")
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(localArtifactBuf, &localArtifactManifest)
|
||||
if err != nil {
|
||||
sig.log.Error().Str("errorType", common.TypeOf(err)).Err(err).
|
||||
Str("repository", localRepo).Str("reference", reference).
|
||||
Msg("couldn't unmarshal local OCI artifact manifest")
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !artifactsEqual(localArtifactManifest, artifact) {
|
||||
sig.log.Info().Str("repository", localRepo).Str("reference", reference).
|
||||
Msg("upstream OCI artifact changed, syncing again")
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
sig.log.Info().Str("repository", localRepo).Str("reference", reference).
|
||||
Msg("skipping OCI artifact, already synced")
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (sig *signaturesCopier) canSkipCosignSignature(localRepo, digestStr string, cosignManifest *ispec.Manifest,
|
||||
) (bool, error) {
|
||||
imageStore := sig.storeController.GetImageStore(localRepo)
|
||||
|
||||
@@ -361,7 +361,7 @@ func TestSyncInternal(t *testing.T) {
|
||||
So(regURL, ShouldNotBeNil)
|
||||
|
||||
ref := ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeArtifactManifest,
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Digest: "fakeDigest",
|
||||
ArtifactType: "application/vnd.cncf.notary.signature",
|
||||
}
|
||||
@@ -406,7 +406,7 @@ func TestSyncInternal(t *testing.T) {
|
||||
|
||||
refs := ispec.Index{Manifests: []ispec.Descriptor{
|
||||
{
|
||||
MediaType: ispec.MediaTypeArtifactManifest,
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Digest: "fakeDigest",
|
||||
ArtifactType: "application/vnd.cncf.notary.signature",
|
||||
},
|
||||
@@ -446,7 +446,7 @@ func TestSyncInternal(t *testing.T) {
|
||||
err = json.Unmarshal(buf, &index)
|
||||
So(err, ShouldBeNil)
|
||||
index.Manifests = append(index.Manifests, ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeArtifactManifest,
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Digest: godigest.FromString(""),
|
||||
ArtifactType: "application/vnd.cncf.notary.signature",
|
||||
})
|
||||
@@ -548,6 +548,59 @@ func TestSyncInternal(t *testing.T) {
|
||||
So(canBeSkipped, ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Test syncOCIRefs with bad mediaType", t, func() {
|
||||
downPort, upPort := test.GetFreePort(), test.GetFreePort()
|
||||
|
||||
downStream := test.StartTestHTTPServer(
|
||||
[]test.RouteHandler{
|
||||
{
|
||||
Route: "",
|
||||
HandlerFunc: func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
},
|
||||
AllowedMethods: []string{},
|
||||
},
|
||||
},
|
||||
downPort,
|
||||
)
|
||||
defer downStream.Close()
|
||||
|
||||
upStream := test.StartTestHTTPServer(
|
||||
[]test.RouteHandler{
|
||||
{
|
||||
Route: "/v2/{name}/manifests/{digest}",
|
||||
HandlerFunc: func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := w.Write([]byte("{}"))
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
},
|
||||
AllowedMethods: []string{"GET"},
|
||||
},
|
||||
},
|
||||
upPort,
|
||||
)
|
||||
defer upStream.Close()
|
||||
|
||||
upStreamURL, err := url.Parse(fmt.Sprintf("http://127.0.0.1:%s", upPort))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
client := &http.Client{}
|
||||
mockRepoDB := mocks.RepoDBMock{}
|
||||
mockImageStore := mocks.MockedImageStore{}
|
||||
sig := newSignaturesCopier(client, syncconf.Credentials{},
|
||||
*upStreamURL, mockRepoDB, storage.StoreController{DefaultStore: mockImageStore},
|
||||
log.NewLogger("debug", ""),
|
||||
)
|
||||
|
||||
digest := godigest.FromString("1")
|
||||
|
||||
err = sig.syncOCIRefs("repo", "repo", digest.String(),
|
||||
ispec.Index{Manifests: []ispec.Descriptor{{MediaType: "bad media type", Digest: digest}}})
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("Test filterRepos()", t, func() {
|
||||
repos := []string{"repo", "repo1", "repo2", "repo/repo2", "repo/repo2/repo3/repo4"}
|
||||
contents := []syncconf.Content{
|
||||
@@ -1265,61 +1318,3 @@ func TestCompareArtifactRefs(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestCompareArtifactManifests(t *testing.T) {
|
||||
testCases := []struct {
|
||||
refs1 ispec.Artifact
|
||||
refs2 ispec.Artifact
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
refs1: ispec.Artifact{
|
||||
MediaType: "mediatype",
|
||||
ArtifactType: "signature",
|
||||
Blobs: []ispec.Descriptor{
|
||||
{
|
||||
Digest: "digest1",
|
||||
},
|
||||
},
|
||||
},
|
||||
refs2: ispec.Artifact{
|
||||
MediaType: "mediatype",
|
||||
ArtifactType: "signature",
|
||||
Blobs: []ispec.Descriptor{
|
||||
{
|
||||
Digest: "digest1",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
refs1: ispec.Artifact{
|
||||
MediaType: "mediatype",
|
||||
ArtifactType: "signature",
|
||||
Blobs: []ispec.Descriptor{
|
||||
{
|
||||
Digest: "digest1",
|
||||
},
|
||||
},
|
||||
},
|
||||
refs2: ispec.Artifact{
|
||||
MediaType: "mediatype",
|
||||
ArtifactType: "signature",
|
||||
Blobs: []ispec.Descriptor{
|
||||
{
|
||||
Digest: "digest2",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
Convey("Test artifactsEqual()", t, func() {
|
||||
for _, test := range testCases {
|
||||
actualResult := artifactsEqual(test.refs1, test.refs2)
|
||||
So(actualResult, ShouldEqual, test.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -400,19 +400,24 @@ func TestORAS(t *testing.T) {
|
||||
|
||||
digest = godigest.FromBytes(resp.Body())
|
||||
|
||||
content := []byte("blob content")
|
||||
adigest := pushBlob(srcBaseURL, repoName, content)
|
||||
// layer
|
||||
layer := []byte("blob content")
|
||||
blobDigest := pushBlob(srcBaseURL, repoName, layer)
|
||||
|
||||
artifactManifest := ispec.Artifact{
|
||||
// config
|
||||
_ = pushBlob(srcBaseURL, repoName, ispec.ScratchDescriptor.Data)
|
||||
|
||||
artifactManifest := ispec.Manifest{
|
||||
MediaType: artifactspec.MediaTypeArtifactManifest,
|
||||
ArtifactType: "application/vnd.oras.artifact",
|
||||
Blobs: []ispec.Descriptor{
|
||||
Layers: []ispec.Descriptor{
|
||||
{
|
||||
MediaType: "application/octet-stream",
|
||||
Digest: adigest,
|
||||
Size: int64(len(content)),
|
||||
Digest: blobDigest,
|
||||
Size: int64(len(layer)),
|
||||
},
|
||||
},
|
||||
Config: ispec.ScratchDescriptor,
|
||||
Subject: &ispec.Descriptor{
|
||||
MediaType: "application/vnd.oci.image.manifest.v1+json",
|
||||
Digest: digest,
|
||||
@@ -420,19 +425,15 @@ func TestORAS(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
content, err = json.Marshal(artifactManifest)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
artManifestBlob, err := json.Marshal(artifactManifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
adigest = godigest.FromBytes(content)
|
||||
artifactDigest := godigest.FromBytes(artManifestBlob)
|
||||
|
||||
// put OCI reference artifact mediaType artifact
|
||||
_, err = resty.R().SetHeader("Content-Type", artifactspec.MediaTypeArtifactManifest).
|
||||
SetBody(content).Put(srcBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", repoName, adigest.String()))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
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)
|
||||
@@ -447,7 +448,7 @@ func TestORAS(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// trigger getORASRefs err
|
||||
err = os.Chmod(path.Join(srcDir, testImage, "blobs/sha256", adigest.Encoded()), 0o000)
|
||||
err = os.Chmod(path.Join(srcDir, testImage, "blobs/sha256", artifactDigest.Encoded()), 0o000)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
resp, err = resty.R().Get(destBaseURL + "/v2/" + testImage + "/manifests/" + digest.String())
|
||||
@@ -455,7 +456,7 @@ func TestORAS(t *testing.T) {
|
||||
So(resp, ShouldNotBeEmpty)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
|
||||
err = os.Chmod(path.Join(srcDir, testImage, "blobs/sha256", adigest.Encoded()), 0o755)
|
||||
err = os.Chmod(path.Join(srcDir, testImage, "blobs/sha256", artifactDigest.Encoded()), 0o755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
resp, err = resty.R().Get(getORASReferrersURL)
|
||||
@@ -473,11 +474,12 @@ func TestORAS(t *testing.T) {
|
||||
err = os.RemoveAll(path.Join(destDir, repoName))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = os.WriteFile(path.Join(srcDir, repoName, "blobs", "sha256", adigest.Encoded()), []byte("wrong content"), 0o600)
|
||||
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(content).Put(srcBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", repoName, adigest.String()))
|
||||
SetBody(artManifestBlob).Put(srcBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", repoName, artifactDigest.String()))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -665,20 +667,33 @@ func TestOnDemand(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// add OCI Ref
|
||||
OCIRefManifest := ispec.Artifact{
|
||||
_ = pushBlob(srcBaseURL, "remote-repo", ispec.ScratchDescriptor.Data)
|
||||
|
||||
OCIRefManifest := ispec.Manifest{
|
||||
Subject: &ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Digest: manifestDigest,
|
||||
},
|
||||
Blobs: []ispec.Descriptor{},
|
||||
MediaType: ispec.MediaTypeArtifactManifest,
|
||||
Config: ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeScratch,
|
||||
Digest: ispec.ScratchDescriptor.Digest,
|
||||
Size: 2,
|
||||
},
|
||||
Layers: []ispec.Descriptor{
|
||||
{
|
||||
MediaType: ispec.MediaTypeScratch,
|
||||
Digest: ispec.ScratchDescriptor.Digest,
|
||||
Size: 2,
|
||||
},
|
||||
},
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
}
|
||||
|
||||
OCIRefManifestBlob, err := json.Marshal(OCIRefManifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
resp, err := resty.R().
|
||||
SetHeader("Content-type", ispec.MediaTypeArtifactManifest).
|
||||
SetHeader("Content-type", ispec.MediaTypeImageManifest).
|
||||
SetBody(OCIRefManifestBlob).
|
||||
Put(srcBaseURL + "/v2/remote-repo/manifests/oci.ref")
|
||||
|
||||
@@ -763,7 +778,7 @@ func TestOnDemand(t *testing.T) {
|
||||
|
||||
dctlr.RepoDB = mocks.RepoDBMock{
|
||||
SetRepoReferenceFn: func(repo, Reference string, manifestDigest godigest.Digest, mediaType string) error {
|
||||
if mediaType == ispec.MediaTypeArtifactManifest {
|
||||
if mediaType == ispec.MediaTypeImageManifest {
|
||||
return sync.ErrTestError
|
||||
}
|
||||
|
||||
@@ -854,7 +869,7 @@ func TestSyncWithNonDistributableBlob(t *testing.T) {
|
||||
nonDistributableLayer := make([]byte, 10)
|
||||
nonDistributableDigest := godigest.FromBytes(nonDistributableLayer)
|
||||
nonDistributableLayerDesc := ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeImageLayerNonDistributableGzip,
|
||||
MediaType: ispec.MediaTypeImageLayerNonDistributableGzip, //nolint:staticcheck
|
||||
Digest: nonDistributableDigest,
|
||||
Size: int64(len(nonDistributableLayer)),
|
||||
URLs: []string{
|
||||
@@ -3018,7 +3033,7 @@ func TestPeriodicallySignaturesErr(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// read manifest
|
||||
var artifactManifest ispec.Artifact
|
||||
var artifactManifest ispec.Manifest
|
||||
for _, ref := range referrers.Manifests {
|
||||
refPath := path.Join(srcDir, repoName, "blobs", string(ref.Digest.Algorithm()), ref.Digest.Encoded())
|
||||
body, err := os.ReadFile(refPath)
|
||||
@@ -3028,7 +3043,7 @@ func TestPeriodicallySignaturesErr(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// triggers perm denied on sig blobs
|
||||
for _, blob := range artifactManifest.Blobs {
|
||||
for _, blob := range artifactManifest.Layers {
|
||||
blobPath := path.Join(srcDir, repoName, "blobs", string(blob.Digest.Algorithm()), blob.Digest.Encoded())
|
||||
err := os.Chmod(blobPath, 0o000)
|
||||
So(err, ShouldBeNil)
|
||||
@@ -3145,7 +3160,7 @@ func TestPeriodicallySignaturesErr(t *testing.T) {
|
||||
|
||||
Convey("of type OCI artifact", func() { //nolint: dupl
|
||||
// read manifest
|
||||
var artifactManifest ispec.Artifact
|
||||
var artifactManifest ispec.Manifest
|
||||
for _, ref := range referrers.Manifests {
|
||||
refPath := path.Join(srcDir, repoName, "blobs", string(ref.Digest.Algorithm()), ref.Digest.Encoded())
|
||||
body, err := os.ReadFile(refPath)
|
||||
@@ -3155,7 +3170,7 @@ func TestPeriodicallySignaturesErr(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// triggers perm denied on artifact blobs
|
||||
for _, blob := range artifactManifest.Blobs {
|
||||
for _, blob := range artifactManifest.Layers {
|
||||
blobPath := path.Join(srcDir, repoName, "blobs", string(blob.Digest.Algorithm()), blob.Digest.Encoded())
|
||||
err := os.Chmod(blobPath, 0o000)
|
||||
So(err, ShouldBeNil)
|
||||
@@ -3349,7 +3364,7 @@ func TestSignatures(t *testing.T) {
|
||||
err = os.RemoveAll(path.Join(destDir, repoName))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
var artifactManifest ispec.Artifact
|
||||
var artifactManifest ispec.Manifest
|
||||
for _, ref := range referrers.Manifests {
|
||||
refPath := path.Join(srcDir, repoName, "blobs", string(ref.Digest.Algorithm()), ref.Digest.Encoded())
|
||||
body, err := os.ReadFile(refPath)
|
||||
@@ -3359,7 +3374,7 @@ func TestSignatures(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// triggers perm denied on notary sig blobs on downstream
|
||||
for _, blob := range artifactManifest.Blobs {
|
||||
for _, blob := range artifactManifest.Layers {
|
||||
blobPath := path.Join(destDir, repoName, "blobs", string(blob.Digest.Algorithm()), blob.Digest.Encoded())
|
||||
err := os.MkdirAll(blobPath, 0o755)
|
||||
So(err, ShouldBeNil)
|
||||
@@ -3392,7 +3407,7 @@ func TestSignatures(t *testing.T) {
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
|
||||
// triggers perm denied on sig blobs
|
||||
for _, blob := range artifactManifest.Blobs {
|
||||
for _, blob := range artifactManifest.Layers {
|
||||
blobPath := path.Join(srcDir, repoName, "blobs", string(blob.Digest.Algorithm()), blob.Digest.Encoded())
|
||||
err := os.Chmod(blobPath, 0o000)
|
||||
So(err, ShouldBeNil)
|
||||
@@ -5390,331 +5405,6 @@ func TestSyncImageIndex(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSyncOCIArtifactsWithTag(t *testing.T) {
|
||||
Convey("Verify syncing tagged OCI artifacts", t, func() {
|
||||
updateDuration, _ := time.ParseDuration("10s")
|
||||
|
||||
sctlr, srcBaseURL, _, _, _ := makeUpstreamServer(t, false, false)
|
||||
|
||||
scm := test.NewControllerManager(sctlr)
|
||||
scm.StartAndWait(sctlr.Config.HTTP.Port)
|
||||
defer scm.StopServer()
|
||||
|
||||
regex := ".*"
|
||||
var semver bool
|
||||
tlsVerify := false
|
||||
|
||||
repoName := "artifact"
|
||||
|
||||
syncRegistryConfig := syncconf.RegistryConfig{
|
||||
Content: []syncconf.Content{
|
||||
{
|
||||
Prefix: repoName,
|
||||
Tags: &syncconf.Tags{
|
||||
Regex: ®ex,
|
||||
Semver: &semver,
|
||||
},
|
||||
},
|
||||
},
|
||||
URLs: []string{srcBaseURL},
|
||||
OnDemand: false,
|
||||
PollInterval: updateDuration,
|
||||
TLSVerify: &tlsVerify,
|
||||
}
|
||||
|
||||
defaultVal := true
|
||||
syncConfig := &syncconf.Config{
|
||||
Enable: &defaultVal,
|
||||
Registries: []syncconf.RegistryConfig{syncRegistryConfig},
|
||||
}
|
||||
|
||||
// create artifact blob
|
||||
buf := []byte("this is an artifact")
|
||||
digest := pushBlob(srcBaseURL, repoName, buf)
|
||||
|
||||
// create artifact config blob
|
||||
cbuf := []byte("{}")
|
||||
cdigest := pushBlob(srcBaseURL, repoName, cbuf)
|
||||
|
||||
// push a referrer artifact
|
||||
manifest := ispec.Manifest{
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Config: ispec.Descriptor{
|
||||
MediaType: "application/vnd.cncf.icecream",
|
||||
Digest: cdigest,
|
||||
Size: int64(len(cbuf)),
|
||||
},
|
||||
Layers: []ispec.Descriptor{
|
||||
{
|
||||
MediaType: "application/octet-stream",
|
||||
Digest: digest,
|
||||
Size: int64(len(buf)),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
artifactManifest := ispec.Artifact{
|
||||
MediaType: ispec.MediaTypeArtifactManifest,
|
||||
ArtifactType: "application/vnd.cncf.icecream",
|
||||
Blobs: []ispec.Descriptor{
|
||||
{
|
||||
MediaType: "application/octet-stream",
|
||||
Digest: digest,
|
||||
Size: int64(len(buf)),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
manifest.SchemaVersion = 2
|
||||
|
||||
content, err := json.Marshal(manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// put OCI artifact mediatype oci image
|
||||
_, err = resty.R().SetHeader("Content-Type", ispec.MediaTypeImageManifest).
|
||||
SetBody(content).Put(srcBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", repoName, "1.0"))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
content, err = json.Marshal(artifactManifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
artifactDigest := godigest.FromBytes(content)
|
||||
|
||||
// put OCI artifact mediatype artifact
|
||||
_, err = resty.R().SetHeader("Content-Type", ispec.MediaTypeArtifactManifest).
|
||||
SetBody(content).Put(srcBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", repoName, "2.0"))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("sync periodically", func() {
|
||||
// start downstream server
|
||||
dctlr, destBaseURL, _, _ := makeDownstreamServer(t, false, syncConfig)
|
||||
|
||||
dcm := test.NewControllerManager(dctlr)
|
||||
dcm.StartAndWait(dctlr.Config.HTTP.Port)
|
||||
defer dcm.StopServer()
|
||||
|
||||
// give it time to set up sync
|
||||
t.Logf("waitsync(%s, %s)", dctlr.Config.Storage.RootDirectory, repoName)
|
||||
waitSync(dctlr.Config.Storage.RootDirectory, repoName)
|
||||
|
||||
resp, err := resty.R().SetHeader("Content-Type", ispec.MediaTypeImageManifest).
|
||||
Get(destBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", repoName, "1.0"))
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
So(resp.Body(), ShouldNotBeEmpty)
|
||||
So(resp.Header().Get("Content-Type"), ShouldNotBeEmpty)
|
||||
|
||||
var syncedManifest ispec.Manifest
|
||||
err = json.Unmarshal(resp.Body(), &syncedManifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(reflect.DeepEqual(syncedManifest, manifest), ShouldEqual, true)
|
||||
|
||||
resp, err = resty.R().SetHeader("Content-Type", ispec.MediaTypeArtifactManifest).
|
||||
Get(destBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", repoName, "2.0"))
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
So(resp.Body(), ShouldNotBeEmpty)
|
||||
So(resp.Header().Get("Content-Type"), ShouldNotBeEmpty)
|
||||
|
||||
var syncedArtifact ispec.Artifact
|
||||
err = json.Unmarshal(resp.Body(), &syncedArtifact)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(reflect.DeepEqual(syncedArtifact, artifactManifest), ShouldEqual, true)
|
||||
|
||||
// for coverage
|
||||
found, err := test.ReadLogFileAndSearchString(dctlr.Config.Log.Output,
|
||||
"skipping OCI artifact", 15*time.Second)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if !found {
|
||||
data, err := os.ReadFile(dctlr.Config.Log.Output)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
t.Logf("downstream log: %s", string(data))
|
||||
}
|
||||
|
||||
So(found, ShouldBeTrue)
|
||||
|
||||
waitSyncFinish(dctlr.Config.Log.Output)
|
||||
})
|
||||
|
||||
Convey("sync on demand", func() {
|
||||
// start downstream server
|
||||
syncConfig.Registries[0].OnDemand = true
|
||||
syncConfig.Registries[0].PollInterval = 0
|
||||
|
||||
dctlr, destBaseURL, _, _ := makeDownstreamServer(t, false, syncConfig)
|
||||
|
||||
dcm := test.NewControllerManager(dctlr)
|
||||
dcm.StartAndWait(dctlr.Config.HTTP.Port)
|
||||
defer dcm.StopServer()
|
||||
|
||||
resp, err := resty.R().SetHeader("Content-Type", ispec.MediaTypeArtifactManifest).
|
||||
Get(destBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", repoName, "2.0"))
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
So(resp.Body(), ShouldNotBeEmpty)
|
||||
So(resp.Header().Get("Content-Type"), ShouldNotBeEmpty)
|
||||
|
||||
var syncedArtifact ispec.Artifact
|
||||
err = json.Unmarshal(resp.Body(), &syncedArtifact)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(reflect.DeepEqual(syncedArtifact, artifactManifest), ShouldEqual, true)
|
||||
|
||||
resp, err = resty.R().SetHeader("Content-Type", ispec.MediaTypeImageManifest).
|
||||
Get(destBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", repoName, "1.0"))
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
So(resp.Body(), ShouldNotBeEmpty)
|
||||
So(resp.Header().Get("Content-Type"), ShouldNotBeEmpty)
|
||||
|
||||
var syncedManifest ispec.Manifest
|
||||
err = json.Unmarshal(resp.Body(), &syncedManifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(reflect.DeepEqual(syncedManifest, manifest), ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("sync periodically error on mediatype", func() {
|
||||
manifestPath := path.Join(sctlr.Config.Storage.RootDirectory, repoName, "blobs", "sha256", artifactDigest.Encoded())
|
||||
So(os.Chmod(manifestPath, 0o000), ShouldBeNil)
|
||||
|
||||
// start downstream server
|
||||
dctlr, destBaseURL, _, _ := makeDownstreamServer(t, false, syncConfig)
|
||||
|
||||
dcm := test.NewControllerManager(dctlr)
|
||||
dcm.StartAndWait(dctlr.Config.HTTP.Port)
|
||||
defer dcm.StopServer()
|
||||
|
||||
defer func() {
|
||||
err := os.Chmod(manifestPath, 0o755)
|
||||
So(err, ShouldBeNil)
|
||||
}()
|
||||
|
||||
found, err := test.ReadLogFileAndSearchString(dctlr.Config.Log.Output,
|
||||
"finished syncing", 15*time.Second)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if !found {
|
||||
data, err := os.ReadFile(dctlr.Config.Log.Output)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
t.Logf("downstream log: %s", string(data))
|
||||
}
|
||||
|
||||
So(found, ShouldBeTrue)
|
||||
|
||||
resp, err := resty.R().SetHeader("Content-Type", ispec.MediaTypeArtifactManifest).
|
||||
Get(destBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", repoName, artifactDigest.String()))
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusNotFound)
|
||||
|
||||
found, err = test.ReadLogFileAndSearchString(dctlr.Config.Log.Output,
|
||||
"couldn't get upstream image", 5*time.Second)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if !found {
|
||||
data, err := os.ReadFile(dctlr.Config.Log.Output)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
t.Logf("downstream log: %s", string(data))
|
||||
}
|
||||
|
||||
So(found, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("sync on demand error on mediatype", func() {
|
||||
// start downstream server
|
||||
syncConfig.Registries[0].OnDemand = true
|
||||
syncConfig.Registries[0].PollInterval = 0
|
||||
|
||||
dctlr, destBaseURL, _, _ := makeDownstreamServer(t, false, syncConfig)
|
||||
|
||||
dcm := test.NewControllerManager(dctlr)
|
||||
dcm.StartAndWait(dctlr.Config.HTTP.Port)
|
||||
defer dcm.StopServer()
|
||||
|
||||
manifestPath := path.Join(sctlr.Config.Storage.RootDirectory, repoName, "blobs", "sha256", artifactDigest.Encoded())
|
||||
So(os.Chmod(manifestPath, 0o000), ShouldBeNil)
|
||||
defer func() {
|
||||
err := os.Chmod(manifestPath, 0o755)
|
||||
So(err, ShouldBeNil)
|
||||
}()
|
||||
|
||||
resp, err := resty.R().SetHeader("Content-Type", ispec.MediaTypeArtifactManifest).
|
||||
Get(destBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", repoName, artifactDigest.String()))
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusNotFound)
|
||||
})
|
||||
|
||||
Convey("sync on demand and periodically error on PutImageManifest", func() {
|
||||
// start downstream server
|
||||
syncConfig.Registries[0].OnDemand = true
|
||||
|
||||
destDir := t.TempDir()
|
||||
destConfig := config.New()
|
||||
|
||||
destConfig.HTTP.Port = test.GetFreePort()
|
||||
destBaseURL := test.GetBaseURL(destConfig.HTTP.Port)
|
||||
|
||||
destConfig.Storage.RootDirectory = destDir
|
||||
|
||||
destConfig.Extensions = &extconf.ExtensionConfig{}
|
||||
destConfig.Extensions.Search = nil
|
||||
destConfig.Extensions.Sync = syncConfig
|
||||
|
||||
destConfig.Log.Output = path.Join(destDir, "sync.log")
|
||||
|
||||
dctlr := api.NewController(destConfig)
|
||||
dcm := test.NewControllerManager(dctlr)
|
||||
|
||||
manifestPath := path.Join(destDir, repoName, "blobs", "sha256", artifactDigest.Encoded())
|
||||
So(os.MkdirAll(manifestPath, 0o755), ShouldBeNil)
|
||||
So(os.Chmod(manifestPath, 0o000), ShouldBeNil)
|
||||
|
||||
dcm.StartAndWait(destConfig.HTTP.Port)
|
||||
|
||||
defer dcm.StopServer()
|
||||
|
||||
defer func() {
|
||||
err := os.Chmod(manifestPath, 0o755)
|
||||
So(err, ShouldBeNil)
|
||||
}()
|
||||
|
||||
found, err := test.ReadLogFileAndSearchString(dctlr.Config.Log.Output,
|
||||
"couldn't upload OCI artifact manifest", 15*time.Second)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if !found {
|
||||
data, err := os.ReadFile(dctlr.Config.Log.Output)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
t.Logf("downstream log: %s", string(data))
|
||||
}
|
||||
|
||||
So(found, ShouldBeTrue)
|
||||
|
||||
resp, err := resty.R().SetHeader("Content-Type", ispec.MediaTypeArtifactManifest).
|
||||
Get(destBaseURL + fmt.Sprintf("/v2/%s/manifests/%s", repoName, artifactDigest.String()))
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusNotFound)
|
||||
|
||||
waitSyncFinish(dctlr.Config.Log.Output)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func generateKeyPairs(tdir string) {
|
||||
// generate a keypair
|
||||
os.Setenv("COSIGN_PASSWORD", "")
|
||||
@@ -5817,6 +5507,35 @@ func pushRepo(url, repoName string) godigest.Digest {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// upload scratch image config
|
||||
resp, err = resty.R().
|
||||
Post(fmt.Sprintf("%s/v2/%s/blobs/uploads/", url, repoName))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if resp.StatusCode() != http.StatusAccepted {
|
||||
panic(fmt.Errorf("invalid status code: %d %w", resp.StatusCode(), errBadStatus))
|
||||
}
|
||||
|
||||
loc = test.Location(url, resp)
|
||||
cblob, cdigest := ispec.ScratchDescriptor.Data, ispec.ScratchDescriptor.Digest
|
||||
|
||||
resp, err = resty.R().
|
||||
SetContentLength(true).
|
||||
SetHeader("Content-Length", fmt.Sprintf("%d", len(cblob))).
|
||||
SetHeader("Content-Type", "application/octet-stream").
|
||||
SetQueryParam("digest", cdigest.String()).
|
||||
SetBody(cblob).
|
||||
Put(loc)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if resp.StatusCode() != http.StatusCreated {
|
||||
panic(fmt.Errorf("invalid status code: %d %w", resp.StatusCode(), errBadStatus))
|
||||
}
|
||||
|
||||
// upload image config blob
|
||||
resp, err = resty.R().
|
||||
Post(fmt.Sprintf("%s/v2/%s/blobs/uploads/", url, repoName))
|
||||
@@ -5829,7 +5548,7 @@ func pushRepo(url, repoName string) godigest.Digest {
|
||||
}
|
||||
|
||||
loc = test.Location(url, resp)
|
||||
cblob, cdigest := test.GetRandomImageConfig()
|
||||
cblob, cdigest = test.GetRandomImageConfig()
|
||||
|
||||
resp, err = resty.R().
|
||||
SetContentLength(true).
|
||||
@@ -5907,10 +5626,15 @@ func pushRepo(url, repoName string) godigest.Digest {
|
||||
},
|
||||
}
|
||||
|
||||
artifactManifest := ispec.Artifact{
|
||||
MediaType: ispec.MediaTypeArtifactManifest,
|
||||
artifactManifest := ispec.Manifest{
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
ArtifactType: "application/vnd.cncf.icecream",
|
||||
Blobs: []ispec.Descriptor{
|
||||
Config: ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeScratch,
|
||||
Digest: ispec.ScratchDescriptor.Digest,
|
||||
Size: 2,
|
||||
},
|
||||
Layers: []ispec.Descriptor{
|
||||
{
|
||||
MediaType: "application/octet-stream",
|
||||
Digest: adigest,
|
||||
@@ -5948,7 +5672,7 @@ func pushRepo(url, repoName string) godigest.Digest {
|
||||
adigest = godigest.FromBytes(content)
|
||||
|
||||
// put OCI reference artifact mediaType artifact
|
||||
_, err = resty.R().SetHeader("Content-Type", ispec.MediaTypeArtifactManifest).
|
||||
_, err = resty.R().SetHeader("Content-Type", ispec.MediaTypeImageManifest).
|
||||
SetBody(content).Put(url + fmt.Sprintf("/v2/%s/manifests/%s", repoName, adigest.String()))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
||||
@@ -590,17 +590,6 @@ func manifestsEqual(manifest1, manifest2 ispec.Manifest) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func artifactsEqual(manifest1, manifest2 ispec.Artifact) bool {
|
||||
if manifest1.ArtifactType == manifest2.ArtifactType &&
|
||||
manifest1.MediaType == manifest2.MediaType {
|
||||
if descriptorsEqual(manifest1.Blobs, manifest2.Blobs) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func artifactDescriptorsEqual(desc1, desc2 []artifactspec.Descriptor) bool {
|
||||
if len(desc1) != len(desc2) {
|
||||
return false
|
||||
@@ -690,16 +679,6 @@ func syncImageWithRefs(ctx context.Context, localRepo, upstreamRepo, reference s
|
||||
upstreamImageDigest := godigest.FromBytes(manifestBuf)
|
||||
|
||||
if !isSupportedMediaType(mediaType) {
|
||||
if mediaType == ispec.MediaTypeArtifactManifest {
|
||||
err = sig.syncOCIArtifact(localRepo, upstreamRepo, reference, manifestBuf) //nolint
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("image", upstreamImageRef.DockerReference().String()).
|
||||
Msg("couldn't sync oci artifact with artifact mediaType")
|
||||
|
||||
return skipped, err
|
||||
}
|
||||
}
|
||||
|
||||
return skipped, nil
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ func GoroutineID() int {
|
||||
|
||||
type goroutineHook struct{}
|
||||
|
||||
func (h goroutineHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {
|
||||
func (h goroutineHook) Run(e *zerolog.Event, level zerolog.Level, _ string) {
|
||||
if level != zerolog.NoLevel {
|
||||
e.Int("goroutine", GoroutineID())
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ package bolt
|
||||
const (
|
||||
ManifestDataBucket = "ManifestData"
|
||||
IndexDataBucket = "IndexData"
|
||||
ArtifactDataBucket = "ArtifactData"
|
||||
RepoMetadataBucket = "RepoMetadata"
|
||||
UserDataBucket = "UserData"
|
||||
VersionBucket = "Version"
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
type DBDriverParameters struct {
|
||||
Endpoint, Region, RepoMetaTablename, ManifestDataTablename, IndexDataTablename,
|
||||
ArtifactDataTablename, VersionTablename, UserDataTablename string
|
||||
VersionTablename, UserDataTablename string
|
||||
}
|
||||
|
||||
func GetDynamoClient(params DBDriverParameters) (*dynamodb.Client, error) {
|
||||
|
||||
@@ -49,11 +49,6 @@ func NewBoltDBWrapper(boltDB *bbolt.DB, log log.Logger) (*DBWrapper, error) {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = transaction.CreateBucketIfNotExists([]byte(bolt.ArtifactDataBucket))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = transaction.CreateBucketIfNotExists([]byte(bolt.RepoMetadataBucket))
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -258,49 +253,6 @@ func (bdw *DBWrapper) GetIndexData(indexDigest godigest.Digest) (repodb.IndexDat
|
||||
return indexMetadata, err
|
||||
}
|
||||
|
||||
func (bdw DBWrapper) SetArtifactData(artifactDigest godigest.Digest, artifactData repodb.ArtifactData) error {
|
||||
err := bdw.DB.Update(func(tx *bbolt.Tx) error {
|
||||
buck := tx.Bucket([]byte(bolt.ArtifactDataBucket))
|
||||
|
||||
imBlob, err := json.Marshal(artifactData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("repodb: error while calculating blob for artifact with digest %s %w", artifactDigest, err)
|
||||
}
|
||||
|
||||
err = buck.Put([]byte(artifactDigest), imBlob)
|
||||
if err != nil {
|
||||
return fmt.Errorf("repodb: error while setting artifact blob for digest %s %w", artifactDigest, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (bdw DBWrapper) GetArtifactData(artifactDigest godigest.Digest) (repodb.ArtifactData, error) {
|
||||
var artifactData repodb.ArtifactData
|
||||
|
||||
err := bdw.DB.View(func(tx *bbolt.Tx) error {
|
||||
buck := tx.Bucket([]byte(bolt.ArtifactDataBucket))
|
||||
|
||||
blob := buck.Get([]byte(artifactDigest))
|
||||
|
||||
if len(blob) == 0 {
|
||||
return zerr.ErrArtifactDataNotFound
|
||||
}
|
||||
|
||||
err := json.Unmarshal(blob, &artifactData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("repodb: error while unmashaling artifact data for digest %s %w", artifactDigest, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return artifactData, err
|
||||
}
|
||||
|
||||
func (bdw DBWrapper) SetReferrer(repo string, referredDigest godigest.Digest, referrer repodb.ReferrerInfo) error {
|
||||
err := bdw.DB.Update(func(tx *bbolt.Tx) error {
|
||||
buck := tx.Bucket([]byte(bolt.RepoMetadataBucket))
|
||||
|
||||
@@ -91,18 +91,6 @@ func TestWrapperErrors(t *testing.T) {
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("GetArtifactData", func() {
|
||||
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
|
||||
artifactBuck := tx.Bucket([]byte(bolt.ArtifactDataBucket))
|
||||
|
||||
return artifactBuck.Put([]byte("artifactDigest"), []byte("wrong json"))
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
_, err = boltdbWrapper.GetArtifactData("artifactDigest")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("SetReferrer", func() {
|
||||
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
|
||||
repoBuck := tx.Bucket([]byte(bolt.RepoMetadataBucket))
|
||||
|
||||
@@ -30,7 +30,6 @@ func TestWrapperErrors(t *testing.T) {
|
||||
repoMetaTablename := "RepoMetadataTable" + uuid.String()
|
||||
manifestDataTablename := "ManifestDataTable" + uuid.String()
|
||||
indexDataTablename := "IndexDataTable" + uuid.String()
|
||||
artifactDataTablename := "ArtifactDataTable" + uuid.String()
|
||||
userDataTablename := "UserDataTable" + uuid.String()
|
||||
|
||||
versionTablename := "Version" + uuid.String()
|
||||
@@ -57,7 +56,6 @@ func TestWrapperErrors(t *testing.T) {
|
||||
RepoMetaTablename: repoMetaTablename,
|
||||
ManifestDataTablename: manifestDataTablename,
|
||||
IndexDataTablename: indexDataTablename,
|
||||
ArtifactDataTablename: artifactDataTablename,
|
||||
VersionTablename: versionTablename,
|
||||
UserDataTablename: userDataTablename,
|
||||
Patches: version.GetDynamoDBPatches(),
|
||||
@@ -99,7 +97,6 @@ func TestWrapperErrors(t *testing.T) {
|
||||
ManifestDataTablename: manifestDataTablename,
|
||||
VersionTablename: versionTablename,
|
||||
IndexDataTablename: indexDataTablename,
|
||||
ArtifactDataTablename: artifactDataTablename,
|
||||
UserDataTablename: userDataTablename,
|
||||
Patches: version.GetDynamoDBPatches(),
|
||||
Log: log.Logger{Logger: zerolog.New(os.Stdout)},
|
||||
|
||||
@@ -42,7 +42,6 @@ func TestIterator(t *testing.T) {
|
||||
manifestDataTablename := "ManifestDataTable" + uuid.String()
|
||||
versionTablename := "Version" + uuid.String()
|
||||
indexDataTablename := "IndexDataTable" + uuid.String()
|
||||
artifactDataTablename := "ArtifactDataTable" + uuid.String()
|
||||
userDataTablename := "UserDataTable" + uuid.String()
|
||||
|
||||
log := log.NewLogger("debug", "")
|
||||
@@ -54,7 +53,6 @@ func TestIterator(t *testing.T) {
|
||||
RepoMetaTablename: repoMetaTablename,
|
||||
ManifestDataTablename: manifestDataTablename,
|
||||
IndexDataTablename: indexDataTablename,
|
||||
ArtifactDataTablename: artifactDataTablename,
|
||||
VersionTablename: versionTablename,
|
||||
UserDataTablename: userDataTablename,
|
||||
}
|
||||
@@ -145,7 +143,6 @@ func TestWrapperErrors(t *testing.T) {
|
||||
manifestDataTablename := "ManifestDataTable" + uuid.String()
|
||||
versionTablename := "Version" + uuid.String()
|
||||
indexDataTablename := "IndexDataTable" + uuid.String()
|
||||
artifactDataTablename := "ArtifactData" + uuid.String()
|
||||
userDataTablename := "UserDataTable" + uuid.String()
|
||||
|
||||
ctx := context.Background()
|
||||
@@ -159,7 +156,6 @@ func TestWrapperErrors(t *testing.T) {
|
||||
RepoMetaTablename: repoMetaTablename,
|
||||
ManifestDataTablename: manifestDataTablename,
|
||||
IndexDataTablename: indexDataTablename,
|
||||
ArtifactDataTablename: artifactDataTablename,
|
||||
UserDataTablename: userDataTablename,
|
||||
VersionTablename: versionTablename,
|
||||
}
|
||||
@@ -417,20 +413,6 @@ func TestWrapperErrors(t *testing.T) {
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("GetArtifactData", func() {
|
||||
dynamoWrapper.ArtifactDataTablename = badTablename
|
||||
_, err = dynamoWrapper.GetArtifactData("dig")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("GetArtifactData unmarhsal error", func() {
|
||||
err = setBadArtifactData(dynamoWrapper.Client, artifactDataTablename, "dig")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
_, err = dynamoWrapper.GetArtifactData("dig")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("SetRepoReference client error", func() {
|
||||
dynamoWrapper.RepoMetaTablename = badTablename
|
||||
digest := digest.FromString("str")
|
||||
@@ -488,7 +470,6 @@ func TestWrapperErrors(t *testing.T) {
|
||||
|
||||
Convey("GetReferrersInfo getData fails", func() {
|
||||
dynamoWrapper.ManifestDataTablename = badTablename
|
||||
dynamoWrapper.ArtifactDataTablename = badTablename
|
||||
err = dynamoWrapper.SetReferrer("repo", "rf", repodb.ReferrerInfo{
|
||||
Digest: "dig1",
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
@@ -497,7 +478,7 @@ func TestWrapperErrors(t *testing.T) {
|
||||
|
||||
err = dynamoWrapper.SetReferrer("repo", "rf", repodb.ReferrerInfo{
|
||||
Digest: "dig2",
|
||||
MediaType: ispec.MediaTypeArtifactManifest,
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@@ -506,11 +487,6 @@ func TestWrapperErrors(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("GetReferrersInfo bad descriptor blob", func() {
|
||||
err = dynamoWrapper.SetArtifactData("dig2", repodb.ArtifactData{
|
||||
ManifestBlob: []byte("bad json"),
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = dynamoWrapper.SetManifestData("dig3", repodb.ManifestData{
|
||||
ManifestBlob: []byte("bad json"),
|
||||
})
|
||||
@@ -518,7 +494,7 @@ func TestWrapperErrors(t *testing.T) {
|
||||
|
||||
err = dynamoWrapper.SetReferrer("repo", "rf", repodb.ReferrerInfo{
|
||||
Digest: "dig2",
|
||||
MediaType: ispec.MediaTypeArtifactManifest,
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@@ -1095,7 +1071,6 @@ func TestWrapperErrors(t *testing.T) {
|
||||
RepoMetaTablename: "",
|
||||
ManifestDataTablename: manifestDataTablename,
|
||||
IndexDataTablename: indexDataTablename,
|
||||
ArtifactDataTablename: artifactDataTablename,
|
||||
UserDataTablename: userDataTablename,
|
||||
VersionTablename: versionTablename,
|
||||
}
|
||||
@@ -1111,7 +1086,6 @@ func TestWrapperErrors(t *testing.T) {
|
||||
RepoMetaTablename: repoMetaTablename,
|
||||
ManifestDataTablename: "",
|
||||
IndexDataTablename: indexDataTablename,
|
||||
ArtifactDataTablename: artifactDataTablename,
|
||||
UserDataTablename: userDataTablename,
|
||||
VersionTablename: versionTablename,
|
||||
}
|
||||
@@ -1127,7 +1101,6 @@ func TestWrapperErrors(t *testing.T) {
|
||||
RepoMetaTablename: repoMetaTablename,
|
||||
ManifestDataTablename: manifestDataTablename,
|
||||
IndexDataTablename: "",
|
||||
ArtifactDataTablename: artifactDataTablename,
|
||||
UserDataTablename: userDataTablename,
|
||||
VersionTablename: versionTablename,
|
||||
}
|
||||
@@ -1143,7 +1116,6 @@ func TestWrapperErrors(t *testing.T) {
|
||||
RepoMetaTablename: repoMetaTablename,
|
||||
ManifestDataTablename: manifestDataTablename,
|
||||
IndexDataTablename: indexDataTablename,
|
||||
ArtifactDataTablename: artifactDataTablename,
|
||||
UserDataTablename: userDataTablename,
|
||||
VersionTablename: "",
|
||||
}
|
||||
@@ -1159,41 +1131,8 @@ func TestWrapperErrors(t *testing.T) {
|
||||
RepoMetaTablename: repoMetaTablename,
|
||||
ManifestDataTablename: manifestDataTablename,
|
||||
IndexDataTablename: indexDataTablename,
|
||||
ArtifactDataTablename: "",
|
||||
UserDataTablename: userDataTablename,
|
||||
VersionTablename: versionTablename,
|
||||
}
|
||||
client, err = dynamo.GetDynamoClient(params)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
_, err = dynamoWrapper.NewDynamoDBWrapper(client, params, log)
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
params = dynamo.DBDriverParameters{ //nolint:contextcheck
|
||||
Endpoint: endpoint,
|
||||
Region: region,
|
||||
RepoMetaTablename: repoMetaTablename,
|
||||
ManifestDataTablename: manifestDataTablename,
|
||||
IndexDataTablename: indexDataTablename,
|
||||
VersionTablename: versionTablename,
|
||||
UserDataTablename: userDataTablename,
|
||||
ArtifactDataTablename: artifactDataTablename,
|
||||
}
|
||||
client, err = dynamo.GetDynamoClient(params)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
_, err = dynamoWrapper.NewDynamoDBWrapper(client, params, log)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
params = dynamo.DBDriverParameters{ //nolint:contextcheck
|
||||
Endpoint: endpoint,
|
||||
Region: region,
|
||||
RepoMetaTablename: repoMetaTablename,
|
||||
ManifestDataTablename: manifestDataTablename,
|
||||
IndexDataTablename: indexDataTablename,
|
||||
VersionTablename: versionTablename,
|
||||
UserDataTablename: "",
|
||||
ArtifactDataTablename: artifactDataTablename,
|
||||
VersionTablename: versionTablename,
|
||||
}
|
||||
client, err = dynamo.GetDynamoClient(params)
|
||||
So(err, ShouldBeNil)
|
||||
@@ -1228,26 +1167,26 @@ func setBadManifestData(client *dynamodb.Client, manifestDataTableName, digest s
|
||||
return err
|
||||
}
|
||||
|
||||
func setBadArtifactData(client *dynamodb.Client, artifactDataTablename, digest string) error {
|
||||
mdAttributeValue, err := attributevalue.Marshal("string")
|
||||
func setBadRepoMeta(client *dynamodb.Client, repoMetadataTableName, repoName string) error {
|
||||
repoAttributeValue, err := attributevalue.Marshal("string")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = client.UpdateItem(context.TODO(), &dynamodb.UpdateItemInput{
|
||||
ExpressionAttributeNames: map[string]string{
|
||||
"#AD": "ArtifactData",
|
||||
"#RM": "RepoMetadata",
|
||||
},
|
||||
ExpressionAttributeValues: map[string]types.AttributeValue{
|
||||
":ArtifactData": mdAttributeValue,
|
||||
":RepoMetadata": repoAttributeValue,
|
||||
},
|
||||
Key: map[string]types.AttributeValue{
|
||||
"ArtifactDigest": &types.AttributeValueMemberS{
|
||||
Value: digest,
|
||||
"RepoName": &types.AttributeValueMemberS{
|
||||
Value: repoName,
|
||||
},
|
||||
},
|
||||
TableName: aws.String(artifactDataTablename),
|
||||
UpdateExpression: aws.String("SET #AD = :ArtifactData"),
|
||||
TableName: aws.String(repoMetadataTableName),
|
||||
UpdateExpression: aws.String("SET #RM = :RepoMetadata"),
|
||||
})
|
||||
|
||||
return err
|
||||
@@ -1278,31 +1217,6 @@ func setBadIndexData(client *dynamodb.Client, indexDataTableName, digest string)
|
||||
return err
|
||||
}
|
||||
|
||||
func setBadRepoMeta(client *dynamodb.Client, repoMetadataTableName, repoName string) error {
|
||||
repoAttributeValue, err := attributevalue.Marshal("string")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = client.UpdateItem(context.TODO(), &dynamodb.UpdateItemInput{
|
||||
ExpressionAttributeNames: map[string]string{
|
||||
"#RM": "RepoMetadata",
|
||||
},
|
||||
ExpressionAttributeValues: map[string]types.AttributeValue{
|
||||
":RepoMetadata": repoAttributeValue,
|
||||
},
|
||||
Key: map[string]types.AttributeValue{
|
||||
"RepoName": &types.AttributeValueMemberS{
|
||||
Value: repoName,
|
||||
},
|
||||
},
|
||||
TableName: aws.String(repoMetadataTableName),
|
||||
UpdateExpression: aws.String("SET #RM = :RepoMetadata"),
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func setBadUserData(client *dynamodb.Client, userDataTablename, userID string) error {
|
||||
userAttributeValue, err := attributevalue.Marshal("string")
|
||||
if err != nil {
|
||||
|
||||
@@ -32,7 +32,6 @@ type DBWrapper struct {
|
||||
RepoMetaTablename string
|
||||
IndexDataTablename string
|
||||
ManifestDataTablename string
|
||||
ArtifactDataTablename string
|
||||
UserDataTablename string
|
||||
VersionTablename string
|
||||
Patches []func(client *dynamodb.Client, tableNames map[string]string) error
|
||||
@@ -45,7 +44,6 @@ func NewDynamoDBWrapper(client *dynamodb.Client, params dynamo.DBDriverParameter
|
||||
RepoMetaTablename: params.RepoMetaTablename,
|
||||
ManifestDataTablename: params.ManifestDataTablename,
|
||||
IndexDataTablename: params.IndexDataTablename,
|
||||
ArtifactDataTablename: params.ArtifactDataTablename,
|
||||
VersionTablename: params.VersionTablename,
|
||||
UserDataTablename: params.UserDataTablename,
|
||||
Patches: version.GetDynamoDBPatches(),
|
||||
@@ -67,11 +65,6 @@ func NewDynamoDBWrapper(client *dynamodb.Client, params dynamo.DBDriverParameter
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = dynamoWrapper.createArtifactDataTable()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = dynamoWrapper.createIndexDataTable()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -301,58 +294,6 @@ func (dwr *DBWrapper) GetIndexData(indexDigest godigest.Digest) (repodb.IndexDat
|
||||
return indexData, nil
|
||||
}
|
||||
|
||||
func (dwr DBWrapper) SetArtifactData(artifactDigest godigest.Digest, artifactData repodb.ArtifactData) error {
|
||||
artifactAttributeValue, err := attributevalue.Marshal(artifactData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = dwr.Client.UpdateItem(context.TODO(), &dynamodb.UpdateItemInput{
|
||||
ExpressionAttributeNames: map[string]string{
|
||||
"#AD": "ArtifactData",
|
||||
},
|
||||
ExpressionAttributeValues: map[string]types.AttributeValue{
|
||||
":ArtifactData": artifactAttributeValue,
|
||||
},
|
||||
Key: map[string]types.AttributeValue{
|
||||
"ArtifactDigest": &types.AttributeValueMemberS{
|
||||
Value: artifactDigest.String(),
|
||||
},
|
||||
},
|
||||
TableName: aws.String(dwr.ArtifactDataTablename),
|
||||
UpdateExpression: aws.String("SET #AD = :ArtifactData"),
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (dwr DBWrapper) GetArtifactData(artifactDigest godigest.Digest) (repodb.ArtifactData, error) {
|
||||
resp, err := dwr.Client.GetItem(context.TODO(), &dynamodb.GetItemInput{
|
||||
TableName: aws.String(dwr.ArtifactDataTablename),
|
||||
Key: map[string]types.AttributeValue{
|
||||
"ArtifactDigest": &types.AttributeValueMemberS{
|
||||
Value: artifactDigest.String(),
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return repodb.ArtifactData{}, err
|
||||
}
|
||||
|
||||
if resp.Item == nil {
|
||||
return repodb.ArtifactData{}, zerr.ErrRepoMetaNotFound
|
||||
}
|
||||
|
||||
var artifactData repodb.ArtifactData
|
||||
|
||||
err = attributevalue.Unmarshal(resp.Item["ArtifactData"], &artifactData)
|
||||
if err != nil {
|
||||
return repodb.ArtifactData{}, err
|
||||
}
|
||||
|
||||
return artifactData, nil
|
||||
}
|
||||
|
||||
func (dwr DBWrapper) SetReferrer(repo string, referredDigest godigest.Digest, referrer repodb.ReferrerInfo) error {
|
||||
resp, err := dwr.Client.GetItem(context.TODO(), &dynamodb.GetItemInput{
|
||||
TableName: aws.String(dwr.RepoMetaTablename),
|
||||
@@ -1664,31 +1605,6 @@ func (dwr *DBWrapper) createIndexDataTable() error {
|
||||
return dwr.waitTableToBeCreated(dwr.IndexDataTablename)
|
||||
}
|
||||
|
||||
func (dwr DBWrapper) createArtifactDataTable() error {
|
||||
_, err := dwr.Client.CreateTable(context.Background(), &dynamodb.CreateTableInput{
|
||||
TableName: aws.String(dwr.ArtifactDataTablename),
|
||||
AttributeDefinitions: []types.AttributeDefinition{
|
||||
{
|
||||
AttributeName: aws.String("ArtifactDigest"),
|
||||
AttributeType: types.ScalarAttributeTypeS,
|
||||
},
|
||||
},
|
||||
KeySchema: []types.KeySchemaElement{
|
||||
{
|
||||
AttributeName: aws.String("ArtifactDigest"),
|
||||
KeyType: types.KeyTypeHash,
|
||||
},
|
||||
},
|
||||
BillingMode: types.BillingModePayPerRequest,
|
||||
})
|
||||
|
||||
if err != nil && !strings.Contains(err.Error(), "Table already exists") {
|
||||
return err
|
||||
}
|
||||
|
||||
return dwr.waitTableToBeCreated(dwr.ManifestDataTablename)
|
||||
}
|
||||
|
||||
func (dwr *DBWrapper) createVersionTable() error {
|
||||
_, err := dwr.Client.CreateTable(context.Background(), &dynamodb.CreateTableInput{
|
||||
TableName: aws.String(dwr.VersionTablename),
|
||||
|
||||
@@ -77,12 +77,6 @@ type RepoDB interface { //nolint:interfacebloat
|
||||
// GetIndexData returns indexData for a given Index from the database
|
||||
GetIndexData(indexDigest godigest.Digest) (IndexData, error)
|
||||
|
||||
// SetArtifactData sets artifactData for a given artifact in the database
|
||||
SetArtifactData(artifactDigest godigest.Digest, artifactData ArtifactData) error
|
||||
|
||||
// GetArtifactData returns artifactData for a given artifact from the database
|
||||
GetArtifactData(artifactDigest godigest.Digest) (ArtifactData, error)
|
||||
|
||||
// SetReferrer adds a referrer to the referrers list of a manifest inside a repo
|
||||
SetReferrer(repo string, referredDigest godigest.Digest, referrer ReferrerInfo) error
|
||||
|
||||
@@ -150,10 +144,6 @@ type ManifestData struct {
|
||||
ConfigBlob []byte
|
||||
}
|
||||
|
||||
type ArtifactData struct {
|
||||
ManifestBlob []byte
|
||||
}
|
||||
|
||||
type ReferrerInfo struct {
|
||||
Digest string
|
||||
MediaType string
|
||||
|
||||
@@ -87,7 +87,6 @@ func TestDynamoDBWrapper(t *testing.T) {
|
||||
manifestDataTablename := "ManifestDataTable" + uuid.String()
|
||||
versionTablename := "Version" + uuid.String()
|
||||
indexDataTablename := "IndexDataTable" + uuid.String()
|
||||
artifactDataTablename := "ArtifactDataTable" + uuid.String()
|
||||
userDataTablename := "UserDataTable" + uuid.String()
|
||||
|
||||
Convey("DynamoDB Wrapper", t, func() {
|
||||
@@ -96,7 +95,6 @@ func TestDynamoDBWrapper(t *testing.T) {
|
||||
RepoMetaTablename: repoMetaTablename,
|
||||
ManifestDataTablename: manifestDataTablename,
|
||||
IndexDataTablename: indexDataTablename,
|
||||
ArtifactDataTablename: artifactDataTablename,
|
||||
VersionTablename: versionTablename,
|
||||
UserDataTablename: userDataTablename,
|
||||
Region: "us-east-2",
|
||||
@@ -2174,27 +2172,6 @@ func RunRepoDBTests(repoDB repodb.RepoDB, preparationFuncs ...func() error) {
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Test artifact logic", func() {
|
||||
artifact, err := test.GetRandomArtifact(nil)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
artifactDigest, err := artifact.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
artifactData, err := artifact.ArtifactData()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = repoDB.SetArtifactData(artifactDigest, artifactData)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
result, err := repoDB.GetArtifactData(artifactDigest)
|
||||
So(err, ShouldBeNil)
|
||||
So(result, ShouldResemble, artifactData)
|
||||
|
||||
_, err = repoDB.GetArtifactData(godigest.FromString("inexistent"))
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Test Referrers", func() {
|
||||
image, err := test.GetRandomImage("tag")
|
||||
So(err, ShouldBeNil)
|
||||
@@ -2221,10 +2198,10 @@ func RunRepoDBTests(repoDB repodb.RepoDB, preparationFuncs ...func() error) {
|
||||
|
||||
// ------- Add Artifact 1
|
||||
|
||||
artifact1, err := test.GetRandomArtifact(&ispec.Descriptor{
|
||||
Digest: referredDigest,
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
})
|
||||
artifact1, err := test.GetImageWithSubject(
|
||||
referredDigest,
|
||||
ispec.MediaTypeImageManifest,
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
artifactDigest1, err := artifact1.Digest()
|
||||
@@ -2238,10 +2215,10 @@ func RunRepoDBTests(repoDB repodb.RepoDB, preparationFuncs ...func() error) {
|
||||
|
||||
// ------- Add Artifact 2
|
||||
|
||||
artifact2, err := test.GetRandomArtifact(&ispec.Descriptor{
|
||||
Digest: referredDigest,
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
})
|
||||
artifact2, err := test.GetImageWithSubject(
|
||||
referredDigest,
|
||||
ispec.MediaTypeImageManifest,
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
artifactDigest2, err := artifact2.Digest()
|
||||
@@ -2249,7 +2226,7 @@ func RunRepoDBTests(repoDB repodb.RepoDB, preparationFuncs ...func() error) {
|
||||
|
||||
err = repoDB.SetReferrer("repo", referredDigest, repodb.ReferrerInfo{
|
||||
Digest: artifactDigest2.String(),
|
||||
MediaType: ispec.MediaTypeArtifactManifest,
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@@ -2263,7 +2240,7 @@ func RunRepoDBTests(repoDB repodb.RepoDB, preparationFuncs ...func() error) {
|
||||
})
|
||||
So(referrers, ShouldContain, repodb.ReferrerInfo{
|
||||
Digest: artifactDigest2.String(),
|
||||
MediaType: ispec.MediaTypeArtifactManifest,
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@@ -2333,12 +2310,6 @@ func RunRepoDBTests(repoDB repodb.RepoDB, preparationFuncs ...func() error) {
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = repoDB.SetReferrer("repo", referredDigest, repodb.ReferrerInfo{
|
||||
Digest: "inexistendArtifactManifestDigest",
|
||||
MediaType: ispec.MediaTypeArtifactManifest,
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// ------- Set existent manifest and artifact manifest
|
||||
err = repoDB.SetManifestData("goodManifest", repodb.ManifestData{
|
||||
ManifestBlob: []byte(`{"artifactType": "unwantedType"}`),
|
||||
@@ -2347,20 +2318,15 @@ func RunRepoDBTests(repoDB repodb.RepoDB, preparationFuncs ...func() error) {
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = repoDB.SetReferrer("repo", referredDigest, repodb.ReferrerInfo{
|
||||
Digest: "goodManifest",
|
||||
Digest: "goodManifestUnwanted",
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
ArtifactType: "unwantedType",
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = repoDB.SetArtifactData("goodArtifact", repodb.ArtifactData{
|
||||
ManifestBlob: []byte(`{"artifactType": "wantedType"}`),
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = repoDB.SetReferrer("repo", referredDigest, repodb.ReferrerInfo{
|
||||
Digest: "goodArtifact",
|
||||
MediaType: ispec.MediaTypeArtifactManifest,
|
||||
Digest: "goodManifest",
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
ArtifactType: "wantedType",
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
@@ -2369,7 +2335,7 @@ func RunRepoDBTests(repoDB repodb.RepoDB, preparationFuncs ...func() error) {
|
||||
So(err, ShouldBeNil)
|
||||
So(len(referrerInfo), ShouldEqual, 1)
|
||||
So(referrerInfo[0].ArtifactType, ShouldResemble, "wantedType")
|
||||
So(referrerInfo[0].Digest, ShouldResemble, "goodArtifact")
|
||||
So(referrerInfo[0].Digest, ShouldResemble, "goodManifest")
|
||||
})
|
||||
|
||||
Convey("FilterRepos", func() {
|
||||
|
||||
@@ -89,9 +89,6 @@ func getDynamoParams(cacheDriverConfig map[string]interface{}, log log.Logger) d
|
||||
indexDataTablename, ok := toStringIfOk(cacheDriverConfig, "indexdatatablename", log)
|
||||
allParametersOk = allParametersOk && ok
|
||||
|
||||
artifactDataTablename, ok := toStringIfOk(cacheDriverConfig, "artifactdatatablename", log)
|
||||
allParametersOk = allParametersOk && ok
|
||||
|
||||
versionTablename, ok := toStringIfOk(cacheDriverConfig, "versiontablename", log)
|
||||
allParametersOk = allParametersOk && ok
|
||||
|
||||
@@ -108,7 +105,6 @@ func getDynamoParams(cacheDriverConfig map[string]interface{}, log log.Logger) d
|
||||
RepoMetaTablename: repoMetaTablename,
|
||||
ManifestDataTablename: manifestDataTablename,
|
||||
IndexDataTablename: indexDataTablename,
|
||||
ArtifactDataTablename: artifactDataTablename,
|
||||
UserDataTablename: userDataTablename,
|
||||
VersionTablename: versionTablename,
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ func TestCreateDynamo(t *testing.T) {
|
||||
RepoMetaTablename: "RepoMetadataTable",
|
||||
ManifestDataTablename: "ManifestDataTable",
|
||||
IndexDataTablename: "IndexDataTable",
|
||||
ArtifactDataTablename: "ArtifactDataTable",
|
||||
UserDataTablename: "UserDataTable",
|
||||
VersionTablename: "Version",
|
||||
Region: "us-east-2",
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
|
||||
zerr "zotregistry.io/zot/errors"
|
||||
zcommon "zotregistry.io/zot/pkg/common"
|
||||
"zotregistry.io/zot/pkg/log"
|
||||
"zotregistry.io/zot/pkg/storage"
|
||||
)
|
||||
@@ -263,13 +264,6 @@ func NewIndexData(repoName string, indexBlob []byte, imageStore storage.ImageSto
|
||||
return indexData
|
||||
}
|
||||
|
||||
func NewArtifactData(repo string, descriptorBlob []byte, imageStore storage.ImageStore,
|
||||
) ArtifactData {
|
||||
return ArtifactData{
|
||||
ManifestBlob: descriptorBlob,
|
||||
}
|
||||
}
|
||||
|
||||
// SetMetadataFromInput tries to set manifest metadata and update repo metadata by adding the current tag
|
||||
// (in case the reference is a tag). The function expects image manifests and indexes (multi arch images).
|
||||
func SetMetadataFromInput(repo, reference, mediaType string, digest godigest.Digest, descriptorBlob []byte,
|
||||
@@ -295,15 +289,6 @@ func SetMetadataFromInput(repo, reference, mediaType string, digest godigest.Dig
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("repodb: error while putting index data")
|
||||
|
||||
return err
|
||||
}
|
||||
case ispec.MediaTypeArtifactManifest:
|
||||
artifactData := NewArtifactData(repo, descriptorBlob, imageStore)
|
||||
|
||||
err := repoDB.SetArtifactData(digest, artifactData)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("repodb: error while putting artifact data")
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -335,43 +320,22 @@ func GetReferredSubject(descriptorBlob []byte, referrerDigest, mediaType string,
|
||||
referrerSubject *ispec.Descriptor
|
||||
)
|
||||
|
||||
switch mediaType {
|
||||
case ispec.MediaTypeImageManifest:
|
||||
var manifestContent ispec.Manifest
|
||||
var manifestContent ispec.Manifest
|
||||
|
||||
err := json.Unmarshal(descriptorBlob, &manifestContent)
|
||||
if err != nil {
|
||||
return "", referrerInfo, false,
|
||||
fmt.Errorf("repodb: can't unmarhsal manifest for digest %s: %w", referrerDigest, err)
|
||||
}
|
||||
err := json.Unmarshal(descriptorBlob, &manifestContent)
|
||||
if err != nil {
|
||||
return "", referrerInfo, false,
|
||||
fmt.Errorf("repodb: can't unmarshal manifest for digest %s: %w", referrerDigest, err)
|
||||
}
|
||||
|
||||
referrerSubject = manifestContent.Subject
|
||||
referrerSubject = manifestContent.Subject
|
||||
|
||||
referrerInfo = ReferrerInfo{
|
||||
Digest: referrerDigest,
|
||||
MediaType: mediaType,
|
||||
ArtifactType: manifestContent.Config.MediaType,
|
||||
Size: len(descriptorBlob),
|
||||
Annotations: manifestContent.Annotations,
|
||||
}
|
||||
case ispec.MediaTypeArtifactManifest:
|
||||
manifestContent := ispec.Artifact{}
|
||||
|
||||
err := json.Unmarshal(descriptorBlob, &manifestContent)
|
||||
if err != nil {
|
||||
return "", referrerInfo, false,
|
||||
fmt.Errorf("repodb: can't unmarhsal artifact manifest for digest %s: %w", referrerDigest, err)
|
||||
}
|
||||
|
||||
referrerSubject = manifestContent.Subject
|
||||
|
||||
referrerInfo = ReferrerInfo{
|
||||
Digest: referrerDigest,
|
||||
MediaType: manifestContent.MediaType,
|
||||
ArtifactType: manifestContent.ArtifactType,
|
||||
Size: len(descriptorBlob),
|
||||
Annotations: manifestContent.Annotations,
|
||||
}
|
||||
referrerInfo = ReferrerInfo{
|
||||
Digest: referrerDigest,
|
||||
MediaType: mediaType,
|
||||
ArtifactType: zcommon.GetManifestArtifactType(manifestContent),
|
||||
Size: len(descriptorBlob),
|
||||
Annotations: manifestContent.Annotations,
|
||||
}
|
||||
|
||||
if referrerSubject == nil || referrerSubject.Digest.String() == "" {
|
||||
|
||||
@@ -237,7 +237,7 @@ func TestParseStorageErrors(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("CheckIsImageSignature -> is signature", func() {
|
||||
manifestContent := ispec.Artifact{
|
||||
manifestContent := ispec.Manifest{
|
||||
Subject: &ispec.Descriptor{
|
||||
Digest: "123",
|
||||
},
|
||||
@@ -292,7 +292,6 @@ func TestParseStorageDynamoWrapper(t *testing.T) {
|
||||
RepoMetaTablename: "RepoMetadataTable",
|
||||
ManifestDataTablename: "ManifestDataTable",
|
||||
IndexDataTablename: "IndexDataTable",
|
||||
ArtifactDataTablename: "ArtifactDataTable",
|
||||
UserDataTablename: "UserDataTable",
|
||||
VersionTablename: "Version",
|
||||
}
|
||||
@@ -515,10 +514,7 @@ func RunParseStorageTests(rootDir string, repoDB repodb.RepoDB) {
|
||||
|
||||
func TestGetReferredSubject(t *testing.T) {
|
||||
Convey("GetReferredSubject error", t, func() {
|
||||
_, _, _, err := repodb.GetReferredSubject([]byte("bad json"), "digest", ispec.MediaTypeArtifactManifest)
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
_, _, _, err = repodb.GetReferredSubject([]byte("bad json"), "digest", ispec.MediaTypeImageManifest)
|
||||
_, _, _, err := repodb.GetReferredSubject([]byte("bad json"), "digest", ispec.MediaTypeImageManifest)
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
}
|
||||
|
||||
+1
-1
@@ -144,7 +144,7 @@ func OnDeleteManifest(repo, reference, mediaType string, digest godigest.Digest,
|
||||
}
|
||||
|
||||
// OnDeleteManifest is called when a manifest is downloaded. It increments the download couter on that manifest.
|
||||
func OnGetManifest(name, reference string, digest godigest.Digest, body []byte,
|
||||
func OnGetManifest(name, reference string, body []byte,
|
||||
storeController storage.StoreController, repoDB repodb.RepoDB, log log.Logger,
|
||||
) error {
|
||||
// check if image is a signature
|
||||
|
||||
+12
-16
@@ -100,7 +100,7 @@ func TestUpdateErrors(t *testing.T) {
|
||||
log := log.NewLogger("debug", "")
|
||||
|
||||
Convey("zerr.ErrOrphanSignature", func() {
|
||||
manifestContent := ispec.Artifact{
|
||||
manifestContent := ispec.Manifest{
|
||||
Subject: &ispec.Descriptor{
|
||||
Digest: "123",
|
||||
},
|
||||
@@ -126,7 +126,7 @@ func TestUpdateErrors(t *testing.T) {
|
||||
log := log.NewLogger("debug", "")
|
||||
|
||||
Convey("CheckIsImageSignature errors", func() {
|
||||
manifestContent := ispec.Artifact{
|
||||
manifestContent := ispec.Manifest{
|
||||
Subject: &ispec.Descriptor{
|
||||
Digest: "123",
|
||||
},
|
||||
@@ -179,7 +179,7 @@ func TestUpdateErrors(t *testing.T) {
|
||||
log := log.NewLogger("debug", "")
|
||||
|
||||
Convey("CheckIsImageSignature errors", func() {
|
||||
manifestContent := ispec.Artifact{
|
||||
manifestContent := ispec.Manifest{
|
||||
Subject: &ispec.Descriptor{
|
||||
Digest: "123",
|
||||
},
|
||||
@@ -192,7 +192,7 @@ func TestUpdateErrors(t *testing.T) {
|
||||
return []byte{}, "", "", zerr.ErrManifestNotFound
|
||||
}
|
||||
|
||||
err = meta.OnGetManifest("repo", "tag1", "digest", manifestBlob,
|
||||
err = meta.OnGetManifest("repo", "tag1", manifestBlob,
|
||||
storeController, repoDB, log)
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
@@ -200,7 +200,7 @@ func TestUpdateErrors(t *testing.T) {
|
||||
return []byte{}, "", "", ErrTestError
|
||||
}
|
||||
|
||||
err = meta.OnGetManifest("repo", "tag1", "media", manifestBlob,
|
||||
err = meta.OnGetManifest("repo", "tag1", manifestBlob,
|
||||
storeController, repoDB, log)
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
@@ -245,22 +245,18 @@ func TestUpdateErrors(t *testing.T) {
|
||||
err := repodb.SetMetadataFromInput("repo", "ref", ispec.MediaTypeImageManifest, "digest",
|
||||
[]byte("{}"), imageStore, repoDB, log)
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
repoDB = mocks.RepoDBMock{
|
||||
Convey("SetMetadataFromInput SetIndexData errors", func() {
|
||||
imageStore := mocks.MockedImageStore{}
|
||||
log := log.NewLogger("debug", "")
|
||||
|
||||
repoDB := mocks.RepoDBMock{
|
||||
SetIndexDataFn: func(digest godigest.Digest, indexData repodb.IndexData) error {
|
||||
return ErrTestError
|
||||
},
|
||||
}
|
||||
err = repodb.SetMetadataFromInput("repo", "ref", ispec.MediaTypeImageIndex, "digest",
|
||||
[]byte("{}"), imageStore, repoDB, log)
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
repoDB = mocks.RepoDBMock{
|
||||
SetArtifactDataFn: func(digest godigest.Digest, artifactData repodb.ArtifactData) error {
|
||||
return ErrTestError
|
||||
},
|
||||
}
|
||||
err = repodb.SetMetadataFromInput("repo", "ref", ispec.MediaTypeArtifactManifest, "digest",
|
||||
err := repodb.SetMetadataFromInput("repo", "ref", ispec.MediaTypeImageIndex, "digest",
|
||||
[]byte("{}"), imageStore, repoDB, log)
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
@@ -125,7 +125,6 @@ func TestVersioningDynamoDB(t *testing.T) {
|
||||
Region: region,
|
||||
RepoMetaTablename: "RepoMetadataTable",
|
||||
ManifestDataTablename: "ManifestDataTable",
|
||||
ArtifactDataTablename: "ArtifactDataTable",
|
||||
IndexDataTablename: "IndexDataTable",
|
||||
UserDataTablename: "UserDataTable",
|
||||
VersionTablename: "Version",
|
||||
|
||||
+78
-98
@@ -16,10 +16,16 @@ import (
|
||||
"github.com/sigstore/cosign/v2/pkg/oci/remote"
|
||||
|
||||
zerr "zotregistry.io/zot/errors"
|
||||
zcommon "zotregistry.io/zot/pkg/common"
|
||||
"zotregistry.io/zot/pkg/scheduler"
|
||||
storageConstants "zotregistry.io/zot/pkg/storage/constants"
|
||||
)
|
||||
|
||||
const (
|
||||
CosignType = "cosign"
|
||||
NotationType = "notation"
|
||||
)
|
||||
|
||||
func SignatureMediaTypes() map[string]bool {
|
||||
return map[string]bool{
|
||||
notreg.ArtifactTypeNotation: true,
|
||||
@@ -106,22 +112,6 @@ func ValidateManifest(imgStore ImageStore, repo, reference, mediaType string, bo
|
||||
|
||||
return "", zerr.ErrBadManifest
|
||||
}
|
||||
case ispec.MediaTypeArtifactManifest:
|
||||
var artifact ispec.Artifact
|
||||
if err := json.Unmarshal(body, &artifact); err != nil {
|
||||
log.Error().Err(err).Msg("unable to unmarshal JSON")
|
||||
|
||||
return "", zerr.ErrBadManifest
|
||||
}
|
||||
|
||||
if artifact.Subject != nil {
|
||||
var m ispec.Descriptor
|
||||
if err := json.Unmarshal(body, &m); err != nil {
|
||||
log.Error().Err(err).Msg("unable to unmarshal JSON")
|
||||
|
||||
return "", zerr.ErrBadManifest
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil
|
||||
@@ -303,6 +293,27 @@ func GetImageIndex(imgStore ImageStore, repo string, digest godigest.Digest, log
|
||||
return imageIndex, nil
|
||||
}
|
||||
|
||||
func GetImageManifest(imgStore ImageStore, repo string, digest godigest.Digest, log zerolog.Logger,
|
||||
) (ispec.Manifest, error) {
|
||||
var manifestContent ispec.Manifest
|
||||
|
||||
manifestBlob, err := imgStore.GetBlobContent(repo, digest)
|
||||
if err != nil {
|
||||
return manifestContent, err
|
||||
}
|
||||
|
||||
manifestPath := path.Join(imgStore.RootDir(), repo, "blobs",
|
||||
digest.Algorithm().String(), digest.Encoded())
|
||||
|
||||
if err := json.Unmarshal(manifestBlob, &manifestContent); err != nil {
|
||||
log.Error().Err(err).Str("path", manifestPath).Msg("invalid JSON")
|
||||
|
||||
return manifestContent, err
|
||||
}
|
||||
|
||||
return manifestContent, nil
|
||||
}
|
||||
|
||||
func RemoveManifestDescByReference(index *ispec.Index, reference string, detectCollisions bool,
|
||||
) (ispec.Descriptor, error) {
|
||||
var removedManifest ispec.Descriptor
|
||||
@@ -456,31 +467,50 @@ func PruneImageManifestsFromIndex(imgStore ImageStore, repo string, digest godig
|
||||
return prunedManifests, nil
|
||||
}
|
||||
|
||||
func ApplyLinter(imgStore ImageStore, linter Lint, repo string, manifestDesc ispec.Descriptor) (bool, error) {
|
||||
func ApplyLinter(imgStore ImageStore, linter Lint, repo string, descriptor ispec.Descriptor) (bool, error) {
|
||||
pass := true
|
||||
|
||||
if linter != nil {
|
||||
tag := manifestDesc.Annotations[ispec.AnnotationRefName]
|
||||
// apply linter only on images, not signatures
|
||||
if manifestDesc.MediaType == ispec.MediaTypeImageManifest &&
|
||||
// check that image manifest is not cosign signature
|
||||
!strings.HasPrefix(tag, "sha256-") &&
|
||||
!strings.HasSuffix(tag, remote.SignatureTagSuffix) {
|
||||
// lint new index with new manifest before writing to disk
|
||||
pass, err := linter.Lint(repo, manifestDesc.Digest, imgStore)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// we'll skip anything that's not a image manifest
|
||||
if descriptor.MediaType != ispec.MediaTypeImageManifest {
|
||||
return pass, nil
|
||||
}
|
||||
|
||||
if !pass {
|
||||
return false, zerr.ErrImageLintAnnotations
|
||||
}
|
||||
if linter != nil && !IsSignature(descriptor) {
|
||||
// lint new index with new manifest before writing to disk
|
||||
pass, err := linter.Lint(repo, descriptor.Digest, imgStore)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !pass {
|
||||
return false, zerr.ErrImageLintAnnotations
|
||||
}
|
||||
}
|
||||
|
||||
return pass, nil
|
||||
}
|
||||
|
||||
func IsSignature(descriptor ispec.Descriptor) bool {
|
||||
tag := descriptor.Annotations[ispec.AnnotationRefName]
|
||||
|
||||
switch descriptor.MediaType {
|
||||
case ispec.MediaTypeImageManifest:
|
||||
// is cosgin signature
|
||||
if strings.HasPrefix(tag, "sha256-") && strings.HasSuffix(tag, remote.SignatureTagSuffix) {
|
||||
return true
|
||||
}
|
||||
|
||||
// is notation signature
|
||||
if descriptor.ArtifactType == notreg.ArtifactTypeNotation {
|
||||
return true
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func GetOrasReferrers(imgStore ImageStore, repo string, gdigest godigest.Digest, artifactType string,
|
||||
log zerolog.Logger,
|
||||
) ([]oras.Descriptor, error) {
|
||||
@@ -609,67 +639,18 @@ func GetReferrers(imgStore ImageStore, repo string, gdigest godigest.Digest, art
|
||||
}
|
||||
|
||||
// filter by artifact type
|
||||
if len(artifactTypes) > 0 {
|
||||
found := false
|
||||
manifestArtifactType := zcommon.GetManifestArtifactType(mfst)
|
||||
|
||||
for _, artifactType := range artifactTypes {
|
||||
if artifactType != "" && mfst.Config.MediaType != artifactType {
|
||||
continue
|
||||
}
|
||||
|
||||
found = true
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
result = append(result, ispec.Descriptor{
|
||||
MediaType: manifest.MediaType,
|
||||
ArtifactType: mfst.Config.MediaType,
|
||||
Size: manifest.Size,
|
||||
Digest: manifest.Digest,
|
||||
Annotations: mfst.Annotations,
|
||||
})
|
||||
} else if manifest.MediaType == ispec.MediaTypeArtifactManifest {
|
||||
var art ispec.Artifact
|
||||
if err := json.Unmarshal(buf, &art); err != nil {
|
||||
log.Error().Err(err).Str("manifest digest", manifest.Digest.String()).Msg("invalid JSON")
|
||||
|
||||
return nilIndex, err
|
||||
}
|
||||
|
||||
if art.Subject == nil || art.Subject.Digest != gdigest {
|
||||
if len(artifactTypes) > 0 && !zcommon.Contains(artifactTypes, manifestArtifactType) {
|
||||
continue
|
||||
}
|
||||
|
||||
// filter by artifact type
|
||||
if len(artifactTypes) > 0 {
|
||||
found := false
|
||||
for _, artifactType := range artifactTypes {
|
||||
if artifactType != "" && art.ArtifactType != artifactType {
|
||||
continue
|
||||
}
|
||||
|
||||
found = true
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
result = append(result, ispec.Descriptor{
|
||||
MediaType: manifest.MediaType,
|
||||
ArtifactType: art.ArtifactType,
|
||||
ArtifactType: manifestArtifactType,
|
||||
Size: manifest.Size,
|
||||
Digest: manifest.Digest,
|
||||
Annotations: art.Annotations,
|
||||
Annotations: mfst.Annotations,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -719,14 +700,13 @@ func GetOrasManifestByDigest(imgStore ImageStore, repo string, digest godigest.D
|
||||
func IsSupportedMediaType(mediaType string) bool {
|
||||
return mediaType == ispec.MediaTypeImageIndex ||
|
||||
mediaType == ispec.MediaTypeImageManifest ||
|
||||
mediaType == ispec.MediaTypeArtifactManifest ||
|
||||
mediaType == oras.MediaTypeArtifactManifest
|
||||
}
|
||||
|
||||
func IsNonDistributable(mediaType string) bool {
|
||||
return mediaType == ispec.MediaTypeImageLayerNonDistributable ||
|
||||
mediaType == ispec.MediaTypeImageLayerNonDistributableGzip ||
|
||||
mediaType == ispec.MediaTypeImageLayerNonDistributableZstd
|
||||
return mediaType == ispec.MediaTypeImageLayerNonDistributable || //nolint:staticcheck
|
||||
mediaType == ispec.MediaTypeImageLayerNonDistributableGzip || //nolint:staticcheck
|
||||
mediaType == ispec.MediaTypeImageLayerNonDistributableZstd //nolint:staticcheck
|
||||
}
|
||||
|
||||
// CheckIsImageSignature checks if the given image (repo:tag) represents a signature. The function
|
||||
@@ -742,30 +722,30 @@ func IsNonDistributable(mediaType string) bool {
|
||||
func CheckIsImageSignature(repoName string, manifestBlob []byte, reference string,
|
||||
storeController StoreController,
|
||||
) (bool, string, godigest.Digest, error) {
|
||||
const cosign = "cosign"
|
||||
|
||||
var manifestContent ispec.Artifact
|
||||
var manifestContent ispec.Manifest
|
||||
|
||||
err := json.Unmarshal(manifestBlob, &manifestContent)
|
||||
if err != nil {
|
||||
return false, "", "", err
|
||||
}
|
||||
|
||||
manifestArtifactType := zcommon.GetManifestArtifactType(manifestContent)
|
||||
|
||||
// check notation signature
|
||||
if _, ok := SignatureMediaTypes()[manifestContent.ArtifactType]; ok && manifestContent.Subject != nil {
|
||||
if _, ok := SignatureMediaTypes()[manifestArtifactType]; ok && manifestContent.Subject != nil {
|
||||
imgStore := storeController.GetImageStore(repoName)
|
||||
|
||||
_, signedImageManifestDigest, _, err := imgStore.GetImageManifest(repoName,
|
||||
manifestContent.Subject.Digest.String())
|
||||
if err != nil {
|
||||
if errors.Is(err, zerr.ErrManifestNotFound) {
|
||||
return true, "notation", signedImageManifestDigest, zerr.ErrOrphanSignature
|
||||
return true, NotationType, signedImageManifestDigest, zerr.ErrOrphanSignature
|
||||
}
|
||||
|
||||
return false, "", "", err
|
||||
}
|
||||
|
||||
return true, "notation", signedImageManifestDigest, nil
|
||||
return true, NotationType, signedImageManifestDigest, nil
|
||||
}
|
||||
|
||||
// check cosign
|
||||
@@ -785,17 +765,17 @@ func CheckIsImageSignature(repoName string, manifestBlob []byte, reference strin
|
||||
signedImageManifestDigest.String())
|
||||
if err != nil {
|
||||
if errors.Is(err, zerr.ErrManifestNotFound) {
|
||||
return true, cosign, signedImageManifestDigest, zerr.ErrOrphanSignature
|
||||
return true, CosignType, signedImageManifestDigest, zerr.ErrOrphanSignature
|
||||
}
|
||||
|
||||
return false, "", "", err
|
||||
}
|
||||
|
||||
if signedImageManifestDigest.String() == "" {
|
||||
return true, cosign, signedImageManifestDigest, zerr.ErrOrphanSignature
|
||||
return true, CosignType, signedImageManifestDigest, zerr.ErrOrphanSignature
|
||||
}
|
||||
|
||||
return true, cosign, signedImageManifestDigest, nil
|
||||
return true, CosignType, signedImageManifestDigest, nil
|
||||
}
|
||||
|
||||
return false, "", "", nil
|
||||
|
||||
+11
-29
@@ -118,7 +118,7 @@ func TestValidateManifest(t *testing.T) {
|
||||
},
|
||||
Layers: []ispec.Descriptor{
|
||||
{
|
||||
MediaType: ispec.MediaTypeImageLayerNonDistributable,
|
||||
MediaType: ispec.MediaTypeImageLayerNonDistributable, //nolint:staticcheck
|
||||
Digest: digest,
|
||||
Size: int64(len(content)),
|
||||
},
|
||||
@@ -299,38 +299,11 @@ func TestGetReferrersErrors(t *testing.T) {
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Trigger unmarshal error on artifact mediaType", func(c C) {
|
||||
index = ispec.Index{
|
||||
Manifests: []ispec.Descriptor{
|
||||
{
|
||||
MediaType: ispec.MediaTypeArtifactManifest,
|
||||
Digest: digest,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
indexBuf, err = json.Marshal(index)
|
||||
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 []byte{}, nil
|
||||
},
|
||||
}
|
||||
|
||||
_, err = storage.GetReferrers(imgStore, "zot-test", validDigest,
|
||||
[]string{artifactType}, log.With().Caller().Logger())
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Trigger nil subject", func(c C) {
|
||||
index = ispec.Index{
|
||||
Manifests: []ispec.Descriptor{
|
||||
{
|
||||
MediaType: ispec.MediaTypeArtifactManifest,
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Digest: digest,
|
||||
},
|
||||
},
|
||||
@@ -398,3 +371,12 @@ func TestGetImageIndexErrors(t *testing.T) {
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIsSignature(t *testing.T) {
|
||||
Convey("Unknown media type", t, func(c C) {
|
||||
isSingature := storage.IsSignature(ispec.Descriptor{
|
||||
MediaType: "unknown media type",
|
||||
})
|
||||
So(isSingature, ShouldBeFalse)
|
||||
})
|
||||
}
|
||||
|
||||
+48
-36
@@ -29,7 +29,7 @@ import (
|
||||
"github.com/sigstore/cosign/v2/pkg/oci/remote"
|
||||
|
||||
zerr "zotregistry.io/zot/errors"
|
||||
"zotregistry.io/zot/pkg/common"
|
||||
zcommon "zotregistry.io/zot/pkg/common"
|
||||
"zotregistry.io/zot/pkg/extensions/monitoring"
|
||||
zlog "zotregistry.io/zot/pkg/log"
|
||||
zreg "zotregistry.io/zot/pkg/regexp"
|
||||
@@ -66,7 +66,7 @@ func (is *ImageStoreLocal) RootDir() string {
|
||||
}
|
||||
|
||||
func (is *ImageStoreLocal) DirExists(d string) bool {
|
||||
return common.DirExists(d)
|
||||
return zcommon.DirExists(d)
|
||||
}
|
||||
|
||||
// NewImageStore returns a new image store backed by a file storage.
|
||||
@@ -535,7 +535,18 @@ func (is *ImageStoreLocal) PutImageManifest(repo, reference, mediaType string, /
|
||||
return "", err
|
||||
}
|
||||
|
||||
// apply linter only on images, not signatures
|
||||
if mediaType == ispec.MediaTypeImageManifest {
|
||||
var manifest ispec.Manifest
|
||||
|
||||
err := json.Unmarshal(body, &manifest)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
desc.ArtifactType = zcommon.GetManifestArtifactType(manifest)
|
||||
}
|
||||
|
||||
// apply linter only on images, not signatures or indexes
|
||||
pass, err := storage.ApplyLinter(is, is.linter, repo, desc)
|
||||
if !pass {
|
||||
is.log.Error().Err(err).Str("repository", repo).Str("reference", reference).Msg("linter didn't pass")
|
||||
@@ -1440,6 +1451,12 @@ func ensureDir(dir string, log zerolog.Logger) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type extendedManifest struct {
|
||||
ispec.Manifest
|
||||
|
||||
Digest godigest.Digest
|
||||
}
|
||||
|
||||
func (is *ImageStoreLocal) garbageCollect(dir string, repo string) error {
|
||||
oci, err := umoci.OpenLayout(dir)
|
||||
if err := test.Error(err); err != nil {
|
||||
@@ -1455,7 +1472,7 @@ func (is *ImageStoreLocal) garbageCollect(dir string, repo string) error {
|
||||
|
||||
referencedByImageIndex := []string{}
|
||||
cosignDescriptors := []ispec.Descriptor{}
|
||||
notationDescriptors := []ispec.Descriptor{}
|
||||
notationManifests := []extendedManifest{}
|
||||
|
||||
/* gather manifests references by multiarch images (to skip gc)
|
||||
gather cosign and notation signatures descriptors */
|
||||
@@ -1479,10 +1496,27 @@ func (is *ImageStoreLocal) garbageCollect(dir string, repo string) error {
|
||||
// gather cosign signatures
|
||||
if strings.HasPrefix(tag, "sha256-") && strings.HasSuffix(tag, remote.SignatureTagSuffix) {
|
||||
cosignDescriptors = append(cosignDescriptors, desc)
|
||||
|
||||
continue
|
||||
}
|
||||
}
|
||||
case ispec.MediaTypeArtifactManifest:
|
||||
notationDescriptors = append(notationDescriptors, desc)
|
||||
|
||||
manifestContent, err := storage.GetImageManifest(is, repo, desc.Digest, is.log)
|
||||
if err != nil {
|
||||
is.log.Error().Err(err).Str("repo", repo).Str("digest", desc.Digest.String()).
|
||||
Msg("gc: failed to read manifest image")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if zcommon.GetManifestArtifactType(manifestContent) == notreg.ArtifactTypeNotation {
|
||||
notationManifests = append(notationManifests, extendedManifest{
|
||||
Digest: desc.Digest,
|
||||
Manifest: manifestContent,
|
||||
})
|
||||
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1500,7 +1534,7 @@ func (is *ImageStoreLocal) garbageCollect(dir string, repo string) error {
|
||||
|
||||
is.log.Info().Msg("gc: notation signatures")
|
||||
|
||||
if err := gcNotationSignatures(is, oci, &index, repo, notationDescriptors); err != nil {
|
||||
if err := gcNotationSignatures(is, oci, &index, repo, notationManifests); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1519,7 +1553,7 @@ func gcUntaggedManifests(imgStore *ImageStoreLocal, oci casext.Engine, index *is
|
||||
) error {
|
||||
for _, desc := range index.Manifests {
|
||||
// skip manifests referenced in image indexex
|
||||
if common.Contains(referencedByImageIndex, desc.Digest.String()) {
|
||||
if zcommon.Contains(referencedByImageIndex, desc.Digest.String()) {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1616,46 +1650,24 @@ func gcCosignSignatures(imgStore *ImageStoreLocal, oci casext.Engine, index *isp
|
||||
}
|
||||
|
||||
func gcNotationSignatures(imgStore *ImageStoreLocal, oci casext.Engine, index *ispec.Index, repo string,
|
||||
notationDescriptors []ispec.Descriptor,
|
||||
notationManifests []extendedManifest,
|
||||
) error {
|
||||
for _, notationDesc := range notationDescriptors {
|
||||
for _, notationManifest := range notationManifests {
|
||||
foundSubject := false
|
||||
// check if we can find the manifest which the signature points to
|
||||
var artManifest ispec.Artifact
|
||||
|
||||
buf, err := imgStore.GetBlobContent(repo, notationDesc.Digest)
|
||||
if err != nil {
|
||||
imgStore.log.Error().Err(err).Str("repository", repo).Str("digest", notationDesc.Digest.String()).
|
||||
Msg("gc: failed to get oras artifact manifest")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(buf, &artManifest); err != nil {
|
||||
imgStore.log.Error().Err(err).Str("repository", repo).Str("digest", notationDesc.Digest.String()).
|
||||
Msg("gc: failed to get oras artifact manifest")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// skip oci artifacts which are not signatures
|
||||
if artManifest.ArtifactType != notreg.ArtifactTypeNotation {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, desc := range index.Manifests {
|
||||
if desc.Digest == artManifest.Subject.Digest {
|
||||
if desc.Digest == notationManifest.Subject.Digest {
|
||||
foundSubject = true
|
||||
}
|
||||
}
|
||||
|
||||
if !foundSubject {
|
||||
// remove manifest
|
||||
imgStore.log.Info().Str("repository", repo).Str("digest", notationDesc.Digest.String()).
|
||||
imgStore.log.Info().Str("repository", repo).Str("digest", notationManifest.Digest.String()).
|
||||
Msg("gc: removing notation signature without subject")
|
||||
|
||||
// no need to check for manifest conflict, if one doesn't have a subject, then none with same digest will have
|
||||
_, _ = storage.RemoveManifestDescByReference(index, notationDesc.Digest.String(), false)
|
||||
_, _ = storage.RemoveManifestDescByReference(index, notationManifest.Digest.String(), false)
|
||||
|
||||
err := oci.PutIndex(context.Background(), *index)
|
||||
if err != nil {
|
||||
@@ -1808,7 +1820,7 @@ func (is *ImageStoreLocal) GetNextDigestWithBlobPaths(lastDigests []godigest.Dig
|
||||
return nil //nolint:nilerr // ignore files which are not blobs
|
||||
}
|
||||
|
||||
if digest == "" && !common.DContains(lastDigests, blobDigest) {
|
||||
if digest == "" && !zcommon.DContains(lastDigests, blobDigest) {
|
||||
digest = blobDigest
|
||||
}
|
||||
|
||||
|
||||
+13
-2
@@ -24,7 +24,7 @@ import (
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
zerr "zotregistry.io/zot/errors"
|
||||
"zotregistry.io/zot/pkg/common"
|
||||
zcommon "zotregistry.io/zot/pkg/common"
|
||||
"zotregistry.io/zot/pkg/extensions/monitoring"
|
||||
zlog "zotregistry.io/zot/pkg/log"
|
||||
zreg "zotregistry.io/zot/pkg/regexp"
|
||||
@@ -438,6 +438,17 @@ func (is *ObjectStorage) PutImageManifest(repo, reference, mediaType string, //n
|
||||
return "", err
|
||||
}
|
||||
|
||||
if mediaType == ispec.MediaTypeImageManifest {
|
||||
var manifest ispec.Manifest
|
||||
|
||||
err := json.Unmarshal(body, &manifest)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
desc.ArtifactType = zcommon.GetManifestArtifactType(manifest)
|
||||
}
|
||||
|
||||
// apply linter only on images, not signatures
|
||||
pass, err := storage.ApplyLinter(is, is.linter, repo, desc)
|
||||
if !pass {
|
||||
@@ -1419,7 +1430,7 @@ func (is *ObjectStorage) GetNextDigestWithBlobPaths(lastDigests []godigest.Diges
|
||||
return nil //nolint:nilerr // ignore files which are not blobs
|
||||
}
|
||||
|
||||
if digest == "" && !common.DContains(lastDigests, blobDigest) {
|
||||
if digest == "" && !zcommon.DContains(lastDigests, blobDigest) {
|
||||
digest = blobDigest
|
||||
}
|
||||
|
||||
|
||||
@@ -584,44 +584,6 @@ func TestGetOrasAndOCIReferrers(t *testing.T) {
|
||||
So(index.Manifests[0].Digest, ShouldEqual, manDigest)
|
||||
})
|
||||
|
||||
Convey("Get oci referrers - application/vnd.oci.artifact.manifest.v1+json", func(c C) {
|
||||
artifactType := "application/vnd.example.icecream.v1"
|
||||
|
||||
artifactManifest := ispec.Artifact{
|
||||
MediaType: ispec.MediaTypeArtifactManifest,
|
||||
ArtifactType: artifactType,
|
||||
Blobs: []ispec.Descriptor{
|
||||
{
|
||||
MediaType: "application/octet-stream",
|
||||
Size: int64(buflen),
|
||||
Digest: digest,
|
||||
},
|
||||
},
|
||||
Subject: &ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Size: int64(mbuflen),
|
||||
Digest: mdigest,
|
||||
},
|
||||
}
|
||||
|
||||
manBuf, err := json.Marshal(artifactManifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manBufLen := len(manBuf)
|
||||
manDigest := godigest.FromBytes(manBuf)
|
||||
|
||||
_, err = imgStore.PutImageManifest(repo, manDigest.Encoded(), ispec.MediaTypeArtifactManifest, manBuf)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
index, err := imgStore.GetReferrers(repo, mdigest, []string{artifactType})
|
||||
So(err, ShouldBeNil)
|
||||
So(index, ShouldNotBeEmpty)
|
||||
So(index.Manifests[1].ArtifactType, ShouldEqual, artifactType)
|
||||
So(index.Manifests[1].MediaType, ShouldEqual, ispec.MediaTypeArtifactManifest)
|
||||
So(index.Manifests[1].Size, ShouldEqual, manBufLen)
|
||||
So(index.Manifests[1].Digest, ShouldEqual, manDigest)
|
||||
})
|
||||
|
||||
Convey("Get oras referrers", func(c C) {
|
||||
artifactManifest := artifactspec.Manifest{}
|
||||
artifactManifest.ArtifactType = "signature-example"
|
||||
|
||||
+26
-95
@@ -105,32 +105,6 @@ func (img Image) Digest() (godigest.Digest, error) {
|
||||
return godigest.FromBytes(blob), nil
|
||||
}
|
||||
|
||||
type Artifact struct {
|
||||
Manifest ispec.Artifact
|
||||
Blobs []ArtifactBlobs
|
||||
Reference string
|
||||
}
|
||||
|
||||
func (a Artifact) Digest() (godigest.Digest, error) {
|
||||
blob, err := json.Marshal(a.Manifest)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return godigest.FromBytes(blob), nil
|
||||
}
|
||||
|
||||
func (a Artifact) ArtifactData() (repodb.ArtifactData, error) {
|
||||
blob, err := json.Marshal(a.Manifest)
|
||||
if err != nil {
|
||||
return repodb.ArtifactData{}, err
|
||||
}
|
||||
|
||||
return repodb.ArtifactData{
|
||||
ManifestBlob: blob,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type ArtifactBlobs struct {
|
||||
Blob []byte
|
||||
MediaType string
|
||||
@@ -588,6 +562,7 @@ func GetImageComponents(layerSize int) (ispec.Image, [][]byte, ispec.Manifest, e
|
||||
schemaVersion := 2
|
||||
|
||||
manifest := ispec.Manifest{
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Versioned: specs.Versioned{
|
||||
SchemaVersion: schemaVersion,
|
||||
},
|
||||
@@ -642,6 +617,7 @@ func GetRandomImageComponents(layerSize int) (ispec.Image, [][]byte, ispec.Manif
|
||||
schemaVersion := 2
|
||||
|
||||
manifest := ispec.Manifest{
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Versioned: specs.Versioned{
|
||||
SchemaVersion: schemaVersion,
|
||||
},
|
||||
@@ -657,7 +633,6 @@ func GetRandomImageComponents(layerSize int) (ispec.Image, [][]byte, ispec.Manif
|
||||
Size: int64(len(layers[0])),
|
||||
},
|
||||
},
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
}
|
||||
|
||||
return config, layers, manifest, nil
|
||||
@@ -702,6 +677,7 @@ func GetImageComponentsWithConfig(conf ispec.Image) (ispec.Image, [][]byte, ispe
|
||||
schemaVersion := 2
|
||||
|
||||
manifest := ispec.Manifest{
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Versioned: specs.Versioned{
|
||||
SchemaVersion: schemaVersion,
|
||||
},
|
||||
@@ -760,6 +736,7 @@ func GetImageWithComponents(config ispec.Image, layers [][]byte) (Image, error)
|
||||
const schemaVersion = 2
|
||||
|
||||
manifest := ispec.Manifest{
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Versioned: specs.Versioned{
|
||||
SchemaVersion: schemaVersion,
|
||||
},
|
||||
@@ -784,49 +761,6 @@ func GetImageWithComponents(config ispec.Image, layers [][]byte) (Image, error)
|
||||
}, nil
|
||||
}
|
||||
|
||||
func GetRandomArtifact(subject *ispec.Descriptor) (Artifact, error) {
|
||||
var randBlob [10]byte
|
||||
|
||||
_, err := rand.Read(randBlob[:])
|
||||
if err != nil {
|
||||
return Artifact{}, err
|
||||
}
|
||||
|
||||
artifactBlobs := []ArtifactBlobs{
|
||||
{
|
||||
Blob: randBlob[:],
|
||||
MediaType: "application/octet-stream",
|
||||
},
|
||||
}
|
||||
|
||||
blobsDescriptors := make([]ispec.Descriptor, 0, len(artifactBlobs))
|
||||
|
||||
for _, artifactBlob := range artifactBlobs {
|
||||
blobsDescriptors = append(blobsDescriptors, ispec.Descriptor{
|
||||
Digest: godigest.FromBytes(artifactBlob.Blob),
|
||||
MediaType: artifactBlob.MediaType,
|
||||
Size: int64(len(artifactBlob.Blob)),
|
||||
})
|
||||
}
|
||||
|
||||
artifactManifest := ispec.Artifact{
|
||||
MediaType: ispec.MediaTypeArtifactManifest,
|
||||
Blobs: blobsDescriptors,
|
||||
Subject: subject,
|
||||
}
|
||||
|
||||
artifactManifestBlob, err := json.Marshal(artifactManifest)
|
||||
if err != nil {
|
||||
return Artifact{}, err
|
||||
}
|
||||
|
||||
return Artifact{
|
||||
Manifest: artifactManifest,
|
||||
Blobs: artifactBlobs,
|
||||
Reference: godigest.FromBytes(artifactManifestBlob).String(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func GetCosignSignatureTagForManifest(manifest ispec.Manifest) (string, error) {
|
||||
manifestBlob, err := json.Marshal(manifest)
|
||||
if err != nil {
|
||||
@@ -906,6 +840,11 @@ func UploadImage(img Image, baseURL, repo string) error {
|
||||
|
||||
cdigest := godigest.FromBytes(cblob)
|
||||
|
||||
if img.Manifest.Config.MediaType == ispec.MediaTypeScratch {
|
||||
cblob = ispec.ScratchDescriptor.Data
|
||||
cdigest = ispec.ScratchDescriptor.Digest
|
||||
}
|
||||
|
||||
resp, err := resty.R().
|
||||
Post(baseURL + "/v2/" + repo + "/blobs/uploads/")
|
||||
if err = Error(err); err != nil {
|
||||
@@ -940,7 +879,7 @@ func UploadImage(img Image, baseURL, repo string) error {
|
||||
}
|
||||
|
||||
resp, err = resty.R().
|
||||
SetHeader("Content-type", "application/vnd.oci.image.manifest.v1+json").
|
||||
SetHeader("Content-type", ispec.MediaTypeImageManifest).
|
||||
SetBody(manifestBlob).
|
||||
Put(baseURL + "/v2/" + repo + "/manifests/" + img.Reference)
|
||||
|
||||
@@ -966,27 +905,6 @@ func DeleteImage(repo, reference, baseURL string) (int, error) {
|
||||
return resp.StatusCode(), err
|
||||
}
|
||||
|
||||
// UploadArtifactManifest is used in tests where we don't need to upload the blobs of the artifact.
|
||||
func UploadArtifactManifest(artifactManifest *ispec.Artifact, ref *string, baseURL, repo string) error {
|
||||
// put manifest
|
||||
artifactManifestBlob, err := json.Marshal(artifactManifest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
reference := godigest.FromBytes(artifactManifestBlob).String()
|
||||
|
||||
if ref != nil {
|
||||
reference = *ref
|
||||
}
|
||||
|
||||
_, err = resty.R().
|
||||
SetHeader("Content-type", ispec.MediaTypeArtifactManifest).
|
||||
SetBody(artifactManifestBlob).
|
||||
Put(baseURL + "/v2/" + repo + "/manifests/" + reference)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func UploadBlob(baseURL, repo string, blob []byte, artifactBlobMediaType string) error {
|
||||
resp, err := resty.R().Post(baseURL + "/v2/" + repo + "/blobs/uploads/")
|
||||
if err != nil {
|
||||
@@ -1252,7 +1170,11 @@ func SignWithNotation(keyName string, reference string, tdir string) error {
|
||||
PlainHTTP: plainHTTP,
|
||||
}
|
||||
|
||||
sigRepo := notreg.NewRepository(remoteRepo)
|
||||
repositoryOpts := notreg.RepositoryOptions{
|
||||
OCIImageManifest: true,
|
||||
}
|
||||
|
||||
sigRepo := notreg.NewRepositoryWithOptions(remoteRepo, repositoryOpts)
|
||||
|
||||
sigOpts := notation.RemoteSignOptions{
|
||||
SignOptions: notation.SignOptions{
|
||||
@@ -1334,7 +1256,11 @@ func VerifyWithNotation(reference string, tdir string) error {
|
||||
PlainHTTP: plainHTTP,
|
||||
}
|
||||
|
||||
repo := notreg.NewRepository(remoteRepo)
|
||||
repositoryOpts := notreg.RepositoryOptions{
|
||||
OCIImageManifest: true,
|
||||
}
|
||||
|
||||
repo := notreg.NewRepositoryWithOptions(remoteRepo, repositoryOpts)
|
||||
|
||||
manifestDesc, err := repo.Resolve(ctx, ref.Reference)
|
||||
if err != nil {
|
||||
@@ -1357,7 +1283,7 @@ func VerifyWithNotation(reference string, tdir string) error {
|
||||
PlainHTTP: plainHTTP,
|
||||
}
|
||||
|
||||
repo = notreg.NewRepository(remoteRepo)
|
||||
repo = notreg.NewRepositoryWithOptions(remoteRepo, repositoryOpts)
|
||||
|
||||
configs := map[string]string{}
|
||||
|
||||
@@ -1587,6 +1513,11 @@ func UploadImageWithBasicAuth(img Image, baseURL, repo, user, password string) e
|
||||
|
||||
cdigest := godigest.FromBytes(cblob)
|
||||
|
||||
if img.Manifest.Config.MediaType == ispec.MediaTypeScratch {
|
||||
cblob = ispec.ScratchDescriptor.Data
|
||||
cdigest = ispec.ScratchDescriptor.Digest
|
||||
}
|
||||
|
||||
resp, err := resty.R().
|
||||
SetBasicAuth(user, password).
|
||||
Post(baseURL + "/v2/" + repo + "/blobs/uploads/")
|
||||
|
||||
@@ -234,18 +234,6 @@ func TestControllerManager(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestUploadArtifact(t *testing.T) {
|
||||
Convey("Put request results in an error", t, func() {
|
||||
port := test.GetFreePort()
|
||||
baseURL := test.GetBaseURL(port)
|
||||
|
||||
artifact := ispec.Artifact{}
|
||||
|
||||
err := test.UploadArtifactManifest(&artifact, nil, baseURL, "test")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUploadBlob(t *testing.T) {
|
||||
Convey("Post request results in an error", t, func() {
|
||||
port := test.GetFreePort()
|
||||
|
||||
@@ -44,10 +44,6 @@ type RepoDBMock struct {
|
||||
|
||||
GetIndexDataFn func(indexDigest godigest.Digest) (repodb.IndexData, error)
|
||||
|
||||
SetArtifactDataFn func(digest godigest.Digest, artifactData repodb.ArtifactData) error
|
||||
|
||||
GetArtifactDataFn func(artifactDigest godigest.Digest) (repodb.ArtifactData, error)
|
||||
|
||||
SetReferrerFn func(repo string, referredDigest godigest.Digest, referrer repodb.ReferrerInfo) error
|
||||
|
||||
DeleteReferrerFn func(repo string, referredDigest godigest.Digest, referrerDigest godigest.Digest) error
|
||||
@@ -348,22 +344,6 @@ func (sdm RepoDBMock) PatchDB() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sdm RepoDBMock) SetArtifactData(digest godigest.Digest, artifactData repodb.ArtifactData) error {
|
||||
if sdm.SetArtifactDataFn != nil {
|
||||
return sdm.SetArtifactDataFn(digest, artifactData)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sdm RepoDBMock) GetArtifactData(artifactDigest godigest.Digest) (repodb.ArtifactData, error) {
|
||||
if sdm.GetArtifactDataFn != nil {
|
||||
return sdm.GetArtifactDataFn(artifactDigest)
|
||||
}
|
||||
|
||||
return repodb.ArtifactData{}, nil
|
||||
}
|
||||
|
||||
func (sdm RepoDBMock) SetReferrer(repo string, referredDigest godigest.Digest, referrer repodb.ReferrerInfo) error {
|
||||
if sdm.SetReferrerFn != nil {
|
||||
return sdm.SetReferrerFn(repo, referredDigest, referrer)
|
||||
|
||||
@@ -376,7 +376,7 @@ func TestExtractImageDetails(t *testing.T) {
|
||||
|
||||
olu := ocilayout.NewBaseOciLayoutUtils(storeController, testLogger)
|
||||
resDigest, resManifest, resIspecImage, resErr := olu.ExtractImageDetails("zot-test", "latest", testLogger)
|
||||
So(string(resDigest), ShouldContainSubstring, "sha256:c52f15d2d4")
|
||||
So(string(resDigest), ShouldContainSubstring, "sha256:8492645f16")
|
||||
So(resManifest.Config.Digest.String(), ShouldContainSubstring, configDigest.Encoded())
|
||||
|
||||
So(resIspecImage.Architecture, ShouldContainSubstring, "amd64")
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type RouteHandler struct {
|
||||
Route string
|
||||
// HandlerFunc is the HTTP handler function that receives a writer for output and an HTTP request as input.
|
||||
HandlerFunc http.HandlerFunc
|
||||
// AllowedMethods specifies the HTTP methods allowed for the current route.
|
||||
AllowedMethods []string
|
||||
}
|
||||
|
||||
// Routes is a map that associates HTTP paths to their corresponding HTTP handlers.
|
||||
type HTTPRoutes []RouteHandler
|
||||
|
||||
func StartTestHTTPServer(routes HTTPRoutes, port string) *http.Server {
|
||||
baseURL := GetBaseURL(port)
|
||||
mux := mux.NewRouter()
|
||||
|
||||
mux.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
|
||||
_, err := w.Write([]byte("{}"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}).Methods(http.MethodGet)
|
||||
|
||||
for _, routeHandler := range routes {
|
||||
mux.HandleFunc(routeHandler.Route, routeHandler.HandlerFunc).Methods(routeHandler.AllowedMethods...)
|
||||
}
|
||||
|
||||
server := &http.Server{ //nolint:gosec
|
||||
Addr: fmt.Sprintf(":%s", port),
|
||||
Handler: mux,
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
WaitTillServerReady(baseURL + "/test")
|
||||
|
||||
return server
|
||||
}
|
||||
Reference in New Issue
Block a user