bake: composable attributes for attestations support

Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax
2025-01-08 15:28:06 +01:00
parent d78e250f06
commit bfc74cf338
4 changed files with 54 additions and 2 deletions

View File

@@ -3,6 +3,16 @@
"default": {
"context": ".",
"dockerfile": "Dockerfile",
"attest": [
{
"mode": "max",
"type": "provenance"
},
{
"disabled": "true",
"type": "sbom"
}
],
"cache-from": [
{
"scope": "build",

View File

@@ -13,6 +13,10 @@
// limitations under the License.
target "default" {
attest = [
"type=provenance,mode=max",
"type=sbom,disabled=true",
]
cache-from = [
"type=gha,scope=build",
"user/repo:cache",

View File

@@ -24,7 +24,7 @@ import {Exec} from '../exec';
import {Util} from '../util';
import {ExecOptions} from '@actions/exec';
import {BakeDefinition, CacheEntry, ExportEntry, SecretEntry, SSHEntry} from '../types/buildx/bake';
import {AttestEntry, BakeDefinition, CacheEntry, ExportEntry, SecretEntry, SSHEntry} from '../types/buildx/bake';
import {BuildMetadata} from '../types/buildx/build';
import {VertexWarning} from '../types/buildkit/client';
@@ -183,6 +183,11 @@ export class Bake {
// convert to composable attributes: https://github.com/docker/buildx/pull/2758
for (const name in definition.target) {
const target = definition.target[name];
if (target['attest'] && Array.isArray(target['attest'])) {
target['attest'] = target['attest'].map((item: string | AttestEntry): AttestEntry => {
return Bake.parseAttestEntry(item);
});
}
if (target['cache-from'] && Array.isArray(target['cache-from'])) {
target['cache-from'] = target['cache-from'].map((item: string | CacheEntry): CacheEntry => {
return Bake.parseCacheEntry(item);
@@ -213,6 +218,34 @@ export class Bake {
return definition;
}
private static parseAttestEntry(item: AttestEntry | string): AttestEntry {
if (typeof item !== 'string') {
return item;
}
const attestEntry: AttestEntry = {type: ''};
const fields = parse(item, {
relaxColumnCount: true,
skipEmptyLines: true
})[0];
for (const field of fields) {
const [key, value] = field
.toString()
.split(/(?<=^[^=]+?)=/)
.map((item: string) => item.trim());
switch (key) {
case 'type':
attestEntry.type = value;
break;
default:
attestEntry[key] = value;
}
}
return attestEntry;
}
private static parseCacheEntry(item: CacheEntry | string): CacheEntry {
if (typeof item !== 'string') {
return item;

View File

@@ -27,7 +27,7 @@ export interface Group {
export interface Target {
description?: string;
args?: Record<string, string>;
attest?: Array<string>;
attest?: Array<AttestEntry> | Array<string>;
'cache-from'?: Array<CacheEntry> | Array<string>;
'cache-to'?: Array<CacheEntry> | Array<string>;
call?: string;
@@ -50,6 +50,11 @@ export interface Target {
ulimits?: Array<string>;
}
export interface AttestEntry {
type: string;
[key: string]: string;
}
export interface CacheEntry {
type: string;
[key: string]: string;