Skip to content

Commit

Permalink
fix: MetaDB fixes related to Docker media types (#2934)
Browse files Browse the repository at this point in the history
* fix: update download counters for docker media types

closes #2929

Signed-off-by: Andrei Aaron <[email protected]>

* fix: handle docker config mediatype in MetaDB

The OS/Arch/Layer History information was not written to MetaDB

Signed-off-by: Andrei Aaron <[email protected]>

---------

Signed-off-by: Andrei Aaron <[email protected]>
  • Loading branch information
andaaron authored Feb 3, 2025
1 parent 4fcd107 commit ea6b6da
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 3 deletions.
14 changes: 14 additions & 0 deletions pkg/compat/compat.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,20 @@ func IsCompatibleManifestListMediaType(mediatype string) bool {
return false
}

func CompatibleConfigMediaTypes() []string {
return []string{docker.MediaTypeImageConfig}
}

func IsCompatibleConfigMediaType(mediatype string) bool {
for _, mt := range CompatibleConfigMediaTypes() {
if mt == mediatype {
return true
}
}

return false
}

func Validate(body []byte, mediaType string) ([]v1.Descriptor, error) {
switch mediaType {
case docker.MediaTypeManifest:
Expand Down
3 changes: 2 additions & 1 deletion pkg/extensions/search/cve/cve.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,8 @@ func getConfigAndDigest(metaDB mTypes.MetaDB, manifestDigestStr string) (ispec.I
}

// we'll fail the execution if the config is not compatible with ispec.Image because we can't scan this type of images.
if manifestData.Manifests[0].Manifest.Config.MediaType != ispec.MediaTypeImageConfig {
configMediaType := manifestData.Manifests[0].Manifest.Config.MediaType
if configMediaType != ispec.MediaTypeImageConfig && !compat.IsCompatibleConfigMediaType(configMediaType) {
return ispec.Image{}, "", zerr.ErrUnexpectedMediaType
}

Expand Down
251 changes: 251 additions & 0 deletions pkg/extensions/search/search_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1749,6 +1749,257 @@ func TestExpandedRepoInfo(t *testing.T) {

So(found, ShouldBeTrue)
})

Convey("Test expanded repo info for docker media type", t, func() {
subpath := "/a"
rootDir := t.TempDir()
subRootDir := t.TempDir()
port := GetFreePort()
baseURL := GetBaseURL(port)
conf := config.New()
conf.HTTP.Port = port
conf.Storage.RootDirectory = rootDir
conf.Storage.GC = false
conf.Storage.SubPaths = make(map[string]config.StorageConfig)
conf.Storage.SubPaths[subpath] = config.StorageConfig{RootDirectory: subRootDir}
defaultVal := true
conf.Extensions = &extconf.ExtensionConfig{
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
}

conf.Extensions.Search.CVE = nil

ctlr := api.NewController(conf)
ctlrManager := NewControllerManager(ctlr)
ctlrManager.StartAndWait(port)

defer ctlrManager.StopServer()

annotations := make(map[string]string)
annotations["org.opencontainers.image.vendor"] = "zot"

configBlob, err := json.Marshal(GetDefaultConfig())
So(err, ShouldBeNil)

uploadedImage := CreateImageWith().RandomLayers(1, 100).
CustomConfigBlob(configBlob, "application/vnd.docker.container.image.v1+json").
Annotations(annotations).Build()

err = UploadImage(uploadedImage, baseURL, "zot-cve-test", "0.0.1")
So(err, ShouldBeNil)

err = UploadImage(uploadedImage, baseURL, "a/zot-cve-test", "0.0.1")
So(err, ShouldBeNil)

err = UploadImage(uploadedImage, baseURL, "zot-test", "0.0.1")
So(err, ShouldBeNil)

err = UploadImage(uploadedImage, baseURL, "a/zot-test", "0.0.1")
So(err, ShouldBeNil)

log := log.NewLogger("debug", "")
metrics := monitoring.NewMetricsServer(false, log)
testStorage := local.NewImageStore(rootDir, false, false, log, metrics, nil, nil, nil)

resp, err := resty.R().Get(baseURL + "/v2/")
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)

resp, err = resty.R().Get(baseURL + graphqlQueryPrefix)
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 422)

query := `{
ExpandedRepoInfo(repo:"zot-cve-test"){
Summary {
Name LastUpdated Size
}
}
}`

resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)

responseStruct := &zcommon.ExpandedRepoInfoResp{}

err = json.Unmarshal(resp.Body(), responseStruct)
So(err, ShouldBeNil)
So(responseStruct.Summary, ShouldNotBeEmpty)
So(responseStruct.Summary.Name, ShouldEqual, "zot-cve-test")

query = `{
ExpandedRepoInfo(repo:"zot-cve-test"){
Images {
Tag
Manifests {
Digest
Layers {Size Digest}
Platform {Os Arch}
}
IsSigned
}
}
}`

resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)

responseStruct = &zcommon.ExpandedRepoInfoResp{}

err = json.Unmarshal(resp.Body(), responseStruct)
So(err, ShouldBeNil)
So(len(responseStruct.ImageSummaries), ShouldNotEqual, 0)
So(len(responseStruct.ImageSummaries[0].Manifests[0].Layers), ShouldNotEqual, 0)

_, testManifestDigest, _, err := testStorage.GetImageManifest("zot-cve-test", "0.0.1")
So(err, ShouldBeNil)

found := false

for _, imageSummary := range responseStruct.ImageSummaries {
if imageSummary.Manifests[0].Digest == testManifestDigest.String() {
found = true

So(imageSummary.IsSigned, ShouldEqual, false)
So(imageSummary.Manifests[0].Platform.Os, ShouldEqual, "linux")
So(imageSummary.Manifests[0].Platform.Arch, ShouldEqual, "amd64")
}
}

So(found, ShouldEqual, true)

err = signature.SignImageUsingCosign("zot-cve-test:0.0.1", port, false)
So(err, ShouldBeNil)

resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)

