Skip to content

Commit 3391599

Browse files
committed
add registry-login input for optional registry auth before build
Signed-off-by: CrazyMax <[email protected]>
1 parent 37573c9 commit 3391599

7 files changed

Lines changed: 130 additions & 15 deletions

File tree

.github/workflows/.test-bake.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,3 +621,25 @@ jobs:
621621
- registry: ghcr.io
622622
username: ${{ github.actor }}
623623
password: ${{ secrets.GITHUB_TOKEN }}
624+
625+
bake-local-login:
626+
uses: ./.github/workflows/bake.yml
627+
if: ${{ github.event_name != 'pull_request' }}
628+
permissions:
629+
contents: read
630+
id-token: write
631+
with:
632+
artifact-name: bake-login-output
633+
artifact-upload: true
634+
context: test
635+
output: local
636+
registry-login: true
637+
sbom: true
638+
sign: true
639+
target: dhi
640+
secrets:
641+
registry-auths: |
642+
- registry: dhi.io
643+
username: ${{ vars.DOCKERPUBLICBOT_USERNAME }}
644+
password: ${{ secrets.DOCKERPUBLICBOT_READ_PAT }}
645+
scope: 'dhi.io@pull'

.github/workflows/.test-build.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,3 +640,24 @@ jobs:
640640
- registry: ghcr.io
641641
username: ${{ github.actor }}
642642
password: ${{ secrets.GITHUB_TOKEN }}
643+
644+
build-local-login:
645+
uses: ./.github/workflows/build.yml
646+
if: ${{ github.event_name != 'pull_request' }}
647+
permissions:
648+
contents: read
649+
id-token: write
650+
with:
651+
artifact-name: build-login-output
652+
artifact-upload: true
653+
file: test/dhi.Dockerfile
654+
output: local
655+
registry-login: true
656+
sbom: true
657+
sign: true
658+
secrets:
659+
registry-auths: |
660+
- registry: dhi.io
661+
username: ${{ vars.DOCKERPUBLICBOT_USERNAME }}
662+
password: ${{ secrets.DOCKERPUBLICBOT_READ_PAT }}
663+
scope: 'dhi.io@pull'

