feat: add support for docker images (#2714)

* feat: add support for docker images

Issue #724

A new config section under "HTTP" called "Compat" is added which
currently takes a list of possible compatible legacy media-types.

https://github.com/opencontainers/image-spec/blob/main/media-types.md#compatibility-matrix

Only "docker2s2" (Docker Manifest V2 Schema V2) is currently supported.

Garbage collection also needs to be made aware of non-OCI compatible
layer types.
feat: add cve support for non-OCI compatible layer types

Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com>

* 

Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com>

* test: add more docker compat tests

Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com>

* feat: add additional validation checks for non-OCI images

Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com>

* ci: make "full" images docker-compatible

Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com>

---------

Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com>
This commit is contained in:
Ramkumar Chinchani
2024-10-31 00:44:04 -07:00
committed by GitHub
parent 403fd4eb61
commit cb2af94b0b
44 changed files with 436 additions and 191 deletions
+31 -3
View File
@@ -11,6 +11,8 @@ import (
"strings"
"time"
dockerList "github.com/distribution/distribution/v3/manifest/manifestlist"
docker "github.com/distribution/distribution/v3/manifest/schema2"
"github.com/distribution/distribution/v3/registry/storage/driver"
godigest "github.com/opencontainers/go-digest"
"github.com/opencontainers/image-spec/schema"
@@ -19,6 +21,7 @@ import (
zerr "zotregistry.dev/zot/errors"
zcommon "zotregistry.dev/zot/pkg/common"
"zotregistry.dev/zot/pkg/compat"
"zotregistry.dev/zot/pkg/extensions/monitoring"
zlog "zotregistry.dev/zot/pkg/log"
"zotregistry.dev/zot/pkg/scheduler"
@@ -62,10 +65,10 @@ func GetManifestDescByReference(index ispec.Index, reference string) (ispec.Desc
}
func ValidateManifest(imgStore storageTypes.ImageStore, repo, reference, mediaType string, body []byte,
log zlog.Logger,
compats []compat.MediaCompatibility, log zlog.Logger,
) error {
// validate the manifest
if !IsSupportedMediaType(mediaType) {
if !IsSupportedMediaType(compats, mediaType) {
log.Debug().Interface("actual", mediaType).
Msg("bad manifest media type")
@@ -145,6 +148,23 @@ func ValidateManifest(imgStore storageTypes.ImageStore, repo, reference, mediaTy
log.Error().Err(err).Str("digest", manifest.Digest.String()).
Msg("failed to stat manifest due to missing manifest blob")
return zerr.ErrBadManifest
}
}
default:
// non-OCI compatible
descriptors, err := compat.Validate(body, mediaType)
if err != nil {
log.Error().Err(err).Msg("failed to unmarshal JSON")
return zerr.ErrBadManifest
}
for _, desc := range descriptors {
if ok, _, _, err := imgStore.StatBlob(repo, desc.Digest); !ok || err != nil {
log.Error().Err(err).Str("digest", desc.Digest.String()).
Msg("failed to stat non-OCI descriptor due to missing blob")
return zerr.ErrBadManifest
}
}
@@ -796,7 +816,15 @@ func getBlobDescriptorFromManifest(imgStore storageTypes.ImageStore, repo string
return ispec.Descriptor{}, zerr.ErrBlobNotFound
}
func IsSupportedMediaType(mediaType string) bool {
func IsSupportedMediaType(compats []compat.MediaCompatibility, mediaType string) bool {
// check for some supported legacy formats if configured
for _, comp := range compats {
if comp == compat.DockerManifestV2SchemaV2 &&
(mediaType == docker.MediaTypeManifest || mediaType == dockerList.MediaTypeManifestList) {
return true
}
}
return mediaType == ispec.MediaTypeImageIndex ||
mediaType == ispec.MediaTypeImageManifest
}
+3 -3
View File
@@ -37,7 +37,7 @@ func TestValidateManifest(t *testing.T) {
Name: "cache",
UseRelPaths: true,
}, log)
imgStore := local.NewImageStore(dir, true, true, log, metrics, nil, cacheDriver)
imgStore := local.NewImageStore(dir, true, true, log, metrics, nil, cacheDriver, nil)
content := []byte("this is a blob")
digest := godigest.FromBytes(content)
@@ -180,7 +180,7 @@ func TestGetReferrersErrors(t *testing.T) {
UseRelPaths: true,
}, log)
imgStore := local.NewImageStore(dir, false, true, log, metrics, nil, cacheDriver)
imgStore := local.NewImageStore(dir, false, true, log, metrics, nil, cacheDriver, nil)
artifactType := "application/vnd.example.icecream.v1"
validDigest := godigest.FromBytes([]byte("blob"))
@@ -401,7 +401,7 @@ func TestGetBlobDescriptorFromRepo(t *testing.T) {
driver := local.New(true)
imgStore := imagestore.NewImageStore(tdir, tdir, true,
true, log, metrics, nil, driver, cacheDriver)
true, log, metrics, nil, driver, cacheDriver, nil)
repoName := "zot-test"