utils/dockerutil/dockerutil.go (77 lines of code) (raw):

// Copyright (c) 2016-2019 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package dockerutil import ( "errors" "fmt" "io" "github.com/docker/distribution" "github.com/docker/distribution/manifest/manifestlist" "github.com/docker/distribution/manifest/schema2" "github.com/uber/kraken/core" ) const ( _v2ManifestType = "application/vnd.docker.distribution.manifest.v2+json" _v2ManifestListType = "application/vnd.docker.distribution.manifest.list.v2+json" ) func ParseManifest(r io.Reader) (distribution.Manifest, core.Digest, error) { b, err := io.ReadAll(r) if err != nil { return nil, core.Digest{}, fmt.Errorf("read: %s", err) } manifest, d, err := ParseManifestV2(b) if err == nil { return manifest, d, err } // Retry with v2 manifest list. return ParseManifestV2List(b) } // ParseManifestV2 returns a parsed v2 manifest and its digest. func ParseManifestV2(bytes []byte) (distribution.Manifest, core.Digest, error) { manifest, desc, err := distribution.UnmarshalManifest(schema2.MediaTypeManifest, bytes) if err != nil { return nil, core.Digest{}, fmt.Errorf("unmarshal manifest: %s", err) } deserializedManifest, ok := manifest.(*schema2.DeserializedManifest) if !ok { return nil, core.Digest{}, errors.New("expected schema2.DeserializedManifest") } version := deserializedManifest.SchemaVersion if version != 2 { return nil, core.Digest{}, fmt.Errorf("unsupported manifest version: %d", version) } d, err := core.ParseSHA256Digest(string(desc.Digest)) if err != nil { return nil, core.Digest{}, fmt.Errorf("parse digest: %s", err) } return manifest, d, nil } // ParseManifestV2List returns a parsed v2 manifest list and its digest. func ParseManifestV2List(bytes []byte) (distribution.Manifest, core.Digest, error) { manifestList, desc, err := distribution.UnmarshalManifest(manifestlist.MediaTypeManifestList, bytes) if err != nil { return nil, core.Digest{}, fmt.Errorf("unmarshal manifestlist: %s", err) } deserializedManifestList, ok := manifestList.(*manifestlist.DeserializedManifestList) if !ok { return nil, core.Digest{}, errors.New("expected manifestlist.DeserializedManifestList") } version := deserializedManifestList.SchemaVersion if version != 2 { return nil, core.Digest{}, fmt.Errorf("unsupported manifest list version: %d", version) } d, err := core.ParseSHA256Digest(string(desc.Digest)) if err != nil { return nil, core.Digest{}, fmt.Errorf("parse digest: %s", err) } return manifestList, d, nil } // GetManifestReferences returns a list of references by a V2 manifest func GetManifestReferences(manifest distribution.Manifest) ([]core.Digest, error) { var refs []core.Digest for _, desc := range manifest.References() { d, err := core.ParseSHA256Digest(string(desc.Digest)) if err != nil { return nil, fmt.Errorf("parse digest: %w", err) } refs = append(refs, d) } return refs, nil } func GetSupportedManifestTypes() string { return fmt.Sprintf("%s,%s", _v2ManifestType, _v2ManifestListType) }