buildx(imagetools): opt to filter attestation manifests by platform
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
This commit is contained in:
15
__tests__/.fixtures/imagetools-06.json
Normal file
15
__tests__/.fixtures/imagetools-06.json
Normal file
@@ -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
__tests__/.fixtures/imagetools-07.json
Normal file
15
__tests__/.fixtures/imagetools-07.json
Normal file
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -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', () => {
|
||||
@@ -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']);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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 {
|
||||
@@ -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}`);
|
||||
}
|
||||
throw new Error(`No attestation descriptors 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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user