distribution/storage/manifest.go
Stephen J Day eaadb82e1e Move Manifest type into storage package
This changeset move the Manifest type into the storage package to make the type
accessible to client and registry without import cycles. The structure of the
manifest was also changed to accuratle reflect the stages of the signing
process. A straw man Manifest.Sign method has been added to start testing this
concept out but will probably be accompanied by the more import
SignedManifest.Verify method as the security model develops.

This is probably the start of a concerted effort to consolidate types across
the client and server portions of the code base but we may want to see how such
a handy type, like the Manifest and SignedManifest, would work in docker core.
2014-11-21 19:37:44 -08:00

126 lines
3.2 KiB
Go

package storage
import (
"encoding/json"
"fmt"
"github.com/docker/libtrust"
"github.com/docker/docker-registry/digest"
)
var (
// ErrManifestUnknown is returned if the manifest is not known by the
// registry.
ErrManifestUnknown = fmt.Errorf("unknown manifest")
// ErrManifestUnverified is returned when the registry is unable to verify
// the manifest.
ErrManifestUnverified = fmt.Errorf("unverified manifest")
)
// Versioned provides a struct with just the manifest schemaVersion. Incoming
// content with unknown schema version can be decoded against this struct to
// check the version.
type Versioned struct {
// SchemaVersion is the image manifest schema that this image follows
SchemaVersion int `json:"schemaVersion"`
}
// Manifest provides the base accessible fields for working with V2 image
// format in the registry.
type Manifest struct {
Versioned
// Name is the name of the image's repository
Name string `json:"name"`
// Tag is the tag of the image specified by this manifest
Tag string `json:"tag"`
// Architecture is the host architecture on which this image is intended to
// run
Architecture string `json:"architecture"`
// FSLayers is a list of filesystem layer blobSums contained in this image
FSLayers []FSLayer `json:"fsLayers"`
// History is a list of unstructured historical data for v1 compatibility
History []ManifestHistory `json:"history"`
}
// Sign signs the manifest with the provided private key, returning a
// SignedManifest. This typically won't be used within the registry, except
// for testing.
func (m *Manifest) Sign(pk libtrust.PrivateKey) (*SignedManifest, error) {
p, err := json.Marshal(m)
if err != nil {
return nil, err
}
js, err := libtrust.NewJSONSignature(p)
if err != nil {
return nil, err
}
if err := js.Sign(pk); err != nil {
return nil, err
}
pretty, err := js.PrettySignature("signatures")
if err != nil {
return nil, err
}
return &SignedManifest{
Manifest: *m,
Raw: pretty,
}, nil
}
// SignedManifest provides an envelope for
type SignedManifest struct {
Manifest
// Raw is the byte representation of the ImageManifest, used for signature
// verification. The manifest byte representation cannot change or it will
// have to be re-signed.
Raw []byte `json:"-"`
}
// UnmarshalJSON populates a new ImageManifest struct from JSON data.
func (m *SignedManifest) UnmarshalJSON(b []byte) error {
var manifest Manifest
if err := json.Unmarshal(b, &manifest); err != nil {
return err
}
m.Manifest = manifest
m.Raw = b
return nil
}
// MarshalJSON returns the contents of raw. If Raw is nil, marshals the inner
// contents.
func (m *SignedManifest) MarshalJSON() ([]byte, error) {
if len(m.Raw) > 0 {
return m.Raw, nil
}
// If the raw data is not available, just dump the inner content.
return json.Marshal(&m.Manifest)
}
// FSLayer is a container struct for BlobSums defined in an image manifest
type FSLayer struct {
// BlobSum is the tarsum of the referenced filesystem image layer
BlobSum digest.Digest `json:"blobSum"`
}
// ManifestHistory stores unstructured v1 compatibility information
type ManifestHistory struct {
// V1Compatibility is the raw v1 compatibility information
V1Compatibility string `json:"v1Compatibility"`
}