From b04b320be1590b7577adae0da27ebc1ed7b45d9e Mon Sep 17 00:00:00 2001 From: nisha Date: Mon, 25 Jul 2022 13:04:57 -0700 Subject: [PATCH] Working Group Proposal for Reference Types This is a culmination of many people's work over the last few months to introduce reference types to OCI as part of the [OCI Reference Types WG](oci-ref-type-wg). This PR contains the changes from our chosen proposal, [Proposal E][proposal-e]. [oci-ref-type-wg]: https://github.com/opencontainers/tob/blob/main/proposals/wg-reference-types.md [proposal-e]: https://github.com/opencontainers/wg-reference-types/blob/main/docs/proposals/PROPOSAL_E.md Co-authored-by: nisha Co-authored-by: Josh Dolitsky <393494+jdolitsky@users.noreply.github.com> Co-authored-by: Sajay Antony Co-authored-by: Lachlan Evenson Co-authored-by: Michael Brown Signed-off-by: Brandon Mitchell --- annotations.md | 10 ++++-- artifact.md | 74 ++++++++++++++++++++++++++++++++++++++ descriptor.md | 39 +++++++++++++++----- image-index.md | 36 +++++++++++++++++++ manifest.md | 10 ++++++ media-types.md | 1 + specs-go/v1/annotations.go | 9 +++++ specs-go/v1/artifact.go | 34 ++++++++++++++++++ specs-go/v1/descriptor.go | 5 ++- specs-go/v1/manifest.go | 5 ++- specs-go/v1/mediatype.go | 3 ++ 11 files changed, 214 insertions(+), 12 deletions(-) create mode 100644 artifact.md create mode 100644 specs-go/v1/artifact.go diff --git a/annotations.md b/annotations.md index 8bf2d7a4d..d9c808b39 100644 --- a/annotations.md +++ b/annotations.md @@ -16,8 +16,11 @@ This property contains arbitrary metadata. ## Pre-Defined Annotation Keys -This specification defines the following annotation keys, intended for but not limited to [image index](image-index.md) and image [manifest](manifest.md) authors: -* **org.opencontainers.image.created** date and time on which the image was built (string, date-time as defined by [RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6)). +This specification defines the following annotation keys, intended for but not limited to [image index](image-index.md), image [manifest](manifest.md), [artifact](artifact.md), and [descriptor](descriptor.md) authors. + +* **org.opencontainers.artifact.created** date and time on which the artifact was built, conforming to [RFC 3339][rfc3339]. +* **org.opencontainers.artifact.description**: human readable description for the artifact (string) +* **org.opencontainers.image.created** date and time on which the image was built, conforming to [RFC 3339][rfc3339]. * **org.opencontainers.image.authors** contact details of the people or organization responsible for the image (freeform string) * **org.opencontainers.image.url** URL to find more information on the image (string) * **org.opencontainers.image.documentation** URL to get documentation on the image (string) @@ -49,6 +52,7 @@ This specification defines the following annotation keys, intended for but not l * This SHOULD be the immediate image sharing zero-indexed layers with the image, such as from a Dockerfile `FROM` statement. * This SHOULD NOT reference any other images used to generate the contents of the image (e.g., multi-stage Dockerfile builds). * If the `image.base.name` annotation is specified, the `image.base.digest` annotation SHOULD be the digest of the manifest referenced by the `image.ref.name` annotation. +* **org.opencontainers.referrers.filtersApplied** Comma separated list of filters applied by the registry in the [referrers listing](https://github.com/opencontainers/distribution-spec/blob/main/spec.md#listing-referrers) (string) ## Back-compatibility with Label Schema @@ -74,3 +78,5 @@ While users are encouraged to use the **org.opencontainers.image** keys, tools M | | `docker.*`, `rkt.*` | No equivalent in the OCI Image Spec | [spdx-license-expression]: https://spdx.org/spdx-specification-21-web-version#h.jxpfx0ykyb60 + +[rfc3339]: https://tools.ietf.org/html/rfc3339#section-5.6 diff --git a/artifact.md b/artifact.md new file mode 100644 index 000000000..e85004982 --- /dev/null +++ b/artifact.md @@ -0,0 +1,74 @@ +# OCI Artifact Manifest Specification + +The goal of the Artifact Manifest Specification is to define content addressable artifacts in order to store them along side container images in a registry. +Like [OCI Images](manifest.md), OCI Artifacts may be referenced by the hash of their manifest. +Unlike OCI Images, OCI Artifacts are not meant to be used by any container runtime. + +Examples of artifacts that may be stored along with container images are Software Bill of Materials (SBOM), Digital Signatures, Provenance data, Supply Chain Attestations, scan results, and Helm charts. + +This section defines the `application/vnd.oci.artifact.manifest.v1+json` [media type](media-types.md). +For the media type(s) that this is compatible with see the [matrix](media-types.md#compatibility-matrix). + +# Artifact Manifest + +## *Artifact Manifest* Property Descriptions + +- **`mediaType`** *string* + + This property MUST be used and contain the media type `application/vnd.oci.artifact.manifest.v1+json`. + +- **`artifactType`** *string* + + This property SHOULD be used and contain the mediaType of the referenced artifact. + If defined, the value MUST comply with [RFC 6838][rfc6838], including the [naming requirements in its section 4.2][rfc6838-s4.2], and MAY be registered with [IANA][iana]. + +- **`blobs`** *array of objects* + + This OPTIONAL property is an array of objects and each item in the array MUST be a [descriptor](descriptor.md). + Each descriptor represents an artifact of any IANA mediaType. + The list MAY be ordered for certain artifact types like scan results. + +- **`refers`** *[descriptor](descriptor.md)* + + This OPTIONAL property specifies a [descriptor](descriptor.md) of another manifest. + This value, used by the [`referrers` API](https://github.com/opencontainers/distribution-spec/blob/main/spec.md#listing-referrers), indicates a relationship to the specified manifest. + +- **`annotations`** *string-string map* + + This OPTIONAL property contains additional metadata for the artifact manifest. + This OPTIONAL property MUST use the [annotation rules](annotations.md#rules). + + See [Pre-Defined Annotation Keys](annotations.md#pre-defined-annotation-keys). + + Annotations MAY be used to filter the response from the [`referrers` API](https://github.com/opencontainers/distribution-spec/blob/main/spec.md#listing-referrers). + +## Examples + +*Example showing an artifact manifest for an example SBOM referencing an image:* + +```jsonc,title=Manifest&mediatype=application/vnd.oci.artifact.manifest.v1%2Bjson +{ + "mediaType": "application/vnd.oci.artifact.manifest.v1+json", + "artifactType": "application/vnd.example.sbom.v1" + "blobs": [ + { + "mediaType": "application/gzip", + "size": 123, + "digest": "sha256:87923725d74f4bfb94c9e86d64170f7521aad8221a5de834851470ca142da630" + } + ], + "refers": { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "size": 1234, + "digest": "sha256:cc06a2839488b8bd2a2b99dcdc03d5cfd818eed72ad08ef3cc197aac64c0d0a0" + }, + "annotations": { + "org.opencontainers.artifact.created": "2022-01-01T14:42:55Z", + "org.example.sbom.format": "json" + } +} +``` + +[iana]: https://www.iana.org/assignments/media-types/media-types.xhtml +[rfc6838]: https://tools.ietf.org/html/rfc6838 +[rfc6838-s4.2]: https://tools.ietf.org/html/rfc6838#section-4.2 diff --git a/descriptor.md b/descriptor.md index e8ca10326..1610f3038 100644 --- a/descriptor.md +++ b/descriptor.md @@ -1,11 +1,12 @@ # OCI Content Descriptors -* An OCI image consists of several different components, arranged in a [Merkle Directed Acyclic Graph (DAG)](https://en.wikipedia.org/wiki/Merkle_tree). -* References between components in the graph are expressed through _Content Descriptors_. -* A Content Descriptor (or simply _Descriptor_) describes the disposition of the targeted content. -* A Content Descriptor includes the type of the content, a content identifier (_digest_), and the byte-size of the raw content. -* Descriptors SHOULD be embedded in other formats to securely reference external content. -* Other formats SHOULD use descriptors to securely reference external content. +- An OCI image consists of several different components, arranged in a [Merkle Directed Acyclic Graph (DAG)](https://en.wikipedia.org/wiki/Merkle_tree). +- References between components in the graph are expressed through _Content Descriptors_. +- A Content Descriptor (or simply _Descriptor_) describes the disposition of the targeted content. +- A Content Descriptor includes the type of the content, a content identifier (_digest_), and the byte-size of the raw content. + Optionally, it includes the type of artifact it is describing. +- Descriptors SHOULD be embedded in other formats to securely reference external content. +- Other formats SHOULD use descriptors to securely reference external content. This section defines the `application/vnd.oci.descriptor.v1+json` [media type](media-types.md). @@ -51,8 +52,16 @@ The following fields contain the primary properties that constitute a Descriptor The decoded data MUST be identical to the referenced content and SHOULD be verified against the [`digest`](#digests) and `size` fields by content consumers. See [Embedded Content](#embedded-content) for when this is appropriate. +- **`artifactType`** *string* + + This OPTIONAL property contains the type of an artifact when the descriptor points to an artifact. + This is the value of `artifactType` when the descriptor references an [artifact manifest](artifact.md). + This is the value of the config descriptor `mediaType` when the descriptor references an [image manifest](manifest.md). + Descriptors pointing to [`application/vnd.oci.image.manifest.v1+json`](manifest.md) SHOULD include the extended field `platform`, see [Image Index Property Descriptions](image-index.md#image-index-property-descriptions) for details. +Descriptors pointing to [`application/vnd.oci.artifact.manifest.v1+json`](artifact.md) SHOULD include the extended field `artifactType`. + ### Reserved Extended _Descriptor_ field additions proposed in other OCI specifications SHOULD first be considered for addition into this specification. @@ -68,7 +77,7 @@ The _algorithm_ specifies the cryptographic hash function and encoding used for A digest string MUST match the following [grammar](considerations.md#ebnf): -``` +```ebnf digest ::= algorithm ":" encoded algorithm ::= algorithm-component (algorithm-separator algorithm-component)* algorithm-component ::= [a-z0-9]+ @@ -104,12 +113,14 @@ Implementations MAY employ [canonicalization](considerations.md#canonicalization ### Digest calculations A _digest_ is calculated by the following pseudo-code, where `H` is the selected hash algorithm, identified by string ``: -``` + +```text let ID(C) = Descriptor.digest let C = let D = ':' + Encode(H(C)) let verified = ID(C) == D ``` + Above, we define the content identifier as `ID(C)`, extracted from the `Descriptor.digest` field. Content `C` is a string of bytes. Function `H` returns the hash of `C` in bytes and is passed to function `Encode` and prefixed with the algorithm to obtain the digest. @@ -190,6 +201,17 @@ In the following example, the descriptor indicates that the referenced manifest } ``` +In the following example, the descriptor indicates the type of artifact it is referencing: + +```json,title=Content%20Descriptor&mediatype=application/vnd.oci.descriptor.v1%2Bjson +{ + "mediaType": "application/vnd.oci.artifact.manifest.v1+json", + "size": 123, + "digest": "sha256:87923725d74f4bfb94c9e86d64170f7521aad8221a5de834851470ca142da630", + "artifactType": "application/vnd.example.sbom.v1" +} +``` + [rfc3986]: https://tools.ietf.org/html/rfc3986 [rfc4634-s4.1]: https://tools.ietf.org/html/rfc4634#section-4.1 [rfc4634-s4.2]: https://tools.ietf.org/html/rfc4634#section-4.2 @@ -198,3 +220,4 @@ In the following example, the descriptor indicates that the referenced manifest [rfc6838-s4.2]: https://tools.ietf.org/html/rfc6838#section-4.2 [rfc7230-s2.7]: https://tools.ietf.org/html/rfc7230#section-2.7 [sha256-vs-sha512]: https://groups.google.com/a/opencontainers.org/forum/#!topic/dev/hsMw7cAwrZE +[iana]: https://www.iana.org/assignments/media-types/media-types.xhtml diff --git a/image-index.md b/image-index.md index ab3dc4e9c..9001472f5 100644 --- a/image-index.md +++ b/image-index.md @@ -35,6 +35,7 @@ For the media type(s) that this document is compatible with, see the [matrix][ma Implementations MUST support at least the following media types: - [`application/vnd.oci.image.manifest.v1+json`](manifest.md) + - [`application/vnd.oci.artifact.manifest.v1+json`](artifact.md) Also, implementations SHOULD support the following media types: @@ -137,5 +138,40 @@ When the variant of the CPU is not listed in the table, values are implementatio } ``` +## Example Image Index with multiple media types + +*Example showing an image index pointing to manifests with multiple media types:* +```json,title=Image%20Index&mediatype=application/vnd.oci.image.index.v1%2Bjson +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.index.v1+json", + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "size": 7143, + "digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f", + "platform": { + "architecture": "ppc64le", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.oci.artifact.manifest.v1+json", + "size": 7682, + "digest": "sha256:601570aaff1b68a61eb9c85b8beca1644e698003e0cdb5bce960f193d265a8b7", + "artifactType": "application/example", + "annotations": { + "com.example.artifactKey1": "value1", + "com.example.artifactKey2": "value2" + } + } + ], + "annotations": { + "com.example.key1": "value1", + "com.example.key2": "value2" + } +} +``` + [go-environment2]: https://golang.org/doc/install/source#environment [matrix]: media-types.md#compatibility-matrix diff --git a/manifest.md b/manifest.md index 29b8b1af7..7e17fa28e 100644 --- a/manifest.md +++ b/manifest.md @@ -65,6 +65,11 @@ Unlike the [image index](image-index.md), which contains information about a set Entries in this field will frequently use the `+gzip` types. +- **`refers`** *[descriptor](descriptor.md)* + + This OPTIONAL property specifies a [descriptor](descriptor.md) of another manifest. + This value, used by the [`referrers` API](https://github.com/opencontainers/distribution-spec/blob/main/spec.md#listing-referrers), indicates a relationship to the specified manifest. + - **`annotations`** *string-string map* This OPTIONAL property contains arbitrary metadata for the image manifest. @@ -101,6 +106,11 @@ Unlike the [image index](image-index.md), which contains information about a set "digest": "sha256:ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736" } ], + "refers": { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "size": 7682, + "digest": "sha256:5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270" + }, "annotations": { "com.example.key1": "value1", "com.example.key2": "value2" diff --git a/media-types.md b/media-types.md index aa0b464b3..e0d324a6a 100644 --- a/media-types.md +++ b/media-types.md @@ -13,6 +13,7 @@ The following media types identify the formats described here and their referenc - `application/vnd.oci.image.layer.nondistributable.v1.tar`: ["Layer", as a tar archive with distribution restrictions](layer.md#non-distributable-layers) - `application/vnd.oci.image.layer.nondistributable.v1.tar+gzip`: ["Layer", as a tar archive with distribution restrictions](layer.md#gzip-media-types) compressed with [gzip][rfc1952] - `application/vnd.oci.image.layer.nondistributable.v1.tar+zstd`: ["Layer", as a tar archive with distribution restrictions](layer.md#zstd-media-types) compressed with [zstd][rfc8478] +- `application/vnd.oci.artifact.manifest.v1+json`: [Artifact manifest](artifact.md) ## Media Type Conflicts diff --git a/specs-go/v1/annotations.go b/specs-go/v1/annotations.go index 581cf7cdf..6f9e6fd3a 100644 --- a/specs-go/v1/annotations.go +++ b/specs-go/v1/annotations.go @@ -59,4 +59,13 @@ const ( // AnnotationBaseImageName is the annotation key for the image reference of the image's base image. AnnotationBaseImageName = "org.opencontainers.image.base.name" + + // AnnotationArtifactCreated is the annotation key for the date and time on which the artifact was built, conforming to RFC 3339. + AnnotationArtifactCreated = "org.opencontainers.artifact.created" + + // AnnotationArtifactDescription is the annotation key for the human readable description for the artifact. + AnnotationArtifactDescription = "org.opencontainers.artifact.description" + + // AnnotationReferrersFiltersApplied is the annotation key for the comma separated list of filters applied by the registry in the referrers listing. + AnnotationReferrersFiltersApplied = "org.opencontainers.referrers.filtersApplied" ) diff --git a/specs-go/v1/artifact.go b/specs-go/v1/artifact.go new file mode 100644 index 000000000..2a18ce106 --- /dev/null +++ b/specs-go/v1/artifact.go @@ -0,0 +1,34 @@ +// Copyright 2022 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 + +// Artifact describes an artifact manifest. +// This structure provides `application/vnd.oci.artifact.manifest.v1+json` mediatype when marshalled to JSON. +type Artifact struct { + // MediaType is the media type of the object this schema refers to. + MediaType string `json:"mediaType"` + + // ArtifactType is the IANA media type of the artifact this schema refers to. + ArtifactType string `json:"artifactType"` + + // Blobs is a collection of blobs referenced by this manifest. + Blobs []Descriptor `json:"blobs,omitempty"` + + // Refers is an optional link to any existing manifest within the repository. + Refers *Descriptor `json:"refers,omitempty"` + + // Annotations contains arbitrary metadata for the artifact manifest. + Annotations map[string]string `json:"annotations,omitempty"` +} diff --git a/specs-go/v1/descriptor.go b/specs-go/v1/descriptor.go index 94f19be62..9654aa5af 100644 --- a/specs-go/v1/descriptor.go +++ b/specs-go/v1/descriptor.go @@ -1,4 +1,4 @@ -// Copyright 2016 The Linux Foundation +// Copyright 2016-2022 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. @@ -44,6 +44,9 @@ type Descriptor struct { // // This should only be used when referring to a manifest. Platform *Platform `json:"platform,omitempty"` + + // ArtifactType is the IANA media type of this artifact. + ArtifactType string `json:"artifactType,omitempty"` } // Platform describes the platform which the image in the manifest runs on. diff --git a/specs-go/v1/manifest.go b/specs-go/v1/manifest.go index 8212d520c..7f2df9863 100644 --- a/specs-go/v1/manifest.go +++ b/specs-go/v1/manifest.go @@ -1,4 +1,4 @@ -// Copyright 2016 The Linux Foundation +// Copyright 2016-2022 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. @@ -30,6 +30,9 @@ type Manifest struct { // Layers is an indexed list of layers referenced by the manifest. Layers []Descriptor `json:"layers"` + // Refers is an optional link to any existing manifest within the repository. + Refers *Descriptor `json:"refers,omitempty"` + // Annotations contains arbitrary metadata for the image manifest. Annotations map[string]string `json:"annotations,omitempty"` } diff --git a/specs-go/v1/mediatype.go b/specs-go/v1/mediatype.go index 4f35ac134..935b481e3 100644 --- a/specs-go/v1/mediatype.go +++ b/specs-go/v1/mediatype.go @@ -54,4 +54,7 @@ const ( // MediaTypeImageConfig specifies the media type for the image configuration. MediaTypeImageConfig = "application/vnd.oci.image.config.v1+json" + + // MediaTypeArtifactManifest specifies the media type for a content descriptor. + MediaTypeArtifactManifest = "application/vnd.oci.artifact.manifest.v1+json" )