Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define image manifest artifactType and guidance #1043

Merged
merged 1 commit into from
Apr 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 90 additions & 3 deletions manifest.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ Unlike the [image index](image-index.md), which contains information about a set
When used, this field MUST contain the media type `application/vnd.oci.image.manifest.v1+json`.
This field usage differs from the [descriptor](descriptor.md#properties) use of `mediaType`.

- **`artifactType`** *string*

This OPTIONAL property contains the type of an artifact when the manifest is used for an artifact.
This MUST be set when `config.mediaType` is set to the [scratch value](#example-of-a-scratch-config-or-layer-descriptor).
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].

- **`config`** *[descriptor](descriptor.md)*

This REQUIRED property references a configuration object for a container, by digest.
Expand All @@ -38,7 +44,8 @@ Unlike the [image index](image-index.md), which contains information about a set

- [`application/vnd.oci.image.config.v1+json`](config.md)

Manifests concerned with portability SHOULD use one of the above media types.
Manifests for container images concerned with portability SHOULD use one of the above media types.
Manifests for artifacts concerned with portability SHOULD use `config.mediaType` as described in [Guidelines for Artifact Usage](#guidelines-for-artifact-usage).

If the manifest uses a different media type than the above, it 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].

Expand Down Expand Up @@ -78,6 +85,8 @@ Unlike the [image index](image-index.md), which contains information about a set

If the manifest uses a different media type than the above, it 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].

See [Guidelines for Artifact Usage](#guidelines-for-artifact-usage) for other uses of the `layers`.

- **`subject`** *[descriptor](descriptor.md)*

This OPTIONAL property specifies a [descriptor](descriptor.md) of another manifest.
Expand Down Expand Up @@ -133,16 +142,94 @@ Unlike the [image index](image-index.md), which contains information about a set

## Example of a SCRATCH config or layer descriptor

Notice that the `mediaType` is subject to the usage or context, while the digest is specifically defined as `ScratchDigestSHA256`
Notice that the `mediaType` is subject to the usage or context, while the digest is specifically defined as `ScratchDigestSHA256`.
When the `ScratchDigestSHA256` is used, the media type SHOULD be set to `application/vnd.oci.scratch.v1+json` to differentiate the descriptor from one pointing to content.

```json,title=SCRATCH%20config&mediatype=application/vnd.oci.descriptor.v1%2Bjson
{
"mediaType": "application/vnd.oci.example+json",
"mediaType": "application/vnd.oci.scratch.v1+json",
"size": 2,
"digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a"
}
```

## Guidelines for Artifact Usage
sudo-bmitch marked this conversation as resolved.
Show resolved Hide resolved

Content other than OCI container images MAY be packaged using the image manifest.
When this is done, the `config.mediaType` value MUST be set to a value specific to the artifact type or the [scratch value](#example-of-a-scratch-config-or-layer-descriptor).
If the `config.mediaType` is set to the scratch value, the `artifactType` MUST be defined.
If the artifact does not need layers, a single layer SHOULD be included with a non-zero size.
Comment on lines +159 to +161
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure if it was part of the discussion I missed (but even if so, I think the explanation should stand here alone): why would I choose to use scratch+artifactType, rather than just setting config.mediaType to whatever specific value I want to use?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect any artifact producing implementation that doesn't need or want a config will use a scratch manifest.

Suppose you just want to upload an SBOM, or a cat gif (image/gif). What do you put in config.mediaType?

If you chose image/gif, some implementations might try to render the config as a gif, or save it as a .gif file on download, etc. The config descriptor however won't point to a gif blob, it'll point to {} and the first layer will be the image/gif.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonboulle the issue that was raised is the config.mediaType must reference the content of the config.digest blob according to the descriptor spec. By using that for artifacts that do not have a dedicated config blob, we have a mismatch between the media type of the blob and the artifactType of the artifact.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I might have asked the question backwards :)
In what circumstance would I set config.mediaType to something other than scratch or an actual (``application/vnd.oci.image.config.v1+json`) config? Is there a use case there we really need to support?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are actual configs that are not application/vnd.oci.image.config.v1+json, e.g. Helm charts and Singularity images. These use cases are following the guidance at https://github.com/opencontainers/artifacts/blob/main/artifact-authors.md. My goal was to avoid breaking those existing artifacts unless there's a strong need to do so.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that's the exact reference that was missing for me. I will think about it for another moment; I would rather it's captured more explicitly here

The suggested content for an unused layer is the [SCRATCH](#example-of-a-scratch-config-or-layer-descriptor) descriptor.

Here is an example manifest for a typical artifact:

```json,title=Artifact%20with%20config&mediatype=application/vnd.oci.image.manifest.v1%2Bjson
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we add artifactType here..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When config.mediaType is defined to something other than scratch, artifactType is optional.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be slightly prescriptive about best practices, should we say that non-image artifacts SHOULD use an artifactType with the scratch config?

Not a MUST.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AaronFriel I'm open to it, but in case there are other opinions, how about we make that a separate PR. Would you like to lead that?

"config": {
"mediaType": "application/vnd.example.config.v1+json",
"digest": "sha256:5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03",
"size": 123
},
"layers": [
{
"mediaType": "application/vnd.example.data.v1.tar+gzip",
"digest": "sha256:e258d248fda94c63753607f7c4494ee0fcbe92f1a76bfdac795c9d84101eb317",
"size": 1234
}
]
}
```

Here is an example manifest for a simple artifact without content in the config, using the scratch descriptor:

```json,title=Artifact%20without%20config&mediatype=application/vnd.oci.image.manifest.v1%2Bjson
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"artifactType": "application/vnd.example+type",
"config": {
"mediaType": "application/vnd.oci.scratch.v1+json",
"digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"size": 2
},
"layers": [
{
"mediaType": "application/vnd.example+type",
"digest": "sha256:e258d248fda94c63753607f7c4494ee0fcbe92f1a76bfdac795c9d84101eb317",
"size": 1234
}
]
}
```

Here is an example manifest for an artifact with only annotations set, and the content of both blobs set to the scratch descriptor:

```json,title=Minimal%20artifact&mediatype=application/vnd.oci.image.manifest.v1%2Bjson
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"artifactType": "application/vnd.example+type",
"config": {
"mediaType": "application/vnd.oci.scratch.v1+json",
"digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"size": 2
},
"layers": [
{
"mediaType": "application/vnd.oci.scratch.v1+json",
"digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"size": 2
}
],
"annotations": {
"oci.opencontainers.image.created": "2023-01-02T03:04:05Z",
"com.example.data": "payload"
}
}
```

[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
1 change: 1 addition & 0 deletions media-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ The following media types identify the formats described here and their referenc
- `application/vnd.oci.image.layer.v1.tar`: ["Layer", as a tar archive](layer.md)
- `application/vnd.oci.image.layer.v1.tar+gzip`: ["Layer", as a tar archive](layer.md#gzip-media-types) compressed with [gzip][rfc1952]
- `application/vnd.oci.image.layer.v1.tar+zstd`: ["Layer", as a tar archive](layer.md#zstd-media-types) compressed with [zstd][rfc8478]
- `application/vnd.oci.scratch.v1+json`: [Scratch blob](manifest.md#example-of-a-scratch-config-or-layer-descriptor)
- `application/vnd.oci.artifact.manifest.v1+json`: [Artifact manifest](artifact.md)

The following media types identify a ["Layer" with distribution restrictions](layer.md#non-distributable-layers), but are **deprecated** and not recommended for future use:
Expand Down
4 changes: 4 additions & 0 deletions schema/image-manifest-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
"description": "the mediatype of the referenced object",
"$ref": "defs-descriptor.json#/definitions/mediaType"
},
"artifactType": {
"description": "the artifact mediatype of the referenced object",
"$ref": "defs-descriptor.json#/definitions/mediaType"
},
"config": {
"$ref": "content-descriptor.json"
},
Expand Down
47 changes: 47 additions & 0 deletions schema/manifest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,53 @@ func TestManifest(t *testing.T) {
`,
fail: true,
},