.github/workflows/bake.yml

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ on:
6565
description: "Push image to the registry (for image output)"
6666
required: false
6767
default: false
68+
registry-login:
69+
type: string
70+
description: "Login to registry before build (one of auto, true or false). Auto enables login only when output is image and push is true"
71+
required: false
72+
default: auto
6873
sbom:
6974
type: boolean
7075
description: "Generate SBOM attestation for the build"
@@ -125,7 +130,7 @@ on:
125130
required: false
126131
secrets:
127132
registry-auths:
128-
description: "Raw authentication to registries, defined as YAML objects (for image output)"
133+
description: "Raw authentication to registries, defined as YAML objects"
129134
required: false
130135
github-token:
131136
description: "GitHub Token used to authenticate against the repository for Git context"
@@ -172,6 +177,7 @@ jobs:
172177
includes: ${{ steps.set.outputs.includes }}
173178
sign: ${{ steps.set.outputs.sign }}
174179
ghaCacheSign: ${{ steps.set.outputs.ghaCacheSign }}
180+
registryLogin: ${{ steps.set.outputs.registryLogin }}
175181
steps:
176182
-
177183
name: Install dependencies
@@ -258,6 +264,7 @@ jobs:
258264
INPUT_FILES: ${{ inputs.files }}
259265
INPUT_OUTPUT: ${{ inputs.output }}
260266
INPUT_PUSH: ${{ inputs.push }}
267+
INPUT_REGISTRY-LOGIN: ${{ inputs.registry-login }}
261268
INPUT_SBOM: ${{ inputs.sbom }}
262269
INPUT_SET: ${{ inputs.set }}
263270
INPUT_SIGN: ${{ inputs.sign }}
@@ -284,6 +291,7 @@ jobs:
284291
const inpFiles = Util.getInputList('files');
285292
const inpOutput = core.getInput('output');
286293
const inpPush = core.getBooleanInput('push');
294+
const inpRegistryLogin = core.getInput('registry-login');
287295
const inpSbom = core.getBooleanInput('sbom');
288296
const inpSet = Util.getInputList('set', {ignoreComma: true, quote: false});
289297
const inpSign = core.getInput('sign');
@@ -314,12 +322,18 @@ jobs:
314322
core.setFailed(`signing attestation manifests requires push to be enabled`);
315323
return;
316324
}
317-
325+
318326
const bakeSource = await new Build().gitContext({subdir: inpContext});
319327
await core.group(`Set bake source`, async () => {
320328
core.info(bakeSource);
321329
});
322330
331+
if (!['auto', 'true', 'false'].includes(inpRegistryLogin)) {
332+
core.setFailed(`Invalid registry-login input: ${inpRegistryLogin}`);
333+
return;
334+
}
335+
const registryLogin = inpRegistryLogin === 'auto' ? inpOutput === 'image' && inpPush : inpRegistryLogin === 'true';
336+
323337
const envs = Object.assign({},
324338
inpVars ? inpVars.reduce((acc, curr) => {
325339
const idx = curr.indexOf('=');
@@ -336,7 +350,7 @@ jobs:
336350
await core.group(`Set envs`, async () => {
337351
core.info(JSON.stringify(envs, null, 2));
338352
});
339-
353+
340354
let def;
341355
let target;
342356
try {
@@ -405,7 +419,7 @@ jobs:
405419
core.setFailed(`Platforms to build exceed matrix size limit of ${inpMatrixSizeLimit}`);
406420
return;
407421
}
408-
422+
409423
const privateRepo = GitHub.context.payload.repository?.private ?? false;
410424
await core.group(`Set privateRepo output`, async () => {
411425
core.info(`privateRepo: ${privateRepo}`);
@@ -440,6 +454,10 @@ jobs:
440454
core.info(`ghaCacheSign: ${ghaCacheSign}`);
441455
core.setOutput('ghaCacheSign', ghaCacheSign);
442456
});
457+
await core.group(`Set registryLogin output`, async () => {
458+
core.info(`registryLogin: ${registryLogin}`);
459+
core.setOutput('registryLogin', registryLogin);
460+
});
443461
444462
build:
445463
runs-on: ${{ matrix.runner }}
@@ -782,7 +800,7 @@ jobs:
782800
});
783801
-
784802
name: Login to registry
785-
if: ${{ inputs.push && inputs.output == 'image' }}
803+
if: ${{ needs.prepare.outputs.registryLogin == 'true' }}
786804
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
787805
with:
788806
registry-auth: ${{ secrets.registry-auths }}

.github/workflows/build.yml

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ on:
8181
description: "Push image to the registry (for image output)"
8282
required: false
8383
default: false
84+
registry-login:
85+
type: string
86+
description: "Login to registry before build (one of auto, true or false). Auto enables login only when output is image and push is true"
87+
required: false
88+
default: auto
8489
sbom:
8590
type: boolean
8691
description: "Generate SBOM attestation for the build"
@@ -128,7 +133,7 @@ on:
128133
required: false
129134
secrets:
130135
registry-auths:
131-
description: "Raw authentication to registries, defined as YAML objects (for image output)"
136+
description: "Raw authentication to registries, defined as YAML objects"
132137
required: false
133138
github-token:
134139
description: "GitHub Token used to authenticate against the repository for Git context"
@@ -176,6 +181,7 @@ jobs:
176181
sign: ${{ steps.set.outputs.sign }}
177182
privateRepo: ${{ steps.set.outputs.privateRepo }}
178183
ghaCacheSign: ${{ steps.set.outputs.ghaCacheSign }}
184+
registryLogin: ${{ steps.set.outputs.registryLogin }}
179185
steps:
180186
-
181187
name: Install dependencies
@@ -252,6 +258,7 @@ jobs:
252258
INPUT_OUTPUT: ${{ inputs.output }}
253259
INPUT_PLATFORMS: ${{ inputs.platforms }}
254260
INPUT_PUSH: ${{ inputs.push }}
261+
INPUT_REGISTRY-LOGIN: ${{ inputs.registry-login }}
255262
INPUT_SIGN: ${{ inputs.sign }}
256263
with:
257264
script: |
@@ -267,6 +274,7 @@ jobs:
267274
const inpPlatforms = Util.getInputList('platforms');
268275
const inpOutput = core.getInput('output');
269276
const inpPush = core.getBooleanInput('push');
277+
const inpRegistryLogin = core.getInput('registry-login');
270278
const inpSign = core.getInput('sign');
271279
272280
let runner = inpRunner;
@@ -294,6 +302,12 @@ jobs:
294302
return;
295303
}
296304
305+
if (!['auto', 'true', 'false'].includes(inpRegistryLogin)) {
306+
core.setFailed(`Invalid registry-login input: ${inpRegistryLogin}`);
307+
return;
308+
}
309+
const registryLogin = inpRegistryLogin === 'auto' ? inpOutput === 'image' && inpPush : inpRegistryLogin === 'true';
310+
297311
if (inpDistribute && inpPlatforms.length > inpMatrixSizeLimit) {
298312
core.setFailed(`Platforms to build exceed matrix size limit of ${inpMatrixSizeLimit}`);
299313
return;
@@ -333,6 +347,10 @@ jobs:
333347
core.info(`ghaCacheSign: ${ghaCacheSign}`);
334348
core.setOutput('ghaCacheSign', ghaCacheSign);
335349
});
350+
await core.group(`Set registryLogin output`, async () => {
351+
core.info(`registryLogin: ${registryLogin}`);
352+
core.setOutput('registryLogin', registryLogin);
353+
});
336354
337355
build:
338356
runs-on: ${{ matrix.runner }}
@@ -640,7 +658,7 @@ jobs:
640658
}
641659
-
642660
name: Login to registry
643-
if: ${{ inputs.push && inputs.output == 'image' }}
661+
if: ${{ needs.prepare.outputs.registryLogin == 'true' }}
644662
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
645663
with:
646664
registry-auth: ${{ secrets.registry-auths }}

