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

Changes the config layer of the feature manifest to a empty descriptor #815

Merged
16 changes: 14 additions & 2 deletions src/spec-configuration/containerCollectionsOCI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ export const DEVCONTAINER_MANIFEST_MEDIATYPE = 'application/vnd.devcontainers';
export const DEVCONTAINER_TAR_LAYER_MEDIATYPE = 'application/vnd.devcontainers.layer.v1+tar';
export const DEVCONTAINER_COLLECTION_LAYER_MEDIATYPE = 'application/vnd.devcontainers.collection.layer.v1+json';

// Empty Descriptor specified in OCI Image Specification.
// Following Spec: https://github.com/opencontainers/image-spec/blob/v1.1.0/manifest.md#guidance-for-an-empty-descriptor
export const OCI_EMPTY_DESCRIPTOR = {
mediaType: 'application/vnd.oci.empty.v1+json',
digest: 'sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a',
size: 2,
dataBytes: Buffer.from('{}')
};

export interface CommonParams {
env: NodeJS.ProcessEnv;
Expand Down Expand Up @@ -60,6 +68,7 @@ export interface OCILayer {
export interface OCIManifest {
digest?: string;
schemaVersion: number;
artifactType?: string;
mediaType: string;
config: {
digest: string;
Expand Down Expand Up @@ -295,10 +304,13 @@ export async function fetchOCIManifestIfExists(params: CommonParams, ref: OCIRef
return;
}

// If the config layer is an empty descriptor, the media type of the manifest must be defined in the artifactType.
// Specification: https://github.com/opencontainers/image-spec/blob/8f3820ccf8f65db8744e626df17fe8a64462aece/manifest.md#guidelines-for-artifact-usage
const { manifestObj } = manifestContainer;
const manifestMediaType = manifestObj.config.mediaType === OCI_EMPTY_DESCRIPTOR.mediaType ? manifestObj.artifactType : manifestObj.config.mediaType;

if (manifestObj.config.mediaType !== DEVCONTAINER_MANIFEST_MEDIATYPE) {
output.write(`(!) Unexpected manifest media type: ${manifestObj.config.mediaType}`, LogLevel.Error);
if (manifestMediaType !== DEVCONTAINER_MANIFEST_MEDIATYPE) {
output.write(`(!) Unexpected manifest media type: ${manifestMediaType}`, LogLevel.Error);
return undefined;
}

Expand Down
15 changes: 8 additions & 7 deletions src/spec-configuration/containerCollectionsOCIPush.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as crypto from 'crypto';
import { delay } from '../spec-common/async';
import { Log, LogLevel } from '../spec-utils/log';
import { isLocalFile } from '../spec-utils/pfs';
import { DEVCONTAINER_COLLECTION_LAYER_MEDIATYPE, DEVCONTAINER_TAR_LAYER_MEDIATYPE, fetchOCIManifestIfExists, OCICollectionRef, OCILayer, OCIManifest, OCIRef, CommonParams, ManifestContainer } from './containerCollectionsOCI';
import { OCI_EMPTY_DESCRIPTOR, DEVCONTAINER_MANIFEST_MEDIATYPE, DEVCONTAINER_COLLECTION_LAYER_MEDIATYPE, DEVCONTAINER_TAR_LAYER_MEDIATYPE, fetchOCIManifestIfExists, OCICollectionRef, OCILayer, OCIManifest, OCIRef, CommonParams, ManifestContainer } from './containerCollectionsOCI';
import { requestEnsureAuthenticated } from './httpOCIRegistry';

// (!) Entrypoint function to push a single feature/template to a registry.
Expand Down Expand Up @@ -44,8 +44,8 @@ export async function pushOCIFeatureOrTemplate(params: CommonParams, ociRef: OCI
{
name: 'configLayer',
digest: manifest.manifestObj.config.digest,
contents: Buffer.alloc(0),
size: manifest.manifestObj.config.size,
contents: OCI_EMPTY_DESCRIPTOR.dataBytes,
},
{
name: 'tgzLayer',
Expand Down Expand Up @@ -119,7 +119,7 @@ export async function pushCollectionMetadata(params: CommonParams, collectionRef
name: 'configLayer',
digest: manifest.manifestObj.config.digest,
size: manifest.manifestObj.config.size,
contents: Buffer.alloc(0),
contents: OCI_EMPTY_DESCRIPTOR.dataBytes,
},
{
name: 'collectionLayer',
Expand Down Expand Up @@ -383,15 +383,16 @@ export async function calculateManifestAndContentDigest(output: Log, ociRef: OCI
// A canonical manifest digest is the sha256 hash of the JSON representation of the manifest, without the signature content.
// See: https://docs.docker.com/registry/spec/api/#content-digests
// Below is an example of a serialized manifest that should resolve to '9726054859c13377c4c3c3c73d15065de59d0c25d61d5652576c0125f2ea8ed3'
// {"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.devcontainers","digest":"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","size":0},"layers":[{"mediaType":"application/vnd.devcontainers.layer.v1+tar","digest":"sha256:b2006e7647191f7b47222ae48df049c6e21a4c5a04acfad0c4ef614d819de4c5","size":15872,"annotations":{"org.opencontainers.image.title":"go.tgz"}}]}
// {"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","artifactType":"application/vnd.devcontainers","config":{"mediaType":"application/vnd.oci.empty.v1+json","digest":"sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a","size":2},"layers":[{"mediaType":"application/vnd.devcontainers.layer.v1+tar","digest":"sha256:b2006e7647191f7b47222ae48df049c6e21a4c5a04acfad0c4ef614d819de4c5","size":15872,"annotations":{"org.opencontainers.image.title":"go.tgz"}}]}

let manifest: OCIManifest = {
schemaVersion: 2,
mediaType: 'application/vnd.oci.image.manifest.v1+json',
artifactType: DEVCONTAINER_MANIFEST_MEDIATYPE,
config: {
mediaType: 'application/vnd.devcontainers',
digest: 'sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', // A zero byte digest for the devcontainer mediaType.
size: 0
mediaType: OCI_EMPTY_DESCRIPTOR.mediaType,
joshspicer marked this conversation as resolved.
Show resolved Hide resolved
digest: OCI_EMPTY_DESCRIPTOR.digest,
size: OCI_EMPTY_DESCRIPTOR.size,
},
layers: [
dataLayer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ describe('Test OCI Push Helper Functions', function () {
const { contentDigest, manifestBuffer } = manifestContainer;

// 'Expected' is taken from intermediate value in oras reference implementation, before hash calculation
assert.strictEqual('{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.devcontainers","digest":"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","size":0},"layers":[{"mediaType":"application/vnd.devcontainers.layer.v1+tar","digest":"sha256:b2006e7647191f7b47222ae48df049c6e21a4c5a04acfad0c4ef614d819de4c5","size":15872,"annotations":{"org.opencontainers.image.title":"go.tgz"}}]}', manifestBuffer.toString());
assert.strictEqual('{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","artifactType":"application/vnd.devcontainers","config":{"mediaType":"application/vnd.oci.empty.v1+json","digest":"sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a","size":2},"layers":[{"mediaType":"application/vnd.devcontainers.layer.v1+tar","digest":"sha256:b2006e7647191f7b47222ae48df049c6e21a4c5a04acfad0c4ef614d819de4c5","size":15872,"annotations":{"org.opencontainers.image.title":"go.tgz"}}]}', manifestBuffer.toString());

// This is the canonical digest of the manifest
assert.strictEqual('sha256:9726054859c13377c4c3c3c73d15065de59d0c25d61d5652576c0125f2ea8ed3', contentDigest);
Expand Down
1 change: 1 addition & 0 deletions src/test/container-features/featureAdvisories.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ function getFeaturesConfig(featureId: string, featureConfigVersion: string, feat
featureRef: getRef(output, `${featureId}:${featureConfigVersion}`)!,
manifest: {
schemaVersion: 1,
artifactType: '',
mediaType: '',
config: {
digest: '',
Expand Down
3 changes: 3 additions & 0 deletions src/test/container-features/featureHelpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,7 @@ chmod +x ./install.sh
},
manifest: {
schemaVersion: 1,
artifactType: '',
mediaType: '',
config: {
digest: '',
Expand Down Expand Up @@ -722,6 +723,7 @@ chmod +x ./install.sh
},
manifest: {
schemaVersion: 1,
artifactType: '',
mediaType: '',
config: {
digest: '',
Expand Down Expand Up @@ -809,6 +811,7 @@ chmod +x ./install.sh
},
manifest: {
schemaVersion: 1,
artifactType: '',
mediaType: '',
config: {
digest: '',
Expand Down
1 change: 1 addition & 0 deletions src/test/imageMetadata.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,7 @@ function getFeaturesConfig(features: Feature[]): FeaturesConfig {
},
manifest: {
schemaVersion: 1,
artifactType: '',
mediaType: '',
config: {
digest: '',
Expand Down
Loading