From ed2672fc3300b43c2e53190c739149d7ce8b7dad Mon Sep 17 00:00:00 2001 From: CrazyMax Date: Wed, 11 Jan 2023 12:12:09 +0100 Subject: [PATCH] add `attests`, `provenance` and `sbom` inputs Signed-off-by: CrazyMax --- .github/workflows/ci.yml | 64 ++++++++++++++++++++++++++++++++++++++++ README.md | 61 ++++++++++++++++++++------------------ action.yml | 9 ++++++ src/context.ts | 19 ++++++++++++ 4 files changed, 124 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 222e971..cdcb319 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -491,6 +491,70 @@ jobs: cache-from: type=gha,scope=nocachefilter cache-to: type=gha,scope=nocachefilter,mode=max + attests: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - target: image + output: type=image,name=localhost:5000/name/app:latest,push=true + - target: binary + output: /tmp/buildx-build + services: + registry: + image: registry:2 + ports: + - 5000:5000 + env: + BUILDX_VERSION: v0.10.0-rc2 # TODO: remove when Buildx v0.10.0 is released + BUILDKIT_IMAGE: moby/buildkit:v0.11.0-rc3 # TODO: remove when BuildKit v0.11.0 is released + 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: ${{ matrix.target }} + outputs: ${{ matrix.output }} + attests: | + type=sbom + type=provenance,mode=max,builder-id=https://github.com/${{ env.GITHUB_REPOSITORY }}/actions/runs/${{ env.GITHUB_RUN_ID }} + cache-from: type=gha,scope=attests-${{ matrix.target }} + cache-to: type=gha,scope=attests-${{ matrix.target }},mode=max + - + name: Inspect image + if: matrix.target == 'image' + run: | + docker buildx imagetools inspect --format "{{json .}}" localhost:5000/name/app:latest | jq + - + name: Check output folder + if: matrix.target == 'binary' + run: | + tree /tmp/buildx-build + - + name: Print provenance + if: matrix.target == 'binary' + run: | + cat /tmp/buildx-build/provenance.json | jq + - + name: Print SBOM + if: matrix.target == 'binary' + run: | + cat /tmp/buildx-build/sbom.spdx.json | jq + multi: runs-on: ubuntu-latest strategy: diff --git a/README.md b/README.md index 1784b03..b7dfdeb 100644 --- a/README.md +++ b/README.md @@ -190,35 +190,38 @@ Following inputs can be used as `step.with` keys > tags: name/app:latest,name/app:1.0.0 > ``` -| Name | Type | Description | -|--------------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `add-hosts` | List/CSV | List of [customs host-to-IP mapping](https://docs.docker.com/engine/reference/commandline/build/#add-entries-to-container-hosts-file---add-host) (e.g., `docker:10.180.0.1`) | -| `allow` | List/CSV | List of [extra privileged entitlement](https://docs.docker.com/engine/reference/commandline/buildx_build/#allow) (e.g., `network.host,security.insecure`) | -| `builder` | String | Builder instance (see [setup-buildx](https://github.com/docker/setup-buildx-action) action) | -| `build-args` | List | List of [build-time variables](https://docs.docker.com/engine/reference/commandline/buildx_build/#build-arg) | -| `build-contexts` | List | List of additional [build contexts](https://docs.docker.com/engine/reference/commandline/buildx_build/#build-context) (e.g., `name=path`) | -| `cache-from` | List | List of [external cache sources](https://docs.docker.com/engine/reference/commandline/buildx_build/#cache-from) (e.g., `type=local,src=path/to/dir`) | -| `cache-to` | List | List of [cache export destinations](https://docs.docker.com/engine/reference/commandline/buildx_build/#cache-to) (e.g., `type=local,dest=path/to/dir`) | -| `cgroup-parent` | String | Optional [parent cgroup](https://docs.docker.com/engine/reference/commandline/build/#use-a-custom-parent-cgroup---cgroup-parent) for the container used in the build | -| `context` | String | Build's context is the set of files located in the specified [`PATH` or `URL`](https://docs.docker.com/engine/reference/commandline/build/) (default [Git context](#git-context)) | -| `file` | String | Path to the Dockerfile. (default `{context}/Dockerfile`) | -| `labels` | List | List of metadata for an image | -| `load` | Bool | [Load](https://docs.docker.com/engine/reference/commandline/buildx_build/#load) is a shorthand for `--output=type=docker` (default `false`) | -| `network` | String | Set the networking mode for the `RUN` instructions during build | -| `no-cache` | Bool | Do not use cache when building the image (default `false`) | -| `no-cache-filters` | List/CSV | Do not cache specified stages | -| `outputs`¹ | List | List of [output destinations](https://docs.docker.com/engine/reference/commandline/buildx_build/#output) (format: `type=local,dest=path`) | -| `platforms` | List/CSV | List of [target platforms](https://docs.docker.com/engine/reference/commandline/buildx_build/#platform) for build | -| `pull` | Bool | Always attempt to pull all referenced images (default `false`) | -| `push` | Bool | [Push](https://docs.docker.com/engine/reference/commandline/buildx_build/#push) is a shorthand for `--output=type=registry` (default `false`) | -| `secrets` | List | List of [secrets](https://docs.docker.com/engine/reference/commandline/buildx_build/#secret) to expose to the build (e.g., `key=string`, `GIT_AUTH_TOKEN=mytoken`) | -| `secret-files` | List | List of [secret files](https://docs.docker.com/engine/reference/commandline/buildx_build/#secret) to expose to the build (e.g., `key=filename`, `MY_SECRET=./secret.txt`) | -| `shm-size` | String | Size of [`/dev/shm`](https://docs.docker.com/engine/reference/commandline/buildx_build/#shm-size) (e.g., `2g`) | -| `ssh` | List | List of [SSH agent socket or keys](https://docs.docker.com/engine/reference/commandline/buildx_build/#ssh) to expose to the build | -| `tags` | List/CSV | List of tags | -| `target` | String | Sets the target stage to build | -| `ulimit` | List | [Ulimit](https://docs.docker.com/engine/reference/commandline/buildx_build/#ulimit) options (e.g., `nofile=1024:1024`) | -| `github-token` | String | GitHub Token used to authenticate against a repository for [Git context](#git-context) (default `${{ github.token }}`) | +| Name | Type | Description | +|--------------------|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `add-hosts` | List/CSV | List of [customs host-to-IP mapping](https://docs.docker.com/engine/reference/commandline/build/#add-entries-to-container-hosts-file---add-host) (e.g., `docker:10.180.0.1`) | +| `allow` | List/CSV | List of [extra privileged entitlement](https://docs.docker.com/engine/reference/commandline/buildx_build/#allow) (e.g., `network.host,security.insecure`) | +| `attests` | List | List of [attestation](https://docs.docker.com/build/attestations/) parameters (e.g., `type=sbom,generator=image`) | +| `builder` | String | Builder instance (see [setup-buildx](https://github.com/docker/setup-buildx-action) action) | +| `build-args` | List | List of [build-time variables](https://docs.docker.com/engine/reference/commandline/buildx_build/#build-arg) | +| `build-contexts` | List | List of additional [build contexts](https://docs.docker.com/engine/reference/commandline/buildx_build/#build-context) (e.g., `name=path`) | +| `cache-from` | List | List of [external cache sources](https://docs.docker.com/engine/reference/commandline/buildx_build/#cache-from) (e.g., `type=local,src=path/to/dir`) | +| `cache-to` | List | List of [cache export destinations](https://docs.docker.com/engine/reference/commandline/buildx_build/#cache-to) (e.g., `type=local,dest=path/to/dir`) | +| `cgroup-parent` | String | Optional [parent cgroup](https://docs.docker.com/engine/reference/commandline/build/#use-a-custom-parent-cgroup---cgroup-parent) for the container used in the build | +| `context` | String | Build's context is the set of files located in the specified [`PATH` or `URL`](https://docs.docker.com/engine/reference/commandline/build/) (default [Git context](#git-context)) | +| `file` | String | Path to the Dockerfile. (default `{context}/Dockerfile`) | +| `labels` | List | List of metadata for an image | +| `load` | Bool | [Load](https://docs.docker.com/engine/reference/commandline/buildx_build/#load) is a shorthand for `--output=type=docker` (default `false`) | +| `network` | String | Set the networking mode for the `RUN` instructions during build | +| `no-cache` | Bool | Do not use cache when building the image (default `false`) | +| `no-cache-filters` | List/CSV | Do not cache specified stages | +| `outputs`¹ | List | List of [output destinations](https://docs.docker.com/engine/reference/commandline/buildx_build/#output) (format: `type=local,dest=path`) | +| `platforms` | List/CSV | List of [target platforms](https://docs.docker.com/engine/reference/commandline/buildx_build/#platform) for build | +| `provenance` | Bool/String | Generate [provenance](https://docs.docker.com/build/attestations/slsa-provenance/) attestation for the build (shorthand for `--attest=type=provenance`) | +| `pull` | Bool | Always attempt to pull all referenced images (default `false`) | +| `push` | Bool | [Push](https://docs.docker.com/engine/reference/commandline/buildx_build/#push) is a shorthand for `--output=type=registry` (default `false`) | +| `sbom` | Bool/String | Generate [SBOM](https://docs.docker.com/build/attestations/sbom/) attestation for the build (shorthand for `--attest=type=sbom`) | +| `secrets` | List | List of [secrets](https://docs.docker.com/engine/reference/commandline/buildx_build/#secret) to expose to the build (e.g., `key=string`, `GIT_AUTH_TOKEN=mytoken`) | +| `secret-files` | List | List of [secret files](https://docs.docker.com/engine/reference/commandline/buildx_build/#secret) to expose to the build (e.g., `key=filename`, `MY_SECRET=./secret.txt`) | +| `shm-size` | String | Size of [`/dev/shm`](https://docs.docker.com/engine/reference/commandline/buildx_build/#shm-size) (e.g., `2g`) | +| `ssh` | List | List of [SSH agent socket or keys](https://docs.docker.com/engine/reference/commandline/buildx_build/#ssh) to expose to the build | +| `tags` | List/CSV | List of tags | +| `target` | String | Sets the target stage to build | +| `ulimit` | List | [Ulimit](https://docs.docker.com/engine/reference/commandline/buildx_build/#ulimit) options (e.g., `nofile=1024:1024`) | +| `github-token` | String | GitHub Token used to authenticate against a repository for [Git context](#git-context) (default `${{ github.token }}`) | > **Note** > diff --git a/action.yml b/action.yml index b12c91c..9edfb3a 100644 --- a/action.yml +++ b/action.yml @@ -13,6 +13,9 @@ inputs: allow: description: "List of extra privileged entitlement (e.g., network.host,security.insecure)" required: false + attests: + description: "List of attestation parameters (e.g., type=sbom,generator=image)" + required: false build-args: description: "List of build-time variables" required: false @@ -60,6 +63,9 @@ inputs: platforms: description: "List of target platforms for build" required: false + provenance: + description: "Generate provenance attestation for the build (shorthand for --attest=type=provenance)" + required: false pull: description: "Always attempt to pull all referenced images" required: false @@ -68,6 +74,9 @@ inputs: description: "Push is a shorthand for --output=type=registry" required: false default: 'false' + sbom: + description: "Generate SBOM attestation for the build (shorthand for --attest=type=sbom)" + required: false secrets: description: "List of secrets to expose to the build (e.g., key=string, GIT_AUTH_TOKEN=mytoken)" required: false diff --git a/src/context.ts b/src/context.ts index cf18e6a..25b7a91 100644 --- a/src/context.ts +++ b/src/context.ts @@ -13,6 +13,7 @@ let _defaultContext, _tmpDir: string; export interface Inputs { addHosts: string[]; allow: string[]; + attests: string[]; buildArgs: string[]; buildContexts: string[]; builder: string; @@ -28,8 +29,10 @@ export interface Inputs { noCacheFilters: string[]; outputs: string[]; platforms: string[]; + provenance: string; pull: boolean; push: boolean; + sbom: string; secrets: string[]; secretFiles: string[]; shmSize: string; @@ -69,6 +72,7 @@ export async function getInputs(defaultContext: string): Promise { return { addHosts: await getInputList('add-hosts'), allow: await getInputList('allow'), + attests: await getInputList('attests', true), buildArgs: await getInputList('build-args', true), buildContexts: await getInputList('build-contexts', true), builder: core.getInput('builder'), @@ -84,8 +88,10 @@ export async function getInputs(defaultContext: string): Promise { noCacheFilters: await getInputList('no-cache-filters'), outputs: await getInputList('outputs', true), platforms: await getInputList('platforms'), + provenance: core.getInput('provenance'), pull: core.getBooleanInput('pull'), push: core.getBooleanInput('push'), + sbom: core.getInput('sbom'), secrets: await getInputList('secrets', true), secretFiles: await getInputList('secret-files', true), shmSize: core.getInput('shm-size'), @@ -115,6 +121,11 @@ async function getBuildArgs(inputs: Inputs, defaultContext: string, context: str if (inputs.allow.length > 0) { args.push('--allow', inputs.allow.join(',')); } + if (buildx.satisfies(buildxVersion, '>=0.10.0')) { + await asyncForEach(inputs.attests, async attest => { + args.push('--attest', attest); + }); + } await asyncForEach(inputs.buildArgs, async buildArg => { args.push('--build-arg', buildArg); }); @@ -150,6 +161,14 @@ async function getBuildArgs(inputs: Inputs, defaultContext: string, context: str if (inputs.platforms.length > 0) { args.push('--platform', inputs.platforms.join(',')); } + if (buildx.satisfies(buildxVersion, '>=0.10.0')) { + if (inputs.provenance) { + args.push('--provenance', inputs.provenance); + } + if (inputs.sbom) { + args.push('--sbom', inputs.sbom); + } + } await asyncForEach(inputs.secrets, async secret => { try { args.push('--secret', await buildx.getSecretString(secret));