Skip to content
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
15 changes: 15 additions & 0 deletions __tests__/.fixtures/imagetools-06.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[
{
"mediaType":"application/vnd.oci.image.manifest.v1+json",
"digest":"sha256:2ba4ad6eae1efcafee73a971953093c7c32b6938f2f9fd4998c8bf4d0fbe76f2",
"size":1113,
"annotations":{
"vnd.docker.reference.digest":"sha256:dccc69dd895968c4f21aa9e43e715f25f0cedfce4b17f1014c88c307928e22fc",
"vnd.docker.reference.type":"attestation-manifest"
},
"platform":{
"architecture":"unknown",
"os":"unknown"
}
}
]
15 changes: 15 additions & 0 deletions __tests__/.fixtures/imagetools-07.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:0709528fae1747ce17638ad2978ee7936b38a294136eaadaf692e415f64b1e03",
"size": 1113,
"annotations": {
"vnd.docker.reference.digest": "sha256:1b6bce668653f08e2d0f9f7c9b646675b2cbce94ce8abdf4eb0eabaef4353045",
"vnd.docker.reference.type": "attestation-manifest"
},
"platform": {
"architecture": "unknown",
"os": "unknown"
}
}
]
18 changes: 18 additions & 0 deletions __tests__/buildx/imagetools.test.itg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ maybe('attestationDescriptors', () => {
const expectedAttestations = <Array<Descriptor>>JSON.parse(fs.readFileSync(path.join(fixturesDir, 'imagetools-05.json'), {encoding: 'utf-8'}).trim());
expect(attestations).toEqual(expectedAttestations);
});
it('returns buildkit attestations descriptors for linux/amd64', async () => {
const attestations = await new ImageTools().attestationDescriptors('moby/buildkit:latest@sha256:79cc6476ab1a3371c9afd8b44e7c55610057c43e18d9b39b68e2b0c2475cc1b6', {os: 'linux', architecture: 'amd64'});
const expectedAttestations = <Array<Descriptor>>JSON.parse(fs.readFileSync(path.join(fixturesDir, 'imagetools-06.json'), {encoding: 'utf-8'}).trim());
expect(attestations).toEqual(expectedAttestations);
});
it('returns buildkit attestations descriptors for linux/arm/v7', async () => {
const attestations = await new ImageTools().attestationDescriptors('moby/buildkit:latest@sha256:79cc6476ab1a3371c9afd8b44e7c55610057c43e18d9b39b68e2b0c2475cc1b6', {os: 'linux', architecture: 'arm', variant: 'v7'});
const expectedAttestations = <Array<Descriptor>>JSON.parse(fs.readFileSync(path.join(fixturesDir, 'imagetools-07.json'), {encoding: 'utf-8'}).trim());
expect(attestations).toEqual(expectedAttestations);
});
});

maybe('attestationDigests', () => {
Expand All @@ -75,4 +85,12 @@ maybe('attestationDigests', () => {
'sha256:d95ca72d4f2a6bc416d4b2f3003b2af9d5f4dea99acec6ad3ab0c2082000a98c'
]);
});
it('returns buildkit attestations digests for linux/amd64', async () => {
const digests = await new ImageTools().attestationDigests('moby/buildkit:latest@sha256:79cc6476ab1a3371c9afd8b44e7c55610057c43e18d9b39b68e2b0c2475cc1b6', {os: 'linux', architecture: 'amd64'});
expect(digests).toEqual(['sha256:2ba4ad6eae1efcafee73a971953093c7c32b6938f2f9fd4998c8bf4d0fbe76f2']);
});
it('returns buildkit attestations digests for linux/arm/v7', async () => {
const digests = await new ImageTools().attestationDigests('moby/buildkit:latest@sha256:79cc6476ab1a3371c9afd8b44e7c55610057c43e18d9b39b68e2b0c2475cc1b6', {os: 'linux', architecture: 'arm', variant: 'v7'});
expect(digests).toEqual(['sha256:0709528fae1747ce17638ad2978ee7936b38a294136eaadaf692e415f64b1e03']);
});
});
38 changes: 31 additions & 7 deletions src/buildx/imagetools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {Exec} from '../exec';

import {Manifest as ImageToolsManifest} from '../types/buildx/imagetools';
import {Image} from '../types/oci/config';
import {Descriptor} from '../types/oci/descriptor';
import {Descriptor, Platform} from '../types/oci/descriptor';
import {Digest} from '../types/oci/digest';

export interface ImageToolsOpts {
Expand Down Expand Up @@ -83,15 +83,39 @@ export class ImageTools {
});
}

public async attestationDescriptors(name: string): Promise<Array<Descriptor>> {
public async attestationDescriptors(name: string, platform?: Platform): Promise<Array<Descriptor>> {
const manifest = await this.inspectManifest(name);
if (typeof manifest === 'object' && manifest !== null && 'manifests' in manifest && Array.isArray(manifest.manifests)) {
return manifest.manifests.filter(m => m.annotations && m.annotations['vnd.docker.reference.type'] === 'attestation-manifest');

if (typeof manifest !== 'object' || manifest === null || !('manifests' in manifest) || !Array.isArray(manifest.manifests)) {
throw new Error(`No descriptor found for ${name}`);
}

const attestations = manifest.manifests.filter(m => m.annotations?.['vnd.docker.reference.type'] === 'attestation-manifest');
if (!platform) {
return attestations;
}

const manifestByDigest = new Map<string, Descriptor>();
for (const m of manifest.manifests) {
if (m.digest) {
manifestByDigest.set(m.digest, m);
}
}
throw new Error(`No attestation descriptors found for ${name}`);

return attestations.filter(attestation => {
const refDigest = attestation.annotations?.['vnd.docker.reference.digest'];
if (!refDigest) {
return false;
}
const referencedManifest = manifestByDigest.get(refDigest);
if (!referencedManifest) {
return false;
}
return referencedManifest.platform?.os === platform.os && referencedManifest.platform?.architecture === platform.architecture && (referencedManifest.platform?.variant ?? '') === (platform.variant ?? '');
});
}

public async attestationDigests(name: string): Promise<Array<Digest>> {
return (await this.attestationDescriptors(name)).map(attestation => attestation.digest);
public async attestationDigests(name: string, platform?: Platform): Promise<Array<Digest>> {
return (await this.attestationDescriptors(name, platform)).map(attestation => attestation.digest);
}
}
Loading