Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

handle attests correctly with provenance and sbom inputs #1086

Merged
merged 2 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 74 additions & 14 deletions __tests__/context.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ nproc=3`],
[
'build',
'--iidfile', path.join(tmpDir, 'iidfile'),
"--provenance", `mode=min,inline-only=true,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`,
'--attest', `type=provenance,mode=min,inline-only=true,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`,
'--metadata-file', path.join(tmpDir, 'metadata-file'),
'.'
]
Expand All @@ -500,7 +500,7 @@ nproc=3`],
[
'build',
'--iidfile', path.join(tmpDir, 'iidfile'),
"--provenance", `builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`,
'--attest', `type=provenance,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`,
'--metadata-file', path.join(tmpDir, 'metadata-file'),
'.'
]
Expand All @@ -519,7 +519,7 @@ nproc=3`],
[
'build',
'--iidfile', path.join(tmpDir, 'iidfile'),
"--provenance", `mode=max,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`,
'--attest', `type=provenance,mode=max,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`,
'--metadata-file', path.join(tmpDir, 'metadata-file'),
'.'
]
Expand All @@ -538,7 +538,7 @@ nproc=3`],
[
'build',
'--iidfile', path.join(tmpDir, 'iidfile'),
"--provenance", 'false',
'--attest', 'type=provenance,disabled=true',
'--metadata-file', path.join(tmpDir, 'metadata-file'),
'.'
]
Expand All @@ -557,7 +557,7 @@ nproc=3`],
[
'build',
'--iidfile', path.join(tmpDir, 'iidfile'),
"--provenance", 'builder-id=foo',
'--attest', 'type=provenance,builder-id=foo',
'--metadata-file', path.join(tmpDir, 'metadata-file'),
'.'
]
Expand Down Expand Up @@ -620,7 +620,7 @@ nproc=3`],
]
],
[
25,
26,
'0.10.0',
new Map<string, string>([
['context', '.'],
Expand All @@ -642,7 +642,7 @@ ANOTHER_SECRET=ANOTHER_SECRET_ENV`]
]
],
[
26,
27,
'0.10.0',
new Map<string, string>([
['context', '.'],
Expand All @@ -663,7 +663,7 @@ ANOTHER_SECRET=ANOTHER_SECRET_ENV`]
]
],
[
27,
28,
'0.11.0',
new Map<string, string>([
['context', '.'],
Expand All @@ -677,13 +677,13 @@ ANOTHER_SECRET=ANOTHER_SECRET_ENV`]
[
'build',
'--output', 'type=local,dest=./release-out',
"--provenance", `mode=min,inline-only=true,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`,
'--attest', `type=provenance,mode=min,inline-only=true,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`,
'--metadata-file', path.join(tmpDir, 'metadata-file'),
'.'
]
],
[
28,
29,
'0.12.0',
new Map<string, string>([
['context', '.'],
Expand All @@ -701,13 +701,13 @@ ANOTHER_SECRET=ANOTHER_SECRET_ENV`]
'--annotation', 'manifest:example3=yyy',
'--annotation', 'manifest-descriptor[linux/amd64]:example4=zzz',
'--output', 'type=local,dest=./release-out',
"--provenance", `mode=min,inline-only=true,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`,
'--attest', `type=provenance,mode=min,inline-only=true,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`,
'--metadata-file', path.join(tmpDir, 'metadata-file'),
'.'
]
],
[
29,
30,
'0.12.0',
new Map<string, string>([
['context', '.'],
Expand All @@ -721,11 +721,71 @@ ANOTHER_SECRET=ANOTHER_SECRET_ENV`]
'build',
'--iidfile', path.join(tmpDir, 'iidfile'),
"--output", `type=image,"name=localhost:5000/name/app:latest,localhost:5000/name/app:foo",push-by-digest=true,name-canonical=true,push=true`,
"--provenance", `mode=min,inline-only=true,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`,
'--attest', `type=provenance,mode=min,inline-only=true,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`,
'--metadata-file', path.join(tmpDir, 'metadata-file'),
'.'
]
]
],
[
31,
'0.13.1',
new Map<string, string>([
['context', '.'],
['load', 'false'],
['no-cache', 'false'],
['push', 'false'],
['pull', 'false'],
['provenance', 'mode=max'],
['sbom', 'true'],
]),
[
'build',
'--iidfile', path.join(tmpDir, 'iidfile'),
'--attest', `type=provenance,mode=max,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`,
'--attest', `type=sbom,disabled=false`,
'--metadata-file', path.join(tmpDir, 'metadata-file'),
'.'
]
],
[
32,
'0.13.1',
new Map<string, string>([
['context', '.'],
['load', 'false'],
['no-cache', 'false'],
['push', 'false'],
['pull', 'false'],
['attests', 'type=provenance,mode=min'],
['provenance', 'mode=max'],
]),
[
'build',
'--iidfile', path.join(tmpDir, 'iidfile'),
'--attest', `type=provenance,mode=max,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`,
'--metadata-file', path.join(tmpDir, 'metadata-file'),
'.'
]
],
[
33,
'0.13.1',
new Map<string, string>([
['context', '.'],
['load', 'false'],
['no-cache', 'false'],
['push', 'false'],
['pull', 'false'],
['attests', 'type=provenance,mode=min'],
]),
[
'build',
'--iidfile', path.join(tmpDir, 'iidfile'),
'--attest', `type=provenance,mode=min,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`,
'--metadata-file', path.join(tmpDir, 'metadata-file'),
'.'
]
],
])(
'[%d] given %p with %p as inputs, returns %p',
async (num: number, buildxVersion: string, inputs: Map<string, string>, expected: Array<string>) => {
Expand Down
2 changes: 1 addition & 1 deletion dist/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

79 changes: 52 additions & 27 deletions src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,6 @@ async function getBuildArgs(inputs: Inputs, context: string, toolkit: Toolkit):
if (inputs.allow.length > 0) {
args.push('--allow', inputs.allow.join(','));
}
if (await toolkit.buildx.versionSatisfies('>=0.10.0')) {
await Util.asyncForEach(inputs.attests, async attest => {
args.push('--attest', attest);
});
} else if (inputs.attests.length > 0) {
core.warning("Attestations are only supported by buildx >= 0.10.0; the input 'attests' is ignored.");
}
if (await toolkit.buildx.versionSatisfies('>=0.12.0')) {
await Util.asyncForEach(inputs.annotations, async annotation => {
args.push('--annotation', annotation);
Expand Down Expand Up @@ -157,26 +150,9 @@ async function getBuildArgs(inputs: Inputs, context: string, toolkit: Toolkit):
args.push('--platform', inputs.platforms.join(','));
}
if (await toolkit.buildx.versionSatisfies('>=0.10.0')) {
if (inputs.provenance) {
args.push('--provenance', inputs.provenance);
} else if ((await toolkit.buildkit.versionSatisfies(inputs.builder, '>=0.11.0')) && !BuildxInputs.hasDockerExporter(inputs.outputs, inputs.load)) {
// if provenance not specified and BuildKit version compatible for
// attestation, set default provenance. Also needs to make sure user
// doesn't want to explicitly load the image to docker.
if (GitHub.context.payload.repository?.private ?? false) {
// if this is a private repository, we set the default provenance
// attributes being set in buildx: https://github.com/docker/buildx/blob/fb27e3f919dcbf614d7126b10c2bc2d0b1927eb6/build/build.go#L603
args.push('--provenance', BuildxInputs.resolveProvenanceAttrs(`mode=min,inline-only=true`));
} else {
// for a public repository, we set max provenance mode.
args.push('--provenance', BuildxInputs.resolveProvenanceAttrs(`mode=max`));
}
}
if (inputs.sbom) {
args.push('--sbom', inputs.sbom);
}
} else if (inputs.provenance || inputs.sbom) {
core.warning("Attestations are only supported by buildx >= 0.10.0; the inputs 'provenance' and 'sbom' are ignored.");
args.push(...(await getAttestArgs(inputs, toolkit)));
} else {
core.warning("Attestations are only supported by buildx >= 0.10.0; the inputs 'attests', 'provenance' and 'sbom' are ignored.");
}
await Util.asyncForEach(inputs.secrets, async secret => {
try {
Expand Down Expand Up @@ -238,3 +214,52 @@ async function getCommonArgs(inputs: Inputs, toolkit: Toolkit): Promise<Array<st
}
return args;
}

async function getAttestArgs(inputs: Inputs, toolkit: Toolkit): Promise<Array<string>> {
const args: Array<string> = [];

// check if provenance attestation is set in attests input
let hasAttestProvenance = false;
await Util.asyncForEach(inputs.attests, async (attest: string) => {
if (BuildxInputs.hasAttestationType('provenance', attest)) {
hasAttestProvenance = true;
}
});

let provenanceSet = false;
let sbomSet = false;
if (inputs.provenance) {
args.push('--attest', BuildxInputs.resolveAttestationAttrs(`type=provenance,${inputs.provenance}`));
provenanceSet = true;
} else if (!hasAttestProvenance && (await toolkit.buildkit.versionSatisfies(inputs.builder, '>=0.11.0')) && !BuildxInputs.hasDockerExporter(inputs.outputs, inputs.load)) {
// if provenance not specified in provenance or attests inputs and BuildKit
// version compatible for attestation, set default provenance. Also needs
// to make sure user doesn't want to explicitly load the image to docker.
if (GitHub.context.payload.repository?.private ?? false) {
// if this is a private repository, we set the default provenance
// attributes being set in buildx: https://github.com/docker/buildx/blob/fb27e3f919dcbf614d7126b10c2bc2d0b1927eb6/build/build.go#L603
args.push('--attest', `type=provenance,${BuildxInputs.resolveProvenanceAttrs(`mode=min,inline-only=true`)}`);
} else {
// for a public repository, we set max provenance mode.
args.push('--attest', `type=provenance,${BuildxInputs.resolveProvenanceAttrs(`mode=max`)}`);
}
}
if (inputs.sbom) {
args.push('--attest', BuildxInputs.resolveAttestationAttrs(`type=sbom,${inputs.sbom}`));
sbomSet = true;
}

// set attests but check if provenance or sbom types already set as
// provenance and sbom inputs take precedence over attests input.
await Util.asyncForEach(inputs.attests, async (attest: string) => {
if (!BuildxInputs.hasAttestationType('provenance', attest) && !BuildxInputs.hasAttestationType('sbom', attest)) {
args.push('--attest', BuildxInputs.resolveAttestationAttrs(attest));
} else if (!provenanceSet && BuildxInputs.hasAttestationType('provenance', attest)) {
args.push('--attest', BuildxInputs.resolveProvenanceAttrs(attest));
} else if (!sbomSet && BuildxInputs.hasAttestationType('sbom', attest)) {
args.push('--attest', attest);
}
});

return args;
}
Loading