Merge pull request #823 from crazy-max/buildx-attestations-digest
buildx(imagetools): return attestations digests
This commit is contained in:
5
__tests__/.fixtures/imagetools-03.json
Normal file
5
__tests__/.fixtures/imagetools-03.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"digest": "sha256:dccc69dd895968c4f21aa9e43e715f25f0cedfce4b17f1014c88c307928e22fc",
|
||||
"size": 1599
|
||||
}
|
||||
141
__tests__/.fixtures/imagetools-04.json
Normal file
141
__tests__/.fixtures/imagetools-04.json
Normal file
@@ -0,0 +1,141 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"mediaType": "application/vnd.oci.image.index.v1+json",
|
||||
"digest": "sha256:79cc6476ab1a3371c9afd8b44e7c55610057c43e18d9b39b68e2b0c2475cc1b6",
|
||||
"size": 4654,
|
||||
"manifests": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"digest": "sha256:dccc69dd895968c4f21aa9e43e715f25f0cedfce4b17f1014c88c307928e22fc",
|
||||
"size": 1599,
|
||||
"platform": {
|
||||
"architecture": "amd64",
|
||||
"os": "linux"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"digest": "sha256:1b6bce668653f08e2d0f9f7c9b646675b2cbce94ce8abdf4eb0eabaef4353045",
|
||||
"size": 1599,
|
||||
"platform": {
|
||||
"architecture": "arm",
|
||||
"os": "linux",
|
||||
"variant": "v7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"digest": "sha256:8f251fda6057e9dffc54f7874b249920f15f1813e9b1406a0cebeca5e4ab1ad9",
|
||||
"size": 1599,
|
||||
"platform": {
|
||||
"architecture": "arm64",
|
||||
"os": "linux"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"digest": "sha256:d306cbc2d506547f136c8e0ea040b929743f298fb2813d9030efdb9d9eee4d51",
|
||||
"size": 1599,
|
||||
"platform": {
|
||||
"architecture": "s390x",
|
||||
"os": "linux"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"digest": "sha256:9d195ff2dc9ef347bb52ebb1c2a6e6587d4bd87019d2ea11df3e7046a3d19708",
|
||||
"size": 1599,
|
||||
"platform": {
|
||||
"architecture": "ppc64le",
|
||||
"os": "linux"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"digest": "sha256:72410c2c4529fca9339ebbcc8db2a1d5cb4d72d72c669f50b6d45d8a0f79fc22",
|
||||
"size": 1599,
|
||||
"platform": {
|
||||
"architecture": "riscv64",
|
||||
"os": "linux"
|
||||
}
|
||||
},
|
||||
{
|
||||
"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"
|
||||
}
|
||||
},
|
||||
{
|
||||
"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"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"digest": "sha256:241b7159129d53923c89708bcc052b3398086a826519896be2f025545916e43e",
|
||||
"size": 1113,
|
||||
"annotations": {
|
||||
"vnd.docker.reference.digest": "sha256:8f251fda6057e9dffc54f7874b249920f15f1813e9b1406a0cebeca5e4ab1ad9",
|
||||
"vnd.docker.reference.type": "attestation-manifest"
|
||||
},
|
||||
"platform": {
|
||||
"architecture": "unknown",
|
||||
"os": "unknown"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"digest": "sha256:97f4a222a7992dba6dc1a43991d0cca1fcffdc25593033c6a3a7ff14c8651cbf",
|
||||
"size": 1113,
|
||||
"annotations": {
|
||||
"vnd.docker.reference.digest": "sha256:d306cbc2d506547f136c8e0ea040b929743f298fb2813d9030efdb9d9eee4d51",
|
||||
"vnd.docker.reference.type": "attestation-manifest"
|
||||
},
|
||||
"platform": {
|
||||
"architecture": "unknown",
|
||||
"os": "unknown"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"digest": "sha256:aa933713d8094b2708120e889acb6f7153dee4e0f3298ccd3e37a584cd0c260d",
|
||||
"size": 1113,
|
||||
"annotations": {
|
||||
"vnd.docker.reference.digest": "sha256:9d195ff2dc9ef347bb52ebb1c2a6e6587d4bd87019d2ea11df3e7046a3d19708",
|
||||
"vnd.docker.reference.type": "attestation-manifest"
|
||||
},
|
||||
"platform": {
|
||||
"architecture": "unknown",
|
||||
"os": "unknown"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"digest": "sha256:d95ca72d4f2a6bc416d4b2f3003b2af9d5f4dea99acec6ad3ab0c2082000a98c",
|
||||
"size": 1113,
|
||||
"annotations": {
|
||||
"vnd.docker.reference.digest": "sha256:72410c2c4529fca9339ebbcc8db2a1d5cb4d72d72c669f50b6d45d8a0f79fc22",
|
||||
"vnd.docker.reference.type": "attestation-manifest"
|
||||
},
|
||||
"platform": {
|
||||
"architecture": "unknown",
|
||||
"os": "unknown"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
80
__tests__/.fixtures/imagetools-05.json
Normal file
80
__tests__/.fixtures/imagetools-05.json
Normal file
@@ -0,0 +1,80 @@
|
||||
[
|
||||
{
|
||||
"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"
|
||||
}
|
||||
},
|
||||
{
|
||||
"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"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType":"application/vnd.oci.image.manifest.v1+json",
|
||||
"digest":"sha256:241b7159129d53923c89708bcc052b3398086a826519896be2f025545916e43e",
|
||||
"size":1113,
|
||||
"annotations":{
|
||||
"vnd.docker.reference.digest":"sha256:8f251fda6057e9dffc54f7874b249920f15f1813e9b1406a0cebeca5e4ab1ad9",
|
||||
"vnd.docker.reference.type":"attestation-manifest"
|
||||
},
|
||||
"platform":{
|
||||
"architecture":"unknown",
|
||||
"os":"unknown"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType":"application/vnd.oci.image.manifest.v1+json",
|
||||
"digest":"sha256:97f4a222a7992dba6dc1a43991d0cca1fcffdc25593033c6a3a7ff14c8651cbf",
|
||||
"size":1113,
|
||||
"annotations":{
|
||||
"vnd.docker.reference.digest":"sha256:d306cbc2d506547f136c8e0ea040b929743f298fb2813d9030efdb9d9eee4d51",
|
||||
"vnd.docker.reference.type":"attestation-manifest"
|
||||
},
|
||||
"platform":{
|
||||
"architecture":"unknown",
|
||||
"os":"unknown"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType":"application/vnd.oci.image.manifest.v1+json",
|
||||
"digest":"sha256:aa933713d8094b2708120e889acb6f7153dee4e0f3298ccd3e37a584cd0c260d",
|
||||
"size":1113,
|
||||
"annotations":{
|
||||
"vnd.docker.reference.digest":"sha256:9d195ff2dc9ef347bb52ebb1c2a6e6587d4bd87019d2ea11df3e7046a3d19708",
|
||||
"vnd.docker.reference.type":"attestation-manifest"
|
||||
},
|
||||
"platform":{
|
||||
"architecture":"unknown",
|
||||
"os":"unknown"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType":"application/vnd.oci.image.manifest.v1+json",
|
||||
"digest":"sha256:d95ca72d4f2a6bc416d4b2f3003b2af9d5f4dea99acec6ad3ab0c2082000a98c",
|
||||
"size":1113,
|
||||
"annotations":{
|
||||
"vnd.docker.reference.digest":"sha256:72410c2c4529fca9339ebbcc8db2a1d5cb4d72d72c669f50b6d45d8a0f79fc22",
|
||||
"vnd.docker.reference.type":"attestation-manifest"
|
||||
},
|
||||
"platform":{
|
||||
"architecture":"unknown",
|
||||
"os":"unknown"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -19,7 +19,10 @@ import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import {ImageTools} from '../../src/buildx/imagetools';
|
||||
|
||||
import {Manifest as ImageToolsManifest} from '../../src/types/buildx/imagetools';
|
||||
import {Image} from '../../src/types/oci/config';
|
||||
import {Descriptor} from '../../src/types/oci/descriptor';
|
||||
|
||||
const fixturesDir = path.join(__dirname, '..', '.fixtures');
|
||||
|
||||
@@ -37,3 +40,39 @@ maybe('inspectImage', () => {
|
||||
expect(image).toEqual(expectedImage);
|
||||
});
|
||||
});
|
||||
|
||||
maybe('inspectManifest', () => {
|
||||
it('inspect descriptor', async () => {
|
||||
const manifest = await new ImageTools().inspectManifest('moby/buildkit:latest@sha256:dccc69dd895968c4f21aa9e43e715f25f0cedfce4b17f1014c88c307928e22fc');
|
||||
const expectedManifest = <Descriptor>JSON.parse(fs.readFileSync(path.join(fixturesDir, 'imagetools-03.json'), {encoding: 'utf-8'}).trim());
|
||||
expect(manifest).toEqual(expectedManifest);
|
||||
});
|
||||
it('inspect index', async () => {
|
||||
const manifest = await new ImageTools().inspectManifest('moby/buildkit:latest@sha256:79cc6476ab1a3371c9afd8b44e7c55610057c43e18d9b39b68e2b0c2475cc1b6');
|
||||
const expectedManifest = <ImageToolsManifest>JSON.parse(fs.readFileSync(path.join(fixturesDir, 'imagetools-04.json'), {encoding: 'utf-8'}).trim());
|
||||
expect(manifest).toEqual(expectedManifest);
|
||||
});
|
||||
});
|
||||
|
||||
maybe('attestationDescriptors', () => {
|
||||
it('returns buildkit attestations descriptors', async () => {
|
||||
const attestations = await new ImageTools().attestationDescriptors('moby/buildkit:latest@sha256:79cc6476ab1a3371c9afd8b44e7c55610057c43e18d9b39b68e2b0c2475cc1b6');
|
||||
const expectedAttestations = <Array<Descriptor>>JSON.parse(fs.readFileSync(path.join(fixturesDir, 'imagetools-05.json'), {encoding: 'utf-8'}).trim());
|
||||
expect(attestations).toEqual(expectedAttestations);
|
||||
});
|
||||
});
|
||||
|
||||
maybe('attestationDigests', () => {
|
||||
it('returns buildkit attestations digests', async () => {
|
||||
const digests = await new ImageTools().attestationDigests('moby/buildkit:latest@sha256:79cc6476ab1a3371c9afd8b44e7c55610057c43e18d9b39b68e2b0c2475cc1b6');
|
||||
// prettier-ignore
|
||||
expect(digests).toEqual([
|
||||
'sha256:2ba4ad6eae1efcafee73a971953093c7c32b6938f2f9fd4998c8bf4d0fbe76f2',
|
||||
'sha256:0709528fae1747ce17638ad2978ee7936b38a294136eaadaf692e415f64b1e03',
|
||||
'sha256:241b7159129d53923c89708bcc052b3398086a826519896be2f025545916e43e',
|
||||
'sha256:97f4a222a7992dba6dc1a43991d0cca1fcffdc25593033c6a3a7ff14c8651cbf',
|
||||
'sha256:aa933713d8094b2708120e889acb6f7153dee4e0f3298ccd3e37a584cd0c260d',
|
||||
'sha256:d95ca72d4f2a6bc416d4b2f3003b2af9d5f4dea99acec6ad3ab0c2082000a98c'
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,7 +17,10 @@
|
||||
import {Buildx} from './buildx';
|
||||
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 {Digest} from '../types/oci/digest';
|
||||
|
||||
export interface ImageToolsOpts {
|
||||
buildx?: Buildx;
|
||||
@@ -58,4 +61,37 @@ export class ImageTools {
|
||||
throw new Error('Unexpected output format');
|
||||
});
|
||||
}
|
||||
|
||||
public async inspectManifest(name: string): Promise<ImageToolsManifest | Descriptor> {
|
||||
const cmd = await this.getInspectCommand([name, '--format', '{{json .Manifest}}']);
|
||||
return await Exec.getExecOutput(cmd.command, cmd.args, {
|
||||
ignoreReturnCode: true,
|
||||
silent: true
|
||||
}).then(res => {
|
||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||
throw new Error(res.stderr.trim());
|
||||
}
|
||||
const parsedOutput = JSON.parse(res.stdout);
|
||||
if (typeof parsedOutput === 'object' && !Array.isArray(parsedOutput) && parsedOutput !== null) {
|
||||
if (Object.prototype.hasOwnProperty.call(parsedOutput, 'manifests')) {
|
||||
return <ImageToolsManifest>parsedOutput;
|
||||
} else {
|
||||
return <Descriptor>parsedOutput;
|
||||
}
|
||||
}
|
||||
throw new Error('Unexpected output format');
|
||||
});
|
||||
}
|
||||
|
||||
public async attestationDescriptors(name: string): 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');
|
||||
}
|
||||
throw new Error(`No attestation descriptors found for ${name}`);
|
||||
}
|
||||
|
||||
public async attestationDigests(name: string): Promise<Array<Digest>> {
|
||||
return (await this.attestationDescriptors(name)).map(attestation => attestation.digest);
|
||||
}
|
||||
}
|
||||
|
||||
28
src/types/buildx/imagetools.ts
Normal file
28
src/types/buildx/imagetools.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright 2025 actions-toolkit authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Versioned} from '../oci/versioned';
|
||||
import {Descriptor} from '../oci/descriptor';
|
||||
import {Digest} from '../oci/digest';
|
||||
|
||||
// https://github.com/docker/buildx/blob/62857022a08552bee5cad0c3044a9a3b185f0b32/util/imagetools/printers.go#L109-L123
|
||||
export interface Manifest extends Versioned {
|
||||
mediaType?: string;
|
||||
digest: Digest;
|
||||
size: number;
|
||||
manifests?: Descriptor[];
|
||||
annotations?: Record<string, string>;
|
||||
}
|
||||
Reference in New Issue
Block a user