mirror of
https://github.com/docker/login-action.git
synced 2026-10-28 10:57:16 +00:00
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cf0eabde3d | |||
| 4c7d088f4b | |||
| 98a3fb834a | |||
| f101fa5d88 | |||
| f2aae0c0ee | |||
| 133c6ab6fa | |||
| 0a3084cdc5 | |||
| 1e7c55a39d | |||
| a358cc1e42 | |||
| 5ad95e8c58 | |||
| a5f1c9995c | |||
| b098de5f1b | |||
| 50d805b48a | |||
| 834ffb646a | |||
| 2fea3b2c5c | |||
| f3f25ba560 | |||
| 0b08f36d38 | |||
| 8fa2c064e3 | |||
| 375309eeb7 | |||
| 5d33b362eb | |||
| 0feb529243 | |||
| 4e12eabf92 | |||
| d3b9cdfa58 | |||
| b773301bab | |||
| a27b71b09c | |||
| 2c873c3656 | |||
| b4bb2a4ec0 | |||
| e800f1e754 | |||
| 783ae9cac5 | |||
| 67ccbdd142 | |||
| 96df24572b | |||
| b1725c2c93 | |||
| 0a596b2e7a | |||
| 5d1ee94869 | |||
| 8febd2275e | |||
| af63523ba5 | |||
| 72edfa6c2e | |||
| 2b7517a3b4 | |||
| eed2509203 | |||
| 07573e7c18 | |||
| 99ffd0f38a |
@@ -0,0 +1,3 @@
|
|||||||
|
FROM docker:29.3@sha256:4d90f1f6c400315c2dba96d3ec93c01e64198395cbba04f79d12adce4f737029
|
||||||
|
|
||||||
|
ENTRYPOINT ["docker"]
|
||||||
@@ -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 }}
|
||||||
@@ -106,11 +106,10 @@ jobs:
|
|||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
-
|
-
|
||||||
name: DinD
|
name: Pull test image from Docker CLI container action
|
||||||
uses: docker://docker:29.3@sha256:4d90f1f6c400315c2dba96d3ec93c01e64198395cbba04f79d12adce4f737029
|
uses: ./.github/actions/docker-pull
|
||||||
with:
|
with:
|
||||||
entrypoint: docker
|
image: ${{ env.GHCR_TEST_IMAGE }}
|
||||||
args: pull ${{ env.GHCR_TEST_IMAGE }}
|
|
||||||
-
|
-
|
||||||
name: Pull test image
|
name: Pull test image
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -35,12 +35,12 @@ jobs:
|
|||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
-
|
-
|
||||||
name: Initialize CodeQL
|
name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
|
uses: github/codeql-action/init@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0
|
||||||
with:
|
with:
|
||||||
languages: javascript-typescript
|
languages: javascript-typescript
|
||||||
build-mode: none
|
build-mode: none
|
||||||
-
|
-
|
||||||
name: Perform CodeQL Analysis
|
name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
|
uses: github/codeql-action/analyze@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0
|
||||||
with:
|
with:
|
||||||
category: "/language:javascript-typescript"
|
category: "/language:javascript-typescript"
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
run:
|
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:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
|
|||||||
@@ -23,13 +23,13 @@ jobs:
|
|||||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
-
|
-
|
||||||
name: Test
|
name: Test
|
||||||
uses: docker/bake-action@d3418bd7d0e9324001bca92fa8ba175ea7e6dc9b # v7.3.0
|
uses: docker/bake-action@018cb6412ab401ebaa809aa5f85966b74628600f # v7.4.0
|
||||||
with:
|
with:
|
||||||
source: .
|
source: .
|
||||||
targets: test
|
targets: test
|
||||||
-
|
-
|
||||||
name: Upload coverage
|
name: Upload coverage
|
||||||
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
|
uses: codecov/codecov-action@0b35c9ecc4f0529d0eb674914510c22f85b196b4 # v7.1.0
|
||||||
with:
|
with:
|
||||||
files: ./coverage/clover.xml
|
files: ./coverage/clover.xml
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ jobs:
|
|||||||
token: ${{ steps.docker-read-app.outputs.token }}
|
token: ${{ steps.docker-read-app.outputs.token }}
|
||||||
-
|
-
|
||||||
name: Build
|
name: Build
|
||||||
uses: docker/bake-action@d3418bd7d0e9324001bca92fa8ba175ea7e6dc9b # v7.3.0
|
uses: docker/bake-action@018cb6412ab401ebaa809aa5f85966b74628600f # v7.4.0
|
||||||
with:
|
with:
|
||||||
source: .
|
source: .
|
||||||
targets: build
|
targets: build
|
||||||
|
|||||||
@@ -41,6 +41,6 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Validate
|
name: Validate
|
||||||
uses: docker/bake-action@d3418bd7d0e9324001bca92fa8ba175ea7e6dc9b # v7.3.0
|
uses: docker/bake-action@018cb6412ab401ebaa809aa5f85966b74628600f # v7.4.0
|
||||||
with:
|
with:
|
||||||
targets: ${{ matrix.target }}
|
targets: ${{ matrix.target }}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
zizmor:
|
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:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
security-events: write
|
security-events: write
|
||||||
|
|||||||
@@ -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:
|
The following environment variables can be set as `step.env` keys:
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
|-------------------------------|--------|---------|-----------------------------------------------------------------------------|
|
|-------------------------------|--------|---------|----------------------------------------------------------------------------------------------------|
|
||||||
| `DOCKERHUB_OIDC_CONNECTIONID` | String | | Docker Hub OIDC connection ID. Required for Docker Hub OIDC login |
|
| `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` |
|
| `DOCKERHUB_OIDC_EXPIREIN` | Number | `300` | Docker Hub OIDC token lifetime in seconds. Must be between `300` (5 minutes) and `21600` (6 hours) |
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import * as path from 'path';
|
|||||||
|
|
||||||
import {Buildx} from '@docker/actions-toolkit/lib/buildx/buildx.js';
|
import {Buildx} from '@docker/actions-toolkit/lib/buildx/buildx.js';
|
||||||
|
|
||||||
import {getAuthList, getInputs} from '../src/context.js';
|
import {getAuthList, getInputs, scopeToConfigDir} from '../src/context.js';
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
vi.restoreAllMocks();
|
vi.restoreAllMocks();
|
||||||
@@ -168,3 +168,43 @@ test('getAuthList masks registry-auth password when present', async () => {
|
|||||||
|
|
||||||
expect(stdoutWriteSpy.mock.calls.map(call => call[0]).join('')).toContain('::add-mask::groundcontrol');
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
test.each([
|
||||||
|
['ghcr.io', 'ghcr.io'],
|
||||||
|
['ghcr.io/', 'ghcr.io'],
|
||||||
|
['https://ghcr.io', 'ghcr.io'],
|
||||||
|
['https://ghcr.io/', 'ghcr.io'],
|
||||||
|
['https://ghcr.io/v2/', 'ghcr.io'],
|
||||||
|
['http://localhost:5000', 'localhost:5000'],
|
||||||
|
['http://localhost:80', 'localhost:80'],
|
||||||
|
['https://ghcr.io:443', 'ghcr.io:443'],
|
||||||
|
['https://012345678910.dkr.ecr.eu-west-3.amazonaws.com', '012345678910.dkr.ecr.eu-west-3.amazonaws.com'],
|
||||||
|
['https://docker.io', 'registry-1.docker.io']
|
||||||
|
])('scopeToConfigDir uses the registry host for %s', (registry, host) => {
|
||||||
|
expect(scopeToConfigDir(registry, 'myorg/myimage@push')).toBe(path.join(Buildx.configDir, 'config', host, 'myorg', 'myimage') + '@push');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('scopeToConfigDir rejects a URL whose host escapes the config directory', () => {
|
||||||
|
expect(() => scopeToConfigDir('https://../', '@push')).toThrow(/Invalid registry/);
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
import {afterEach, expect, test, vi} from 'vitest';
|
import {afterEach, expect, test, vi} from 'vitest';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
import {Buildx} from '@docker/actions-toolkit/lib/buildx/buildx.js';
|
||||||
import {Docker} from '@docker/actions-toolkit/lib/docker/docker.js';
|
import {Docker} from '@docker/actions-toolkit/lib/docker/docker.js';
|
||||||
|
|
||||||
import {login, loginStandard, logout} from '../src/docker.js';
|
import * as aws from '../src/aws.js';
|
||||||
|
import {getAuthList} from '../src/context.js';
|
||||||
|
import {login, loginECR, loginStandard, logout} from '../src/docker.js';
|
||||||
import * as dockerhub from '../src/dockerhub.js';
|
import * as dockerhub from '../src/dockerhub.js';
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@@ -92,3 +96,29 @@ test('logout calls exec', async () => {
|
|||||||
ignoreReturnCode: true
|
ignoreReturnCode: true
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('loginECR and logout use the config dir of the registry host', async () => {
|
||||||
|
const execSpy = vi.spyOn(Docker, 'getExecOutput').mockResolvedValue({
|
||||||
|
exitCode: 0,
|
||||||
|
stdout: '',
|
||||||
|
stderr: ''
|
||||||
|
});
|
||||||
|
const registry = '012345678910.dkr.ecr.eu-west-3.amazonaws.com';
|
||||||
|
vi.spyOn(aws, 'getRegistriesData').mockResolvedValue([
|
||||||
|
{
|
||||||
|
registry: `https://${registry}`,
|
||||||
|
username: 'AWS',
|
||||||
|
password: 'world'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
const scope = 'myapp@push';
|
||||||
|
const [auth] = getAuthList({registry, username: 'CAFEBABE', password: 'DEADBEEF', scope, ecr: 'auto', logout: true, registryAuth: ''});
|
||||||
|
await loginECR(auth.registry, auth.username, auth.password, auth.scope);
|
||||||
|
await logout(auth.registry, auth.configDir);
|
||||||
|
|
||||||
|
const expectedConfigDir = path.join(Buildx.configDir, 'config', registry, 'myapp@push');
|
||||||
|
expect(execSpy).toHaveBeenCalledTimes(2);
|
||||||
|
expect(execSpy.mock.calls[0][1]?.env?.DOCKER_CONFIG).toBe(expectedConfigDir);
|
||||||
|
expect(execSpy.mock.calls[1][1]?.env?.DOCKER_CONFIG).toBe(expectedConfigDir);
|
||||||
|
});
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {beforeEach, describe, expect, test, vi} from 'vitest';
|
|||||||
import * as dockerhub from '../src/dockerhub.js';
|
import * as dockerhub from '../src/dockerhub.js';
|
||||||
|
|
||||||
vi.mock('@actions/core', () => ({
|
vi.mock('@actions/core', () => ({
|
||||||
|
debug: vi.fn(),
|
||||||
getIDToken: vi.fn(),
|
getIDToken: vi.fn(),
|
||||||
info: vi.fn(),
|
info: vi.fn(),
|
||||||
setSecret: vi.fn()
|
setSecret: vi.fn()
|
||||||
@@ -83,13 +84,22 @@ describe('getOIDCToken', () => {
|
|||||||
expect(body.get('connection_id')).toBe(validConnectionID);
|
expect(body.get('connection_id')).toBe(validConnectionID);
|
||||||
expect(body.get('expires_in')).toBe('300');
|
expect(body.get('expires_in')).toBe('300');
|
||||||
expect(setSecretMock).toHaveBeenCalledWith('hub-token');
|
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 () => {
|
test('uses custom token expiration', async () => {
|
||||||
process.env.DOCKERHUB_OIDC_EXPIREIN = '900';
|
process.env.DOCKERHUB_OIDC_EXPIREIN = '21600';
|
||||||
await dockerhub.getOIDCToken('docker.io', 'dbowie');
|
await dockerhub.getOIDCToken('docker.io', 'dbowie');
|
||||||
const body = new URLSearchParams(postSpy.mock.calls[0][1]);
|
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 () => {
|
test('uses stage identity host for stage registry', async () => {
|
||||||
@@ -112,9 +122,9 @@ describe('getOIDCToken', () => {
|
|||||||
expect(postSpy).not.toHaveBeenCalled();
|
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;
|
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(getIDTokenMock).not.toHaveBeenCalled();
|
||||||
expect(postSpy).not.toHaveBeenCalled();
|
expect(postSpy).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|||||||
+123
-120
File diff suppressed because one or more lines are too long
+4
-4
File diff suppressed because one or more lines are too long
+59
-3
@@ -2399,7 +2399,7 @@ SOFTWARE.
|
|||||||
The following npm packages may be included in this product:
|
The following npm packages may be included in this product:
|
||||||
|
|
||||||
- js-yaml@5.2.1
|
- js-yaml@5.2.1
|
||||||
- js-yaml@5.2.2
|
- js-yaml@5.5.0
|
||||||
|
|
||||||
These packages each contain the following license:
|
These packages each contain the following license:
|
||||||
|
|
||||||
@@ -4976,7 +4976,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||||||
|
|
||||||
The following npm package may be included in this product:
|
The following npm package may be included in this product:
|
||||||
|
|
||||||
- undici@6.27.0
|
- undici@6.29.1
|
||||||
|
|
||||||
This package contains the following license:
|
This package contains the following license:
|
||||||
|
|
||||||
@@ -5243,6 +5243,62 @@ IN THE SOFTWARE.
|
|||||||
|
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
The following npm package may be included in this product:
|
||||||
|
|
||||||
|
- argparse@3.0.3
|
||||||
|
|
||||||
|
This package contains the following license:
|
||||||
|
|
||||||
|
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
|
||||||
|
|
||||||
|
1. This LICENSE AGREEMENT is between the Python Software Foundation
|
||||||
|
("PSF"), and the Individual or Organization ("Licensee") accessing and
|
||||||
|
otherwise using this software ("Python") in source or binary form and
|
||||||
|
its associated documentation.
|
||||||
|
|
||||||
|
2. Subject to the terms and conditions of this License Agreement, PSF hereby
|
||||||
|
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
|
||||||
|
analyze, test, perform and/or display publicly, prepare derivative works,
|
||||||
|
distribute, and otherwise use Python alone or in any derivative version,
|
||||||
|
provided, however, that PSF's License Agreement and PSF's notice of copyright,
|
||||||
|
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||||
|
2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Python Software Foundation;
|
||||||
|
All Rights Reserved" are retained in Python alone or in any derivative version
|
||||||
|
prepared by Licensee.
|
||||||
|
|
||||||
|
3. In the event Licensee prepares a derivative work that is based on
|
||||||
|
or incorporates Python or any part thereof, and wants to make
|
||||||
|
the derivative work available to others as provided herein, then
|
||||||
|
Licensee hereby agrees to include in any such work a brief summary of
|
||||||
|
the changes made to Python.
|
||||||
|
|
||||||
|
4. PSF is making Python available to Licensee on an "AS IS"
|
||||||
|
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||||
|
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
|
||||||
|
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||||
|
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
|
||||||
|
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||||
|
|
||||||
|
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
||||||
|
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
||||||
|
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
|
||||||
|
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||||
|
|
||||||
|
6. This License Agreement will automatically terminate upon a material
|
||||||
|
breach of its terms and conditions.
|
||||||
|
|
||||||
|
7. Nothing in this License Agreement shall be deemed to create any
|
||||||
|
relationship of agency, partnership, or joint venture between PSF and
|
||||||
|
Licensee. This License Agreement does not grant permission to use PSF
|
||||||
|
trademarks or trade name in a trademark sense to endorse or promote
|
||||||
|
products or services of Licensee, or any third party.
|
||||||
|
|
||||||
|
8. By copying, installing or otherwise using Python, Licensee
|
||||||
|
agrees to be bound by the terms and conditions of this License
|
||||||
|
Agreement.
|
||||||
|
|
||||||
|
-----------
|
||||||
|
|
||||||
The following npm package may be included in this product:
|
The following npm package may be included in this product:
|
||||||
|
|
||||||
- glob@10.5.0
|
- glob@10.5.0
|
||||||
@@ -5563,7 +5619,7 @@ THE SOFTWARE.
|
|||||||
|
|
||||||
The following npm package may be included in this product:
|
The following npm package may be included in this product:
|
||||||
|
|
||||||
- csv-parse@7.0.1
|
- csv-parse@7.0.3
|
||||||
|
|
||||||
This package contains the following license:
|
This package contains the following license:
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -30,7 +30,7 @@
|
|||||||
"@docker/actions-toolkit": "^0.94.0",
|
"@docker/actions-toolkit": "^0.94.0",
|
||||||
"http-proxy-agent": "^9.1.0",
|
"http-proxy-agent": "^9.1.0",
|
||||||
"https-proxy-agent": "^9.1.0",
|
"https-proxy-agent": "^9.1.0",
|
||||||
"js-yaml": "^5.2.2",
|
"js-yaml": "^5.5.0",
|
||||||
"uuid": "^14.0.1"
|
"uuid": "^14.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
+5
-2
@@ -62,7 +62,7 @@ export function getAuthList(inputs: Inputs): Array<Auth> {
|
|||||||
username: auth.username,
|
username: auth.username,
|
||||||
password: auth.password,
|
password: auth.password,
|
||||||
scope: auth.scope,
|
scope: auth.scope,
|
||||||
ecr: auth.ecr || 'auto',
|
ecr: String(auth.ecr ?? '') || 'auto',
|
||||||
configDir: scopeToConfigDir(registry, auth.scope)
|
configDir: scopeToConfigDir(registry, auth.scope)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -77,8 +77,11 @@ export function scopeToConfigDir(registry: string, scope?: string): string {
|
|||||||
if (scopeDisabled() || !scope || scope === '') {
|
if (scopeDisabled() || !scope || scope === '') {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
const schemeEnd = registry.indexOf('://');
|
||||||
|
// A neutral scheme preserves explicit ports, including HTTP(S) default ports.
|
||||||
|
const registryHost = schemeEnd === -1 ? registry : new URL(`registry://${registry.slice(schemeEnd + 3)}`).host;
|
||||||
const configRoot = path.resolve(Buildx.configDir, 'config');
|
const configRoot = path.resolve(Buildx.configDir, 'config');
|
||||||
const registryDir = path.resolve(configRoot, registry === 'docker.io' ? 'registry-1.docker.io' : registry);
|
const registryDir = path.resolve(configRoot, registryHost === 'docker.io' ? 'registry-1.docker.io' : registryHost);
|
||||||
if (!isChildPath(configRoot, registryDir)) {
|
if (!isChildPath(configRoot, registryDir)) {
|
||||||
throw new Error(`Invalid registry '${registry}': resolved config path escapes the Buildx config directory`);
|
throw new Error(`Invalid registry '${registry}': resolved config path escapes the Buildx config directory`);
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-1
@@ -15,7 +15,7 @@ interface OIDCTokenResponse {
|
|||||||
const registries = new Set(['', 'docker.io', 'registry-1.docker.io', 'registry-1-stage.docker.io', 'dhi.io']);
|
const registries = new Set(['', 'docker.io', 'registry-1.docker.io', 'registry-1-stage.docker.io', 'dhi.io']);
|
||||||
const defaultExpiresIn = 300;
|
const defaultExpiresIn = 300;
|
||||||
const minExpiresIn = 300;
|
const minExpiresIn = 300;
|
||||||
const maxExpiresIn = 3600;
|
const maxExpiresIn = 21600;
|
||||||
const maxRetries = 5;
|
const maxRetries = 5;
|
||||||
|
|
||||||
export const isDockerHubOIDC = (registry: string, password: string): boolean => {
|
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 expiresIn = getExpiresIn();
|
||||||
const identityHost = registry === 'registry-1-stage.docker.io' ? 'identity-stage.docker.com' : 'identity.docker.com';
|
const identityHost = registry === 'registry-1-stage.docker.io' ? 'identity-stage.docker.com' : 'identity.docker.com';
|
||||||
const audience = `https://${identityHost}`;
|
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 idToken = await core.getIDToken(audience);
|
||||||
const http: httpm.HttpClient = new httpm.HttpClient('github.com/docker/login-action', [], {
|
const http: httpm.HttpClient = new httpm.HttpClient('github.com/docker/login-action', [], {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -49,10 +53,12 @@ export const getOIDCToken = async (registry: string, username: string): Promise<
|
|||||||
data.set('connection_id', connectionID);
|
data.set('connection_id', connectionID);
|
||||||
data.set('expires_in', expiresIn.toString());
|
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 resp = await postWithRetry(http, `https://${identityHost}/oauth/token`, data.toString());
|
||||||
|
|
||||||
const tokenResp = <OIDCTokenResponse>JSON.parse(await handleResponse(resp));
|
const tokenResp = <OIDCTokenResponse>JSON.parse(await handleResponse(resp));
|
||||||
core.setSecret(tokenResp.access_token);
|
core.setSecret(tokenResp.access_token);
|
||||||
|
core.info(`Docker Hub OIDC token exchange succeeded`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
username,
|
username,
|
||||||
@@ -70,16 +76,20 @@ const getExpiresIn = (): number => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const postWithRetry = async (http: httpm.HttpClient, url: string, data: string): Promise<httpm.HttpClientResponse> => {
|
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);
|
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++) {
|
for (let attempt = 0; (resp.message.statusCode || HttpCodes.InternalServerError) === HttpCodes.TooManyRequests && attempt < maxRetries; attempt++) {
|
||||||
const delay = parseRetryAfter(resp.message.headers['retry-after']);
|
const delay = parseRetryAfter(resp.message.headers['retry-after']);
|
||||||
if (delay === null) {
|
if (delay === null) {
|
||||||
|
core.debug(`Docker Hub OIDC token request rate limited without retry-after header`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
await resp.readBody();
|
await resp.readBody();
|
||||||
core.info(`Docker Hub OIDC token request rate limited, retrying in ${delay}ms (attempt ${attempt + 1}/${maxRetries})`);
|
core.info(`Docker Hub OIDC token request rate limited, retrying in ${delay}ms (attempt ${attempt + 1}/${maxRetries})`);
|
||||||
await new Promise(resolve => setTimeout(resolve, delay));
|
await new Promise(resolve => setTimeout(resolve, delay));
|
||||||
resp = await http.post(url, data);
|
resp = await http.post(url, data);
|
||||||
|
core.debug(`Docker Hub OIDC token request returned status code ${resp.message.statusCode || HttpCodes.InternalServerError}`);
|
||||||
}
|
}
|
||||||
return resp;
|
return resp;
|
||||||
};
|
};
|
||||||
@@ -101,6 +111,7 @@ const parseRetryAfter = (value: string | string[] | undefined): number | null =>
|
|||||||
const handleResponse = async (resp: httpm.HttpClientResponse): Promise<string> => {
|
const handleResponse = async (resp: httpm.HttpClientResponse): Promise<string> => {
|
||||||
const body = await resp.readBody();
|
const body = await resp.readBody();
|
||||||
const statusCode = resp.message.statusCode || HttpCodes.InternalServerError;
|
const statusCode = resp.message.statusCode || HttpCodes.InternalServerError;
|
||||||
|
core.debug(`Docker Hub OIDC token response status code: ${statusCode}`);
|
||||||
if (statusCode < HttpCodes.OK || statusCode >= HttpCodes.MultipleChoices) {
|
if (statusCode < HttpCodes.OK || statusCode >= HttpCodes.MultipleChoices) {
|
||||||
throw parseError(statusCode, body);
|
throw parseError(statusCode, body);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1165,20 +1165,30 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@humanfs/core@npm:^0.19.1":
|
"@humanfs/core@npm:^0.19.2":
|
||||||
version: 0.19.1
|
version: 0.19.2
|
||||||
resolution: "@humanfs/core@npm:0.19.1"
|
resolution: "@humanfs/core@npm:0.19.2"
|
||||||
checksum: 10/270d936be483ab5921702623bc74ce394bf12abbf57d9145a69e8a0d1c87eb1c768bd2d93af16c5705041e257e6d9cc7529311f63a1349f3678abc776fc28523
|
dependencies:
|
||||||
|
"@humanfs/types": "npm:^0.15.0"
|
||||||
|
checksum: 10/c6c0273721ec8df3d36a57c390a11a168d0a2f513d78bceb25165bded4fcb73609b1a317edc6c8f331cefd4b47285dde0b1e6679e08ef7f062232ec14fe05312
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@humanfs/node@npm:^0.16.6":
|
"@humanfs/node@npm:^0.16.6":
|
||||||
version: 0.16.7
|
version: 0.16.8
|
||||||
resolution: "@humanfs/node@npm:0.16.7"
|
resolution: "@humanfs/node@npm:0.16.8"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@humanfs/core": "npm:^0.19.1"
|
"@humanfs/core": "npm:^0.19.2"
|
||||||
|
"@humanfs/types": "npm:^0.15.0"
|
||||||
"@humanwhocodes/retry": "npm:^0.4.0"
|
"@humanwhocodes/retry": "npm:^0.4.0"
|
||||||
checksum: 10/b3633d3dce898592cac515ba5e6693c78e6be92863541d3eaf2c009b10f52b2fa62ff6e6e06f240f2447ddbe7b5f1890bc34e9308470675c876eee207553a08d
|
checksum: 10/ed01b3c066d9cec7526d139b9e71ca00ee4a30b3b5f5f5c198eb069c3509a3e167e180ba7e1e5a83b9571e906c4908bd20402b47586887452311af7354995e95
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@humanfs/types@npm:^0.15.0":
|
||||||
|
version: 0.15.0
|
||||||
|
resolution: "@humanfs/types@npm:0.15.0"
|
||||||
|
checksum: 10/dea3cc7fd8f8d4d088ed8d0a9921cf12bd8e1cdf40a6133106b03a6e2aebcc9a6f1771b3643b7ec71baae90d08245db34069dfcc861da8d678662741e6c3c986
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -2561,6 +2571,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"argparse@npm:^3.0.3":
|
||||||
|
version: 3.0.3
|
||||||
|
resolution: "argparse@npm:3.0.3"
|
||||||
|
checksum: 10/6834e247fe8a8d21a0061dc2b7134ae79625d9ab795eca043d8ba9434be3bc1e7d049c9a4aa01bd3d6bfc145b29addfb290d17b8b3f7b11710cc52ab13629f31
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"assertion-error@npm:^2.0.1":
|
"assertion-error@npm:^2.0.1":
|
||||||
version: 2.0.1
|
version: 2.0.1
|
||||||
resolution: "assertion-error@npm:2.0.1"
|
resolution: "assertion-error@npm:2.0.1"
|
||||||
@@ -3104,9 +3121,9 @@ __metadata:
|
|||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"csv-parse@npm:^7.0.1":
|
"csv-parse@npm:^7.0.1":
|
||||||
version: 7.0.1
|
version: 7.0.3
|
||||||
resolution: "csv-parse@npm:7.0.1"
|
resolution: "csv-parse@npm:7.0.3"
|
||||||
checksum: 10/5c914f01181dbb381068b98e17b49361d853faa95db3e8e82bc96b6a0de5313ecc8325a77db35ff66644d7747099965ba3167ec21bd9ce4500edf21b5bdd49bf
|
checksum: 10/98d80273b47603cbf754f4b75e7ea769ea63eb83fa18e4c92061e64b3575694eb98151100ddbb907670e7210ef7eac594ef850ecd3f23119062eeb8d9a2e2684
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -3174,7 +3191,7 @@ __metadata:
|
|||||||
globals: "npm:^17.3.0"
|
globals: "npm:^17.3.0"
|
||||||
http-proxy-agent: "npm:^9.1.0"
|
http-proxy-agent: "npm:^9.1.0"
|
||||||
https-proxy-agent: "npm:^9.1.0"
|
https-proxy-agent: "npm:^9.1.0"
|
||||||
js-yaml: "npm:^5.2.2"
|
js-yaml: "npm:^5.5.0"
|
||||||
prettier: "npm:^3.8.1"
|
prettier: "npm:^3.8.1"
|
||||||
typescript: "npm:^5.9.3"
|
typescript: "npm:^5.9.3"
|
||||||
uuid: "npm:^14.0.1"
|
uuid: "npm:^14.0.1"
|
||||||
@@ -4357,14 +4374,14 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"js-yaml@npm:^5.2.2":
|
"js-yaml@npm:^5.5.0":
|
||||||
version: 5.2.2
|
version: 5.5.0
|
||||||
resolution: "js-yaml@npm:5.2.2"
|
resolution: "js-yaml@npm:5.5.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
argparse: "npm:^2.0.1"
|
argparse: "npm:^3.0.3"
|
||||||
bin:
|
bin:
|
||||||
js-yaml: bin/js-yaml.mjs
|
js-yaml: bin/js-yaml.mjs
|
||||||
checksum: 10/2b4c2933af12c97e1c4894a4f27fe9b06dab70a64a96bb50624b4429bef6bf11008bde20d868bce52a36784473314efc30078ba6025b58cf7537961e23b1ae9c
|
checksum: 10/c01359a4fe69a1c032e9e57d7387a1cbdfbbd45bc69924885a3c9a9a020e066627dc125f7b46f7b929186b5a65471ae5fa478d3f773e35f7ccdf57d32fcf369f
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -4864,12 +4881,12 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"nanoid@npm:^3.3.16":
|
"nanoid@npm:^3.3.17":
|
||||||
version: 3.3.16
|
version: 3.3.18
|
||||||
resolution: "nanoid@npm:3.3.16"
|
resolution: "nanoid@npm:3.3.18"
|
||||||
bin:
|
bin:
|
||||||
nanoid: bin/nanoid.cjs
|
nanoid: bin/nanoid.cjs
|
||||||
checksum: 10/8004af92b5541af1dbd23b69845b5026f777d5b7ef07163cea1837aae86e052ced8b383cecbf8a4f1b5e77ae207df96dc45e16b9e0fa3c4b761d085f1e42851b
|
checksum: 10/1b3b4fdac831b92b56d1dbe8b1e63a372432faf86ea383134e3b53141ef8108a60b7f84343b5cefecac9550bb74edf8164da93ea07d1c4f757039bc75d8a5d9e
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -5282,23 +5299,23 @@ __metadata:
|
|||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"postcss-selector-parser@npm:^7.0.0":
|
"postcss-selector-parser@npm:^7.0.0":
|
||||||
version: 7.1.1
|
version: 7.1.6
|
||||||
resolution: "postcss-selector-parser@npm:7.1.1"
|
resolution: "postcss-selector-parser@npm:7.1.6"
|
||||||
dependencies:
|
dependencies:
|
||||||
cssesc: "npm:^3.0.0"
|
cssesc: "npm:^3.0.0"
|
||||||
util-deprecate: "npm:^1.0.2"
|
util-deprecate: "npm:^1.0.2"
|
||||||
checksum: 10/bb3c6455b20af26a556e3021e21101d8470252644e673c1612f7348ff8dd41b11321329f0694cf299b5b94863f823480b72d3e2f4bd3a89dc43e2d8c0dbad341
|
checksum: 10/8b00b63c8ae9eab8567bebf2710971dcd832a7a20a9cae7059d92aee3df38fbcd13ce454bdc09c54e777dbddd0df38966227000091c88002741b8575f3878f05
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"postcss@npm:^8.5.6":
|
"postcss@npm:^8.5.6":
|
||||||
version: 8.5.22
|
version: 8.5.26
|
||||||
resolution: "postcss@npm:8.5.22"
|
resolution: "postcss@npm:8.5.26"
|
||||||
dependencies:
|
dependencies:
|
||||||
nanoid: "npm:^3.3.16"
|
nanoid: "npm:^3.3.17"
|
||||||
picocolors: "npm:^1.1.1"
|
picocolors: "npm:^1.1.1"
|
||||||
source-map-js: "npm:^1.2.1"
|
source-map-js: "npm:^1.2.1"
|
||||||
checksum: 10/7944444f267f2d94c7caeed66f3da56d5b947bd4a7e57a166a5161af25c6006dd73f40e2a1a6822f3d7fccc2fa005778c03058368eb7efca1b5038aec55abd14
|
checksum: 10/842a624f822f77cb37264cc24f0cf97c0a69dd8d6f7b4a6d76b5a8dc95355899dd044f33a2d4e890da858293de570fce18dff453f3b629ff14cac67a3591895a
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -5773,9 +5790,9 @@ __metadata:
|
|||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"source-map-js@npm:^1.2.1":
|
"source-map-js@npm:^1.2.1":
|
||||||
version: 1.2.1
|
version: 1.2.2
|
||||||
resolution: "source-map-js@npm:1.2.1"
|
resolution: "source-map-js@npm:1.2.2"
|
||||||
checksum: 10/ff9d8c8bf096d534a5b7707e0382ef827b4dd360a577d3f34d2b9f48e12c9d230b5747974ee7c607f0df65113732711bb701fe9ece3c7edbd43cb2294d707df3
|
checksum: 10/4807c894bb6280c8b84886159b96080e3996f42c6e8015e647881edfd4f955f6024ceebb8bb40d33ce8b106e24b2e29c133575e1c60c01c8aae57a05fdf17761
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -6238,9 +6255,9 @@ __metadata:
|
|||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"undici@npm:^6.23.0, undici@npm:^6.25.0":
|
"undici@npm:^6.23.0, undici@npm:^6.25.0":
|
||||||
version: 6.27.0
|
version: 6.29.1
|
||||||
resolution: "undici@npm:6.27.0"
|
resolution: "undici@npm:6.29.1"
|
||||||
checksum: 10/30c18cdb235edf4dd36f8aa3ace1ffaf44060289a7d62ad44c33180d2d74a224015d25574812f62ce9c625b5beb1b0b766495b650fedf356aca11eed7ce2c816
|
checksum: 10/92acb64ec190fe3499dec69830fdfc48e28f6f19627bad7563cfd57c37b4e95379c12b8ac15a2e6a8739eaac358f17503a229c160d3dc8774141b1e270d8aa57
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user