mirror of
https://github.com/go-gitea/gitea
synced 2025-07-21 17:58:35 +00:00
Fix OCI manifest parser (#34797)
Do not parse the media type we don't know.
This commit is contained in:
@@ -4,7 +4,6 @@
|
|||||||
package container
|
package container
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -72,20 +71,39 @@ type Manifest struct {
|
|||||||
Size int64 `json:"size"`
|
Size int64 `json:"size"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsMediaTypeValid(mt string) bool {
|
||||||
|
return strings.HasPrefix(mt, "application/vnd.docker.") || strings.HasPrefix(mt, "application/vnd.oci.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsMediaTypeImageManifest(mt string) bool {
|
||||||
|
return strings.EqualFold(mt, oci.MediaTypeImageManifest) || strings.EqualFold(mt, "application/vnd.docker.distribution.manifest.v2+json")
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsMediaTypeImageIndex(mt string) bool {
|
||||||
|
return strings.EqualFold(mt, oci.MediaTypeImageIndex) || strings.EqualFold(mt, "application/vnd.docker.distribution.manifest.list.v2+json")
|
||||||
|
}
|
||||||
|
|
||||||
// ParseImageConfig parses the metadata of an image config
|
// ParseImageConfig parses the metadata of an image config
|
||||||
func ParseImageConfig(mt string, r io.Reader) (*Metadata, error) {
|
func ParseImageConfig(mediaType string, r io.Reader) (*Metadata, error) {
|
||||||
if strings.EqualFold(mt, helm.ConfigMediaType) {
|
if strings.EqualFold(mediaType, helm.ConfigMediaType) {
|
||||||
return parseHelmConfig(r)
|
return parseHelmConfig(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fallback to OCI Image Config
|
// fallback to OCI Image Config
|
||||||
return parseOCIImageConfig(r)
|
// FIXME: this fallback is not right, we should strictly check the media type in the future
|
||||||
|
metadata, err := parseOCIImageConfig(r)
|
||||||
|
if err != nil {
|
||||||
|
if !IsMediaTypeImageManifest(mediaType) {
|
||||||
|
return &Metadata{Platform: "unknown/unknown"}, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return metadata, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseOCIImageConfig(r io.Reader) (*Metadata, error) {
|
func parseOCIImageConfig(r io.Reader) (*Metadata, error) {
|
||||||
var image oci.Image
|
var image oci.Image
|
||||||
// EOF means empty input, still use the default data
|
if err := json.NewDecoder(r).Decode(&image); err != nil {
|
||||||
if err := json.NewDecoder(r).Decode(&image); err != nil && !errors.Is(err, io.EOF) {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -59,10 +59,8 @@ func TestParseImageConfig(t *testing.T) {
|
|||||||
assert.ElementsMatch(t, []string{author}, metadata.Authors)
|
assert.ElementsMatch(t, []string{author}, metadata.Authors)
|
||||||
assert.Equal(t, projectURL, metadata.ProjectURL)
|
assert.Equal(t, projectURL, metadata.ProjectURL)
|
||||||
assert.Equal(t, repositoryURL, metadata.RepositoryURL)
|
assert.Equal(t, repositoryURL, metadata.RepositoryURL)
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseOCIImageConfig(t *testing.T) {
|
metadata, err = ParseImageConfig("anything-unknown", strings.NewReader(""))
|
||||||
metadata, err := parseOCIImageConfig(strings.NewReader(""))
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &Metadata{Type: TypeOCI, Platform: DefaultPlatform, ImageLayers: []string{}}, metadata)
|
assert.Equal(t, &Metadata{Platform: "unknown/unknown"}, metadata)
|
||||||
}
|
}
|
||||||
|
@@ -693,6 +693,8 @@ func ContainerRoutes() *web.Router {
|
|||||||
&container.Auth{},
|
&container.Auth{},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// TODO: Content Discovery / References (not implemented yet)
|
||||||
|
|
||||||
r.Get("", container.ReqContainerAccess, container.DetermineSupport)
|
r.Get("", container.ReqContainerAccess, container.DetermineSupport)
|
||||||
r.Group("/token", func() {
|
r.Group("/token", func() {
|
||||||
r.Get("", container.Authenticate)
|
r.Get("", container.Authenticate)
|
||||||
|
@@ -29,18 +29,6 @@ import (
|
|||||||
oci "github.com/opencontainers/image-spec/specs-go/v1"
|
oci "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func isMediaTypeValid(mt string) bool {
|
|
||||||
return strings.HasPrefix(mt, "application/vnd.docker.") || strings.HasPrefix(mt, "application/vnd.oci.")
|
|
||||||
}
|
|
||||||
|
|
||||||
func isMediaTypeImageManifest(mt string) bool {
|
|
||||||
return strings.EqualFold(mt, oci.MediaTypeImageManifest) || strings.EqualFold(mt, "application/vnd.docker.distribution.manifest.v2+json")
|
|
||||||
}
|
|
||||||
|
|
||||||
func isMediaTypeImageIndex(mt string) bool {
|
|
||||||
return strings.EqualFold(mt, oci.MediaTypeImageIndex) || strings.EqualFold(mt, "application/vnd.docker.distribution.manifest.list.v2+json")
|
|
||||||
}
|
|
||||||
|
|
||||||
// manifestCreationInfo describes a manifest to create
|
// manifestCreationInfo describes a manifest to create
|
||||||
type manifestCreationInfo struct {
|
type manifestCreationInfo struct {
|
||||||
MediaType string
|
MediaType string
|
||||||
@@ -66,16 +54,16 @@ func processManifest(ctx context.Context, mci *manifestCreationInfo, buf *packag
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isMediaTypeValid(mci.MediaType) {
|
if !container_module.IsMediaTypeValid(mci.MediaType) {
|
||||||
mci.MediaType = index.MediaType
|
mci.MediaType = index.MediaType
|
||||||
if !isMediaTypeValid(mci.MediaType) {
|
if !container_module.IsMediaTypeValid(mci.MediaType) {
|
||||||
return "", errManifestInvalid.WithMessage("MediaType not recognized")
|
return "", errManifestInvalid.WithMessage("MediaType not recognized")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if isMediaTypeImageManifest(mci.MediaType) {
|
if container_module.IsMediaTypeImageManifest(mci.MediaType) {
|
||||||
return processOciImageManifest(ctx, mci, buf)
|
return processOciImageManifest(ctx, mci, buf)
|
||||||
} else if isMediaTypeImageIndex(mci.MediaType) {
|
} else if container_module.IsMediaTypeImageIndex(mci.MediaType) {
|
||||||
return processOciImageIndex(ctx, mci, buf)
|
return processOciImageIndex(ctx, mci, buf)
|
||||||
}
|
}
|
||||||
return "", errManifestInvalid
|
return "", errManifestInvalid
|
||||||
@@ -201,7 +189,7 @@ func processOciImageIndex(ctx context.Context, mci *manifestCreationInfo, buf *p
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, manifest := range index.Manifests {
|
for _, manifest := range index.Manifests {
|
||||||
if !isMediaTypeImageManifest(manifest.MediaType) {
|
if !container_module.IsMediaTypeImageManifest(manifest.MediaType) {
|
||||||
return errManifestInvalid
|
return errManifestInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,7 +324,7 @@ func createPackageAndVersion(ctx context.Context, mci *manifestCreationInfo, met
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if isMediaTypeImageIndex(mci.MediaType) {
|
if container_module.IsMediaTypeImageIndex(mci.MediaType) {
|
||||||
if pv.CreatedUnix.AsTime().Before(time.Now().Add(-24 * time.Hour)) {
|
if pv.CreatedUnix.AsTime().Before(time.Now().Add(-24 * time.Hour)) {
|
||||||
if err = packages_service.DeletePackageVersionAndReferences(ctx, pv); err != nil {
|
if err = packages_service.DeletePackageVersionAndReferences(ctx, pv); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
Reference in New Issue
Block a user