github.com/microsoft/docker@v1.5.0-rc2/graph/manifest.go (about) 1 package graph 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "io/ioutil" 9 10 log "github.com/Sirupsen/logrus" 11 "github.com/docker/docker/engine" 12 "github.com/docker/docker/pkg/tarsum" 13 "github.com/docker/docker/registry" 14 "github.com/docker/docker/runconfig" 15 "github.com/docker/libtrust" 16 ) 17 18 func (s *TagStore) CmdManifest(job *engine.Job) engine.Status { 19 if len(job.Args) != 1 { 20 return job.Errorf("usage: %s NAME", job.Name) 21 } 22 name := job.Args[0] 23 tag := job.Getenv("tag") 24 if tag == "" { 25 tag = "latest" 26 } 27 28 // Resolve the Repository name from fqn to endpoint + name 29 repoInfo, err := registry.ParseRepositoryInfo(name) 30 if err != nil { 31 return job.Error(err) 32 } 33 34 manifestBytes, err := s.newManifest(name, repoInfo.RemoteName, tag) 35 if err != nil { 36 return job.Error(err) 37 } 38 39 _, err = job.Stdout.Write(manifestBytes) 40 if err != nil { 41 return job.Error(err) 42 } 43 44 return engine.StatusOK 45 } 46 47 func (s *TagStore) newManifest(localName, remoteName, tag string) ([]byte, error) { 48 manifest := ®istry.ManifestData{ 49 Name: remoteName, 50 Tag: tag, 51 SchemaVersion: 1, 52 } 53 localRepo, err := s.Get(localName) 54 if err != nil { 55 return nil, err 56 } 57 if localRepo == nil { 58 return nil, fmt.Errorf("Repo does not exist: %s", localName) 59 } 60 61 // Get the top-most layer id which the tag points to 62 layerId, exists := localRepo[tag] 63 if !exists { 64 return nil, fmt.Errorf("Tag does not exist for %s: %s", localName, tag) 65 } 66 layersSeen := make(map[string]bool) 67 68 layer, err := s.graph.Get(layerId) 69 if err != nil { 70 return nil, err 71 } 72 manifest.Architecture = layer.Architecture 73 manifest.FSLayers = make([]*registry.FSLayer, 0, 4) 74 manifest.History = make([]*registry.ManifestHistory, 0, 4) 75 var metadata runconfig.Config 76 if layer.Config != nil { 77 metadata = *layer.Config 78 } 79 80 for ; layer != nil; layer, err = layer.GetParent() { 81 if err != nil { 82 return nil, err 83 } 84 85 if layersSeen[layer.ID] { 86 break 87 } 88 if layer.Config != nil && metadata.Image != layer.ID { 89 err = runconfig.Merge(&metadata, layer.Config) 90 if err != nil { 91 return nil, err 92 } 93 } 94 95 checksum := layer.Checksum 96 if tarsum.VersionLabelForChecksum(checksum) != tarsum.Version1.String() { 97 archive, err := layer.TarLayer() 98 if err != nil { 99 return nil, err 100 } 101 102 tarSum, err := tarsum.NewTarSum(archive, true, tarsum.Version1) 103 if err != nil { 104 return nil, err 105 } 106 if _, err := io.Copy(ioutil.Discard, tarSum); err != nil { 107 return nil, err 108 } 109 110 checksum = tarSum.Sum(nil) 111 } 112 113 jsonData, err := layer.RawJson() 114 if err != nil { 115 return nil, fmt.Errorf("Cannot retrieve the path for {%s}: %s", layer.ID, err) 116 } 117 118 manifest.FSLayers = append(manifest.FSLayers, ®istry.FSLayer{BlobSum: checksum}) 119 120 layersSeen[layer.ID] = true 121 122 manifest.History = append(manifest.History, ®istry.ManifestHistory{V1Compatibility: string(jsonData)}) 123 } 124 125 manifestBytes, err := json.MarshalIndent(manifest, "", " ") 126 if err != nil { 127 return nil, err 128 } 129 130 return manifestBytes, nil 131 } 132 133 func (s *TagStore) verifyManifest(eng *engine.Engine, manifestBytes []byte) (*registry.ManifestData, bool, error) { 134 sig, err := libtrust.ParsePrettySignature(manifestBytes, "signatures") 135 if err != nil { 136 return nil, false, fmt.Errorf("error parsing payload: %s", err) 137 } 138 139 keys, err := sig.Verify() 140 if err != nil { 141 return nil, false, fmt.Errorf("error verifying payload: %s", err) 142 } 143 144 payload, err := sig.Payload() 145 if err != nil { 146 return nil, false, fmt.Errorf("error retrieving payload: %s", err) 147 } 148 149 var manifest registry.ManifestData 150 if err := json.Unmarshal(payload, &manifest); err != nil { 151 return nil, false, fmt.Errorf("error unmarshalling manifest: %s", err) 152 } 153 if manifest.SchemaVersion != 1 { 154 return nil, false, fmt.Errorf("unsupported schema version: %d", manifest.SchemaVersion) 155 } 156 157 var verified bool 158 for _, key := range keys { 159 job := eng.Job("trust_key_check") 160 b, err := key.MarshalJSON() 161 if err != nil { 162 return nil, false, fmt.Errorf("error marshalling public key: %s", err) 163 } 164 namespace := manifest.Name 165 if namespace[0] != '/' { 166 namespace = "/" + namespace 167 } 168 stdoutBuffer := bytes.NewBuffer(nil) 169 170 job.Args = append(job.Args, namespace) 171 job.Setenv("PublicKey", string(b)) 172 // Check key has read/write permission (0x03) 173 job.SetenvInt("Permission", 0x03) 174 job.Stdout.Add(stdoutBuffer) 175 if err = job.Run(); err != nil { 176 return nil, false, fmt.Errorf("error running key check: %s", err) 177 } 178 result := engine.Tail(stdoutBuffer, 1) 179 log.Debugf("Key check result: %q", result) 180 if result == "verified" { 181 verified = true 182 } 183 } 184 185 return &manifest, verified, nil 186 } 187 188 func checkValidManifest(manifest *registry.ManifestData) error { 189 if len(manifest.FSLayers) != len(manifest.History) { 190 return fmt.Errorf("length of history not equal to number of layers") 191 } 192 193 if len(manifest.FSLayers) == 0 { 194 return fmt.Errorf("no FSLayers in manifest") 195 } 196 197 return nil 198 }