err = json.Unmarshal(resp.Body(), responseStruct)
So(err, ShouldBeNil)
So(len(responseStruct.ImageSummaries), ShouldNotEqual, 0)
So(len(responseStruct.ImageSummaries[0].Manifests[0].Layers), ShouldNotEqual, 0)

_, testManifestDigest, _, err = testStorage.GetImageManifest("zot-cve-test", "0.0.1")
So(err, ShouldBeNil)

found = false

for _, imageSummary := range responseStruct.ImageSummaries {
if imageSummary.Manifests[0].Digest == testManifestDigest.String() {
found = true

So(imageSummary.IsSigned, ShouldEqual, true)
So(imageSummary.Manifests[0].Platform.Os, ShouldEqual, "linux")
So(imageSummary.Manifests[0].Platform.Arch, ShouldEqual, "amd64")
}
}

So(found, ShouldEqual, true)

query = `{
ExpandedRepoInfo(repo:""){
Images {
Tag
}
}
}`

resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)

query = `{
ExpandedRepoInfo(repo:"zot-test"){
Images {
RepoName
Tag IsSigned
Manifests{
Digest
Layers {Size Digest}
Platform {Os Arch}
}
}
}
}`
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)

err = json.Unmarshal(resp.Body(), responseStruct)
So(err, ShouldBeNil)
So(len(responseStruct.ImageSummaries), ShouldNotEqual, 0)
So(len(responseStruct.ImageSummaries[0].Manifests[0].Layers), ShouldNotEqual, 0)

_, testManifestDigest, _, err = testStorage.GetImageManifest("zot-test", "0.0.1")
So(err, ShouldBeNil)

found = false

for _, imageSummary := range responseStruct.ImageSummaries {
if imageSummary.Manifests[0].Digest == testManifestDigest.String() {
found = true

So(imageSummary.IsSigned, ShouldEqual, false)
So(imageSummary.Manifests[0].Platform.Os, ShouldEqual, "linux")
So(imageSummary.Manifests[0].Platform.Arch, ShouldEqual, "amd64")
}
}

So(found, ShouldEqual, true)

err = signature.SignImageUsingCosign("zot-test@"+testManifestDigest.String(), port, false)
So(err, ShouldBeNil)

resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "/query?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)

err = json.Unmarshal(resp.Body(), responseStruct)
So(err, ShouldBeNil)
So(len(responseStruct.ImageSummaries), ShouldNotEqual, 0)
So(len(responseStruct.ImageSummaries[0].Manifests[0].Layers), ShouldNotEqual, 0)

_, testManifestDigest, _, err = testStorage.GetImageManifest("zot-test", "0.0.1")
So(err, ShouldBeNil)

found = false

for _, imageSummary := range responseStruct.ImageSummaries {
if imageSummary.Manifests[0].Digest == testManifestDigest.String() {
found = true

So(imageSummary.IsSigned, ShouldEqual, true)
So(imageSummary.Manifests[0].Platform.Os, ShouldEqual, "linux")
So(imageSummary.Manifests[0].Platform.Arch, ShouldEqual, "amd64")
}
}

So(found, ShouldEqual, true)

manifestDigest := uploadedImage.ManifestDescriptor.Digest

err = os.Remove(path.Join(rootDir, "zot-test/blobs/sha256", manifestDigest.Encoded()))
So(err, ShouldBeNil)

resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)

err = json.Unmarshal(resp.Body(), responseStruct)
So(err, ShouldBeNil)
})
}

func TestDerivedImageList(t *testing.T) {
Expand Down
4 changes: 3 additions & 1 deletion pkg/meta/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
v1 "github.com/opencontainers/image-spec/specs-go/v1"

zcommon "zotregistry.dev/zot/pkg/common"
"zotregistry.dev/zot/pkg/compat"
"zotregistry.dev/zot/pkg/log"
mTypes "zotregistry.dev/zot/pkg/meta/types"
"zotregistry.dev/zot/pkg/storage"
Expand Down Expand Up @@ -117,7 +118,8 @@ func OnGetManifest(name, reference, mediaType string, body []byte,
return nil
}

if !(mediaType == v1.MediaTypeImageManifest || mediaType == v1.MediaTypeImageIndex) {
if !(mediaType == v1.MediaTypeImageManifest || mediaType == v1.MediaTypeImageIndex ||
compat.IsCompatibleManifestMediaType(mediaType) || compat.IsCompatibleManifestListMediaType(mediaType)) {
return nil
}

Expand Down
3 changes: 2 additions & 1 deletion pkg/meta/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,8 @@ func SetImageMetaFromInput(ctx context.Context, repo, reference, mediaType strin
return err
}

if manifestContent.Config.MediaType == ispec.MediaTypeImageConfig {
if manifestContent.Config.MediaType == ispec.MediaTypeImageConfig ||
compat.IsCompatibleConfigMediaType(manifestContent.Config.MediaType) {
configBlob, err := imageStore.GetBlobContent(repo, manifestContent.Config.Digest)
if err != nil {
return err
Expand Down

0 comments on commit ea6b6da

Please sign in to comment.