diff --git a/image/image_test.go b/image/image_test.go index 8c3c0c9..e808e7d 100644 --- a/image/image_test.go +++ b/image/image_test.go @@ -103,7 +103,7 @@ var ( "layers": [ { "digest": "", - "mediaType": "application/vnd.oci.image.layer.tar+gzip", + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", "size": } ], diff --git a/image/manifest_test.go b/image/manifest_test.go index f50b2ed..81242e1 100644 --- a/image/manifest_test.go +++ b/image/manifest_test.go @@ -108,7 +108,7 @@ func TestUnpackLayer(t *testing.T) { testManifest := manifest{ Layers: []descriptor{descriptor{ - MediaType: "application/vnd.oci.image.layer.tar+gzip", + MediaType: "application/vnd.oci.image.layer.v1.tar+gzip", Digest: fmt.Sprintf("sha256:%s", fmt.Sprintf("%x", h.Sum(nil))), }}, } @@ -169,7 +169,7 @@ func TestUnpackLayerRemovePartialyUnpackedFile(t *testing.T) { testManifest := manifest{ Layers: []descriptor{descriptor{ - MediaType: "application/vnd.oci.image.layer.tar+gzip", + MediaType: "application/vnd.oci.image.layer.v1.tar+gzip", Digest: fmt.Sprintf("sha256:%s", fmt.Sprintf("%x", h.Sum(nil))), }}, } diff --git a/vendor/github.com/opencontainers/image-spec/schema/config-schema.json b/vendor/github.com/opencontainers/image-spec/schema/config-schema.json new file mode 100644 index 0000000..4aa2609 --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/schema/config-schema.json @@ -0,0 +1,38 @@ +{ + "description": "OpenContainer Config Specification", + "$schema": "http://json-schema.org/draft-04/schema#", + "id": "https://opencontainers.org/schema/image/config", + "type": "object", + "properties": { + "created": { + "type": "string", + "format": "date-time" + }, + "author": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "os": { + "type": "string" + }, + "config": { + "$ref": "defs-config.json#/definitions/config" + }, + "rootfs": { + "$ref": "defs-config.json#/definitions/rootfs" + }, + "history": { + "type": "array", + "items": { + "$ref": "defs-config.json#/definitions/history" + } + } + }, + "required": [ + "architecture", + "os", + "rootfs" + ] +} diff --git a/vendor/github.com/opencontainers/image-spec/schema/config_test.go b/vendor/github.com/opencontainers/image-spec/schema/config_test.go new file mode 100644 index 0000000..27c1487 --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/schema/config_test.go @@ -0,0 +1,165 @@ +// Copyright 2016 The Linux Foundation +// +// 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 schema_test + +import ( + "strings" + "testing" + + "github.com/opencontainers/image-spec/schema" +) + +func TestConfig(t *testing.T) { + for i, tt := range []struct { + config string + fail bool + }{ + // expected failure: field "os" has numeric value, must be string + { + config: ` +{ + "architecture": "amd64", + "os": 123 +} +`, + fail: true, + }, + + // expected failure: field "config.User" has numeric value, must be string + { + config: ` +{ + "created": "2015-10-31T22:22:56.015925234Z", + "author": "Alyssa P. Hacker ", + "architecture": "amd64", + "os": "linux", + "config": { + "User": 1234 + } +} +`, + fail: true, + }, + + // expected failue: history has string value, must be an array + { + config: ` +{ + "history": "should be an array" +} +`, + fail: true, + }, + + // expected failure: Env has numeric value, must be a string + { + config: ` +{ + "config": { + "Env": [ + 7353 + ] + } +} +`, + fail: true, + }, + + // expected failure: config.Volumes has string array, must be an object (string set) + { + config: ` +{ + "config": { + "Volumes": [ + "/var/job-result-data", + "/var/log/my-app-logs" + ] + } +} +`, + fail: true, + }, + + // expected failue: invalid JSON + { + config: `invalid JSON`, + fail: true, + }, + + { + config: ` +{ + "created": "2015-10-31T22:22:56.015925234Z", + "author": "Alyssa P. Hacker ", + "architecture": "amd64", + "os": "linux", + "config": { + "User": "1:1", + "Memory": 2048, + "MemorySwap": 4096, + "CpuShares": 8, + "ExposedPorts": { + "8080/tcp": {} + }, + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "FOO=docker_is_a_really", + "BAR=great_tool_you_know" + ], + "Entrypoint": [ + "/bin/sh" + ], + "Cmd": [ + "--foreground", + "--config", + "/etc/my-app.d/default.cfg" + ], + "Volumes": { + "/var/job-result-data": {}, + "/var/log/my-app-logs": {} + }, + "WorkingDir": "/home/alice" + }, + "rootfs": { + "diff_ids": [ + "sha256:9d3dd9504c685a304985025df4ed0283e47ac9ffa9bd0326fddf4d59513f0827", + "sha256:2b689805fbd00b2db1df73fae47562faac1a626d5f61744bfe29946ecff5d73d" + ], + "type": "layers" + }, + "history": [ + { + "created": "2015-10-31T22:22:54.690851953Z", + "created_by": "/bin/sh -c #(nop) ADD file:a3bc1e842b69636f9df5256c49c5374fb4eef1e281fe3f282c65fb853ee171c5 in /" + }, + { + "created": "2015-10-31T22:22:55.613815829Z", + "created_by": "/bin/sh -c #(nop) CMD [\"sh\"]", + "empty_layer": true + } + ] +} +`, + fail: false, + }, + } { + r := strings.NewReader(tt.config) + err := schema.MediaTypeImageConfig.Validate(r) + + if got := err != nil; tt.fail != got { + t.Errorf("test %d: expected validation failure %t but got %t, err %v", i, tt.fail, got, err) + } + } +} diff --git a/vendor/github.com/opencontainers/image-spec/schema/content-descriptor.json b/vendor/github.com/opencontainers/image-spec/schema/content-descriptor.json new file mode 100644 index 0000000..cd122aa --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/schema/content-descriptor.json @@ -0,0 +1,32 @@ +{ + "description": "OpenContainer Content Descriptor Specification", + "$schema": "http://json-schema.org/draft-04/schema#", + "id": "https://opencontainers.org/schema/descriptor", + "type": "object", + "properties": { + "mediaType": { + "description": "the mediatype of the referenced object", + "$ref": "defs-image.json#definitions/mediaType" + }, + "size": { + "description": "the size in bytes of the referenced object", + "$ref": "defs.json#/definitions/int64" + }, + "digest": { + "$ref": "defs-image.json#definitions/digest" + }, + "urls": { + "description": "a list of urls from which this object may be downloaded", + "type": "array", + "items": { + "type": "string", + "format": "uri" + } + } + }, + "required": [ + "mediaType", + "size", + "digest" + ] +} diff --git a/vendor/github.com/opencontainers/image-spec/schema/defs-config.json b/vendor/github.com/opencontainers/image-spec/schema/defs-config.json new file mode 100644 index 0000000..adad2fb --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/schema/defs-config.json @@ -0,0 +1,112 @@ +{ + "description": "Definitions particular to OpenContainer Config Specification", + "definitions": { + "config": { + "type": "object", + "properties": { + "User": { + "type": "string" + }, + "Memory": { + "$ref": "defs.json#/definitions/int64" + }, + "MemorySwap": { + "$ref": "defs.json#/definitions/int64" + }, + "CpuShares": { + "$ref": "defs.json#/definitions/int64" + }, + "ExposedPorts": { + "$ref": "defs.json#/definitions/mapStringObject" + }, + "Env": { + "type": "array", + "items": { + "type": "string" + } + }, + "Entrypoint": { + "oneOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "null" + } + ] + }, + "Cmd": { + "oneOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "null" + } + ] + }, + "Volumes": { + "oneOf": [ + { + "$ref": "defs.json#/definitions/mapStringObject" + }, + { + "type": "null" + } + ] + }, + "WorkingDir": { + "type": "string" + } + } + }, + "rootfs": { + "type": "object", + "properties": { + "diff_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "type": { + "type": "string", + "enum": [ + "layers" + ] + } + }, + "required": [ + "diff_ids", + "type" + ] + }, + "history": { + "type": "object", + "properties": { + "created": { + "type": "string", + "format": "date-time" + }, + "author": { + "type": "string" + }, + "created_by": { + "type": "string" + }, + "comment": { + "type": "string" + }, + "empty_layer": { + "type": "boolean" + } + } + } + } +} diff --git a/vendor/github.com/opencontainers/image-spec/schema/defs-image.json b/vendor/github.com/opencontainers/image-spec/schema/defs-image.json new file mode 100644 index 0000000..b0046a0 --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/schema/defs-image.json @@ -0,0 +1,96 @@ +{ + "description": "Definitions particular to OpenContainer Image Specification", + "definitions": { + "mediaType": { + "id": "https://opencontainers.org/schema/image/mediaType", + "type": "string", + "pattern": "^[a-z]+/[0-9a-zA-Z.+]+$" + }, + "digest": { + "description": "the cryptographic checksum digest of the object, in the pattern ':'", + "type": "string", + "pattern": "^[a-z0-9_+.-]+:[a-f0-9]+$" + }, + "manifestDescriptor": { + "id": "https://opencontainers.org/schema/image/manifestDescriptor", + "type": "object", + "required": [ + "mediaType", + "size", + "digest", + "platform" + ], + "properties": { + "mediaType": { + "description": "the mediatype of the referenced object", + "$ref": "#definitions/mediaType" + }, + "size": { + "description": "the size in bytes of the referenced object", + "$ref": "defs.json#/definitions/int64" + }, + "digest": { + "$ref": "#definitions/digest" + }, + "urls": { + "description": "a list of urls from which this object may be downloaded", + "type": "array", + "items": { + "type": "string", + "format": "uri" + } + }, + "platform": { + "id": "https://opencontainers.org/schema/image/platform", + "type": "object", + "required": [ + "architecture", + "os" + ], + "properties": { + "architecture": { + "id": "https://opencontainers.org/schema/image/platform/architecture", + "type": "string" + }, + "os": { + "id": "https://opencontainers.org/schema/image/platform/os", + "type": "string" + }, + "os.version": { + "id": "https://opencontainers.org/schema/image/platform/os.version", + "type": "string" + }, + "os.features": { + "id": "https://opencontainers.org/schema/image/platform/os.features", + "type": "array", + "items": { + "type": "string" + } + }, + "variant": { + "type": "string" + }, + "features": { + "type": "array", + "items": { + "type": "string" + }, + "additionalProperties": false + } + } + } + } + }, + "annotations": { + "id": "https://opencontainers.org/schema/image/annotations", + "oneOf": [ + { + "$ref": "defs.json#/definitions/mapStringString" + }, + { + "type": "null" + } + ] + } + } +} diff --git a/vendor/github.com/opencontainers/image-spec/schema/defs.json b/vendor/github.com/opencontainers/image-spec/schema/defs.json new file mode 100644 index 0000000..4eccc5e --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/schema/defs.json @@ -0,0 +1,168 @@ +{ + "description": "Definitions used throughout the OpenContainer Specification", + "definitions": { + "int8": { + "type": "integer", + "minimum": -128, + "maximum": 127 + }, + "int16": { + "type": "integer", + "minimum": -32768, + "maximum": 32767 + }, + "int32": { + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + "int64": { + "type": "integer", + "minimum": -9223372036854776000, + "maximum": 9223372036854776000 + }, + "uint8": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "uint16": { + "type": "integer", + "minimum": 0, + "maximum": 65535 + }, + "uint32": { + "type": "integer", + "minimum": 0, + "maximum": 4294967295 + }, + "uint64": { + "type": "integer", + "minimum": 0, + "maximum": 18446744073709552000 + }, + "uint16Pointer": { + "oneOf": [ + { + "$ref": "#/definitions/uint16" + }, + { + "type": "null" + } + ] + }, + "uint64Pointer": { + "oneOf": [ + { + "$ref": "#/definitions/uint64" + }, + { + "type": "null" + } + ] + }, + "stringPointer": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "mapStringString": { + "type": "object", + "patternProperties": { + ".{1,}": { + "type": "string" + } + } + }, + "mapStringObject": { + "type": "object", + "patternProperties": { + ".{1,}": { + "type": "object" + } + } + }, + "UID": { + "$ref": "#/definitions/uint32" + }, + "GID": { + "$ref": "#/definitions/uint32" + }, + "ArrayOfGIDs": { + "type": "array", + "items": { + "$ref": "#/definitions/GID" + } + }, + "ArrayOfStrings": { + "type": "array", + "items": { + "type": "string" + } + }, + "FilePath": { + "type": "string" + }, + "Env": { + "$ref": "#/definitions/ArrayOfStrings" + }, + "Hook": { + "properties": { + "path": { + "$ref": "#/definitions/FilePath" + }, + "args": { + "$ref": "#/definitions/ArrayOfStrings" + }, + "env": { + "$ref": "#/definitions/Env" + } + } + }, + "ArrayOfHooks": { + "type": "array", + "items": { + "$ref": "#/definitions/Hook" + } + }, + "IDMapping": { + "properties": { + "hostID": { + "$ref": "#/definitions/uint32" + }, + "containerID": { + "$ref": "#/definitions/uint32" + }, + "size": { + "$ref": "#/definitions/uint32" + } + } + }, + "Mount": { + "properties": { + "source": { + "$ref": "#/definitions/FilePath" + }, + "destination": { + "$ref": "#/definitions/FilePath" + }, + "options": { + "$ref": "#/definitions/ArrayOfStrings" + }, + "type": { + "type": "string" + } + }, + "required": [ + "destination", + "source", + "type" + ] + } + } +} diff --git a/vendor/github.com/opencontainers/image-spec/schema/fs.go b/vendor/github.com/opencontainers/image-spec/schema/fs.go index 5f4db5d..1dea532 100644 --- a/vendor/github.com/opencontainers/image-spec/schema/fs.go +++ b/vendor/github.com/opencontainers/image-spec/schema/fs.go @@ -204,69 +204,73 @@ var _escData = map[string]*_escFile{ "/config-schema.json": { local: "config-schema.json", - size: 710, - modtime: 1466466955, + size: 774, + modtime: 1478057674, compressed: ` -H4sIAAAJbogA/5SRPW7DMAyFd5/CcDLWUYdOWXuADj2BKlMxA1gUSGYICt+9+olbGygKdzGMx/e9J1Gf -Tdt2A4hjjIoUunPbvUUIrxTUYgBu05/HS/sewaFHZ4vrKWNHcSNMNiOjajwbcxUKfVVPxBczsPXaP7+Y -qh0qh8OCSGIotbmlTQpW3QYnewHjSn8l9R4hs/RxBadVi5wSWBEkTfJ1kuYYrMLwLaxQUcZQ44ruiSer -eTIkpFecoCuzuVo6e9OR+I+orZvdiJoOd2PYy5DsdT52sXIfGXw5PHjp6/iUX+FgkoIB82vJssNNFhOp -l/9nPbhN1oiixPffrmGZ7f1n3Wk307p0d+1S8eDmZvnOzdx8BQAA//964XeexgIAAA== +H4sIAAAJbogA/5SRvW7rMAyFdz+F4WS8ju7QKWsfoEPHooMqUzEDWFRJZgiKvHv1EzcxEBTuEsSH/M4R +ya+mbbsBxDFGRQrdvu1eIoRnCmoxALfpn8dD+xrBoUdnS9e/jG3FjTDZjIyqcW/MUSj0Vd0RH8zA1mv/ +/8lUbVM5HGZEEkMpzc1pUrDabXCyBzCu5FdSzxEySx9HcFq1yMmBFUFSJY+TNMdgFYYf4Q4VZQzVruie +eLKaK0NCesUJulK71JbOnnQk/sVq2c1uRE2POzGsZUjWdl53cde9ZfDl8eClr+VdvsLGJAUD5mvJvMOF +FxOpl797XbmF14iixOdHY1hme76tO+1mug9dHTtHXLlLM/+WN3QMnyfkcvK3B5e4bXo5ffp4by7NdwAA +AP//XlvgsQYDAAA= `, }, "/content-descriptor.json": { local: "content-descriptor.json", - size: 616, - modtime: 1466180793, + size: 836, + modtime: 1478141504, compressed: ` -H4sIAAAJbogA/4yRMVPDMAyF9/wKXdqR1gxMXWFngI1jcG0lVe9iG1kMhet/x4oTSGGgW/L8vvck+7MB -aD1mx5SEYmh30D4mDPcxiKWADPqFQeBhMkWGp4SOOnJ2JG40Yp3dAQer+EEk7Yw55hg2Vd1G7o1n28nm -9s5UbVU58jOSCxNLs5ub84hVt/Hf7ZWTU0Il4/6ITqqWuPAshLmc6GJFG9CTfa7mKv3dVw4Io09DIXag -AmOHXKZBD4uOEV+XM+U8dnlDg+1xq8uuyj8F0tRsfnpH6lzhNtPHf5OoBSjA/iSYr5hmvgkqz9QjX/Z5 -6jHLsvGa4SeqJjVTWsv49k6M+mAvvy93ud5ldfl5bc7NVwAAAP//Zc2MR2gCAAA= +H4sIAAAJbogA/5SSP2/iQBDFe3+KkaE88BXoCtpLnyLpohSLd2wPwrvO7CDkRHz37HhtMImUPw3Cb99v +5j173zKA3GIomToh7/It5Pcduv/eiSGHDPoPncDdaPIMDx2WVFFpBuKPjliGssHWKN6IdNui2AfvVkld +e64Ly6aS1d9NkbRF4shOSIiMj5vLaXMYsOQu7GV74qTvUEm/22MpSes48iyEIZ5osai1aMk8JnOSPveV +BmHw6VDwFajAWCHHNGhhtmPAl/FMOYtVWFFralxr2UV8Jkc6NRTXvQN1TnAe6PW7JGoBcrDrBcMv06Qc +xTwIOfm3uQ1hqcYg8xg/aTRSN5OOfAhf1DFwoCDaQY1QsW/h1FDZxE4UxibQmh52CNaf3MEbi/babfrK +htn0V5kE2/nemTMIk6sv1nhSeW6Nto1pKR/1czb9DlVyxpcjMeplfPp4ceaf7vYNxofn7Jy9BwAA//9L +DLQ9RAMAAA== `, }, "/defs-config.json": { local: "defs-config.json", - size: 2154, - modtime: 1466467007, + size: 2270, + modtime: 1478057674, compressed: ` -H4sIAAAJbogA/+RVzY7TMBC+5ymswLGwF8SB6y5HVKQIOCBUucl4O0vsscYTIEL77jjZquSnCWlLT3uo -mkz8/cyMPf6dKJUWEHJGL0gufafSOzDosHkLymsWzKtSsxJSaw/ulpxodMAqPhm8V5mHHA3musWvnggP -DJGw0YjBvF1+eI8RqT00grR9gFxaaBv3TB6iLoTO6hj/FIB7kQ5HEEZ3nx4+Pa7+4j6AJa6HyJcMpkFG -s+H1QyD34qbj+wadvH0zx5f91P7/cd76KttpHqR8EeX7X54CFB+J5VRWq33WFnT91Jrj/O7HVDc0s67T -VfcTCtihjZn+RakJUeHaU0x7qE0O1k1OX3sCfblZizM2/2G1b3dgedaFq8qyz9Tl+XZ8q9ji2eb+mcrK -jg/JwvzP3fXXzuoL8fcoe4fLx1vS/d9zpUwkJlwyYgs0ZoPFqMDXP9ilroEndZflv8Mg/Ul/cgFyBi0w -OmADH70CGGKrpd1XEfpK0MLxgakr2dFZN9je1WY7usUWoclaGA/MJVCwXupN25sp+JaoBO0me5M0v8fk -TwAAAP//dkZ6ZWoIAAA= +H4sIAAAJbogA/+RVzY7TMBC+5yksw7GwF8SB6y5HVKQKOCBUucl4O0vsMeMJEKF9d5xs6cZJG7q79MSh +ajLx9zMz9vhXoZSuIJaMQZC8fqP0FVj02L1FFQwLlk1tWAmpZQB/SV4MemCVnixeq1WAEi2Wpscv7gj3 +DImw00jBsl++f08RaQN0grS5gVJ6aB8PTAGSLsTB6hT/EIGzyIAjCqO/1vtPt4t73DtwxO0Y+ZzBdshk +Nr68ieSfXQx8X6CX16/m+FY/TPh3nJehWW0Nj1J+EuXbn4EiVO+J5aGszoRVX9DlXWsO8/vvx7phmE2r +F8NPKODGNmb6l6SOiAq3gVLaY23ysOxy+pwJ5HKzFmds/sVqbndkedaFb+o6ZxryfDm8VVz13+b+kerG +TQ/Jifk/dtefO6tPxF+T7BWePt6K4f+OSzOR2PiUEVuhtWusJgU+/8HerZ/LPpMF37hJx3VtWuCoD1e8 +GKlqhm8NMlQZz30Nxu6KIeOfmm8xSn67PLjoJYMRmBzquewtsTPS7+UEfSHo4PCQNo1s6VG35s7VejO5 +OU9Ck3MwHdKnQMEFadd9J4/BN0Q1GH/0PBTd77b4HQAA//9fxiKD3ggAAA== `, }, "/defs-image.json": { local: "defs-image.json", - size: 2528, - modtime: 1466438460, + size: 2753, + modtime: 1478141527, compressed: ` -H4sIAAAJbogA/7RWy27bMBC8+ysIJUAOfqjXGkGAoEGBnlIgPTVQgY20kphKpLqkgzqB/r2k3k+nrt0b -ueQOZ4Zjym8LxpwAlU8801wKZ8ucOwy54HamWAakub9LgJiW7D5D8UkKDVwgsS8pRMgeMvR5yH0o2lcl -XgNg8OwRpphiwOHbPsOmZIo8sAfGWmdq67rSwPs1vNpIilzlx5iCy+1RbguxqgF0CegoTVxEbT0DrZEK -OT8eYf3qLd3HD+uPZnS7/r5ZestLp9ialx1OwCNUukttYIqOkfm0z7SMCLKY+8ww83+qXcrKXiZDZjfJ -p2f09YpxUUwrIuzqOgYV32yvY/wNgbEshaTqvLk6Xo/R4i23ZhTerj8Xk4GgFAQPDfhdJUPSCb6PsUaE -S9ltnfDXjhPacx6rWi8Eq7ao+GtvXt1Fp5IloENJqVOVvNYXMuRNRFF15M2kbe5ai71WR32FhCGSsQQD -NpBVQFyaddt70cl5J5vN1nyo8X0qdptNztNeo/pLOvUNcKExQpo+f5TveSXV1kmY5iIGQMflqUGZ1DGl -cTJNxQqQH3NtGnaEvR6zJpXTKXg9xJngjDGHq/+s1j1AdfzL7y3nY2Hno2XATiSzeTEnlCk+H6kG9FRy -IYJ1/LyWtaiz9IAI9uNlk4B0iss7woy0g0JfgDiI4S/8aL8OmfXfhI2gIAiKxwiSr92faQiJwsWcJ+24 -HuW9LyIIITX0/5UcHYEuSPMRkgLvw97TNPnKmkdWbZ6VFBdu78sB2UPhy8PAnY4vb1MPpdgliTMS7S3q -Wb7IF38CAAD//wKthPngCQAA +H4sIAAAJbogA/7RWy27bMBA8x19BKAFy8EM9FAVqBAGK5tJTCqSnBm6xoVYWU4lUSTqpE/jfu5RkmXol +UOOebC6Xw5nhLqnnCWNBhIZrkVuhZLBkwRXGQgo3MiwHbQXfpKCZVew6R/lZSQtComZfMlgju8mRi1hw +KJbPSrwagPDcFhTMMBLwbZtjHaKgiNyGibW5WYahIni+hzcLpdeh4QlmEAq3VXiAmO0BbAkYGKuFXB/i +OViLupDz4xbmT6tpePtu/pH+fZp/X0xX07OgSN2VK4JIrNFYn1rLFJsg43qbW7XWkCeCM2LGf5lNxsq1 +TMXMJam7e+R2xoQshhURdn6RgEkulxcJ/oGILMsgrVZeno/XQ1p+Thfz1XRJo5hGHUUZSBET+lWlQ+k3 +GN/F6jAudR/iGn9vhEa3z20Va1TB7BA04qkxrg7Di+Qp2FjpLKhCq4MxmshTjaLx5A2U29C5FrlOx/4M +NcaoyRKMWEtWAXFG827tqVfoXnHWqbu2xtepuDRXOndbi2YkHWJjFvdGydPQJyak/fC+n1Sn6oflVak+ +zEmw0al5RRSwVJTN4ZJZrFXGHql9ElImTKWHZbBld8gi9ShTRe0RNRXuawy0hm1zSljMSg4njdS6gcqw +Kx5wSomzCFxw1+tIXWgtVeP6pUbpVdF3hr3dUsyA5gmJ5HajsbGG5pQJvMCqgTjQGF3M9uw/qw1foNo9 +mcb0rivseLQI7I1kFg+0Q1nQxyNVg76VXIzgHD+uZQfUQXrdbiy3rDuSsRHC/I7sE/oAWoBsX1aj/XrJ +rP8mrAMFUVTcq5B+9ds0htTgZMgT78aa+L/7Fx+kVBaan12jS8AHqR9ZJfE6blxNvQ/GwAOUQX5T+HLT +csfz5bnvopSbNA06oleT/Wg32U3+BgAA//8jeF0swQoAAA== `, }, "/defs.json": { local: "defs.json", size: 3193, - modtime: 1466180793, + modtime: 1470056192, compressed: ` H4sIAAAJbogA/7RWTXPaMBC98ys8tEfa2PIX9NYp/cghAzOZnjo9uGYBtSCpstxpmuG/VzLGWPZiMKWH JPau9r23T6tYzwPHGS4gSyUVinI2fOMMp7CkjJq3zMkzWDhqLXm+WvNc6UdwZgLYO85UQhlI51FASpc0 @@ -285,7 +289,7 @@ MrVJbn8cB+ZnN/gbAAD//0JyEpx5DAAA "/image-manifest-schema.json": { local: "image-manifest-schema.json", size: 1032, - modtime: 1466180793, + modtime: 1470056192, compressed: ` H4sIAAAJbogA/6RSPU/zMBDe8ytOacc39TswdWViQAxULIjBJOfkqsYOPoNUVf3v+KMujsoAdMyTez7u 8R0qgLpDbi1Njoyu11A/TKhvjXaSNFq4G2WPcC81KWQHjxO2pKiVcfpfoC+5HXCUgTo4N62F2LLRTUJX @@ -300,7 +304,7 @@ X3p8DwgEAAA= "/manifest-list-schema.json": { local: "manifest-list-schema.json", size: 1010, - modtime: 1466180793, + modtime: 1470056192, compressed: ` H4sIAAAJbogA/6ySMU/7MBDF93yKU9rxn/o/MHWFBQnEQMWCGExyaa5q7OAzSFXV747tS0qiMIDoUqkv fu9+7+xjBpBXyKWjzpM1+Rryhw7NtTVek0EHt63eItxrQzWyhzsKP48dllRTqZPlX8xYctlgq6O/8b5b diff --git a/vendor/github.com/opencontainers/image-spec/schema/image-manifest-schema.json b/vendor/github.com/opencontainers/image-spec/schema/image-manifest-schema.json new file mode 100644 index 0000000..f25c85f --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/schema/image-manifest-schema.json @@ -0,0 +1,36 @@ +{ + "description": "OpenContainer Image Manifest Specification", + "$schema": "http://json-schema.org/draft-04/schema#", + "id": "https://opencontainers.org/schema/image/manifest", + "type": "object", + "properties": { + "schemaVersion": { + "description": "This field specifies the image manifest schema version as an integer", + "id": "https://opencontainers.org/schema/image/manifest/schemaVersion", + "type": "integer" + }, + "mediaType": { + "id": "https://opencontainers.org/schema/image/manifest/mediaType", + "$ref": "defs-image.json#/definitions/mediaType" + }, + "config": { + "$ref": "content-descriptor.json" + }, + "layers": { + "type": "array", + "items": { + "$ref": "content-descriptor.json" + } + }, + "annotations": { + "id": "https://opencontainers.org/schema/image/manifest-list/annotations", + "$ref": "defs-image.json#/definitions/annotations" + } + }, + "required": [ + "schemaVersion", + "mediaType", + "config", + "layers" + ] +} diff --git a/vendor/github.com/opencontainers/image-spec/schema/manifest-list-schema.json b/vendor/github.com/opencontainers/image-spec/schema/manifest-list-schema.json new file mode 100644 index 0000000..261db7d --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/schema/manifest-list-schema.json @@ -0,0 +1,32 @@ +{ + "description": "OpenContainer Image Manifest List Specification", + "$schema": "http://json-schema.org/draft-04/schema#", + "id": "https://opencontainers.org/schema/image/manifest-list", + "type": "object", + "properties": { + "schemaVersion": { + "description": "This field specifies the image manifest-list schema version as an integer", + "id": "https://opencontainers.org/schema/image/manifest-list/schemaVersion", + "type": "integer" + }, + "mediaType": { + "id": "https://opencontainers.org/schema/image/manifest-list/mediaType", + "$ref": "defs-image.json#/definitions/mediaType" + }, + "manifests": { + "type": "array", + "items": { + "$ref": "defs-image.json#/definitions/manifestDescriptor" + } + }, + "annotations": { + "id": "https://opencontainers.org/schema/image/manifest-list/annotations", + "$ref": "defs-image.json#/definitions/annotations" + } + }, + "required": [ + "schemaVersion", + "mediaType", + "manifests" + ] +} diff --git a/vendor/github.com/opencontainers/image-spec/schema/manifest_backwards_compatibility_test.go b/vendor/github.com/opencontainers/image-spec/schema/manifest_backwards_compatibility_test.go new file mode 100644 index 0000000..4bd055c --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/schema/manifest_backwards_compatibility_test.go @@ -0,0 +1,230 @@ +// Copyright 2016 The Linux Foundation +// +// 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 schema_test + +import ( + "crypto/sha256" + "encoding/hex" + "fmt" + "strings" + "testing" + + "github.com/opencontainers/image-spec/schema" + "github.com/opencontainers/image-spec/specs-go/v1" +) + +var compatMap = map[string]string{ + "application/vnd.docker.distribution.manifest.list.v2+json": v1.MediaTypeImageManifestList, + "application/vnd.docker.distribution.manifest.v2+json": v1.MediaTypeImageManifest, + "application/vnd.docker.image.rootfs.diff.tar.gzip": v1.MediaTypeImageLayer, + "application/vnd.docker.container.image.v1+json": v1.MediaTypeImageConfig, +} + +// convertFormats converts Docker v2.2 image format JSON documents to OCI +// format by simply replacing instances of the strings found in the compatMap +// found in the input string. +func convertFormats(input string) string { + out := input + for k, v := range compatMap { + out = strings.Replace(out, v, k, -1) + } + return out +} + +func TestBackwardsCompatibilityManifestList(t *testing.T) { + for i, tt := range []struct { + manifest string + digest string + fail bool + }{ + { + digest: "sha256:e588eb8123f2031a41f2e60bc27f30a4388e181e07410aff392f7dc96b585969", + manifest: `{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", + "manifests": [ + { + "mediaType": "application/vnd.docker.distribution.manifest.v1+json", + "size": 2094, + "digest": "sha256:7820f9a86d4ad15a2c4f0c0e5479298df2aa7c2f6871288e2ef8546f3e7b6783", + "platform": { + "architecture": "ppc64le", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.docker.distribution.manifest.v1+json", + "size": 1922, + "digest": "sha256:ae1b0e06e8ade3a11267564a26e750585ba2259c0ecab59ab165ad1af41d1bdd", + "platform": { + "architecture": "amd64", + "os": "linux", + "features": [ + "sse" + ] + } + }, + { + "mediaType": "application/vnd.docker.distribution.manifest.v1+json", + "size": 2084, + "digest": "sha256:e4c0df75810b953d6717b8f8f28298d73870e8aa2a0d5e77b8391f16fdfbbbe2", + "platform": { + "architecture": "s390x", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.docker.distribution.manifest.v1+json", + "size": 2084, + "digest": "sha256:07ebe243465ef4a667b78154ae6c3ea46fdb1582936aac3ac899ea311a701b40", + "platform": { + "architecture": "arm", + "os": "linux", + "variant": "armv7" + } + }, + { + "mediaType": "application/vnd.docker.distribution.manifest.v1+json", + "size": 2090, + "digest": "sha256:fb2fc0707b86dafa9959fe3d29e66af8787aee4d9a23581714be65db4265ad8a", + "platform": { + "architecture": "arm64", + "os": "linux", + "variant": "armv8" + } + } + ] +}`, + fail: false, + }, + } { + sum := sha256.Sum256([]byte(tt.manifest)) + got := fmt.Sprintf("sha256:%s", hex.EncodeToString(sum[:])) + if tt.digest != got { + t.Errorf("test %d: expected digest %s but got %s", i, tt.digest, got) + } + + manifest := convertFormats(tt.manifest) + r := strings.NewReader(manifest) + err := schema.MediaTypeManifestList.Validate(r) + + if got := err != nil; tt.fail != got { + t.Errorf("test %d: expected validation failure %t but got %t, err %v", i, tt.fail, got, err) + } + } +} + +func TestBackwardsCompatibilityManifest(t *testing.T) { + for i, tt := range []struct { + manifest string + digest string + fail bool + }{ + // manifest pulled from docker hub using hash value + // + // curl -L -H "Authorization: Bearer ..." -H \ + // "Accept: application/vnd.docker.distribution.manifest.v2+json" \ + // https://registry-1.docker.io/v2/library/docker/manifests/sha256:888206c77cd2811ec47e752ba291e5b7734e3ef137dfd222daadaca39a9f17bc + { + digest: "sha256:888206c77cd2811ec47e752ba291e5b7734e3ef137dfd222daadaca39a9f17bc", + manifest: `{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/octet-stream", + "size": 3210, + "digest": "sha256:5359a4f250650c20227055957e353e8f8a74152f35fe36f00b6b1f9fc19c8861" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 2310272, + "digest": "sha256:fae91920dcd4542f97c9350b3157139a5d901362c2abec284de5ebd1b45b4957" + }, + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 913022, + "digest": "sha256:f384f6ab36adad485192f09379c0b58dc612a3cde82c551e082a7c29a87c95da" + }, + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 9861668, + "digest": "sha256:ed0d2dd5e1a0e5e650a330a864c8a122e9aa91fa6ba9ac6f0bd1882e59df55e7" + }, + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 465, + "digest": "sha256:ec4d00b58417c45f7ddcfde7bcad8c9d62a7d6d5d17cdc1f7d79bcb2e22c1491" + } + ] +}`, + fail: false, + }, + } { + sum := sha256.Sum256([]byte(tt.manifest)) + got := fmt.Sprintf("sha256:%s", hex.EncodeToString(sum[:])) + if tt.digest != got { + t.Errorf("test %d: expected digest %s but got %s", i, tt.digest, got) + } + + manifest := convertFormats(tt.manifest) + r := strings.NewReader(manifest) + err := schema.MediaTypeManifest.Validate(r) + + if got := err != nil; tt.fail != got { + t.Errorf("test %d: expected validation failure %t but got %t, err %v", i, tt.fail, got, err) + } + } +} + +func TestBackwardsCompatibilityConfig(t *testing.T) { + for i, tt := range []struct { + config string + digest string + fail bool + }{ + // config pulled from docker hub blob store + // + // $ TOKEN=$(curl https://auth.docker.io/token\?service\=registry.docker.io\&scope\=repository:library/docker:pull | jq -r .token) + // $ CONFIG_DIGEST=$(curl -H "Authorization: Bearer ${TOKEN}" -H 'Accept: application/vnd.docker.distribution.manifest.v2+json' https://index.docker.io/v2/library/docker/manifests/1.12.1 | jq -r .config.digest) + // $ curl -LH "Authorization: Bearer ${TOKEN}" https://index.docker.io/v2/library/docker/blobs/${CONFIG_DIGEST} + { + digest: "sha256:a059ea7356d5b5a9e0f6352bfa463e7bd4721c2ade3ef168603826e0de6fe54b", + config: `{"architecture":"amd64","config":{"Hostname":"09713501c176","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","DOCKER_BUCKET=get.docker.com","DOCKER_VERSION=1.12.1","DOCKER_SHA256=05ceec7fd937e1416e5dce12b0b6e1c655907d349d52574319a1e875077ccb79"],"Cmd":["sh"],"Image":"sha256:32e2e3ccf2a4fbaa75b078bf539cd5ea2e374a4242665a5ec3f3c01e7a3eefb8","Volumes":null,"WorkingDir":"","Entrypoint":["docker-entrypoint.sh"],"OnBuild":[],"Labels":{}},"container":"15a30be053fb3069a7879b4ea537e84689d8e8e8ba94dc4dd499271506803ba1","container_config":{"Hostname":"09713501c176","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","DOCKER_BUCKET=get.docker.com","DOCKER_VERSION=1.12.1","DOCKER_SHA256=05ceec7fd937e1416e5dce12b0b6e1c655907d349d52574319a1e875077ccb79"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"sh\"]"],"Image":"sha256:32e2e3ccf2a4fbaa75b078bf539cd5ea2e374a4242665a5ec3f3c01e7a3eefb8","Volumes":null,"WorkingDir":"","Entrypoint":["docker-entrypoint.sh"],"OnBuild":[],"Labels":{}},"created":"2016-10-10T23:04:00.821781828Z","docker_version":"1.12.1","history":[{"created":"2016-09-23T16:29:57.276868291Z","created_by":"/bin/sh -c #(nop) ADD file:d6ee3ba7a4d59b161917082cc7242c660c61bb3f3cc1549c7e2dfff2b0de7104 in / "},{"created":"2016-09-23T16:36:54.024611637Z","created_by":"/bin/sh -c apk add --no-cache \t\tca-certificates \t\tcurl \t\topenssl"},{"created":"2016-09-23T16:36:54.365914519Z","created_by":"/bin/sh -c #(nop) ENV DOCKER_BUCKET=get.docker.com","empty_layer":true},{"created":"2016-09-23T16:36:54.662005049Z","created_by":"/bin/sh -c #(nop) ENV DOCKER_VERSION=1.12.1","empty_layer":true},{"created":"2016-09-23T16:36:54.946033025Z","created_by":"/bin/sh -c #(nop) ENV DOCKER_SHA256=05ceec7fd937e1416e5dce12b0b6e1c655907d349d52574319a1e875077ccb79","empty_layer":true},{"created":"2016-09-23T16:36:58.535084011Z","created_by":"/bin/sh -c set -x \t\u0026\u0026 curl -fSL \"https://${DOCKER_BUCKET}/builds/Linux/x86_64/docker-${DOCKER_VERSION}.tgz\" -o docker.tgz \t\u0026\u0026 echo \"${DOCKER_SHA256} *docker.tgz\" | sha256sum -c - \t\u0026\u0026 tar -xzvf docker.tgz \t\u0026\u0026 mv docker/* /usr/local/bin/ \t\u0026\u0026 rmdir docker \t\u0026\u0026 rm docker.tgz \t\u0026\u0026 docker -v"},{"created":"2016-10-10T23:04:00.334158993Z","created_by":"/bin/sh -c #(nop) COPY file:399605dc1850a60a586b5494ab538bad495fd6f94eabca0c5f8a26468ce6030f in /usr/local/bin/ "},{"created":"2016-10-10T23:04:00.577900192Z","created_by":"/bin/sh -c #(nop) ENTRYPOINT [\"docker-entrypoint.sh\"]","empty_layer":true},{"created":"2016-10-10T23:04:00.821781828Z","created_by":"/bin/sh -c #(nop) CMD [\"sh\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:9007f5987db353ec398a223bc5a135c5a9601798ba20a1abba537ea2f8ac765f","sha256:1b06990ff0df8dad281fad7e6e4c5e91f32f8f8c095d6c74cf1e90a6f4407e28","sha256:9d12251ce74aac7619a83641ab72431a8d82e58bcd8a262c2bb0cdb280f1f3b5","sha256:17a7f292c2427adfc75c3a789bab8efec925dc38c5437bf83d2f528013ab80e2"]}}`, + fail: false, + }, + { + // fedora:23 from docker hub + // both Entrypoint and Cmd can be nullable + digest: "sha256:a20665eb1fe2912accb3d5dadaed360430df0d1aa46874875886947d61d3d4ee", + config: `{"architecture":"amd64","author":"Patrick Uiterwijk \u003cpatrick@puiterwijk.org\u003e","config":{"Hostname":"8dfe43d80430","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":null,"Image":"sha256:6986ae504bbf843512d680cc959484452034965db15f75ee8bdd1b107f61500b","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"container":"6249cd2c4b1d6b1bf05903364cbcb95781508994d6407c1564d494e748ea1b41","container_config":{"Hostname":"8dfe43d80430","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ADD file:293a6e463aa402bb8f80eb5cfc937f375cedc6843abaeb9eccfe3923bb3fc80b in /"],"Image":"sha256:6986ae504bbf843512d680cc959484452034965db15f75ee8bdd1b107f61500b","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2016-06-10T18:44:31.784795904Z","docker_version":"1.10.3","history":[{"created":"2016-06-10T18:44:03.360264073Z","author":"Patrick Uiterwijk \u003cpatrick@puiterwijk.org\u003e","created_by":"/bin/sh -c #(nop) MAINTAINER Patrick Uiterwijk \u003cpatrick@puiterwijk.org\u003e","empty_layer":true},{"created":"2016-06-10T18:44:31.784795904Z","author":"Patrick Uiterwijk \u003cpatrick@puiterwijk.org\u003e","created_by":"/bin/sh -c #(nop) ADD file:293a6e463aa402bb8f80eb5cfc937f375cedc6843abaeb9eccfe3923bb3fc80b in /"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:d43f38155a799dc53d8fbb9f3bc11f51805f4027cd5c3d10b9823201cd5b9400"]}}`, + fail: false, + }, + } { + sum := sha256.Sum256([]byte(tt.config)) + got := fmt.Sprintf("sha256:%s", hex.EncodeToString(sum[:])) + if tt.digest != got { + t.Errorf("test %d: expected digest %s but got %s", i, tt.digest, got) + } + + config := convertFormats(tt.config) + r := strings.NewReader(config) + err := schema.MediaTypeImageConfig.Validate(r) + + if got := err != nil; tt.fail != got { + t.Errorf("test %d: expected validation failure %t but got %t, err %v", i, tt.fail, got, err) + } + } +} diff --git a/vendor/github.com/opencontainers/image-spec/schema/manifest_test.go b/vendor/github.com/opencontainers/image-spec/schema/manifest_test.go new file mode 100644 index 0000000..f1cb51d --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/schema/manifest_test.go @@ -0,0 +1,124 @@ +// Copyright 2016 The Linux Foundation +// +// 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 schema_test + +import ( + "strings" + "testing" + + "github.com/opencontainers/image-spec/schema" +) + +func TestManifest(t *testing.T) { + for i, tt := range []struct { + manifest string + fail bool + }{ + // expected failure: mediaType does not match pattern + { + manifest: ` +{ + "schemaVersion": 2, + "mediaType": "invalid" +} +`, + fail: true, + }, + + // expected failure: config.size is a string, expected integer + { + manifest: ` +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "size": "1470", + "digest": "sha256:c86f7763873b6c0aae22d963bab59b4f5debbed6685761b5951584f6efb0633b" + }, + "layers": [] +} +`, + fail: true, + }, + + // expected failure: layers.size is string, expected integer + { + manifest: ` +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "size": 1470, + "digest": "sha256:c86f7763873b6c0aae22d963bab59b4f5debbed6685761b5951584f6efb0633b" + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "size": "675598", + "digest": "sha256:c86f7763873b6c0aae22d963bab59b4f5debbed6685761b5951584f6efb0633b" + } + ] +} +`, + fail: true, + }, + + // valid manifest + { + manifest: ` +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "size": 1470, + "digest": "sha256:c86f7763873b6c0aae22d963bab59b4f5debbed6685761b5951584f6efb0633b" + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "size": 675598, + "digest": "sha256:9d3dd9504c685a304985025df4ed0283e47ac9ffa9bd0326fddf4d59513f0827" + }, + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "size": 156, + "digest": "sha256:2b689805fbd00b2db1df73fae47562faac1a626d5f61744bfe29946ecff5d73d" + }, + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "size": 148, + "digest": "sha256:c57089565e894899735d458f0fd4bb17a0f1e0df8d72da392b85c9b35ee777cd" + } + ], + "annotations": { + "key1": "value1", + "key2": "value2" + } +} +`, + fail: false, + }, + } { + r := strings.NewReader(tt.manifest) + err := schema.MediaTypeManifest.Validate(r) + + if got := err != nil; tt.fail != got { + t.Errorf("test %d: expected validation failure %t but got %t, err %v", i, tt.fail, got, err) + } + } +} diff --git a/vendor/github.com/opencontainers/image-spec/schema/spec_test.go b/vendor/github.com/opencontainers/image-spec/schema/spec_test.go new file mode 100644 index 0000000..2a6f4a4 --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/schema/spec_test.go @@ -0,0 +1,187 @@ +// Copyright 2016 The Linux Foundation +// +// 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 schema_test + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "net/url" + "os" + "strings" + "testing" + + "github.com/opencontainers/image-spec/schema" + "github.com/pkg/errors" + "github.com/russross/blackfriday" +) + +var ( + errFormatInvalid = errors.New("format: invalid") +) + +func TestValidateDescriptor(t *testing.T) { + validate(t, "../descriptor.md") +} + +func TestValidateManifest(t *testing.T) { + validate(t, "../manifest.md") +} + +func TestValidateManifestList(t *testing.T) { + validate(t, "../manifest-list.md") +} + +func TestValidateConfig(t *testing.T) { + validate(t, "../config.md") +} + +// TODO(sur): include examples from all specification files +func validate(t *testing.T, name string) { + m, err := os.Open(name) + if err != nil { + t.Fatal(err) + } + defer m.Close() + + examples, err := extractExamples(m) + if err != nil { + t.Fatal(err) + } + + for _, example := range examples { + if example.Err == errFormatInvalid && example.Mediatype == "" { // ignore + continue + } + + if example.Err != nil { + printFields(t, "error", example.Mediatype, example.Title, example.Err) + t.Error(err) + continue + } + + err = schema.Validator(example.Mediatype).Validate(strings.NewReader(example.Body)) + if err == nil { + printFields(t, "ok", example.Mediatype, example.Title) + t.Log(example.Body, "---") + continue + } + + var errs []error + if verr, ok := errors.Cause(err).(schema.ValidationError); ok { + errs = verr.Errs + } else { + printFields(t, "error", example.Mediatype, example.Title, err) + t.Error(err) + t.Log(example.Body, "---") + continue + } + + for _, err := range errs { + // TOOD(stevvooe): This is nearly useless without file, line no. + printFields(t, "invalid", example.Mediatype, example.Title) + t.Error(err) + fmt.Println(example.Body, "---") + continue + } + } +} + +// renderer allows one to incercept fenced blocks in markdown documents. +type renderer struct { + blackfriday.Renderer + fn func(text []byte, lang string) +} + +func (r *renderer) BlockCode(out *bytes.Buffer, text []byte, lang string) { + r.fn(text, lang) + r.Renderer.BlockCode(out, text, lang) +} + +type example struct { + Lang string // gets raw "lang" field + Title string + Mediatype string + Body string + Err error + + // TODO(stevvooe): Figure out how to keep track of revision, file, line so + // that we can trace back verification output. +} + +// parseExample treats the field as a syntax,attribute tuple separated by a comma. +// Attributes are encoded as a url values. +// +// An example of this is `json,title=Foo%20Bar&mediatype=application/json. We +// get that the "lang" is json, the title is "Foo Bar" and the mediatype is +// "application/json". +// +// This preserves syntax highlighting and lets us tag examples with further +// metadata. +func parseExample(lang, body string) (e example) { + e.Lang = lang + e.Body = body + + parts := strings.SplitN(lang, ",", 2) + if len(parts) < 2 { + e.Err = errFormatInvalid + return + } + + m, err := url.ParseQuery(parts[1]) + if err != nil { + e.Err = err + return + } + + e.Mediatype = m.Get("mediatype") + e.Title = m.Get("title") + return +} + +func extractExamples(rd io.Reader) ([]example, error) { + p, err := ioutil.ReadAll(rd) + if err != nil { + return nil, err + } + + var examples []example + renderer := &renderer{ + Renderer: blackfriday.HtmlRenderer(0, "test test", ""), + fn: func(text []byte, lang string) { + examples = append(examples, parseExample(lang, string(text))) + }, + } + + // just pass over the markdown and ignore the rendered result. We just want + // the side-effect of calling back for each code block. + // TODO(stevvooe): Consider just parsing these with a scanner. It will be + // faster and we can retain file, line no. + blackfriday.MarkdownOptions(p, renderer, blackfriday.Options{ + Extensions: blackfriday.EXTENSION_FENCED_CODE, + }) + + return examples, nil +} + +// printFields prints each value tab separated. +func printFields(t *testing.T, vs ...interface{}) { + var ss []string + for _, f := range vs { + ss = append(ss, fmt.Sprint(f)) + } + t.Log(strings.Join(ss, "\t")) +} diff --git a/vendor/github.com/opencontainers/image-spec/schema/validator.go b/vendor/github.com/opencontainers/image-spec/schema/validator.go index 3c640e7..432e7b9 100644 --- a/vendor/github.com/opencontainers/image-spec/schema/validator.go +++ b/vendor/github.com/opencontainers/image-spec/schema/validator.go @@ -16,10 +16,12 @@ package schema import ( "bytes" + "encoding/json" "fmt" "io" "io/ioutil" + "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "github.com/xeipuuv/gojsonschema" ) @@ -28,6 +30,12 @@ import ( // and implements validation against a JSON schema. type Validator string +type validateDescendantsFunc func(r io.Reader) error + +var mapValidateDescendants = map[Validator]validateDescendantsFunc{ + MediaTypeManifest: validateManifestDescendants, +} + // ValidationError contains all the errors that happened during validation. type ValidationError struct { Errs []error @@ -44,6 +52,16 @@ func (v Validator) Validate(src io.Reader) error { return errors.Wrap(err, "unable to read the document file") } + if f, ok := mapValidateDescendants[v]; ok { + if f == nil { + return fmt.Errorf("internal error: mapValidateDescendents[%q] is nil", v) + } + err = f(bytes.NewReader(buf)) + if err != nil { + return err + } + } + sl := gojsonschema.NewReferenceLoaderFileSystem("file:///"+specs[v], fs) ml := gojsonschema.NewStringLoader(string(buf)) @@ -73,3 +91,29 @@ type unimplemented string func (v unimplemented) Validate(src io.Reader) error { return fmt.Errorf("%s: unimplemented", v) } + +func validateManifestDescendants(r io.Reader) error { + header := v1.Manifest{} + + buf, err := ioutil.ReadAll(r) + if err != nil { + return errors.Wrapf(err, "error reading the io stream") + } + + err = json.Unmarshal(buf, &header) + if err != nil { + return errors.Wrap(err, "manifest format mismatch") + } + + if header.Config.MediaType != string(v1.MediaTypeImageConfig) { + fmt.Printf("warning: config %s has an unknown media type: %s\n", header.Config.Digest, header.Config.MediaType) + } + + for _, layer := range header.Layers { + if layer.MediaType != string(v1.MediaTypeImageLayer) && + layer.MediaType != string(v1.MediaTypeImageLayerNonDistributable) { + fmt.Printf("warning: layer %s has an unknown media type: %s\n", layer.Digest, layer.MediaType) + } + } + return nil +} diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go index ccf3af9..d423836 100644 --- a/vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go +++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go @@ -17,34 +17,34 @@ package v1 // ImageConfig defines the execution parameters which should be used as a base when running a container using an image. type ImageConfig struct { // User defines the username or UID which the process in the container should run as. - User string `json:"User"` + User string `json:"User,omitempty"` // Memory defines the memory limit. - Memory int64 `json:"Memory"` + Memory int64 `json:"Memory,omitempty"` // MemorySwap defines the total memory usage limit (memory + swap). - MemorySwap int64 `json:"MemorySwap"` + MemorySwap int64 `json:"MemorySwap,omitempty"` // CPUShares is the CPU shares (relative weight vs. other containers). - CPUShares int64 `json:"CpuShares"` + CPUShares int64 `json:"CpuShares,omitempty"` // ExposedPorts a set of ports to expose from a container running this image. - ExposedPorts map[string]struct{} `json:"ExposedPorts"` + ExposedPorts map[string]struct{} `json:"ExposedPorts,omitempty"` // Env is a list of environment variables to be used in a container. - Env []string `json:"Env"` + Env []string `json:"Env,omitempty"` // Entrypoint defines a list of arguments to use as the command to execute when the container starts. - Entrypoint []string `json:"Entrypoint"` + Entrypoint []string `json:"Entrypoint,omitempty"` // Cmd defines the default arguments to the entrypoint of the container. - Cmd []string `json:"Cmd"` + Cmd []string `json:"Cmd,omitempty"` // Volumes is a set of directories which should be created as data volumes in a container running this image. - Volumes map[string]struct{} `json:"Volumes"` + Volumes map[string]struct{} `json:"Volumes,omitempty"` // WorkingDir sets the current working directory of the entrypoint process in the container. - WorkingDir string `json:"WorkingDir"` + WorkingDir string `json:"WorkingDir,omitempty"` } // RootFS describes a layer content addresses @@ -59,28 +59,28 @@ type RootFS struct { // History describes the history of a layer. type History struct { // Created is the creation time. - Created string `json:"created"` + Created string `json:"created,omitempty"` // CreatedBy is the command which created the layer. - CreatedBy string `json:"created_by"` + CreatedBy string `json:"created_by,omitempty"` // Author is the author of the build point. - Author string `json:"author"` + Author string `json:"author,omitempty"` // Comment is a custom message set when creating the layer. - Comment string `json:"comment"` + Comment string `json:"comment,omitempty"` // EmptyLayer is used to mark if the history item created a filesystem diff. - EmptyLayer bool `json:"empty_layer"` + EmptyLayer bool `json:"empty_layer,omitempty"` } // Image is the JSON structure which describes some basic information about the image. type Image struct { // Created defines an ISO-8601 formatted combined date and time at which the image was created. - Created string `json:"created"` + Created string `json:"created,omitempty"` // Author defines the name and/or email address of the person or entity which created and is responsible for maintaining the image. - Author string `json:"author"` + Author string `json:"author,omitempty"` // Architecture is the CPU architecture which the binaries in this image are built to run on. Architecture string `json:"architecture"` @@ -89,11 +89,11 @@ type Image struct { OS string `json:"os"` // Config defines the execution parameters which should be used as a base when running a container using the image. - Config ImageConfig `json:"config"` + Config ImageConfig `json:"config,omitempty"` // RootFS references the layer content addresses used by the image. RootFS RootFS `json:"rootfs"` // History describes the history of each layer. - History []History `json:"history"` + History []History `json:"history,omitempty"` } diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/descriptor.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/descriptor.go similarity index 88% rename from vendor/github.com/opencontainers/image-spec/specs-go/descriptor.go rename to vendor/github.com/opencontainers/image-spec/specs-go/v1/descriptor.go index 7a20655..83dde96 100644 --- a/vendor/github.com/opencontainers/image-spec/specs-go/descriptor.go +++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/descriptor.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package specs +package v1 // Descriptor describes the disposition of targeted content. type Descriptor struct { @@ -24,4 +24,7 @@ type Descriptor struct { // Size specifies the size in bytes of the blob. Size int64 `json:"size"` + + // URLs specifies a list of URLs from which this object MAY be downloaded + URLs []string `json:"urls,omitempty"` } diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/layout.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/layout.go new file mode 100644 index 0000000..a54a461 --- /dev/null +++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/layout.go @@ -0,0 +1,21 @@ +// Copyright 2016 The Linux Foundation +// +// 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 v1 + +// ImageLayout is the structure in the "oci-layout" file, found in the root +// of an OCI Image-layout directory. +type ImageLayout struct { + Version string `json:"imageLayoutVersion"` +} diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest.go index 10bde08..7d16043 100644 --- a/vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest.go +++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest.go @@ -22,11 +22,11 @@ type Manifest struct { // Config references a configuration object for a container, by digest. // The referenced configuration object is a JSON blob that the runtime uses to set up the container. - Config specs.Descriptor `json:"config"` + Config Descriptor `json:"config"` // Layers is an indexed list of layers referenced by the manifest. - Layers []specs.Descriptor `json:"layers"` + Layers []Descriptor `json:"layers"` // Annotations contains arbitrary metadata for the manifest list. - Annotations map[string]string `json:"annotations"` + Annotations map[string]string `json:"annotations,omitempty"` } diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest_list.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest_list.go index 8c02ee2..d127ab6 100644 --- a/vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest_list.go +++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest_list.go @@ -44,7 +44,7 @@ type Platform struct { // ManifestDescriptor describes a platform specific manifest. type ManifestDescriptor struct { - specs.Descriptor + Descriptor // Platform describes the platform which the image in the manifest runs on. Platform Platform `json:"platform"` @@ -58,5 +58,5 @@ type ManifestList struct { Manifests []ManifestDescriptor `json:"manifests"` // Annotations contains arbitrary metadata for the manifest list. - Annotations map[string]string `json:"annotations"` + Annotations map[string]string `json:"annotations,omitempty"` } diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go index 90199dd..d6592f5 100644 --- a/vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go +++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go @@ -25,11 +25,11 @@ const ( MediaTypeImageManifestList = "application/vnd.oci.image.manifest.list.v1+json" // MediaTypeImageLayer is the media type used for layers referenced by the manifest. - MediaTypeImageLayer = "application/vnd.oci.image.layer.tar+gzip" + MediaTypeImageLayer = "application/vnd.oci.image.layer.v1.tar+gzip" // MediaTypeImageLayerNonDistributable is the media type for layers referenced by // the manifest but with distribution restrictions. - MediaTypeImageLayerNonDistributable = "application/vnd.oci.image.layer.nondistributable.tar+gzip" + MediaTypeImageLayerNonDistributable = "application/vnd.oci.image.layer.nondistributable.v1.tar+gzip" // MediaTypeImageConfig specifies the media type for the image configuration. MediaTypeImageConfig = "application/vnd.oci.image.config.v1+json" diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/version.go b/vendor/github.com/opencontainers/image-spec/specs-go/version.go index 7770429..48df9ac 100644 --- a/vendor/github.com/opencontainers/image-spec/specs-go/version.go +++ b/vendor/github.com/opencontainers/image-spec/specs-go/version.go @@ -18,14 +18,14 @@ import "fmt" const ( // VersionMajor is for an API incompatible changes - VersionMajor = 0 + VersionMajor = 1 // VersionMinor is for functionality in a backwards-compatible manner - VersionMinor = 3 + VersionMinor = 0 // VersionPatch is for backwards-compatible bug fixes VersionPatch = 0 // VersionDev indicates development branch. Releases will be empty string. - VersionDev = "-dev" + VersionDev = "-rc2-dev" ) // Version is the specification version that the package types support. diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/versioned.go b/vendor/github.com/opencontainers/image-spec/specs-go/versioned.go index ca0bd41..d01a1a8 100644 --- a/vendor/github.com/opencontainers/image-spec/specs-go/versioned.go +++ b/vendor/github.com/opencontainers/image-spec/specs-go/versioned.go @@ -22,5 +22,5 @@ type Versioned struct { SchemaVersion int `json:"schemaVersion"` // MediaType is the media type of this schema. - MediaType string `json:"mediaType,omitempty"` + MediaType string `json:"mediaType"` } diff --git a/vendor/vendor.json b/vendor/vendor.json new file mode 100644 index 0000000..d9ed7d7 --- /dev/null +++ b/vendor/vendor.json @@ -0,0 +1,28 @@ +{ + "comment": "", + "ignore": "", + "package": [ + { + "checksumSHA1": "DeZix5Yc300bYfELeYJi4HVfLRw=", + "origin": "github.com/opencontainers/image-tools/vendor/github.com/opencontainers/image-spec/schema", + "path": "github.com/opencontainers/image-spec/schema", + "revision": "dda124e315cb08f68ccbb1c30810634019268258", + "revisionTime": "2016-11-07T08:57:11Z" + }, + { + "checksumSHA1": "BZp8hLZMjS0KNXsyO+QKl3BGPUw=", + "origin": "github.com/opencontainers/image-tools/vendor/github.com/opencontainers/image-spec/specs-go", + "path": "github.com/opencontainers/image-spec/specs-go", + "revision": "dda124e315cb08f68ccbb1c30810634019268258", + "revisionTime": "2016-11-07T08:57:11Z" + }, + { + "checksumSHA1": "vmsyC1PQY3HIGNYI/NtPQWpV8so=", + "origin": "github.com/opencontainers/image-tools/vendor/github.com/opencontainers/image-spec/specs-go/v1", + "path": "github.com/opencontainers/image-spec/specs-go/v1", + "revision": "dda124e315cb08f68ccbb1c30810634019268258", + "revisionTime": "2016-11-07T08:57:11Z" + } + ], + "rootPath": "github.com/opencontainers/image-tools" +}