// valid manifest for an artifact with a dedicated config
{
manifest: `
{
"schemaVersion": 2,
"mediaType" : "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.example.config+json",
"size": 1470,
"digest": "sha256:c86f7763873b6c0aae22d963bab59b4f5debbed6685761b5951584f6efb0633b"
},
"layers": [
{
"mediaType": "application/vnd.example.data+type",
"size": 675598,
"digest": "sha256:9d3dd9504c685a304985025df4ed0283e47ac9ffa9bd0326fddf4d59513f0827"
}
]
}
`,
fail: false,
},

// valid manifest for an artifact using the scratch config and artifactType
{
manifest: `
{
"schemaVersion": 2,
"mediaType" : "application/vnd.oci.image.manifest.v1+json",
"artifactType": "application/vnd.example+type",
"config": {
"mediaType": "application/vnd.oci.scratch.v1+json",
"size": 2,
"digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a"
},
"layers": [
{
"mediaType": "application/vnd.example+type",
"size": 675598,
"digest": "sha256:9d3dd9504c685a304985025df4ed0283e47ac9ffa9bd0326fddf4d59513f0827"
}
]
}
`,
fail: false,
},
} {
r := strings.NewReader(tt.manifest)
err := schema.ValidatorMediaTypeManifest.Validate(r)
Expand Down
3 changes: 3 additions & 0 deletions specs-go/v1/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ type Manifest struct {
// MediaType specifies the type of this document data structure e.g. `application/vnd.oci.image.manifest.v1+json`
MediaType string `json:"mediaType,omitempty"`

// ArtifactType specifies the IANA media type of artifact when the manifest is used for an artifact.
ArtifactType string `json:"artifactType,omitempty"`

// 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 Descriptor `json:"config"`
Expand Down
3 changes: 3 additions & 0 deletions specs-go/v1/mediatype.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ const (
// MediaTypeImageConfig specifies the media type for the image configuration.
MediaTypeImageConfig = "application/vnd.oci.image.config.v1+json"

// MediaTypeScratch specifies the media type for an unused blob containing the value `{}`
MediaTypeScratch = "application/vnd.oci.scratch.v1+json"

// MediaTypeArtifactManifest specifies the media type for a content descriptor.
MediaTypeArtifactManifest = "application/vnd.oci.artifact.manifest.v1+json"
)