mirror of
https://github.com/containers/skopeo.git
synced 2025-07-31 22:45:20 +00:00
Compute the digest in (skopeo inspect) instead of trusting the registry
Compute the digest ourselves, the registry is in general untrusted and computing it ourserlves is easy enough. The stop passing the unverifiedCanonicalDigest value around, simplifying ImageSource.GetManifest and related code. In particular, remove retrieveRawManifest and have internal users just call Manifest() now that we don't need the digest.
This commit is contained in:
parent
e3d257e7b5
commit
60e8d63712
@ -54,7 +54,7 @@ func copyHandler(context *cli.Context) {
|
||||
}
|
||||
signBy := context.String("sign-by")
|
||||
|
||||
manifest, _, err := src.GetManifest()
|
||||
manifest, err := src.GetManifest()
|
||||
if err != nil {
|
||||
logrus.Fatalf("Error reading manifest: %s", err.Error())
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/projectatomic/skopeo/dockerutils"
|
||||
)
|
||||
|
||||
// inspectOutput is the output format of (skopeo inspect), primarily so that we can format it with a simple json.MarshalIndent.
|
||||
@ -37,22 +38,26 @@ var inspectCmd = cli.Command{
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
rawManifest, err := img.Manifest()
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
if c.Bool("raw") {
|
||||
b, err := img.Manifest()
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
fmt.Println(string(rawManifest))
|
||||
return
|
||||
}
|
||||
imgInspect, err := img.Inspect()
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
manifestDigest, err := dockerutils.ManifestDigest(rawManifest)
|
||||
if err != nil {
|
||||
logrus.Fatalf("Error computing manifest digest: %s", err.Error())
|
||||
}
|
||||
outputData := inspectOutput{
|
||||
Name: imgInspect.Name,
|
||||
Tag: imgInspect.Tag,
|
||||
Digest: imgInspect.Digest,
|
||||
Digest: manifestDigest,
|
||||
RepoTags: imgInspect.RepoTags,
|
||||
Created: imgInspect.Created,
|
||||
DockerVersion: imgInspect.DockerVersion,
|
||||
|
@ -84,13 +84,8 @@ func (s *dirImageSource) IntendedDockerReference() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (s *dirImageSource) GetManifest() ([]byte, string, error) {
|
||||
manifest, err := ioutil.ReadFile(manifestPath(s.dir))
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
return manifest, "", nil // FIXME? unverifiedCanonicalDigest value - really primarily used by dockerImage
|
||||
func (s *dirImageSource) GetManifest() ([]byte, error) {
|
||||
return ioutil.ReadFile(manifestPath(s.dir))
|
||||
}
|
||||
|
||||
func (s *dirImageSource) GetLayer(digest string) (io.ReadCloser, error) {
|
||||
|
@ -20,8 +20,7 @@ var (
|
||||
|
||||
type dockerImage struct {
|
||||
src *dockerImageSource
|
||||
digest string
|
||||
rawManifest []byte
|
||||
cachedManifest []byte // Private cache for Manifest(); nil if not yet known.
|
||||
cachedSignatures [][]byte // Private cache for Signatures(); nil if not yet known.
|
||||
}
|
||||
|
||||
@ -44,10 +43,14 @@ func (i *dockerImage) IntendedDockerReference() string {
|
||||
|
||||
// Manifest is like ImageSource.GetManifest, but the result is cached; it is OK to call this however often you need.
|
||||
func (i *dockerImage) Manifest() ([]byte, error) {
|
||||
if err := i.retrieveRawManifest(); err != nil {
|
||||
return nil, err
|
||||
if i.cachedManifest == nil {
|
||||
m, err := i.src.GetManifest()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i.cachedManifest = m
|
||||
}
|
||||
return i.rawManifest, nil
|
||||
return i.cachedManifest, nil
|
||||
}
|
||||
|
||||
// Signatures is like ImageSource.GetSignatures, but the result is cached; it is OK to call this however often you need.
|
||||
@ -76,7 +79,7 @@ func (i *dockerImage) Inspect() (*types.DockerImageManifest, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
imgManifest, err := makeImageManifest(i.src.ref.FullName(), ms1, i.digest, tags)
|
||||
imgManifest, err := makeImageManifest(i.src.ref.FullName(), ms1, tags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -122,7 +125,7 @@ type v1Image struct {
|
||||
OS string `json:"os,omitempty"`
|
||||
}
|
||||
|
||||
func makeImageManifest(name string, m *manifestSchema1, dgst string, tagList []string) (*types.DockerImageManifest, error) {
|
||||
func makeImageManifest(name string, m *manifestSchema1, tagList []string) (*types.DockerImageManifest, error) {
|
||||
v1 := &v1Image{}
|
||||
if err := json.Unmarshal([]byte(m.History[0].V1Compatibility), v1); err != nil {
|
||||
return nil, err
|
||||
@ -130,7 +133,6 @@ func makeImageManifest(name string, m *manifestSchema1, dgst string, tagList []s
|
||||
return &types.DockerImageManifest{
|
||||
Name: name,
|
||||
Tag: m.Tag,
|
||||
Digest: dgst,
|
||||
RepoTags: tagList,
|
||||
DockerVersion: v1.DockerVersion,
|
||||
Created: v1.Created,
|
||||
@ -181,25 +183,13 @@ func sanitize(s string) string {
|
||||
return strings.Replace(s, "/", "-", -1)
|
||||
}
|
||||
|
||||
func (i *dockerImage) retrieveRawManifest() error {
|
||||
if i.rawManifest != nil {
|
||||
return nil
|
||||
}
|
||||
manblob, unverifiedCanonicalDigest, err := i.src.GetManifest()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.rawManifest = manblob
|
||||
i.digest = unverifiedCanonicalDigest
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *dockerImage) getSchema1Manifest() (manifest, error) {
|
||||
if err := i.retrieveRawManifest(); err != nil {
|
||||
manblob, err := i.Manifest()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mschema1 := &manifestSchema1{}
|
||||
if err := json.Unmarshal(i.rawManifest, mschema1); err != nil {
|
||||
if err := json.Unmarshal(manblob, mschema1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := fixManifestLayers(mschema1); err != nil {
|
||||
|
@ -55,23 +55,24 @@ func (s *dockerImageSource) IntendedDockerReference() string {
|
||||
return fmt.Sprintf("%s:%s", s.ref.Name(), s.tag)
|
||||
}
|
||||
|
||||
func (s *dockerImageSource) GetManifest() (manifest []byte, unverifiedCanonicalDigest string, err error) {
|
||||
func (s *dockerImageSource) GetManifest() ([]byte, error) {
|
||||
url := fmt.Sprintf(manifestURL, s.ref.RemoteName(), s.tag)
|
||||
// TODO(runcom) set manifest version header! schema1 for now - then schema2 etc etc and v1
|
||||
// TODO(runcom) NO, switch on the resulter manifest like Docker is doing
|
||||
res, err := s.c.makeRequest("GET", url, nil, nil)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
manblob, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
return nil, err
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return nil, "", errFetchManifest{res.StatusCode, manblob}
|
||||
return nil, errFetchManifest{res.StatusCode, manblob}
|
||||
}
|
||||
return manblob, res.Header.Get("Docker-Content-Digest"), nil
|
||||
// We might validate manblob against the Docker-Content-Digest header here to protect against transport errors.
|
||||
return manblob, nil
|
||||
}
|
||||
|
||||
func (s *dockerImageSource) GetLayer(digest string) (io.ReadCloser, error) {
|
||||
|
@ -193,9 +193,9 @@ func (s *openshiftImageSource) IntendedDockerReference() string {
|
||||
return s.client.canonicalDockerReference()
|
||||
}
|
||||
|
||||
func (s *openshiftImageSource) GetManifest() (manifest []byte, unverifiedCanonicalDigest string, err error) {
|
||||
func (s *openshiftImageSource) GetManifest() ([]byte, error) {
|
||||
if err := s.ensureImageIsResolved(); err != nil {
|
||||
return nil, "", err
|
||||
return nil, err
|
||||
}
|
||||
return s.docker.GetManifest()
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ type ImageSource interface {
|
||||
// May be "" if unknown.
|
||||
IntendedDockerReference() string
|
||||
// GetManifest returns the image's manifest. It may use a remote (= slow) service.
|
||||
GetManifest() (manifest []byte, unverifiedCanonicalDigest string, err error)
|
||||
GetManifest() ([]byte, error)
|
||||
GetLayer(digest string) (io.ReadCloser, error)
|
||||
// GetSignatures returns the image's signatures. It may use a remote (= slow) service.
|
||||
GetSignatures() ([][]byte, error)
|
||||
@ -71,7 +71,6 @@ type Image interface {
|
||||
type DockerImageManifest struct {
|
||||
Name string
|
||||
Tag string
|
||||
Digest string
|
||||
RepoTags []string
|
||||
Created time.Time
|
||||
DockerVersion string
|
||||
|
Loading…
Reference in New Issue
Block a user