diff --git a/.github/workflows/.test-bake.yml b/.github/workflows/.test-bake.yml index ae02fb9f..d7aade36 100644 --- a/.github/workflows/.test-bake.yml +++ b/.github/workflows/.test-bake.yml @@ -599,13 +599,20 @@ jobs: contents: read id-token: write with: - setup-qemu: true - artifact-upload: false context: test - output: local - target: go + output: image + push: false + target: vars vars: | XX_VERSION=1.9.0 + DOCKER_METADATA_OUTPUT_VERSION=caller-version + meta-images: example/app + meta-tags: | + type=raw,value=vars-one + type=raw,value=vars-two + meta-labels: | + org.example.vars.one=one + org.example.vars.two=two bake-auth-scope: uses: ./.github/workflows/bake.yml diff --git a/.github/workflows/bake.yml b/.github/workflows/bake.yml index 7cc51ada..b3a264ae 100644 --- a/.github/workflows/bake.yml +++ b/.github/workflows/bake.yml @@ -347,6 +347,7 @@ jobs: const { GitHub } = require('@docker/github-builder-runtime/lib/github/github'); const { RunnerMapping } = require('@docker/github-builder-runtime/lib/github-builder/runner-mapping'); const { BakeTargets } = require('@docker/github-builder-runtime/lib/github-builder/bake-targets'); + const { BakeVars } = require('@docker/github-builder-runtime/lib/github-builder/bake-vars'); const { Util } = require('@docker/github-builder-runtime/lib/util'); const inpSbomImage = core.getInput('sbom-image'); @@ -359,7 +360,7 @@ jobs: const inpArtifactUpload = core.getBooleanInput('artifact-upload'); const inpJobNamePrefix = core.getInput('job-name-prefix'); const inpContext = core.getInput('context'); - const inpVars = Util.getInputList('vars'); + const inpVars = Util.getInputList('vars', {ignoreComma: true, quote: false}); const inpFiles = Util.getInputList('files'); const inpOutput = core.getInput('output'); const inpPush = core.getBooleanInput('push'); @@ -409,21 +410,12 @@ jobs: } const registryLogin = inpRegistryLogin === 'auto' ? inpOutput === 'image' && inpPush : inpRegistryLogin === 'true'; - const envs = Object.assign({}, - inpVars ? inpVars.reduce((acc, curr) => { - const idx = curr.indexOf('='); - if (idx !== -1) { - acc[curr.substring(0, idx)] = curr.substring(idx + 1); - } - return acc; - }, {}) : {}, - { - BUILDKIT_MULTI_PLATFORM: '1', - BUILDX_BAKE_GIT_AUTH_TOKEN: inpGitHubToken - } - ); - await core.group(`Set envs`, async () => { - core.info(JSON.stringify(Object.keys(envs).sort(), null, 2)); + const bakeVars = BakeVars.resolve(inpVars); + await core.group(`Set bake vars`, async () => { + core.info(JSON.stringify(bakeVars.map(value => { + const idx = value.indexOf('='); + return idx === -1 ? '' : value.substring(0, idx); + }).sort(), null, 2)); }); const metaImages = inpMetaImages.map(image => image.toLowerCase()); @@ -448,9 +440,14 @@ jobs: overrides: [...validationOverrides, '*.secrets='], sbom: inpSbom ? `generator=${inpSbomImage}` : 'false', source: bakeSource, - targets: [inpTarget] + targets: [inpTarget], + vars: bakeVars, + githubToken: inpGitHubToken }, { - env: Object.keys(envs).length > 0 ? envs : undefined + env: { + BUILDKIT_MULTI_PLATFORM: '1', + BUILDX_BAKE_DISABLE_VARS_ENV_LOOKUP: '1' + } }); if (!def) { throw new Error('Bake definition not set'); @@ -857,6 +854,7 @@ jobs: const os = require('os'); const { Build } = require('@docker/github-builder-runtime/lib/buildx/build'); const { BuildSecrets } = require('@docker/github-builder-runtime/lib/github-builder/build-secrets'); + const { BakeVars } = require('@docker/github-builder-runtime/lib/github-builder/bake-vars'); const { GitHub } = require('@docker/github-builder-runtime/lib/github/github'); const { Util } = require('@docker/github-builder-runtime/lib/util'); @@ -879,7 +877,7 @@ jobs: const inpSbom = core.getBooleanInput('sbom'); const inpSet = Util.getInputList('set', {ignoreComma: true, quote: false}); const inpTarget = core.getInput('target'); - const inpVars = Util.getInputList('vars'); + const inpVars = Util.getInputList('vars', {ignoreComma: true, quote: false}); const inpBuildkitProxyNetwork = core.getBooleanInput('buildkit-proxy-network'); const inpMetaImages = core.getMultilineInput('meta-images'); @@ -924,27 +922,15 @@ jobs: } core.setOutput('secret-dir', buildSecrets.directory); - const envs = Object.assign({}, - inpVars ? inpVars.reduce((acc, curr) => { - const idx = curr.indexOf('='); - if (idx !== -1) { - acc[curr.substring(0, idx)] = curr.substring(idx + 1); - } - return acc; - }, {}) : {}, - { - BUILDKIT_MULTI_PLATFORM: '1' - } - ); - - // Git authentication is supplied directly to the Bake action. - delete envs.BUILDX_BAKE_GIT_AUTH_TOKEN; - - await core.group(`Set envs`, async () => { - core.info(JSON.stringify(Object.keys(envs).sort(), null, 2)); - core.setOutput('envs', JSON.stringify(envs)); + const bakeVars = BakeVars.resolve(inpVars); + await core.group(`Set bake vars`, async () => { + core.info(JSON.stringify(bakeVars.map(value => { + const idx = value.indexOf('='); + return idx === -1 ? '' : value.substring(0, idx); + }).sort(), null, 2)); + core.setOutput('vars', JSON.stringify(bakeVars)); }); - + let bakeFiles = inpFiles; await core.group(`Set bake files`, async () => { if (bakeFiles.length === 0) { @@ -1019,8 +1005,11 @@ jobs: targets: ${{ steps.prepare.outputs.target }} sbom: ${{ steps.prepare.outputs.sbom }} set: ${{ steps.prepare.outputs.overrides }} + vars: ${{ steps.prepare.outputs.vars }} github-token: ${{ secrets.github-token || github.token }} - env: ${{ fromJson(steps.prepare.outputs.envs || '{}') }} + env: + BUILDKIT_MULTI_PLATFORM: '1' + BUILDX_BAKE_DISABLE_VARS_ENV_LOOKUP: '1' - name: Remove build secrets if: ${{ always() && steps.prepare.outputs.secret-dir != '' }} diff --git a/README.md b/README.md index 2751ecdb..08220c38 100644 --- a/README.md +++ b/README.md @@ -377,6 +377,14 @@ jobs: | `meta-flavor` | List | | [Flavor](https://github.com/docker/metadata-action?tab=readme-ov-file#flavor-input) defines a global behavior for `meta-tags` | | `buildkit-proxy-network` | Bool | `false` | Enable BuildKit proxy network mode for default Dockerfile `RUN` networking. See [BuildKit proxy network](#buildkit-proxy-network). | +> [!NOTE] +> The `vars` input is passed to Buildx as explicit Bake variables. Ambient +> environment lookup for Bake variables is disabled. The `CI` environment variable +> and variables with `GITHUB_`, `RUNNER_`, or `DOCKER_METADATA_OUTPUT_` prefixes +> are forwarded as explicit vars for workflows that declare them in their Bake +> definition. Multiline metadata values are preserved. Caller-provided vars take +> precedence over these forwarded values. + ### Secrets | Name | Default | Description | diff --git a/test/docker-bake.hcl b/test/docker-bake.hcl index adbbd19c..21aca2fe 100644 --- a/test/docker-bake.hcl +++ b/test/docker-bake.hcl @@ -15,6 +15,34 @@ variable "XX_VERSION" { default = null } +variable "BUILDX_VERSION" { + default = "not-leaked" +} + +variable "CI" { + default = "" +} + +variable "GITHUB_SHA" { + default = "" +} + +variable "RUNNER_OS" { + default = "" +} + +variable "DOCKER_METADATA_OUTPUT_VERSION" { + default = "" +} + +variable "DOCKER_METADATA_OUTPUT_TAGS" { + default = "" +} + +variable "DOCKER_METADATA_OUTPUT_LABELS" { + default = "" +} + target "go" { inherits = ["docker-metadata-action"] args = { @@ -23,6 +51,20 @@ target "go" { dockerfile = "go.Dockerfile" } +target "vars" { + args = { + BUILDX_VERSION = BUILDX_VERSION + CI = CI + GITHUB_SHA = GITHUB_SHA + RUNNER_OS = RUNNER_OS + XX_VERSION = XX_VERSION + DOCKER_METADATA_OUTPUT_VERSION = DOCKER_METADATA_OUTPUT_VERSION + DOCKER_METADATA_OUTPUT_TAGS = DOCKER_METADATA_OUTPUT_TAGS + DOCKER_METADATA_OUTPUT_LABELS = DOCKER_METADATA_OUTPUT_LABELS + } + dockerfile = "vars.Dockerfile" +} + target "go-cross" { inherits = ["go"] platforms = ["linux/amd64", "linux/arm64"] diff --git a/test/vars.Dockerfile b/test/vars.Dockerfile new file mode 100644 index 00000000..8c830ec6 --- /dev/null +++ b/test/vars.Dockerfile @@ -0,0 +1,25 @@ +# syntax=docker/dockerfile:1 + +FROM alpine +ARG BUILDX_VERSION +ARG CI +ARG GITHUB_SHA +ARG RUNNER_OS +ARG XX_VERSION +ARG DOCKER_METADATA_OUTPUT_VERSION +ARG DOCKER_METADATA_OUTPUT_TAGS +ARG DOCKER_METADATA_OUTPUT_LABELS +RUN test "$BUILDX_VERSION" = "not-leaked" +RUN test "$CI" = "true" +RUN test -n "$GITHUB_SHA" +RUN test -n "$RUNNER_OS" +RUN test "$XX_VERSION" = "1.9.0" +RUN test "$DOCKER_METADATA_OUTPUT_VERSION" = "caller-version" +RUN printf '%s\n' "$DOCKER_METADATA_OUTPUT_TAGS" | grep -Fx 'example/app:vars-one' \ + && printf '%s\n' "$DOCKER_METADATA_OUTPUT_TAGS" | grep -Fx 'example/app:vars-two' +RUN printf '%s\n' "$DOCKER_METADATA_OUTPUT_LABELS" | grep -Fx 'org.example.vars.one=one' \ + && printf '%s\n' "$DOCKER_METADATA_OUTPUT_LABELS" | grep -Fx 'org.example.vars.two=two' +RUN mkdir -p /out && printf 'ok\n' > /out/vars.txt + +FROM scratch +COPY --from=0 /out /