Skip to content

Commit f136d06

Browse files
committed
buildx(imagetools): opt to filter attestation manifests by platform
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
1 parent 6e1b0e6 commit f136d06

File tree

4 files changed

+79
-7
lines changed

4 files changed

+79
-7
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[
2+
{
3+
"mediaType":"application/vnd.oci.image.manifest.v1+json",
4+
"digest":"sha256:2ba4ad6eae1efcafee73a971953093c7c32b6938f2f9fd4998c8bf4d0fbe76f2",
5+
"size":1113,
6+
"annotations":{
7+
"vnd.docker.reference.digest":"sha256:dccc69dd895968c4f21aa9e43e715f25f0cedfce4b17f1014c88c307928e22fc",
8+
"vnd.docker.reference.type":"attestation-manifest"
9+
},
10+
"platform":{
11+
"architecture":"unknown",
12+
"os":"unknown"
13+
}
14+
}
15+
]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[
2+
{
3+
"mediaType": "application/vnd.oci.image.manifest.v1+json",
4+
"digest": "sha256:0709528fae1747ce17638ad2978ee7936b38a294136eaadaf692e415f64b1e03",
5+
"size": 1113,
6+
"annotations": {
7+
"vnd.docker.reference.digest": "sha256:1b6bce668653f08e2d0f9f7c9b646675b2cbce94ce8abdf4eb0eabaef4353045",
8+
"vnd.docker.reference.type": "attestation-manifest"
9+
},
10+
"platform": {
11+
"architecture": "unknown",
12+
"os": "unknown"
13+
}
14+
}
15+
]

__tests__/buildx/imagetools.test.itg.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,16 @@ maybe('attestationDescriptors', () => {
6060
const expectedAttestations = <Array<Descriptor>>JSON.parse(fs.readFileSync(path.join(fixturesDir, 'imagetools-05.json'), {encoding: 'utf-8'}).trim());
6161
expect(attestations).toEqual(expectedAttestations);
6262
});
63+
it('returns buildkit attestations descriptors for linux/amd64', async () => {
64+
const attestations = await new ImageTools().attestationDescriptors('moby/buildkit:latest@sha256:79cc6476ab1a3371c9afd8b44e7c55610057c43e18d9b39b68e2b0c2475cc1b6', {os: 'linux', architecture: 'amd64'});
65+
const expectedAttestations = <Array<Descriptor>>JSON.parse(fs.readFileSync(path.join(fixturesDir, 'imagetools-06.json'), {encoding: 'utf-8'}).trim());
66+
expect(attestations).toEqual(expectedAttestations);
67+
});
68+
it('returns buildkit attestations descriptors for linux/arm/v7', async () => {
69+
const attestations = await new ImageTools().attestationDescriptors('moby/buildkit:latest@sha256:79cc6476ab1a3371c9afd8b44e7c55610057c43e18d9b39b68e2b0c2475cc1b6', {os: 'linux', architecture: 'arm', variant: 'v7'});
70+
const expectedAttestations = <Array<Descriptor>>JSON.parse(fs.readFileSync(path.join(fixturesDir, 'imagetools-07.json'), {encoding: 'utf-8'}).trim());
71+
expect(attestations).toEqual(expectedAttestations);
72+
});
6373
});
6474

6575
maybe('attestationDigests', () => {
@@ -75,4 +85,12 @@ maybe('attestationDigests', () => {
7585
'sha256:d95ca72d4f2a6bc416d4b2f3003b2af9d5f4dea99acec6ad3ab0c2082000a98c'
7686
]);
7787
});
88+
it('returns buildkit attestations digests for linux/amd64', async () => {
89+
const digests = await new ImageTools().attestationDigests('moby/buildkit:latest@sha256:79cc6476ab1a3371c9afd8b44e7c55610057c43e18d9b39b68e2b0c2475cc1b6', {os: 'linux', architecture: 'amd64'});
90+
expect(digests).toEqual(['sha256:2ba4ad6eae1efcafee73a971953093c7c32b6938f2f9fd4998c8bf4d0fbe76f2']);
91+
});
92+
it('returns buildkit attestations digests for linux/arm/v7', async () => {
93+
const digests = await new ImageTools().attestationDigests('moby/buildkit:latest@sha256:79cc6476ab1a3371c9afd8b44e7c55610057c43e18d9b39b68e2b0c2475cc1b6', {os: 'linux', architecture: 'arm', variant: 'v7'});
94+
expect(digests).toEqual(['sha256:0709528fae1747ce17638ad2978ee7936b38a294136eaadaf692e415f64b1e03']);
95+
});
7896
});

src/buildx/imagetools.ts

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {Exec} from '../exec';
1919

2020
import {Manifest as ImageToolsManifest} from '../types/buildx/imagetools';
2121
import {Image} from '../types/oci/config';
22-
import {Descriptor} from '../types/oci/descriptor';
22+
import {Descriptor, Platform} from '../types/oci/descriptor';
2323
import {Digest} from '../types/oci/digest';
2424

2525
export interface ImageToolsOpts {
@@ -83,15 +83,39 @@ export class ImageTools {
8383
});
8484
}
8585

86-
public async attestationDescriptors(name: string): Promise<Array<Descriptor>> {
86+
public async attestationDescriptors(name: string, platform?: Platform): Promise<Array<Descriptor>> {
8787
const manifest = await this.inspectManifest(name);
88-
if (typeof manifest === 'object' && manifest !== null && 'manifests' in manifest && Array.isArray(manifest.manifests)) {
89-
return manifest.manifests.filter(m => m.annotations && m.annotations['vnd.docker.reference.type'] === 'attestation-manifest');
88+
89+
if (typeof manifest !== 'object' || manifest === null || !('manifests' in manifest) || !Array.isArray(manifest.manifests)) {
90+
throw new Error(`No descriptor found for ${name}`);
91+
}
92+
93+
const attestations = manifest.manifests.filter(m => m.annotations?.['vnd.docker.reference.type'] === 'attestation-manifest');
94+
if (!platform) {
95+
return attestations;
96+
}
97+
98+
const manifestByDigest = new Map<string, Descriptor>();
99+
for (const m of manifest.manifests) {
100+
if (m.digest) {
101+
manifestByDigest.set(m.digest, m);
102+
}
90103
}
91-
throw new Error(`No attestation descriptors found for ${name}`);
104+
105+
return attestations.filter(attestation => {
106+
const refDigest = attestation.annotations?.['vnd.docker.reference.digest'];
107+
if (!refDigest) {
108+
return false;
109+
}
110+
const referencedManifest = manifestByDigest.get(refDigest);
111+
if (!referencedManifest) {
112+
return false;
113+
}
114+
return referencedManifest.platform?.os === platform.os && referencedManifest.platform?.architecture === platform.architecture && (referencedManifest.platform?.variant ?? '') === (platform.variant ?? '');
115+
});
92116
}
93117

94-
public async attestationDigests(name: string): Promise<Array<Digest>> {
95-
return (await this.attestationDescriptors(name)).map(attestation => attestation.digest);
118+
public async attestationDigests(name: string, platform?: Platform): Promise<Array<Digest>> {
119+
return (await this.attestationDescriptors(name, platform)).map(attestation => attestation.digest);
96120
}
97121
}

0 commit comments

Comments
 (0)