Merge pull request #759 from crazy-max/fix-provenance-input

Fix provenance input
This commit is contained in:
CrazyMax 2023-01-13 13:06:45 +01:00 committed by GitHub
commit d1b0eb0a29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 188 additions and 13 deletions

@ -523,6 +523,41 @@ jobs:
file: ./test/go/Dockerfile
outputs: type=cacheonly
provenance:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
attrs:
- ''
- mode=max
- builder-id=foo
- false
- true
steps:
-
name: Checkout
uses: actions/checkout@v3
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
with:
version: ${{ inputs.buildx-version || env.BUILDX_VERSION }}
driver-opts: |
network=host
image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }}
-
name: Build
uses: ./
with:
context: ./test/go
file: ./test/go/Dockerfile
target: binary
outputs: type=oci,dest=/tmp/build.tar
provenance: ${{ matrix.attrs }}
cache-from: type=gha,scope=provenance
cache-to: type=gha,scope=provenance,mode=max
sbom:
runs-on: ubuntu-latest
strategy:

@ -2,6 +2,7 @@ import {beforeEach, describe, expect, it, jest, test} from '@jest/globals';
import * as fs from 'fs';
import * as path from 'path';
import * as buildx from '../src/buildx';
import * as context from '../src/context';
const pgp = `-----BEGIN PGP PRIVATE KEY BLOCK-----
@ -127,6 +128,8 @@ jest.spyOn(context, 'tmpNameSync').mockImplementation((): string => {
return path.join('/tmp/.docker-build-push-jest', '.tmpname-jest').split(path.sep).join(path.posix.sep);
});
jest.spyOn(buildx, 'satisfiesBuildKitVersion').mockResolvedValueOnce(true);
describe('getArgs', () => {
beforeEach(() => {
process.env = Object.keys(process.env).reduce((object, key) => {
@ -159,7 +162,11 @@ describe('getArgs', () => {
1,
'0.4.2',
new Map<string, string>([
['build-args', 'MY_ARG=val1,val2,val3\nARG=val'],
['build-args', `MY_ARG=val1,val2,val3
ARG=val
"MULTILINE=aaaa
bbbb
ccc"`],
['load', 'false'],
['no-cache', 'false'],
['push', 'false'],
@ -169,6 +176,7 @@ describe('getArgs', () => {
'build',
'--build-arg', 'MY_ARG=val1,val2,val3',
'--build-arg', 'ARG=val',
'--build-arg', `MULTILINE=aaaa\nbbbb\nccc`,
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
'https://github.com/docker/build-push-action.git#refs/heads/test-jest'
]
@ -517,7 +525,119 @@ nproc=3`],
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
'https://github.com/docker/build-push-action.git#refs/heads/test-jest:subdir'
]
],
[
17,
'0.8.2',
new Map<string, string>([
['context', '.'],
['load', 'false'],
['no-cache', 'false'],
['push', 'false'],
['pull', 'false'],
['provenance', 'true'],
]),
[
'build',
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
'.'
]
],
[
18,
'0.10.0',
new Map<string, string>([
['context', '.'],
['load', 'false'],
['no-cache', 'false'],
['push', 'false'],
['pull', 'false'],
]),
[
'build',
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
"--provenance", `mode=min,inline-only=true,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`,
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
'.'
]
],
[
19,
'0.10.0',
new Map<string, string>([
['context', '.'],
['load', 'false'],
['no-cache', 'false'],
['push', 'false'],
['pull', 'false'],
['provenance', 'true'],
]),
[
'build',
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
"--provenance", `builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`,
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
'.'
]
],
[
20,
'0.10.0',
new Map<string, string>([
['context', '.'],
['load', 'false'],
['no-cache', 'false'],
['push', 'false'],
['pull', 'false'],
['provenance', 'mode=max'],
]),
[
'build',
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
"--provenance", `mode=max,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`,
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
'.'
]
],
[
21,
'0.10.0',
new Map<string, string>([
['context', '.'],
['load', 'false'],
['no-cache', 'false'],
['push', 'false'],
['pull', 'false'],
['provenance', 'false'],
]),
[
'build',
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
"--provenance", 'false',
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
'.'
]
],
[
22,
'0.10.0',
new Map<string, string>([
['context', '.'],
['load', 'false'],
['no-cache', 'false'],
['push', 'false'],
['pull', 'false'],
['provenance', 'builder-id=foo'],
]),
[
'build',
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
"--provenance", 'builder-id=foo',
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
'.'
]
],
])(
'[%d] given %p with %p as inputs, returns %p',
async (num: number, buildxVersion: string, inputs: Map<string, string>, expected: Array<string>) => {

@ -68,6 +68,8 @@ FROM docker/buildx-bin:${BUILDX_VERSION} as buildx
FROM deps AS test
ENV RUNNER_TEMP=/tmp/github_runner
ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache
ENV GITHUB_REPOSITORY=docker/build-push-action
ENV GITHUB_RUN_ID=123456789
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules \
--mount=type=bind,from=docker,source=/usr/local/bin/docker,target=/usr/bin/docker \

2
dist/index.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

@ -68,6 +68,10 @@ export function tmpNameSync(options?: tmp.TmpNameOptions): string {
return tmp.tmpNameSync(options);
}
export function provenanceBuilderID(): string {
return `${process.env.GITHUB_SERVER_URL || 'https://github.com'}/${github.context.repo.owner}/${github.context.repo.repo}/actions/runs/${github.context.runId}`;
}
export async function getInputs(defaultContext: string): Promise<Inputs> {
return {
addHosts: await getInputList('add-hosts'),
@ -88,7 +92,7 @@ export async function getInputs(defaultContext: string): Promise<Inputs> {
noCacheFilters: await getInputList('no-cache-filters'),
outputs: await getInputList('outputs', true),
platforms: await getInputList('platforms'),
provenance: core.getInput('provenance'),
provenance: getProvenanceInput('provenance'),
pull: core.getBooleanInput('pull'),
push: core.getBooleanInput('push'),
sbom: core.getInput('sbom'),
@ -162,9 +166,8 @@ async function getBuildArgs(inputs: Inputs, defaultContext: string, context: str
args.push('--platform', inputs.platforms.join(','));
}
if (buildx.satisfies(buildxVersion, '>=0.10.0')) {
const prvBuilderID = `${process.env.GITHUB_SERVER_URL || 'https://github.com'}/${github.context.repo.owner}/${github.context.repo.repo}/actions/runs/${github.context.runId}`;
if (inputs.provenance) {
args.push('--provenance', getProvenanceAttrs(inputs.provenance, prvBuilderID));
args.push('--provenance', inputs.provenance);
} else if ((await buildx.satisfiesBuildKitVersion(inputs.builder, '>=0.11.0', standalone)) && !hasDockerExport(inputs)) {
// if provenance not specified and BuildKit version compatible for
// attestation, set default provenance. Also needs to make sure user
@ -172,12 +175,10 @@ async function getBuildArgs(inputs: Inputs, defaultContext: string, context: str
if (fromPayload('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
// along the builder-id attribute.
args.push('--provenance', `mode=min,inline-only=true,builder-id=${prvBuilderID}`);
args.push('--provenance', getProvenanceAttrs(`mode=min,inline-only=true`));
} else {
// for a public repository, we set max provenance mode and the
// builder-id attribute.
args.push('--provenance', `mode=max,builder-id=${prvBuilderID}`);
// for a public repository, we set max provenance mode.
args.push('--provenance', getProvenanceAttrs(`mode=max`));
}
}
if (inputs.sbom) {
@ -298,7 +299,24 @@ function select(obj: any, path: string): any {
return select(obj[key], path.slice(i + 1));
}
function getProvenanceAttrs(input: string, builderID: string): string {
function getProvenanceInput(name: string): string {
const input = core.getInput(name);
if (!input) {
// if input is not set, default values will be set later.
return input;
}
const builderID = provenanceBuilderID();
try {
return core.getBooleanInput(name) ? `builder-id=${builderID}` : 'false';
} catch (err) {
// not a valid boolean, so we assume it's a string
return getProvenanceAttrs(input);
}
}
function getProvenanceAttrs(input: string): string {
const builderID = provenanceBuilderID();
// parse attributes from input
const fields = parse(input, {
relaxColumnCount: true,
skipEmptyLines: true