mirror of
https://github.com/docker/login-action.git
synced 2025-08-15 04:39:38 +08:00
Compare commits
40 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
49ed152c8e | ||
|
b61a9ce7bd | ||
|
3a136a8631 | ||
|
b312880b69 | ||
|
795794e081 | ||
|
1edf6180e0 | ||
|
8e66ad4089 | ||
|
7c79b598ea | ||
|
24a38e0d6d | ||
|
70e1ff84cb | ||
|
0828e0e718 | ||
|
56f72fcef0 | ||
|
f169e16aaa | ||
|
fa178e4710 | ||
|
a4bf4e934e | ||
|
2bbd6e81e1 | ||
|
f6d32ad023 | ||
|
b4595c8bf9 | ||
|
dd4fa0671b | ||
|
4e3538592e | ||
|
bb984efc56 | ||
|
722888132b | ||
|
17780b56b7 | ||
|
39857b3b45 | ||
|
5fcc728422 | ||
|
9fb8721eb9 | ||
|
4e3c9375bb | ||
|
4b59a429db | ||
|
6af3c118c8 | ||
|
caca3368ce | ||
|
17f28ab24d | ||
|
a875dd0e21 | ||
|
7948fffc49 | ||
|
5fcefb941d | ||
|
3bb2d084df | ||
|
242fb9a356 | ||
|
fa72313bc3 | ||
|
088f62a4f2 | ||
|
7929ac7647 | ||
|
9376d24995 |
23
.eslintrc.json
Normal file
23
.eslintrc.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"node": true,
|
||||||
|
"es2021": true,
|
||||||
|
"jest/globals": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
"plugin:jest/recommended",
|
||||||
|
"plugin:prettier/recommended"
|
||||||
|
],
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": "latest",
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"@typescript-eslint",
|
||||||
|
"jest",
|
||||||
|
"prettier"
|
||||||
|
]
|
||||||
|
}
|
38
.github/workflows/ci.yml
vendored
38
.github/workflows/ci.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
-
|
-
|
||||||
name: Stop docker
|
name: Stop docker
|
||||||
run: |
|
run: |
|
||||||
@@ -39,7 +39,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
-
|
-
|
||||||
name: Login to GitHub Container Registry
|
name: Login to GitHub Container Registry
|
||||||
uses: ./
|
uses: ./
|
||||||
@@ -56,7 +56,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
-
|
-
|
||||||
name: Login to GitHub Container Registry
|
name: Login to GitHub Container Registry
|
||||||
uses: ./
|
uses: ./
|
||||||
@@ -76,6 +76,20 @@ jobs:
|
|||||||
docker image prune -a -f >/dev/null 2>&1
|
docker image prune -a -f >/dev/null 2>&1
|
||||||
docker pull ghcr.io/docker-ghactiontest/test
|
docker pull ghcr.io/docker-ghactiontest/test
|
||||||
|
|
||||||
|
acr:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
-
|
||||||
|
name: Login to ACR
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
registry: ${{ secrets.AZURE_REGISTRY_NAME }}.azurecr.io
|
||||||
|
username: ${{ secrets.AZURE_CLIENT_ID }}
|
||||||
|
password: ${{ secrets.AZURE_CLIENT_SECRET }}
|
||||||
|
|
||||||
dockerhub:
|
dockerhub:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
@@ -87,7 +101,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
-
|
-
|
||||||
name: Login to Docker Hub
|
name: Login to Docker Hub
|
||||||
uses: ./
|
uses: ./
|
||||||
@@ -106,7 +120,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
-
|
-
|
||||||
name: Login to ECR
|
name: Login to ECR
|
||||||
uses: ./
|
uses: ./
|
||||||
@@ -126,7 +140,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
-
|
-
|
||||||
name: Configure AWS Credentials
|
name: Configure AWS Credentials
|
||||||
uses: aws-actions/configure-aws-credentials@v1
|
uses: aws-actions/configure-aws-credentials@v1
|
||||||
@@ -151,7 +165,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
-
|
-
|
||||||
name: Login to Public ECR
|
name: Login to Public ECR
|
||||||
uses: ./
|
uses: ./
|
||||||
@@ -173,7 +187,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
-
|
-
|
||||||
name: Configure AWS Credentials
|
name: Configure AWS Credentials
|
||||||
uses: aws-actions/configure-aws-credentials@v1
|
uses: aws-actions/configure-aws-credentials@v1
|
||||||
@@ -198,7 +212,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
-
|
-
|
||||||
name: Login to GitHub Container Registry
|
name: Login to GitHub Container Registry
|
||||||
uses: ./
|
uses: ./
|
||||||
@@ -218,7 +232,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
-
|
-
|
||||||
name: Login to GitLab
|
name: Login to GitLab
|
||||||
uses: ./
|
uses: ./
|
||||||
@@ -238,7 +252,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
-
|
-
|
||||||
name: Login to Google Artifact Registry
|
name: Login to Google Artifact Registry
|
||||||
uses: ./
|
uses: ./
|
||||||
@@ -258,7 +272,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
-
|
-
|
||||||
name: Login to Google Container Registry
|
name: Login to Google Container Registry
|
||||||
uses: ./
|
uses: ./
|
||||||
|
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
-
|
-
|
||||||
name: Validate
|
name: Validate
|
||||||
uses: docker/bake-action@v1
|
uses: docker/bake-action@v1
|
||||||
@@ -29,6 +29,6 @@ jobs:
|
|||||||
targets: test
|
targets: test
|
||||||
-
|
-
|
||||||
name: Upload coverage
|
name: Upload coverage
|
||||||
uses: codecov/codecov-action@v2
|
uses: codecov/codecov-action@v3
|
||||||
with:
|
with:
|
||||||
file: ./coverage/clover.xml
|
file: ./coverage/clover.xml
|
||||||
|
104
README.md
104
README.md
@@ -39,7 +39,7 @@ name: ci
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: master
|
branches: main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
login:
|
login:
|
||||||
@@ -64,7 +64,7 @@ name: ci
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: master
|
branches: main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
login:
|
login:
|
||||||
@@ -92,7 +92,7 @@ name: ci
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: master
|
branches: main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
login:
|
login:
|
||||||
@@ -118,7 +118,7 @@ name: ci
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: master
|
branches: main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
login:
|
login:
|
||||||
@@ -142,6 +142,45 @@ jobs:
|
|||||||
> Google Container Registry, use the information [on this page](https://cloud.google.com/artifact-registry/docs/transition/transition-from-gcr)
|
> Google Container Registry, use the information [on this page](https://cloud.google.com/artifact-registry/docs/transition/transition-from-gcr)
|
||||||
> to learn about transitioning to Google Artifact Registry.
|
> to learn about transitioning to Google Artifact Registry.
|
||||||
|
|
||||||
|
You can use either workload identity federation based keyless authentication or service account based authentication.
|
||||||
|
|
||||||
|
#### Workload identity federation based authentication
|
||||||
|
|
||||||
|
Configure the workload identity federation for github actions in gcloud (for steps, [refer here](https://github.com/google-github-actions/auth#setting-up-workload-identity-federation)). In the steps, your service account should the ability to push to GCR. Then use google-github-actions/auth action for authentication using workload identity like below:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: ci
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
login:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- id: 'auth'
|
||||||
|
name: 'Authenticate to Google Cloud'
|
||||||
|
uses: 'google-github-actions/auth@v0'
|
||||||
|
with:
|
||||||
|
token_format: 'access_token'
|
||||||
|
workload_identity_provider: '<workload_identity_provider>'
|
||||||
|
service_account: '<service_account>'
|
||||||
|
|
||||||
|
- name: Login to GCR
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
registry: gcr.io
|
||||||
|
username: oauth2accesstoken
|
||||||
|
password: ${{ steps.auth.outputs.access_token }}
|
||||||
|
```
|
||||||
|
|
||||||
|
> Replace `<workload_identity_provider>` with configured workload identity provider. For steps to configure, [refer here](https://github.com/google-github-actions/auth#setting-up-workload-identity-federation).
|
||||||
|
|
||||||
|
> Replace `<service_account>` with configured service account in workload identity provider which has access to push to GCR
|
||||||
|
|
||||||
|
#### Service account based authentication
|
||||||
|
|
||||||
Use a service account with the ability to push to GCR and [configure access control](https://cloud.google.com/container-registry/docs/access-control).
|
Use a service account with the ability to push to GCR and [configure access control](https://cloud.google.com/container-registry/docs/access-control).
|
||||||
Then create and download the JSON key for this service account and save content of `.json` file
|
Then create and download the JSON key for this service account and save content of `.json` file
|
||||||
[as a secret](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets-for-a-repository)
|
[as a secret](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets-for-a-repository)
|
||||||
@@ -153,7 +192,7 @@ name: ci
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: master
|
branches: main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
login:
|
login:
|
||||||
@@ -170,6 +209,47 @@ jobs:
|
|||||||
|
|
||||||
### Google Artifact Registry (GAR)
|
### Google Artifact Registry (GAR)
|
||||||
|
|
||||||
|
You can use either workload identity federation based keyless authentication or service account based authentication.
|
||||||
|
|
||||||
|
#### Workload identity federation based authentication
|
||||||
|
|
||||||
|
Configure the workload identity federation for github actions in gcloud (for steps, [refer here](https://github.com/google-github-actions/auth#setting-up-workload-identity-federation)). In the steps, your service account should the ability to push to GAR. Then use google-github-actions/auth action for authentication using workload identity like below:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: ci
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
login:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- id: 'auth'
|
||||||
|
name: 'Authenticate to Google Cloud'
|
||||||
|
uses: 'google-github-actions/auth@v0'
|
||||||
|
with:
|
||||||
|
token_format: 'access_token'
|
||||||
|
workload_identity_provider: '<workload_identity_provider>'
|
||||||
|
service_account: '<service_account>'
|
||||||
|
|
||||||
|
- name: Login to GAR
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
registry: <location>-docker.pkg.dev
|
||||||
|
username: oauth2accesstoken
|
||||||
|
password: ${{ steps.auth.outputs.access_token }}
|
||||||
|
```
|
||||||
|
> Replace `<workload_identity_provider>` with configured workload identity provider
|
||||||
|
|
||||||
|
> Replace `<service_account>` with configured service account in workload identity provider which has access to push to GCR
|
||||||
|
|
||||||
|
> Replace `<location>` with the regional or multi-regional [location](https://cloud.google.com/artifact-registry/docs/repo-organize#locations)
|
||||||
|
> of the repository where the image is stored.
|
||||||
|
|
||||||
|
#### Service account based authentication
|
||||||
|
|
||||||
Use a service account with the ability to push to GAR and [configure access control](https://cloud.google.com/artifact-registry/docs/access-control).
|
Use a service account with the ability to push to GAR and [configure access control](https://cloud.google.com/artifact-registry/docs/access-control).
|
||||||
Then create and download the JSON key for this service account and save content of `.json` file
|
Then create and download the JSON key for this service account and save content of `.json` file
|
||||||
[as a secret](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets-for-a-repository)
|
[as a secret](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets-for-a-repository)
|
||||||
@@ -181,7 +261,7 @@ name: ci
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: master
|
branches: main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
login:
|
login:
|
||||||
@@ -210,7 +290,7 @@ name: ci
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: master
|
branches: main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
login:
|
login:
|
||||||
@@ -233,7 +313,7 @@ name: ci
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: master
|
branches: main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
login:
|
login:
|
||||||
@@ -260,7 +340,7 @@ name: ci
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: master
|
branches: main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
login:
|
login:
|
||||||
@@ -293,7 +373,7 @@ name: ci
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: master
|
branches: main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
login:
|
login:
|
||||||
@@ -327,7 +407,7 @@ name: ci
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: master
|
branches: main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
login:
|
login:
|
||||||
@@ -353,7 +433,7 @@ name: ci
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: master
|
branches: main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
login:
|
login:
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import {beforeEach, describe, expect, jest, test} from '@jest/globals';
|
||||||
import {AuthorizationData} from '@aws-sdk/client-ecr';
|
import {AuthorizationData} from '@aws-sdk/client-ecr';
|
||||||
import * as aws from '../src/aws';
|
import * as aws from '../src/aws';
|
||||||
|
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import {expect, test} from '@jest/globals';
|
||||||
import {getInputs} from '../src/context';
|
import {getInputs} from '../src/context';
|
||||||
|
|
||||||
test('with password and username getInputs does not throw error', async () => {
|
test('with password and username getInputs does not throw error', async () => {
|
||||||
|
@@ -1,24 +1,24 @@
|
|||||||
|
import {expect, jest, test} from '@jest/globals';
|
||||||
import {loginStandard, logout} from '../src/docker';
|
import {loginStandard, logout} from '../src/docker';
|
||||||
|
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
import * as exec from '@actions/exec';
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
process.env['RUNNER_TEMP'] = path.join(__dirname, 'runner');
|
process.env['RUNNER_TEMP'] = path.join(__dirname, 'runner');
|
||||||
|
|
||||||
test('loginStandard calls exec', async () => {
|
test('loginStandard calls exec', async () => {
|
||||||
const execSpy: jest.SpyInstance = jest.spyOn(exec, 'getExecOutput');
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
execSpy.mockImplementation(() =>
|
// @ts-ignore
|
||||||
Promise.resolve({
|
const execSpy = jest.spyOn(exec, 'getExecOutput').mockImplementation(async () => {
|
||||||
|
return {
|
||||||
exitCode: expect.any(Number),
|
exitCode: expect.any(Number),
|
||||||
stdout: expect.any(Function),
|
stdout: expect.any(Function),
|
||||||
stderr: expect.any(Function)
|
stderr: expect.any(Function)
|
||||||
})
|
};
|
||||||
);
|
});
|
||||||
|
|
||||||
const username: string = 'dbowie';
|
const username = 'dbowie';
|
||||||
const password: string = 'groundcontrol';
|
const password = 'groundcontrol';
|
||||||
const registry: string = 'https://ghcr.io';
|
const registry = 'https://ghcr.io';
|
||||||
|
|
||||||
await loginStandard(registry, username, password);
|
await loginStandard(registry, username, password);
|
||||||
|
|
||||||
@@ -30,16 +30,17 @@ test('loginStandard calls exec', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('logout calls exec', async () => {
|
test('logout calls exec', async () => {
|
||||||
const execSpy: jest.SpyInstance = jest.spyOn(exec, 'getExecOutput');
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
execSpy.mockImplementation(() =>
|
// @ts-ignore
|
||||||
Promise.resolve({
|
const execSpy = jest.spyOn(exec, 'getExecOutput').mockImplementation(async () => {
|
||||||
|
return {
|
||||||
exitCode: expect.any(Number),
|
exitCode: expect.any(Number),
|
||||||
stdout: expect.any(Function),
|
stdout: expect.any(Function),
|
||||||
stderr: expect.any(Function)
|
stderr: expect.any(Function)
|
||||||
})
|
};
|
||||||
);
|
});
|
||||||
|
|
||||||
const registry: string = 'https://ghcr.io';
|
const registry = 'https://ghcr.io';
|
||||||
|
|
||||||
await logout(registry);
|
await logout(registry);
|
||||||
|
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import {expect, jest, test} from '@jest/globals';
|
||||||
import osm = require('os');
|
import osm = require('os');
|
||||||
|
|
||||||
import {run} from '../src/main';
|
import {run} from '../src/main';
|
||||||
@@ -7,37 +8,30 @@ import * as stateHelper from '../src/state-helper';
|
|||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
|
|
||||||
test('errors without username and password', async () => {
|
test('errors without username and password', async () => {
|
||||||
const platSpy = jest.spyOn(osm, 'platform');
|
jest.spyOn(osm, 'platform').mockImplementation(() => 'linux');
|
||||||
platSpy.mockImplementation(() => 'linux');
|
|
||||||
|
|
||||||
process.env['INPUT_LOGOUT'] = 'true'; // default value
|
process.env['INPUT_LOGOUT'] = 'true'; // default value
|
||||||
|
const coreSpy = jest.spyOn(core, 'setFailed');
|
||||||
const coreSpy: jest.SpyInstance = jest.spyOn(core, 'setFailed');
|
|
||||||
|
|
||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(coreSpy).toHaveBeenCalledWith('Username and password required');
|
expect(coreSpy).toHaveBeenCalledWith('Username and password required');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('successful with username and password', async () => {
|
test('successful with username and password', async () => {
|
||||||
const platSpy = jest.spyOn(osm, 'platform');
|
jest.spyOn(osm, 'platform').mockImplementation(() => 'linux');
|
||||||
platSpy.mockImplementation(() => 'linux');
|
const setRegistrySpy = jest.spyOn(stateHelper, 'setRegistry');
|
||||||
|
const setLogoutSpy = jest.spyOn(stateHelper, 'setLogout');
|
||||||
|
const dockerSpy = jest.spyOn(docker, 'login').mockImplementation(jest.fn());
|
||||||
|
|
||||||
const setRegistrySpy: jest.SpyInstance = jest.spyOn(stateHelper, 'setRegistry');
|
const username = 'dbowie';
|
||||||
const setLogoutSpy: jest.SpyInstance = jest.spyOn(stateHelper, 'setLogout');
|
|
||||||
const dockerSpy: jest.SpyInstance = jest.spyOn(docker, 'login');
|
|
||||||
dockerSpy.mockImplementation(() => {});
|
|
||||||
|
|
||||||
const username: string = 'dbowie';
|
|
||||||
process.env[`INPUT_USERNAME`] = username;
|
process.env[`INPUT_USERNAME`] = username;
|
||||||
|
|
||||||
const password: string = 'groundcontrol';
|
const password = 'groundcontrol';
|
||||||
process.env[`INPUT_PASSWORD`] = password;
|
process.env[`INPUT_PASSWORD`] = password;
|
||||||
|
|
||||||
const ecr: string = 'auto';
|
const ecr = 'auto';
|
||||||
process.env['INPUT_ECR'] = ecr;
|
process.env['INPUT_ECR'] = ecr;
|
||||||
|
|
||||||
const logout: boolean = false;
|
const logout = false;
|
||||||
process.env['INPUT_LOGOUT'] = String(logout);
|
process.env['INPUT_LOGOUT'] = String(logout);
|
||||||
|
|
||||||
await run();
|
await run();
|
||||||
@@ -48,27 +42,25 @@ test('successful with username and password', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('calls docker login', async () => {
|
test('calls docker login', async () => {
|
||||||
const platSpy = jest.spyOn(osm, 'platform');
|
jest.spyOn(osm, 'platform').mockImplementation(() => 'linux');
|
||||||
platSpy.mockImplementation(() => 'linux');
|
const setRegistrySpy = jest.spyOn(stateHelper, 'setRegistry');
|
||||||
|
const setLogoutSpy = jest.spyOn(stateHelper, 'setLogout');
|
||||||
|
const dockerSpy = jest.spyOn(docker, 'login');
|
||||||
|
dockerSpy.mockImplementation(jest.fn());
|
||||||
|
|
||||||
const setRegistrySpy: jest.SpyInstance = jest.spyOn(stateHelper, 'setRegistry');
|
const username = 'dbowie';
|
||||||
const setLogoutSpy: jest.SpyInstance = jest.spyOn(stateHelper, 'setLogout');
|
|
||||||
const dockerSpy: jest.SpyInstance = jest.spyOn(docker, 'login');
|
|
||||||
dockerSpy.mockImplementation(() => {});
|
|
||||||
|
|
||||||
const username: string = 'dbowie';
|
|
||||||
process.env[`INPUT_USERNAME`] = username;
|
process.env[`INPUT_USERNAME`] = username;
|
||||||
|
|
||||||
const password: string = 'groundcontrol';
|
const password = 'groundcontrol';
|
||||||
process.env[`INPUT_PASSWORD`] = password;
|
process.env[`INPUT_PASSWORD`] = password;
|
||||||
|
|
||||||
const registry: string = 'ghcr.io';
|
const registry = 'ghcr.io';
|
||||||
process.env[`INPUT_REGISTRY`] = registry;
|
process.env[`INPUT_REGISTRY`] = registry;
|
||||||
|
|
||||||
const ecr: string = 'auto';
|
const ecr = 'auto';
|
||||||
process.env['INPUT_ECR'] = ecr;
|
process.env['INPUT_ECR'] = ecr;
|
||||||
|
|
||||||
const logout: boolean = true;
|
const logout = true;
|
||||||
process.env['INPUT_LOGOUT'] = String(logout);
|
process.env['INPUT_LOGOUT'] = String(logout);
|
||||||
|
|
||||||
await run();
|
await run();
|
||||||
|
@@ -26,6 +26,6 @@ inputs:
|
|||||||
required: false
|
required: false
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: 'node12'
|
using: 'node16'
|
||||||
main: 'dist/index.js'
|
main: 'dist/index.js'
|
||||||
post: 'dist/index.js'
|
post: 'dist/index.js'
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
# syntax=docker/dockerfile:1.3-labs
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
ARG NODE_VERSION
|
ARG NODE_VERSION=16
|
||||||
ARG DOCKER_VERSION=20.10.10
|
ARG DOCKER_VERSION=20.10.13
|
||||||
ARG BUILDX_VERSION=0.7.0
|
ARG BUILDX_VERSION=0.8.1
|
||||||
|
|
||||||
FROM node:${NODE_VERSION}-alpine AS base
|
FROM node:${NODE_VERSION}-alpine AS base
|
||||||
RUN apk add --no-cache cpio findutils git
|
RUN apk add --no-cache cpio findutils git
|
||||||
@@ -57,10 +57,10 @@ RUN --mount=type=bind,target=.,rw \
|
|||||||
FROM scratch AS format-update
|
FROM scratch AS format-update
|
||||||
COPY --from=format /out /
|
COPY --from=format /out /
|
||||||
|
|
||||||
FROM deps AS format-validate
|
FROM deps AS lint
|
||||||
RUN --mount=type=bind,target=.,rw \
|
RUN --mount=type=bind,target=.,rw \
|
||||||
--mount=type=cache,target=/src/node_modules \
|
--mount=type=cache,target=/src/node_modules \
|
||||||
yarn run format-check
|
yarn run lint
|
||||||
|
|
||||||
FROM docker:${DOCKER_VERSION} as docker
|
FROM docker:${DOCKER_VERSION} as docker
|
||||||
FROM docker/buildx-bin:${BUILDX_VERSION} as buildx
|
FROM docker/buildx-bin:${BUILDX_VERSION} as buildx
|
31455
dist/index.js
generated
vendored
31455
dist/index.js
generated
vendored
File diff suppressed because one or more lines are too long
1
dist/index.js.map
generated
vendored
Normal file
1
dist/index.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
9468
dist/licenses.txt
generated
vendored
Normal file
9468
dist/licenses.txt
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
dist/sourcemap-register.js
generated
vendored
Normal file
1
dist/sourcemap-register.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -1,13 +1,3 @@
|
|||||||
variable "NODE_VERSION" {
|
|
||||||
default = "12"
|
|
||||||
}
|
|
||||||
|
|
||||||
target "node-version" {
|
|
||||||
args = {
|
|
||||||
NODE_VERSION = NODE_VERSION
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
group "default" {
|
group "default" {
|
||||||
targets = ["build"]
|
targets = ["build"]
|
||||||
}
|
}
|
||||||
@@ -17,54 +7,47 @@ group "pre-checkin" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group "validate" {
|
group "validate" {
|
||||||
targets = ["format-validate", "build-validate", "vendor-validate"]
|
targets = ["lint", "build-validate", "vendor-validate"]
|
||||||
}
|
}
|
||||||
|
|
||||||
target "build" {
|
target "build" {
|
||||||
inherits = ["node-version"]
|
dockerfile = "dev.Dockerfile"
|
||||||
dockerfile = "./hack/build.Dockerfile"
|
|
||||||
target = "build-update"
|
target = "build-update"
|
||||||
output = ["."]
|
output = ["."]
|
||||||
}
|
}
|
||||||
|
|
||||||
target "build-validate" {
|
target "build-validate" {
|
||||||
inherits = ["node-version"]
|
dockerfile = "dev.Dockerfile"
|
||||||
dockerfile = "./hack/build.Dockerfile"
|
|
||||||
target = "build-validate"
|
target = "build-validate"
|
||||||
output = ["type=cacheonly"]
|
output = ["type=cacheonly"]
|
||||||
}
|
}
|
||||||
|
|
||||||
target "format" {
|
target "format" {
|
||||||
inherits = ["node-version"]
|
dockerfile = "dev.Dockerfile"
|
||||||
dockerfile = "./hack/build.Dockerfile"
|
|
||||||
target = "format-update"
|
target = "format-update"
|
||||||
output = ["."]
|
output = ["."]
|
||||||
}
|
}
|
||||||
|
|
||||||
target "format-validate" {
|
target "lint" {
|
||||||
inherits = ["node-version"]
|
dockerfile = "dev.Dockerfile"
|
||||||
dockerfile = "./hack/build.Dockerfile"
|
target = "lint"
|
||||||
target = "format-validate"
|
|
||||||
output = ["type=cacheonly"]
|
output = ["type=cacheonly"]
|
||||||
}
|
}
|
||||||
|
|
||||||
target "vendor-update" {
|
target "vendor-update" {
|
||||||
inherits = ["node-version"]
|
dockerfile = "dev.Dockerfile"
|
||||||
dockerfile = "./hack/build.Dockerfile"
|
|
||||||
target = "vendor-update"
|
target = "vendor-update"
|
||||||
output = ["."]
|
output = ["."]
|
||||||
}
|
}
|
||||||
|
|
||||||
target "vendor-validate" {
|
target "vendor-validate" {
|
||||||
inherits = ["node-version"]
|
dockerfile = "dev.Dockerfile"
|
||||||
dockerfile = "./hack/build.Dockerfile"
|
|
||||||
target = "vendor-validate"
|
target = "vendor-validate"
|
||||||
output = ["type=cacheonly"]
|
output = ["type=cacheonly"]
|
||||||
}
|
}
|
||||||
|
|
||||||
target "test" {
|
target "test" {
|
||||||
inherits = ["node-version"]
|
dockerfile = "dev.Dockerfile"
|
||||||
dockerfile = "./hack/build.Dockerfile"
|
|
||||||
target = "test-coverage"
|
target = "test-coverage"
|
||||||
output = ["./coverage"]
|
output = ["./coverage"]
|
||||||
}
|
}
|
||||||
|
@@ -2,11 +2,9 @@ module.exports = {
|
|||||||
clearMocks: true,
|
clearMocks: true,
|
||||||
moduleFileExtensions: ['js', 'ts'],
|
moduleFileExtensions: ['js', 'ts'],
|
||||||
setupFiles: ["dotenv/config"],
|
setupFiles: ["dotenv/config"],
|
||||||
testEnvironment: 'node',
|
|
||||||
testMatch: ['**/*.test.ts'],
|
testMatch: ['**/*.test.ts'],
|
||||||
testRunner: 'jest-circus/runner',
|
|
||||||
transform: {
|
transform: {
|
||||||
'^.+\\.ts$': 'ts-jest'
|
'^.+\\.ts$': 'ts-jest'
|
||||||
},
|
},
|
||||||
verbose: false
|
verbose: true
|
||||||
}
|
}
|
43
package.json
43
package.json
@@ -3,11 +3,11 @@
|
|||||||
"description": "GitHub Action to login against a Docker registry",
|
"description": "GitHub Action to login against a Docker registry",
|
||||||
"main": "lib/main.js",
|
"main": "lib/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc && ncc build",
|
"build": "ncc build src/main.ts --source-map --minify --license licenses.txt",
|
||||||
"format": "prettier --write **/*.ts",
|
"lint": "eslint src/**/*.ts __tests__/**/*.ts",
|
||||||
"format-check": "prettier --check **/*.ts",
|
"format": "eslint --fix src/**/*.ts __tests__/**/*.ts",
|
||||||
"test": "jest --coverage",
|
"test": "jest --coverage",
|
||||||
"pre-checkin": "yarn run format && yarn run build"
|
"all": "yarn run build && yarn run format && yarn test"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -28,22 +28,27 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.6.0",
|
"@actions/core": "^1.6.0",
|
||||||
"@actions/exec": "^1.1.0",
|
"@actions/exec": "^1.1.1",
|
||||||
"@actions/io": "^1.1.1",
|
"@actions/io": "^1.1.2",
|
||||||
"@aws-sdk/client-ecr": "^3.44.0",
|
"@aws-sdk/client-ecr": "^3.53.0",
|
||||||
"@aws-sdk/client-ecr-public": "^3.43.0"
|
"@aws-sdk/client-ecr-public": "^3.53.0",
|
||||||
|
"http-proxy-agent": "^5.0.0",
|
||||||
|
"https-proxy-agent": "^5.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^26.0.23",
|
"@types/node": "^16.11.26",
|
||||||
"@types/node": "^14.17.4",
|
"@typescript-eslint/eslint-plugin": "^5.14.0",
|
||||||
"@vercel/ncc": "^0.28.6",
|
"@typescript-eslint/parser": "^5.14.0",
|
||||||
"dotenv": "^8.6.0",
|
"@vercel/ncc": "^0.33.3",
|
||||||
"jest": "^26.6.3",
|
"dotenv": "^16.0.0",
|
||||||
"jest-circus": "^26.6.3",
|
"eslint": "^8.11.0",
|
||||||
"jest-runtime": "^26.6.3",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"prettier": "^2.3.2",
|
"eslint-plugin-jest": "^26.1.1",
|
||||||
"ts-jest": "^26.5.6",
|
"eslint-plugin-prettier": "^4.0.0",
|
||||||
"typescript": "^3.9.10",
|
"jest": "^27.2.5",
|
||||||
"typescript-formatter": "^7.2.2"
|
"prettier": "^2.3.1",
|
||||||
|
"ts-jest": "^27.1.2",
|
||||||
|
"ts-node": "^10.7.0",
|
||||||
|
"typescript": "^4.4.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
31
src/aws.ts
31
src/aws.ts
@@ -1,6 +1,9 @@
|
|||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import {ECR} from '@aws-sdk/client-ecr';
|
import {ECR} from '@aws-sdk/client-ecr';
|
||||||
import {ECRPUBLIC} from '@aws-sdk/client-ecr-public';
|
import {ECRPUBLIC} from '@aws-sdk/client-ecr-public';
|
||||||
|
import {NodeHttpHandler} from '@aws-sdk/node-http-handler';
|
||||||
|
import {HttpProxyAgent} from 'http-proxy-agent';
|
||||||
|
import {HttpsProxyAgent} from 'https-proxy-agent';
|
||||||
|
|
||||||
const ecrRegistryRegex = /^(([0-9]{12})\.dkr\.ecr\.(.+)\.amazonaws\.com(.cn)?)(\/([^:]+)(:.+)?)?$/;
|
const ecrRegistryRegex = /^(([0-9]{12})\.dkr\.ecr\.(.+)\.amazonaws\.com(.cn)?)(\/([^:]+)(:.+)?)?$/;
|
||||||
|
|
||||||
@@ -31,7 +34,7 @@ export const getAccountIDs = (registry: string): string[] => {
|
|||||||
if (!matches) {
|
if (!matches) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
let accountIDs: Array<string> = [matches[2]];
|
const accountIDs: Array<string> = [matches[2]];
|
||||||
if (process.env.AWS_ACCOUNT_IDS) {
|
if (process.env.AWS_ACCOUNT_IDS) {
|
||||||
accountIDs.push(...process.env.AWS_ACCOUNT_IDS.split(','));
|
accountIDs.push(...process.env.AWS_ACCOUNT_IDS.split(','));
|
||||||
}
|
}
|
||||||
@@ -54,6 +57,20 @@ export const getRegistriesData = async (registry: string, username?: string, pas
|
|||||||
authTokenRequest['registryIds'] = accountIDs;
|
authTokenRequest['registryIds'] = accountIDs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let httpProxyAgent;
|
||||||
|
const httpProxy = process.env.http_proxy || process.env.HTTP_PROXY || '';
|
||||||
|
if (httpProxy) {
|
||||||
|
core.debug(`Using http proxy ${httpProxy}`);
|
||||||
|
httpProxyAgent = new HttpProxyAgent(httpProxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
let httpsProxyAgent;
|
||||||
|
const httpsProxy = process.env.https_proxy || process.env.HTTPS_PROXY || '';
|
||||||
|
if (httpsProxy) {
|
||||||
|
core.debug(`Using https proxy ${httpsProxy}`);
|
||||||
|
httpsProxyAgent = new HttpsProxyAgent(httpsProxy);
|
||||||
|
}
|
||||||
|
|
||||||
const credentials =
|
const credentials =
|
||||||
username && password
|
username && password
|
||||||
? {
|
? {
|
||||||
@@ -67,7 +84,11 @@ export const getRegistriesData = async (registry: string, username?: string, pas
|
|||||||
const ecrPublic = new ECRPUBLIC({
|
const ecrPublic = new ECRPUBLIC({
|
||||||
customUserAgent: 'docker-login-action',
|
customUserAgent: 'docker-login-action',
|
||||||
credentials,
|
credentials,
|
||||||
region: region
|
region: region,
|
||||||
|
requestHandler: new NodeHttpHandler({
|
||||||
|
httpAgent: httpProxyAgent,
|
||||||
|
httpsAgent: httpsProxyAgent
|
||||||
|
})
|
||||||
});
|
});
|
||||||
const authTokenResponse = await ecrPublic.getAuthorizationToken(authTokenRequest);
|
const authTokenResponse = await ecrPublic.getAuthorizationToken(authTokenRequest);
|
||||||
if (!authTokenResponse.authorizationData || !authTokenResponse.authorizationData.authorizationToken) {
|
if (!authTokenResponse.authorizationData || !authTokenResponse.authorizationData.authorizationToken) {
|
||||||
@@ -87,7 +108,11 @@ export const getRegistriesData = async (registry: string, username?: string, pas
|
|||||||
const ecr = new ECR({
|
const ecr = new ECR({
|
||||||
customUserAgent: 'docker-login-action',
|
customUserAgent: 'docker-login-action',
|
||||||
credentials,
|
credentials,
|
||||||
region: region
|
region: region,
|
||||||
|
requestHandler: new NodeHttpHandler({
|
||||||
|
httpAgent: httpProxyAgent,
|
||||||
|
httpsAgent: httpsProxyAgent
|
||||||
|
})
|
||||||
});
|
});
|
||||||
const authTokenResponse = await ecr.getAuthorizationToken(authTokenRequest);
|
const authTokenResponse = await ecr.getAuthorizationToken(authTokenRequest);
|
||||||
if (!Array.isArray(authTokenResponse.authorizationData) || !authTokenResponse.authorizationData.length) {
|
if (!Array.isArray(authTokenResponse.authorizationData) || !authTokenResponse.authorizationData.length) {
|
||||||
|
@@ -27,7 +27,7 @@ export async function loginStandard(registry: string, username: string, password
|
|||||||
throw new Error('Username and password required');
|
throw new Error('Username and password required');
|
||||||
}
|
}
|
||||||
|
|
||||||
let loginArgs: Array<string> = ['login', '--password-stdin'];
|
const loginArgs: Array<string> = ['login', '--password-stdin'];
|
||||||
loginArgs.push('--username', username);
|
loginArgs.push('--username', username);
|
||||||
loginArgs.push(registry);
|
loginArgs.push(registry);
|
||||||
|
|
||||||
|
@@ -2,17 +2,18 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es6",
|
"target": "es6",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"lib": [
|
|
||||||
"es6",
|
|
||||||
"dom"
|
|
||||||
],
|
|
||||||
"newLine": "lf",
|
"newLine": "lf",
|
||||||
"outDir": "./lib",
|
"outDir": "./lib",
|
||||||
"rootDir": "./src",
|
"rootDir": "./src",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"esModuleInterop": true,
|
"useUnknownInCatchVariables": false,
|
||||||
"sourceMap": true
|
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules", "**/*.test.ts"]
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"**/*.test.ts",
|
||||||
|
"jest.config.ts"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user