Merge pull request #935 from crazy-max/imagetools-filter-platform
buildx(imagetools): opt to filter attestation manifests by platform
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());
|
const expectedAttestations = <Array<Descriptor>>JSON.parse(fs.readFileSync(path.join(fixturesDir, 'imagetools-05.json'), {encoding: 'utf-8'}).trim());
|
||||||
expect(attestations).toEqual(expectedAttestations);
|
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', () => {
|
maybe('attestationDigests', () => {
|
||||||
@@ -75,4 +85,12 @@ maybe('attestationDigests', () => {
|
|||||||
'sha256:d95ca72d4f2a6bc416d4b2f3003b2af9d5f4dea99acec6ad3ab0c2082000a98c'
|
'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 {Manifest as ImageToolsManifest} from '../types/buildx/imagetools';
|
||||||
import {Image} from '../types/oci/config';
|
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';
|
import {Digest} from '../types/oci/digest';
|
||||||
|
|
||||||
export interface ImageToolsOpts {
|
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);
|
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>> {
|
public async attestationDigests(name: string, platform?: Platform): Promise<Array<Digest>> {
|
||||||
return (await this.attestationDescriptors(name)).map(attestation => attestation.digest);
|
return (await this.attestationDescriptors(name, platform)).map(attestation => attestation.digest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user