README.md

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ jobs:
239239
| `output` | String | | Build output destination (one of [`image`](https://docs.docker.com/build/exporters/image-registry/) or [`local`](https://docs.docker.com/build/exporters/local-tar/)). Unlike the `build-push-action`, it only accepts `image` or `local`. The reusable workflow takes care of setting the `outputs` attribute |
240240
| `platforms` | List/CSV | | List of [target platforms](https://docs.docker.com/engine/reference/commandline/buildx_build/#platform) to build |
241241
| `push` | Bool | `false` | [Push](https://docs.docker.com/engine/reference/commandline/buildx_build/#push) image to the registry (for `image` output) |
242+
| `registry-login` | String | `auto` | Login to registry before build (one of `auto`, `true` or `false`). `auto` enables login only when output is `image` and push is `true` |
242243
| `sbom` | Bool | `false` | Generate [SBOM](https://docs.docker.com/build/attestations/sbom/) attestation for the build |
243244
| `shm-size` | String | | Size of [`/dev/shm`](https://docs.docker.com/engine/reference/commandline/buildx_build/#shm-size) (e.g., `2g`) |
244245
| `sign` | String | `auto` | Sign attestation manifest for `image` output or artifacts for `local` output, can be one of `auto`, `true` or `false`. The `auto` mode will enable signing if `push` is enabled for pushing the `image` or if `artifact-upload` is enabled for uploading the `local` build output as GitHub Artifact |
@@ -250,6 +251,16 @@ jobs:
250251
| `meta-tags` | List | | [List of tags](https://github.com/docker/metadata-action?tab=readme-ov-file#tags-input) as key-value pair attributes |
251252
| `meta-flavor` | List | | [Flavor](https://github.com/docker/metadata-action?tab=readme-ov-file#flavor-input) defines a global behavior for `meta-tags` |
252253

254+
> [!NOTE]
255+
> `registry-login: true` forces a pre-build login attempt and will fail if the
256+
> resolved credentials are empty, for example, on forked pull requests where
257+
> secrets are not exposed. Gate this input at the caller side if you need
258+
> fork-safe behavior:
259+
>
260+
> ```yaml
261+
> registry-login: ${{ github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork }}
262+
> ```
263+
253264
> [!TIP]
254265
> When `output=image`, following inputs support Handlebars templates rendered
255266
> from selected `docker/metadata-action` outputs:
@@ -275,10 +286,10 @@ jobs:
275286

276287
#### Secrets
277288

278-
| Name | Default | Description |
279-
|------------------|-----------------------|--------------------------------------------------------------------------------|
280-
| `registry-auths` | | Raw authentication to registries, defined as YAML objects (for `image` output) |
281-
| `github-token` | `${{ github.token }}` | GitHub Token used to authenticate against the repository for Git context |
289+
| Name | Default | Description |
290+
|------------------|-----------------------|----------------------------------------------------------------------------------------------------------------|
291+
| `registry-auths` | | Raw authentication to registries, defined as YAML objects (used for push/signing and optional pre-build login) |
292+
| `github-token` | `${{ github.token }}` | GitHub Token used to authenticate against the repository for Git context |
282293

283294
#### Outputs
284295

@@ -384,6 +395,7 @@ jobs:
384395
| `files` | List | `{context}/docker-bake.hcl` | List of bake definition files |
385396
| `output` | String | | Build output destination (one of [`image`](https://docs.docker.com/build/exporters/image-registry/) or [`local`](https://docs.docker.com/build/exporters/local-tar/)). |
386397
| `push` | Bool | `false` | Push image to the registry (for `image` output) |
398+
| `registry-login` | String | `auto` | Login to registry before build (one of `auto`, `true` or `false`). `auto` enables login only when output is `image` and push is `true` |
387399
| `sbom` | Bool | `false` | Generate [SBOM](https://docs.docker.com/build/attestations/sbom/) attestation for the build |
388400
| `set` | List | | List of [target values to override](https://docs.docker.com/engine/reference/commandline/buildx_bake/#set) (e.g., `targetpattern.key=value`) |
389401
| `sign` | String | `auto` | Sign attestation manifest for `image` output or artifacts for `local` output, can be one of `auto`, `true` or `false`. The `auto` mode will enable signing if `push` is enabled for pushing the `image` or if `artifact-upload` is enabled for uploading the `local` build output as GitHub Artifact |
@@ -397,6 +409,16 @@ jobs:
397409
| `meta-annotations` | List | | [List of custom annotations](https://github.com/docker/metadata-action?tab=readme-ov-file#overwrite-labels-and-annotations) |
398410
| `meta-flavor` | List | | [Flavor](https://github.com/docker/metadata-action?tab=readme-ov-file#flavor-input) defines a global behavior for `meta-tags` |
399411

412+
> [!NOTE]
413+
> `registry-login: true` forces a pre-build login attempt and will fail if the
414+
> resolved credentials are empty, for example, on forked pull requests where
415+
> secrets are not exposed. Gate this input at the caller side if you need
416+
> fork-safe behavior:
417+
>
418+
> ```yaml
419+
> registry-login: ${{ github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork }}
420+
> ```
421+
400422
> [!TIP]
401423
> When `output=image`, the `set` input supports Handlebars templates rendered
402424
> from selected `docker/metadata-action` outputs.
@@ -419,10 +441,10 @@ jobs:
419441

420442
#### Secrets
421443

422-
| Name | Default | Description |
423-
|------------------|-----------------------|--------------------------------------------------------------------------------|
424-
| `registry-auths` | | Raw authentication to registries, defined as YAML objects (for `image` output) |
425-
| `github-token` | `${{ github.token }}` | GitHub Token used to authenticate against the repository for Git context |
444+
| Name | Default | Description |
445+
|------------------|-----------------------|----------------------------------------------------------------------------------------------------------------|
446+
| `registry-auths` | | Raw authentication to registries, defined as YAML objects (used for push/signing and optional pre-build login) |
447+
| `github-token` | `${{ github.token }}` | GitHub Token used to authenticate against the repository for Git context |
426448

427449
#### Outputs
428450

test/dhi.Dockerfile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# syntax=docker/dockerfile:1
2+
3+
FROM dhi.io/alpine-base:3.23 AS base
4+
ARG TARGETPLATFORM
5+
RUN echo "Hello, World! This is ${TARGETPLATFORM}" > /tmp/hello.txt
6+
ARG BUILDKIT_SBOM_SCAN_STAGE=true
7+
8+
FROM scratch
9+
COPY --from=base /tmp/hello.txt /

test/docker-bake.hcl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,8 @@ target "generated-hello2" {
6767
dockerfile = "hello.Dockerfile"
6868
output = ["type=cacheonly"]
6969
}
70+
71+
target "dhi" {
72+
inherits = ["docker-metadata-action"]
73+
dockerfile = "dhi.Dockerfile"
74+
}

0 commit comments

Comments
 (0)