Compare commits

...
Author SHA1 Message Date
dependabot[bot] 5d33b362eb build(deps): bump the crazy-max-dot-github group across 1 directory with 2 updates
Bumps the crazy-max-dot-github group with 2 updates in the / directory: [crazy-max/.github/.github/workflows/pr-assign-author.yml](https://github.com/crazy-max/.github) and [crazy-max/.github/.github/workflows/zizmor.yml](https://github.com/crazy-max/.github).


Updates `crazy-max/.github/.github/workflows/pr-assign-author.yml` from 1.10.1 to 1.11.0
- [Release notes](https://github.com/crazy-max/.github/releases)
- [Commits](https://github.com/crazy-max/.github/compare/46267a6e61cd56aac2fc79943df180152f4c89d6...f91220cba053bd54299ba645a599ee8ed436f222)

Updates `crazy-max/.github/.github/workflows/zizmor.yml` from 1.10.1 to 1.11.0
- [Release notes](https://github.com/crazy-max/.github/releases)
- [Commits](https://github.com/crazy-max/.github/compare/46267a6e61cd56aac2fc79943df180152f4c89d6...f91220cba053bd54299ba645a599ee8ed436f222)

---
updated-dependencies:
- dependency-name: crazy-max/.github/.github/workflows/pr-assign-author.yml
  dependency-version: 1.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: crazy-max-dot-github
- dependency-name: crazy-max/.github/.github/workflows/zizmor.yml
  dependency-version: 1.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: crazy-max-dot-github
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-10-19 05:52:13 +00:00
CrazyMax d3b9cdfa58 Merge pull request #1089 from crazy-max/fix-registry-auth-ecr-false
preserve explicit ECR settings in registry-auth
2026-10-16 20:24:38 +02:00
CrazyMax a27b71b09c chore: update generated content
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2026-10-05 14:23:04 +02:00
CrazyMax 2c873c3656 test: simplify registry-auth ECR regression coverage
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2026-10-05 14:23:04 +02:00
breken-ai b4bb2a4ec0 keep registry-auth ecr: false instead of falling back to auto
registry-auth is parsed as YAML, so `ecr: false` (unquoted) is the
boolean false, and `auth.ecr || 'auto'` turned it into 'auto'. For an
ECR registry this runs the AWS SDK login with the given username and
password as AWS access keys, instead of the plain docker login the user
asked for. Only the quoted string "false" worked.

Convert the value to a string and only default to 'auto' when it is
missing or empty.

Assisted-By: Claude
Signed-off-by: breken-ai <312387581+breken-ai@users.noreply.github.com>
2026-10-05 14:21:32 +02:00
CrazyMax 783ae9cac5 Merge pull request #1064 from docker/dependabot/github_actions/codeql-actions-ce612e0709
build(deps): bump the codeql-actions group across 1 directory with 2 updates
2026-09-16 10:57:53 +02:00
dependabot[bot] b1725c2c93 build(deps): bump the codeql-actions group across 1 directory with 2 updates
Bumps the codeql-actions group with 2 updates in the / directory: [github/codeql-action/init](https://github.com/github/codeql-action) and [github/codeql-action/analyze](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.37.3 to 4.37.8
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81...db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28)

Updates `github/codeql-action/analyze` from 4.37.3 to 4.37.8
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81...db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28)

---
updated-dependencies:
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-actions
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-25 05:54:40 +00:00
CrazyMax 0a596b2e7a Merge pull request #1073 from quentin-laplanche-docker/ci/remove-docker-notation
ci: replace registry container action reference
2026-08-24 15:27:36 +02:00
Quentin LaplancheandCodex 5d1ee94869 ci: replace registry container action reference
Use a local Docker container action so the runner still exercises its container-action mounts and environment without a docker:// workflow reference.

Signed-off-by: Quentin Laplanche <quentin.laplanche@docker.com>

Co-authored-by: Codex <noreply@openai.com>
2026-08-24 15:15:07 +02:00
Tõnis Tiigi af63523ba5 Merge pull request #1061 from docker/dockerhub-oidc-logs
log Docker Hub OIDC token exchange progress
2026-08-11 11:56:25 +03:00
CrazyMax 72edfa6c2e chore: update generated content
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2026-08-06 16:52:13 +02:00
CrazyMax 2b7517a3b4 log Docker Hub OIDC token exchange progress
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2026-08-06 16:51:47 +02:00
CrazyMax eed2509203 Merge pull request #1068 from crazy-max/dockerhub-oidc-increase-expire-in
raise Docker Hub OIDC max expiry to 6 hours
2026-08-06 12:07:08 +02:00
CrazyMax 07573e7c18 chore: update generated content
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2026-08-06 11:54:13 +02:00
CrazyMax 99ffd0f38a raise Docker Hub OIDC max expiry to 6 hours
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2026-08-06 11:53:57 +02:00
13 changed files with 112 additions and 54 deletions
+3
View File
@@ -0,0 +1,3 @@
FROM docker:29.3@sha256:4d90f1f6c400315c2dba96d3ec93c01e64198395cbba04f79d12adce4f737029
ENTRYPOINT ["docker"]
+15
View File
@@ -0,0 +1,15 @@
name: Pull Docker image
description: Pull an image from a Docker container action
inputs:
image:
description: Image reference to pull
required: true
runs:
using: docker
image: Dockerfile
args:
- pull
- ${{ inputs.image }}
+3 -4
View File
@@ -106,11 +106,10 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
-
name: DinD
uses: docker://docker:29.3@sha256:4d90f1f6c400315c2dba96d3ec93c01e64198395cbba04f79d12adce4f737029
name: Pull test image from Docker CLI container action
uses: ./.github/actions/docker-pull
with:
entrypoint: docker
args: pull ${{ env.GHCR_TEST_IMAGE }}
image: ${{ env.GHCR_TEST_IMAGE }}
-
name: Pull test image
run: |
+2 -2
View File
@@ -35,12 +35,12 @@ jobs:
node-version: ${{ env.NODE_VERSION }}
-
name: Initialize CodeQL
uses: github/codeql-action/init@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
with:
languages: javascript-typescript
build-mode: none
-
name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
with:
category: "/language:javascript-typescript"
+1 -1
View File
@@ -11,7 +11,7 @@ on:
jobs:
run:
uses: crazy-max/.github/.github/workflows/pr-assign-author.yml@46267a6e61cd56aac2fc79943df180152f4c89d6 # v1.10.1
uses: crazy-max/.github/.github/workflows/pr-assign-author.yml@f91220cba053bd54299ba645a599ee8ed436f222 # v1.11.0
permissions:
contents: read
pull-requests: write
+1 -1
View File
@@ -19,7 +19,7 @@ on:
jobs:
zizmor:
uses: crazy-max/.github/.github/workflows/zizmor.yml@46267a6e61cd56aac2fc79943df180152f4c89d6 # v1.10.1
uses: crazy-max/.github/.github/workflows/zizmor.yml@f91220cba053bd54299ba645a599ee8ed436f222 # v1.11.0
permissions:
contents: read
security-events: write
+4 -4
View File
@@ -757,10 +757,10 @@ The following inputs can be used as `step.with` keys:
The following environment variables can be set as `step.env` keys:
| Name | Type | Default | Description |
|-------------------------------|--------|---------|-----------------------------------------------------------------------------|
| `DOCKERHUB_OIDC_CONNECTIONID` | String | | Docker Hub OIDC connection ID. Required for Docker Hub OIDC login |
| `DOCKERHUB_OIDC_EXPIREIN` | Number | `300` | Docker Hub OIDC token lifetime in seconds. Must be between `300` and `3600` |
| Name | Type | Default | Description |
|-------------------------------|--------|---------|----------------------------------------------------------------------------------------------------|
| `DOCKERHUB_OIDC_CONNECTIONID` | String | | Docker Hub OIDC connection ID. Required for Docker Hub OIDC login |
| `DOCKERHUB_OIDC_EXPIREIN` | Number | `300` | Docker Hub OIDC token lifetime in seconds. Must be between `300` (5 minutes) and `21600` (6 hours) |
## Contributing
+20
View File
@@ -168,3 +168,23 @@ test('getAuthList masks registry-auth password when present', async () => {
expect(stdoutWriteSpy.mock.calls.map(call => call[0]).join('')).toContain('::add-mask::groundcontrol');
});
// prettier-ignore
test.each([
['false', 'false'],
['"false"', 'false'],
['true', 'true'],
['auto', 'auto'],
['""', 'auto']
])('getAuthList normalizes registry-auth ecr: %s', (ecr, expected) => {
const [auth] = getAuthList({
registry: '',
username: '',
password: '',
scope: '',
ecr: '',
logout: true,
registryAuth: `- registry: 012345678910.dkr.ecr.eu-west-3.amazonaws.com\n username: AWS\n password: token\n ecr: ${ecr}\n`
});
expect(auth.ecr).toBe(expected);
});
+14 -4
View File
@@ -5,6 +5,7 @@ import {beforeEach, describe, expect, test, vi} from 'vitest';
import * as dockerhub from '../src/dockerhub.js';
vi.mock('@actions/core', () => ({
debug: vi.fn(),
getIDToken: vi.fn(),
info: vi.fn(),
setSecret: vi.fn()
@@ -83,13 +84,22 @@ describe('getOIDCToken', () => {
expect(body.get('connection_id')).toBe(validConnectionID);
expect(body.get('expires_in')).toBe('300');
expect(setSecretMock).toHaveBeenCalledWith('hub-token');
expect(core.info).toHaveBeenCalledWith('Docker Hub OIDC detected for docker.io');
expect(core.info).toHaveBeenCalledWith('Retrieving GitHub OIDC token for Docker Hub');
expect(core.info).toHaveBeenCalledWith('Exchanging GitHub OIDC token for Docker Hub token');
expect(core.info).toHaveBeenCalledWith('Docker Hub OIDC token exchange succeeded');
expect(core.debug).toHaveBeenCalledWith('Docker Hub OIDC token audience: https://identity.docker.com');
expect(core.debug).toHaveBeenCalledWith('Docker Hub OIDC token expiration: 300s');
expect(core.debug).toHaveBeenCalledWith('Sending Docker Hub OIDC token request to https://identity.docker.com/oauth/token');
expect(core.debug).toHaveBeenCalledWith('Docker Hub OIDC token request returned status code 200');
expect(core.debug).toHaveBeenCalledWith('Docker Hub OIDC token response status code: 200');
});
test('uses custom token expiration', async () => {
process.env.DOCKERHUB_OIDC_EXPIREIN = '900';
process.env.DOCKERHUB_OIDC_EXPIREIN = '21600';
await dockerhub.getOIDCToken('docker.io', 'dbowie');
const body = new URLSearchParams(postSpy.mock.calls[0][1]);
expect(body.get('expires_in')).toBe('900');
expect(body.get('expires_in')).toBe('21600');
});
test('uses stage identity host for stage registry', async () => {
@@ -112,9 +122,9 @@ describe('getOIDCToken', () => {
expect(postSpy).not.toHaveBeenCalled();
});
test.each(['not-a-number', '299', '3601'])('validates token expiration %p', async expiresIn => {
test.each(['not-a-number', '299', '21601'])('validates token expiration %p', async expiresIn => {
process.env.DOCKERHUB_OIDC_EXPIREIN = expiresIn;
await expect(dockerhub.getOIDCToken('docker.io', 'dbowie')).rejects.toThrow(`Invalid DOCKERHUB_OIDC_EXPIREIN: ${expiresIn}. Must be between 300 and 3600`);
await expect(dockerhub.getOIDCToken('docker.io', 'dbowie')).rejects.toThrow(`Invalid DOCKERHUB_OIDC_EXPIREIN: ${expiresIn}. Must be between 300 and 21600`);
expect(getIDTokenMock).not.toHaveBeenCalled();
expect(postSpy).not.toHaveBeenCalled();
});
Generated Vendored
+33 -33
View File
File diff suppressed because one or more lines are too long
Generated Vendored
+3 -3
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -62,7 +62,7 @@ export function getAuthList(inputs: Inputs): Array<Auth> {
username: auth.username,
password: auth.password,
scope: auth.scope,
ecr: auth.ecr || 'auto',
ecr: String(auth.ecr ?? '') || 'auto',
configDir: scopeToConfigDir(registry, auth.scope)
};
});
+12 -1
View File
@@ -15,7 +15,7 @@ interface OIDCTokenResponse {
const registries = new Set(['', 'docker.io', 'registry-1.docker.io', 'registry-1-stage.docker.io', 'dhi.io']);
const defaultExpiresIn = 300;
const minExpiresIn = 300;
const maxExpiresIn = 3600;
const maxExpiresIn = 21600;
const maxRetries = 5;
export const isDockerHubOIDC = (registry: string, password: string): boolean => {
@@ -35,6 +35,10 @@ export const getOIDCToken = async (registry: string, username: string): Promise<
const expiresIn = getExpiresIn();
const identityHost = registry === 'registry-1-stage.docker.io' ? 'identity-stage.docker.com' : 'identity.docker.com';
const audience = `https://${identityHost}`;
core.info(`Docker Hub OIDC detected for ${registry || 'docker.io'}`);
core.debug(`Docker Hub OIDC token audience: ${audience}`);
core.debug(`Docker Hub OIDC token expiration: ${expiresIn}s`);
core.info(`Retrieving GitHub OIDC token for Docker Hub`);
const idToken = await core.getIDToken(audience);
const http: httpm.HttpClient = new httpm.HttpClient('github.com/docker/login-action', [], {
headers: {
@@ -49,10 +53,12 @@ export const getOIDCToken = async (registry: string, username: string): Promise<
data.set('connection_id', connectionID);
data.set('expires_in', expiresIn.toString());
core.info(`Exchanging GitHub OIDC token for Docker Hub token`);
const resp = await postWithRetry(http, `https://${identityHost}/oauth/token`, data.toString());
const tokenResp = <OIDCTokenResponse>JSON.parse(await handleResponse(resp));
core.setSecret(tokenResp.access_token);
core.info(`Docker Hub OIDC token exchange succeeded`);
return {
username,
@@ -70,16 +76,20 @@ const getExpiresIn = (): number => {
};
const postWithRetry = async (http: httpm.HttpClient, url: string, data: string): Promise<httpm.HttpClientResponse> => {
core.debug(`Sending Docker Hub OIDC token request to ${url}`);
let resp = await http.post(url, data);
core.debug(`Docker Hub OIDC token request returned status code ${resp.message.statusCode || HttpCodes.InternalServerError}`);
for (let attempt = 0; (resp.message.statusCode || HttpCodes.InternalServerError) === HttpCodes.TooManyRequests && attempt < maxRetries; attempt++) {
const delay = parseRetryAfter(resp.message.headers['retry-after']);
if (delay === null) {
core.debug(`Docker Hub OIDC token request rate limited without retry-after header`);
break;
}
await resp.readBody();
core.info(`Docker Hub OIDC token request rate limited, retrying in ${delay}ms (attempt ${attempt + 1}/${maxRetries})`);
await new Promise(resolve => setTimeout(resolve, delay));
resp = await http.post(url, data);
core.debug(`Docker Hub OIDC token request returned status code ${resp.message.statusCode || HttpCodes.InternalServerError}`);
}
return resp;
};
@@ -101,6 +111,7 @@ const parseRetryAfter = (value: string | string[] | undefined): number | null =>
const handleResponse = async (resp: httpm.HttpClientResponse): Promise<string> => {
const body = await resp.readBody();
const statusCode = resp.message.statusCode || HttpCodes.InternalServerError;
core.debug(`Docker Hub OIDC token response status code: ${statusCode}`);
if (statusCode < HttpCodes.OK || statusCode >= HttpCodes.MultipleChoices) {
throw parseError(statusCode, body);
}