mirror of
https://github.com/docker/login-action.git
synced 2025-08-18 01:59:53 +08:00
Compare commits
51 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
42d299face | ||
|
4858b0b5ea | ||
|
1d7d8649e7 | ||
|
58855695bb | ||
|
d9927c4142 | ||
|
b9a4d91ee5 | ||
|
b20b9f5e31 | ||
|
cb21399f71 | ||
|
faae4d6665 | ||
|
4d84a3c20f | ||
|
6f7ca8828b | ||
|
b776a64ec0 | ||
|
f6476db6e9 | ||
|
46ab6d5c3c | ||
|
1cce1654e0 | ||
|
9537342dee | ||
|
7f47463f56 | ||
|
8807319764 | ||
|
ebac4bd30d | ||
|
499663a42c | ||
|
70b0f7898e | ||
|
885923496b | ||
|
ab92432d0b | ||
|
1828bf2d51 | ||
|
25c0ca8bab | ||
|
f11d2ba650 | ||
|
3f83d7b89c | ||
|
c9c0083563 | ||
|
f694e84504 | ||
|
b30d77254f | ||
|
95778bc566 | ||
|
2c6df6a22f | ||
|
c41c9a5c65 | ||
|
fc6fe565d2 | ||
|
10428f39dc | ||
|
1b4cf55146 | ||
|
5bcefc987c | ||
|
169057673d | ||
|
5d62c58fc3 | ||
|
73cda5dad9 | ||
|
5ffec3343b | ||
|
305d960cac | ||
|
9a9ae26c89 | ||
|
48af9f2a97 | ||
|
c08e3a84a9 | ||
|
f12fe5c78d | ||
|
b566635cc9 | ||
|
b8e54a5ea5 | ||
|
d64238b93b | ||
|
763661a124 | ||
|
41fba5a8c6 |
8
.github/dependabot.yml
vendored
8
.github/dependabot.yml
vendored
@@ -5,8 +5,8 @@ updates:
|
|||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
labels:
|
labels:
|
||||||
- ":game_die: dependencies"
|
- "dependencies"
|
||||||
- ":robot: bot"
|
- "bot"
|
||||||
- package-ecosystem: "npm"
|
- package-ecosystem: "npm"
|
||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
@@ -14,5 +14,5 @@ updates:
|
|||||||
allow:
|
allow:
|
||||||
- dependency-type: "production"
|
- dependency-type: "production"
|
||||||
labels:
|
labels:
|
||||||
- ":game_die: dependencies"
|
- "dependencies"
|
||||||
- ":robot: bot"
|
- "bot"
|
||||||
|
BIN
.github/ghcr-manage-actions-access.gif
vendored
BIN
.github/ghcr-manage-actions-access.gif
vendored
Binary file not shown.
Before Width: | Height: | Size: 99 KiB |
93
.github/workflows/ci.yml
vendored
93
.github/workflows/ci.yml
vendored
@@ -3,7 +3,7 @@ name: ci
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 10 * * *' # everyday at 10am
|
- cron: '0 10 * * *'
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- 'master'
|
- 'master'
|
||||||
@@ -25,7 +25,7 @@ jobs:
|
|||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
logout:
|
logout:
|
||||||
@@ -45,7 +45,7 @@ jobs:
|
|||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
logout: ${{ matrix.logout }}
|
logout: ${{ matrix.logout }}
|
||||||
|
|
||||||
@@ -82,9 +82,8 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os:
|
os:
|
||||||
- ubuntu-20.04
|
- ubuntu-latest
|
||||||
- ubuntu-18.04
|
- windows-latest
|
||||||
- ubuntu-16.04
|
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
@@ -102,9 +101,8 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os:
|
os:
|
||||||
- ubuntu-20.04
|
- ubuntu-latest
|
||||||
- ubuntu-18.04
|
- windows-latest
|
||||||
- ubuntu-16.04
|
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
@@ -113,7 +111,7 @@ jobs:
|
|||||||
name: Login to ECR
|
name: Login to ECR
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
registry: ${{ secrets.AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.AWS_REGION }}.amazonaws.com
|
registry: ${{ secrets.AWS_ACCOUNT_NUMBER }}.dkr.ecr.us-east-1.amazonaws.com
|
||||||
username: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
username: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
|
|
||||||
@@ -123,9 +121,8 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os:
|
os:
|
||||||
- ubuntu-20.04
|
- ubuntu-latest
|
||||||
- ubuntu-18.04
|
- windows-latest
|
||||||
- ubuntu-16.04
|
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
@@ -136,12 +133,12 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
aws-region: ${{ secrets.AWS_REGION }}
|
aws-region: us-east-1
|
||||||
-
|
-
|
||||||
name: Login to ECR
|
name: Login to ECR
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
registry: ${{ secrets.AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.AWS_REGION }}.amazonaws.com
|
registry: ${{ secrets.AWS_ACCOUNT_NUMBER }}.dkr.ecr.us-east-1.amazonaws.com
|
||||||
|
|
||||||
ecr-public:
|
ecr-public:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
@@ -149,9 +146,8 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os:
|
os:
|
||||||
- ubuntu-20.04
|
- ubuntu-latest
|
||||||
- ubuntu-18.04
|
- windows-latest
|
||||||
- ubuntu-16.04
|
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
@@ -163,9 +159,42 @@ jobs:
|
|||||||
registry: public.ecr.aws
|
registry: public.ecr.aws
|
||||||
username: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
username: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
|
env:
|
||||||
|
AWS_REGION: us-east-1
|
||||||
|
|
||||||
|
ecr-public-aws-creds:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os:
|
||||||
|
- ubuntu-latest
|
||||||
|
- windows-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
-
|
||||||
|
name: Configure AWS Credentials
|
||||||
|
uses: aws-actions/configure-aws-credentials@v1
|
||||||
|
with:
|
||||||
|
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
|
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
|
aws-region: us-east-1
|
||||||
|
-
|
||||||
|
name: Login to ECR
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
registry: public.ecr.aws
|
||||||
|
|
||||||
github-container:
|
github-container:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os:
|
||||||
|
- ubuntu-latest
|
||||||
|
- windows-latest
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
@@ -175,11 +204,17 @@ jobs:
|
|||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
gitlab:
|
gitlab:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os:
|
||||||
|
- ubuntu-latest
|
||||||
|
- windows-latest
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
@@ -193,7 +228,13 @@ jobs:
|
|||||||
password: ${{ secrets.GITLAB_TOKEN }}
|
password: ${{ secrets.GITLAB_TOKEN }}
|
||||||
|
|
||||||
google-artifact:
|
google-artifact:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os:
|
||||||
|
- ubuntu-latest
|
||||||
|
- windows-latest
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
@@ -207,7 +248,13 @@ jobs:
|
|||||||
password: ${{ secrets.GAR_JSON_KEY }}
|
password: ${{ secrets.GAR_JSON_KEY }}
|
||||||
|
|
||||||
google-container:
|
google-container:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os:
|
||||||
|
- ubuntu-latest
|
||||||
|
- windows-latest
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
|
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -29,6 +29,6 @@ jobs:
|
|||||||
targets: test
|
targets: test
|
||||||
-
|
-
|
||||||
name: Upload coverage
|
name: Upload coverage
|
||||||
uses: codecov/codecov-action@v1
|
uses: codecov/codecov-action@v2
|
||||||
with:
|
with:
|
||||||
file: ./coverage/clover.xml
|
file: ./coverage/clover.xml
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"printWidth": 120,
|
"printWidth": 240,
|
||||||
"tabWidth": 2,
|
"tabWidth": 2,
|
||||||
"useTabs": false,
|
"useTabs": false,
|
||||||
"semi": true,
|
"semi": true,
|
||||||
|
19
README.md
19
README.md
@@ -55,10 +55,7 @@ jobs:
|
|||||||
|
|
||||||
### GitHub Container Registry
|
### GitHub Container Registry
|
||||||
|
|
||||||
To use the [GitHub Container Registry](https://docs.github.com/en/packages/getting-started-with-github-container-registry),
|
To authenticate against the [GitHub Container Registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry),
|
||||||
you need to [enable this feature for your personal or organization account](https://docs.github.com/en/packages/guides/enabling-improved-container-support).
|
|
||||||
|
|
||||||
To [authenticate against it](https://docs.github.com/en/packages/guides/migrating-to-github-container-registry-for-docker-images#authenticating-with-the-container-registry),
|
|
||||||
use the [`GITHUB_TOKEN`](https://docs.github.com/en/actions/reference/authentication-in-a-workflow) for the best
|
use the [`GITHUB_TOKEN`](https://docs.github.com/en/actions/reference/authentication-in-a-workflow) for the best
|
||||||
security and experience.
|
security and experience.
|
||||||
|
|
||||||
@@ -78,13 +75,12 @@ jobs:
|
|||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v1
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
```
|
```
|
||||||
|
|
||||||
You may need to manage write and read access of GitHub Actions for repositories in the container settings:
|
You may need to [manage write and read access of GitHub Actions](https://docs.github.com/en/packages/managing-github-packages-using-github-actions-workflows/publishing-and-installing-a-package-with-github-actions#upgrading-a-workflow-that-accesses-ghcrio)
|
||||||
|
for repositories in the container settings.
|
||||||

|
|
||||||
|
|
||||||
You can also use a [personal access token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token)
|
You can also use a [personal access token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token)
|
||||||
with the [appropriate scopes](https://docs.github.com/en/packages/getting-started-with-github-container-registry/migrating-to-github-container-registry-for-docker-images#authenticating-with-the-container-registry).
|
with the [appropriate scopes](https://docs.github.com/en/packages/getting-started-with-github-container-registry/migrating-to-github-container-registry-for-docker-images#authenticating-with-the-container-registry).
|
||||||
@@ -149,7 +145,8 @@ jobs:
|
|||||||
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)
|
||||||
called `GCR_JSON_KEY` in your GitHub repo. Ensure you set the username to `_json_key`.
|
called `GCR_JSON_KEY` in your GitHub repo. Ensure you set the username to `_json_key`,
|
||||||
|
or `_json_key_base64` if you use a base64-encoded key.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
name: ci
|
name: ci
|
||||||
@@ -176,7 +173,8 @@ jobs:
|
|||||||
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)
|
||||||
called `GAR_JSON_KEY` in your GitHub repo. Ensure you set the username to `_json_key`.
|
called `GAR_JSON_KEY` in your GitHub repo. Ensure you set the username to `_json_key`,
|
||||||
|
or `_json_key_base64` if you use a base64-encoded key.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
name: ci
|
name: ci
|
||||||
@@ -381,6 +379,7 @@ Following inputs can be used as `step.with` keys
|
|||||||
| `registry` | String | | Server address of Docker registry. If not set then will default to Docker Hub |
|
| `registry` | String | | Server address of Docker registry. If not set then will default to Docker Hub |
|
||||||
| `username` | String | | Username used to log against the Docker registry |
|
| `username` | String | | Username used to log against the Docker registry |
|
||||||
| `password` | String | | Password or personal access token used to log against the Docker registry |
|
| `password` | String | | Password or personal access token used to log against the Docker registry |
|
||||||
|
| `ecr` | String | `auto` | Specifies whether the given registry is ECR (`auto`, `true` or `false`) |
|
||||||
| `logout` | Bool | `true` | Log out from the Docker registry at the end of a job |
|
| `logout` | Bool | `true` | Log out from the Docker registry at the end of a job |
|
||||||
|
|
||||||
## Keep up-to-date with GitHub Dependabot
|
## Keep up-to-date with GitHub Dependabot
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import * as semver from 'semver';
|
import {AuthorizationData} from '@aws-sdk/client-ecr';
|
||||||
import * as aws from '../src/aws';
|
import * as aws from '../src/aws';
|
||||||
|
|
||||||
describe('isECR', () => {
|
describe('isECR', () => {
|
||||||
@@ -10,7 +10,7 @@ describe('isECR', () => {
|
|||||||
['390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn', true],
|
['390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn', true],
|
||||||
['public.ecr.aws', true]
|
['public.ecr.aws', true]
|
||||||
])('given registry %p', async (registry, expected) => {
|
])('given registry %p', async (registry, expected) => {
|
||||||
expect(await aws.isECR(registry)).toEqual(expected);
|
expect(aws.isECR(registry)).toEqual(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -23,40 +23,7 @@ describe('isPubECR', () => {
|
|||||||
['390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn', false],
|
['390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn', false],
|
||||||
['public.ecr.aws', true]
|
['public.ecr.aws', true]
|
||||||
])('given registry %p', async (registry, expected) => {
|
])('given registry %p', async (registry, expected) => {
|
||||||
expect(await aws.isPubECR(registry)).toEqual(expected);
|
expect(aws.isPubECR(registry)).toEqual(expected);
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getCLI', () => {
|
|
||||||
it('exists', async () => {
|
|
||||||
const awsPath = await aws.getCLI();
|
|
||||||
console.log(`awsPath: ${awsPath}`);
|
|
||||||
expect(awsPath).not.toEqual('');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('execCLI', () => {
|
|
||||||
it('--version not empty', async () => {
|
|
||||||
const cliCmdOutput = await aws.execCLI(['--version']);
|
|
||||||
console.log(`cliCmdOutput: ${cliCmdOutput}`);
|
|
||||||
expect(cliCmdOutput).not.toEqual('');
|
|
||||||
}, 100000);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getCLIVersion', () => {
|
|
||||||
it('valid', async () => {
|
|
||||||
const cliVersion = await aws.getCLIVersion();
|
|
||||||
console.log(`cliVersion: ${cliVersion}`);
|
|
||||||
expect(semver.valid(cliVersion)).not.toBeNull();
|
|
||||||
}, 100000);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('parseCLIVersion', () => {
|
|
||||||
test.each([
|
|
||||||
['v1', 'aws-cli/1.18.120 Python/2.7.17 Linux/5.3.0-1034-azure botocore/1.17.43', '1.18.120'],
|
|
||||||
['v2', 'aws-cli/2.0.41 Python/3.7.3 Linux/4.19.104-microsoft-standard exe/x86_64.ubuntu.18', '2.0.41']
|
|
||||||
])('given aws %p', async (version, stdout, expected) => {
|
|
||||||
expect(await aws.parseCLIVersion(stdout)).toEqual(expected);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -67,33 +34,122 @@ describe('getRegion', () => {
|
|||||||
['390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn', 'cn-northwest-1'],
|
['390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn', 'cn-northwest-1'],
|
||||||
['public.ecr.aws', 'us-east-1']
|
['public.ecr.aws', 'us-east-1']
|
||||||
])('given registry %p', async (registry, expected) => {
|
])('given registry %p', async (registry, expected) => {
|
||||||
expect(await aws.getRegion(registry)).toEqual(expected);
|
expect(aws.getRegion(registry)).toEqual(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getAccountIDs', () => {
|
describe('getAccountIDs', () => {
|
||||||
test.each([
|
test.each([
|
||||||
['012345678901.dkr.ecr.eu-west-3.amazonaws.com', undefined, ['012345678901']],
|
['012345678901.dkr.ecr.eu-west-3.amazonaws.com', undefined, ['012345678901']],
|
||||||
[
|
['012345678901.dkr.ecr.eu-west-3.amazonaws.com', '012345678910,023456789012', ['012345678901', '012345678910', '023456789012']],
|
||||||
'012345678901.dkr.ecr.eu-west-3.amazonaws.com',
|
['012345678901.dkr.ecr.eu-west-3.amazonaws.com', '012345678901,012345678910,023456789012', ['012345678901', '012345678910', '023456789012']],
|
||||||
'012345678910,023456789012',
|
['390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn', '012345678910,023456789012', ['390948362332', '012345678910', '023456789012']],
|
||||||
['012345678901', '012345678910', '023456789012']
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'012345678901.dkr.ecr.eu-west-3.amazonaws.com',
|
|
||||||
'012345678901,012345678910,023456789012',
|
|
||||||
['012345678901', '012345678910', '023456789012']
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn',
|
|
||||||
'012345678910,023456789012',
|
|
||||||
['390948362332', '012345678910', '023456789012']
|
|
||||||
],
|
|
||||||
['public.ecr.aws', undefined, []]
|
['public.ecr.aws', undefined, []]
|
||||||
])('given registry %p', async (registry, accountIDsEnv, expected) => {
|
])('given registry %p', async (registry, accountIDsEnv, expected) => {
|
||||||
if (accountIDsEnv) {
|
if (accountIDsEnv) {
|
||||||
process.env.AWS_ACCOUNT_IDS = accountIDsEnv;
|
process.env.AWS_ACCOUNT_IDS = accountIDsEnv;
|
||||||
}
|
}
|
||||||
expect(await aws.getAccountIDs(registry)).toEqual(expected);
|
expect(aws.getAccountIDs(registry)).toEqual(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const mockEcrGetAuthToken = jest.fn();
|
||||||
|
const mockEcrPublicGetAuthToken = jest.fn();
|
||||||
|
jest.mock('@aws-sdk/client-ecr', () => {
|
||||||
|
return {
|
||||||
|
ECR: jest.fn(() => ({
|
||||||
|
getAuthorizationToken: mockEcrGetAuthToken
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
});
|
||||||
|
jest.mock('@aws-sdk/client-ecr-public', () => {
|
||||||
|
return {
|
||||||
|
ECRPUBLIC: jest.fn(() => ({
|
||||||
|
getAuthorizationToken: mockEcrPublicGetAuthToken
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getRegistriesData', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
delete process.env.AWS_ACCOUNT_IDS;
|
||||||
|
});
|
||||||
|
// prettier-ignore
|
||||||
|
test.each([
|
||||||
|
[
|
||||||
|
'012345678901.dkr.ecr.aws-region-1.amazonaws.com',
|
||||||
|
'dkr.ecr.aws-region-1.amazonaws.com', undefined,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
registry: '012345678901.dkr.ecr.aws-region-1.amazonaws.com',
|
||||||
|
username: '012345678901',
|
||||||
|
password: 'world'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'012345678901.dkr.ecr.eu-west-3.amazonaws.com',
|
||||||
|
'dkr.ecr.eu-west-3.amazonaws.com',
|
||||||
|
'012345678910,023456789012',
|
||||||
|
[
|
||||||
|
{
|
||||||
|
registry: '012345678901.dkr.ecr.eu-west-3.amazonaws.com',
|
||||||
|
username: '012345678901',
|
||||||
|
password: 'world'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
registry: '012345678910.dkr.ecr.eu-west-3.amazonaws.com',
|
||||||
|
username: '012345678910',
|
||||||
|
password: 'world'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
registry: '023456789012.dkr.ecr.eu-west-3.amazonaws.com',
|
||||||
|
username: '023456789012',
|
||||||
|
password: 'world'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'public.ecr.aws',
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
registry: 'public.ecr.aws',
|
||||||
|
username: 'AWS',
|
||||||
|
password: 'world'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
])('given registry %p', async (registry, fqdn, accountIDsEnv, expected: aws.RegistryData[]) => {
|
||||||
|
if (accountIDsEnv) {
|
||||||
|
process.env.AWS_ACCOUNT_IDS = accountIDsEnv;
|
||||||
|
}
|
||||||
|
const accountIDs = aws.getAccountIDs(registry);
|
||||||
|
const authData: AuthorizationData[] = [];
|
||||||
|
if (accountIDs.length == 0) {
|
||||||
|
mockEcrPublicGetAuthToken.mockImplementation(() => {
|
||||||
|
return Promise.resolve({
|
||||||
|
authorizationData: {
|
||||||
|
authorizationToken: Buffer.from(`AWS:world`).toString('base64'),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
aws.getAccountIDs(registry).forEach(accountID => {
|
||||||
|
authData.push({
|
||||||
|
authorizationToken: Buffer.from(`${accountID}:world`).toString('base64'),
|
||||||
|
proxyEndpoint: `${accountID}.${fqdn}`
|
||||||
|
});
|
||||||
|
});
|
||||||
|
mockEcrGetAuthToken.mockImplementation(() => {
|
||||||
|
return Promise.resolve({
|
||||||
|
authorizationData: authData
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const regData = await aws.getRegistriesData(registry);
|
||||||
|
expect(regData).toEqual(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
import osm = require('os');
|
|
||||||
|
|
||||||
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 () => {
|
||||||
|
@@ -34,6 +34,9 @@ test('successful with username and password', async () => {
|
|||||||
const password: string = 'groundcontrol';
|
const password: string = 'groundcontrol';
|
||||||
process.env[`INPUT_PASSWORD`] = password;
|
process.env[`INPUT_PASSWORD`] = password;
|
||||||
|
|
||||||
|
const ecr: string = 'auto';
|
||||||
|
process.env['INPUT_ECR'] = ecr;
|
||||||
|
|
||||||
const logout: boolean = false;
|
const logout: boolean = false;
|
||||||
process.env['INPUT_LOGOUT'] = String(logout);
|
process.env['INPUT_LOGOUT'] = String(logout);
|
||||||
|
|
||||||
@@ -41,7 +44,7 @@ test('successful with username and password', async () => {
|
|||||||
|
|
||||||
expect(setRegistrySpy).toHaveBeenCalledWith('');
|
expect(setRegistrySpy).toHaveBeenCalledWith('');
|
||||||
expect(setLogoutSpy).toHaveBeenCalledWith(logout);
|
expect(setLogoutSpy).toHaveBeenCalledWith(logout);
|
||||||
expect(dockerSpy).toHaveBeenCalledWith('', username, password);
|
expect(dockerSpy).toHaveBeenCalledWith('', username, password, ecr);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('calls docker login', async () => {
|
test('calls docker login', async () => {
|
||||||
@@ -62,6 +65,9 @@ test('calls docker login', async () => {
|
|||||||
const registry: string = 'ghcr.io';
|
const registry: string = 'ghcr.io';
|
||||||
process.env[`INPUT_REGISTRY`] = registry;
|
process.env[`INPUT_REGISTRY`] = registry;
|
||||||
|
|
||||||
|
const ecr: string = 'auto';
|
||||||
|
process.env['INPUT_ECR'] = ecr;
|
||||||
|
|
||||||
const logout: boolean = true;
|
const logout: boolean = true;
|
||||||
process.env['INPUT_LOGOUT'] = String(logout);
|
process.env['INPUT_LOGOUT'] = String(logout);
|
||||||
|
|
||||||
@@ -69,5 +75,5 @@ test('calls docker login', async () => {
|
|||||||
|
|
||||||
expect(setRegistrySpy).toHaveBeenCalledWith(registry);
|
expect(setRegistrySpy).toHaveBeenCalledWith(registry);
|
||||||
expect(setLogoutSpy).toHaveBeenCalledWith(logout);
|
expect(setLogoutSpy).toHaveBeenCalledWith(logout);
|
||||||
expect(dockerSpy).toHaveBeenCalledWith(registry, username, password);
|
expect(dockerSpy).toHaveBeenCalledWith(registry, username, password, ecr);
|
||||||
});
|
});
|
||||||
|
@@ -16,6 +16,10 @@ inputs:
|
|||||||
password:
|
password:
|
||||||
description: 'Password or personal access token used to log against the Docker registry'
|
description: 'Password or personal access token used to log against the Docker registry'
|
||||||
required: false
|
required: false
|
||||||
|
ecr:
|
||||||
|
description: 'Specifies whether the given registry is ECR (auto, true or false)'
|
||||||
|
default: 'auto'
|
||||||
|
required: false
|
||||||
logout:
|
logout:
|
||||||
description: 'Log out from the Docker registry at the end of a job'
|
description: 'Log out from the Docker registry at the end of a job'
|
||||||
default: 'true'
|
default: 'true'
|
||||||
|
3
codecov.yml
Normal file
3
codecov.yml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
comment: false
|
||||||
|
github_checks:
|
||||||
|
annotations: false
|
34409
dist/index.js
generated
vendored
34409
dist/index.js
generated
vendored
File diff suppressed because one or more lines are too long
@@ -31,6 +31,7 @@ target "build-validate" {
|
|||||||
inherits = ["node-version"]
|
inherits = ["node-version"]
|
||||||
dockerfile = "./hack/build.Dockerfile"
|
dockerfile = "./hack/build.Dockerfile"
|
||||||
target = "build-validate"
|
target = "build-validate"
|
||||||
|
output = ["type=cacheonly"]
|
||||||
}
|
}
|
||||||
|
|
||||||
target "format" {
|
target "format" {
|
||||||
@@ -44,24 +45,26 @@ target "format-validate" {
|
|||||||
inherits = ["node-version"]
|
inherits = ["node-version"]
|
||||||
dockerfile = "./hack/build.Dockerfile"
|
dockerfile = "./hack/build.Dockerfile"
|
||||||
target = "format-validate"
|
target = "format-validate"
|
||||||
|
output = ["type=cacheonly"]
|
||||||
}
|
}
|
||||||
|
|
||||||
target "vendor-update" {
|
target "vendor-update" {
|
||||||
inherits = ["node-version"]
|
inherits = ["node-version"]
|
||||||
dockerfile = "./hack/vendor.Dockerfile"
|
dockerfile = "./hack/build.Dockerfile"
|
||||||
target = "update"
|
target = "vendor-update"
|
||||||
output = ["."]
|
output = ["."]
|
||||||
}
|
}
|
||||||
|
|
||||||
target "vendor-validate" {
|
target "vendor-validate" {
|
||||||
inherits = ["node-version"]
|
inherits = ["node-version"]
|
||||||
dockerfile = "./hack/vendor.Dockerfile"
|
dockerfile = "./hack/build.Dockerfile"
|
||||||
target = "validate"
|
target = "vendor-validate"
|
||||||
|
output = ["type=cacheonly"]
|
||||||
}
|
}
|
||||||
|
|
||||||
target "test" {
|
target "test" {
|
||||||
inherits = ["node-version"]
|
inherits = ["node-version"]
|
||||||
dockerfile = "./hack/test.Dockerfile"
|
dockerfile = "./hack/build.Dockerfile"
|
||||||
target = "test-coverage"
|
target = "test-coverage"
|
||||||
output = ["./coverage"]
|
output = ["./coverage"]
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
# syntax=docker/dockerfile:1.2
|
# syntax=docker/dockerfile:1.3-labs
|
||||||
|
|
||||||
ARG NODE_VERSION
|
ARG NODE_VERSION
|
||||||
|
ARG DOCKER_VERSION=20.10.10
|
||||||
|
ARG BUILDX_VERSION=0.7.0
|
||||||
|
|
||||||
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
|
||||||
@@ -8,7 +11,22 @@ WORKDIR /src
|
|||||||
FROM base AS deps
|
FROM base AS deps
|
||||||
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 install
|
yarn install && mkdir /vendor && cp yarn.lock /vendor
|
||||||
|
|
||||||
|
FROM scratch AS vendor-update
|
||||||
|
COPY --from=deps /vendor /
|
||||||
|
|
||||||
|
FROM deps AS vendor-validate
|
||||||
|
RUN --mount=type=bind,target=.,rw <<EOT
|
||||||
|
set -e
|
||||||
|
git add -A
|
||||||
|
cp -rf /vendor/* .
|
||||||
|
if [ -n "$(git status --porcelain -- yarn.lock)" ]; then
|
||||||
|
echo >&2 'ERROR: Vendor result differs. Please vendor your package with "docker buildx bake vendor-update"'
|
||||||
|
git status --porcelain -- yarn.lock
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
EOT
|
||||||
|
|
||||||
FROM deps AS build
|
FROM deps AS build
|
||||||
RUN --mount=type=bind,target=.,rw \
|
RUN --mount=type=bind,target=.,rw \
|
||||||
@@ -19,13 +37,16 @@ FROM scratch AS build-update
|
|||||||
COPY --from=build /out /
|
COPY --from=build /out /
|
||||||
|
|
||||||
FROM build AS build-validate
|
FROM build AS build-validate
|
||||||
RUN --mount=type=bind,target=.,rw \
|
RUN --mount=type=bind,target=.,rw <<EOT
|
||||||
git add -A && cp -rf /out/* .; \
|
set -e
|
||||||
if [ -n "$(git status --porcelain -- dist)" ]; then \
|
git add -A
|
||||||
echo >&2 'ERROR: Build result differs. Please build first with "docker buildx bake build"'; \
|
cp -rf /out/* .
|
||||||
git status --porcelain -- dist; \
|
if [ -n "$(git status --porcelain -- dist)" ]; then
|
||||||
exit 1; \
|
echo >&2 'ERROR: Build result differs. Please build first with "docker buildx bake build"'
|
||||||
fi
|
git status --porcelain -- dist
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
EOT
|
||||||
|
|
||||||
FROM deps AS format
|
FROM deps AS format
|
||||||
RUN --mount=type=bind,target=.,rw \
|
RUN --mount=type=bind,target=.,rw \
|
||||||
@@ -39,4 +60,19 @@ COPY --from=format /out /
|
|||||||
FROM deps AS format-validate
|
FROM deps AS format-validate
|
||||||
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 format-check
|
||||||
|
|
||||||
|
FROM docker:${DOCKER_VERSION} as docker
|
||||||
|
FROM docker/buildx-bin:${BUILDX_VERSION} as buildx
|
||||||
|
|
||||||
|
FROM deps AS test
|
||||||
|
ENV RUNNER_TEMP=/tmp/github_runner
|
||||||
|
ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache
|
||||||
|
RUN --mount=type=bind,target=.,rw \
|
||||||
|
--mount=type=cache,target=/src/node_modules \
|
||||||
|
--mount=type=bind,from=docker,source=/usr/local/bin/docker,target=/usr/bin/docker \
|
||||||
|
--mount=type=bind,from=buildx,source=/buildx,target=/usr/libexec/docker/cli-plugins/docker-buildx \
|
||||||
|
yarn run test --coverageDirectory=/tmp/coverage
|
||||||
|
|
||||||
|
FROM scratch AS test-coverage
|
||||||
|
COPY --from=test /tmp/coverage /
|
||||||
|
@@ -1,34 +0,0 @@
|
|||||||
# syntax=docker/dockerfile:1.2
|
|
||||||
ARG NODE_VERSION
|
|
||||||
|
|
||||||
FROM node:${NODE_VERSION}-alpine AS base
|
|
||||||
RUN apk add --no-cache binutils curl git unzip
|
|
||||||
ENV GLIBC_VER=2.31-r0
|
|
||||||
RUN curl -sL "https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub" -o "/etc/apk/keys/sgerrand.rsa.pub" \
|
|
||||||
&& curl -sLO "https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-${GLIBC_VER}.apk" \
|
|
||||||
&& curl -sLO "https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-bin-${GLIBC_VER}.apk" \
|
|
||||||
&& apk add --no-cache \
|
|
||||||
glibc-${GLIBC_VER}.apk \
|
|
||||||
glibc-bin-${GLIBC_VER}.apk \
|
|
||||||
&& curl -sL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" \
|
|
||||||
&& unzip -qq "awscliv2.zip" \
|
|
||||||
&& ./aws/install \
|
|
||||||
&& aws --version
|
|
||||||
WORKDIR /src
|
|
||||||
|
|
||||||
FROM base AS deps
|
|
||||||
RUN --mount=type=bind,target=.,rw \
|
|
||||||
--mount=type=cache,target=/src/node_modules \
|
|
||||||
yarn install
|
|
||||||
|
|
||||||
FROM deps AS test
|
|
||||||
ENV RUNNER_TEMP=/tmp/github_runner
|
|
||||||
ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache
|
|
||||||
RUN --mount=type=bind,target=.,rw \
|
|
||||||
--mount=type=cache,target=/src/node_modules \
|
|
||||||
--mount=type=bind,from=crazymax/docker,source=/usr/libexec/docker/cli-plugins/docker-buildx,target=/usr/libexec/docker/cli-plugins/docker-buildx \
|
|
||||||
--mount=type=bind,from=crazymax/docker,source=/usr/local/bin/docker,target=/usr/bin/docker \
|
|
||||||
yarn run test --coverageDirectory=/tmp/coverage
|
|
||||||
|
|
||||||
FROM scratch AS test-coverage
|
|
||||||
COPY --from=test /tmp/coverage /
|
|
@@ -1,23 +0,0 @@
|
|||||||
# syntax=docker/dockerfile:1.2
|
|
||||||
ARG NODE_VERSION
|
|
||||||
|
|
||||||
FROM node:${NODE_VERSION}-alpine AS base
|
|
||||||
RUN apk add --no-cache git
|
|
||||||
WORKDIR /src
|
|
||||||
|
|
||||||
FROM base AS vendored
|
|
||||||
RUN --mount=type=bind,target=.,rw \
|
|
||||||
--mount=type=cache,target=/src/node_modules \
|
|
||||||
yarn install && mkdir /out && cp yarn.lock /out
|
|
||||||
|
|
||||||
FROM scratch AS update
|
|
||||||
COPY --from=vendored /out /
|
|
||||||
|
|
||||||
FROM vendored AS validate
|
|
||||||
RUN --mount=type=bind,target=.,rw \
|
|
||||||
git add -A && cp -rf /out/* .; \
|
|
||||||
if [ -n "$(git status --porcelain -- yarn.lock)" ]; then \
|
|
||||||
echo >&2 'ERROR: Vendor result differs. Please vendor your package with "docker buildx bake vendor-update"'; \
|
|
||||||
git status --porcelain -- yarn.lock; \
|
|
||||||
exit 1; \
|
|
||||||
fi
|
|
25
package.json
25
package.json
@@ -27,22 +27,23 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.4.0",
|
"@actions/core": "^1.6.0",
|
||||||
"@actions/exec": "^1.1.0",
|
"@actions/exec": "^1.1.0",
|
||||||
"@actions/io": "^1.1.1",
|
"@actions/io": "^1.1.1",
|
||||||
"semver": "^7.3.5"
|
"@aws-sdk/client-ecr": "^3.44.0",
|
||||||
|
"@aws-sdk/client-ecr-public": "^3.43.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^26.0.3",
|
"@types/jest": "^26.0.23",
|
||||||
"@types/node": "^14.0.14",
|
"@types/node": "^14.17.4",
|
||||||
"@vercel/ncc": "^0.23.0",
|
"@vercel/ncc": "^0.28.6",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.6.0",
|
||||||
"jest": "^26.1.0",
|
"jest": "^26.6.3",
|
||||||
"jest-circus": "^26.1.0",
|
"jest-circus": "^26.6.3",
|
||||||
"jest-runtime": "^26.1.0",
|
"jest-runtime": "^26.6.3",
|
||||||
"prettier": "^2.0.5",
|
"prettier": "^2.3.2",
|
||||||
"ts-jest": "^26.1.1",
|
"ts-jest": "^26.5.6",
|
||||||
"typescript": "^3.9.5",
|
"typescript": "^3.9.10",
|
||||||
"typescript-formatter": "^7.2.2"
|
"typescript-formatter": "^7.2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
120
src/aws.ts
120
src/aws.ts
@@ -1,6 +1,6 @@
|
|||||||
import * as semver from 'semver';
|
import * as core from '@actions/core';
|
||||||
import * as exec from '@actions/exec';
|
import {ECR} from '@aws-sdk/client-ecr';
|
||||||
import * as io from '@actions/io';
|
import {ECRPUBLIC} from '@aws-sdk/client-ecr-public';
|
||||||
|
|
||||||
const ecrRegistryRegex = /^(([0-9]{12})\.dkr\.ecr\.(.+)\.amazonaws\.com(.cn)?)(\/([^:]+)(:.+)?)?$/;
|
const ecrRegistryRegex = /^(([0-9]{12})\.dkr\.ecr\.(.+)\.amazonaws\.com(.cn)?)(\/([^:]+)(:.+)?)?$/;
|
||||||
|
|
||||||
@@ -38,61 +38,71 @@ export const getAccountIDs = (registry: string): string[] => {
|
|||||||
return accountIDs.filter((item, index) => accountIDs.indexOf(item) === index);
|
return accountIDs.filter((item, index) => accountIDs.indexOf(item) === index);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getCLI = async (): Promise<string> => {
|
export interface RegistryData {
|
||||||
return io.which('aws', true);
|
registry: string;
|
||||||
};
|
username: string;
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
||||||
export const execCLI = async (args: string[]): Promise<string> => {
|
export const getRegistriesData = async (registry: string, username?: string, password?: string): Promise<RegistryData[]> => {
|
||||||
return exec
|
const region = getRegion(registry);
|
||||||
.getExecOutput(await getCLI(), args, {
|
const accountIDs = getAccountIDs(registry);
|
||||||
ignoreReturnCode: true,
|
|
||||||
silent: true
|
const authTokenRequest = {};
|
||||||
})
|
if (accountIDs.length > 0) {
|
||||||
.then(res => {
|
core.debug(`Requesting AWS ECR auth token for ${accountIDs.join(', ')}`);
|
||||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
authTokenRequest['registryIds'] = accountIDs;
|
||||||
throw new Error(res.stderr.trim());
|
}
|
||||||
} else if (res.stderr.length > 0) {
|
|
||||||
return res.stderr.trim();
|
const credentials =
|
||||||
} else {
|
username && password
|
||||||
return res.stdout.trim();
|
? {
|
||||||
|
accessKeyId: username,
|
||||||
|
secretAccessKey: password
|
||||||
|
}
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
if (isPubECR(registry)) {
|
||||||
|
core.info(`AWS Public ECR detected with ${region} region`);
|
||||||
|
const ecrPublic = new ECRPUBLIC({
|
||||||
|
customUserAgent: 'docker-login-action',
|
||||||
|
credentials,
|
||||||
|
region: region
|
||||||
|
});
|
||||||
|
const authTokenResponse = await ecrPublic.getAuthorizationToken(authTokenRequest);
|
||||||
|
if (!authTokenResponse.authorizationData || !authTokenResponse.authorizationData.authorizationToken) {
|
||||||
|
throw new Error('Could not retrieve an authorization token from AWS Public ECR');
|
||||||
|
}
|
||||||
|
const authToken = Buffer.from(authTokenResponse.authorizationData.authorizationToken, 'base64').toString('utf-8');
|
||||||
|
const creds = authToken.split(':', 2);
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
registry: 'public.ecr.aws',
|
||||||
|
username: creds[0],
|
||||||
|
password: creds[1]
|
||||||
}
|
}
|
||||||
});
|
];
|
||||||
};
|
|
||||||
|
|
||||||
export const getCLIVersion = async (): Promise<string> => {
|
|
||||||
return parseCLIVersion(await execCLI(['--version']));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const parseCLIVersion = async (stdout: string): Promise<string> => {
|
|
||||||
const matches = /aws-cli\/([0-9.]+)/.exec(stdout);
|
|
||||||
if (!matches) {
|
|
||||||
throw new Error(`Cannot parse AWS CLI version`);
|
|
||||||
}
|
|
||||||
return semver.clean(matches[1]);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getDockerLoginCmds = async (
|
|
||||||
cliVersion: string,
|
|
||||||
registry: string,
|
|
||||||
region: string,
|
|
||||||
accountIDs: string[]
|
|
||||||
): Promise<string[]> => {
|
|
||||||
let ecrCmd = (await isPubECR(registry)) ? 'ecr-public' : 'ecr';
|
|
||||||
if (semver.satisfies(cliVersion, '>=2.0.0') || (await isPubECR(registry))) {
|
|
||||||
return execCLI([ecrCmd, 'get-login-password', '--region', region]).then(pwd => {
|
|
||||||
return [`docker login --username AWS --password ${pwd} ${registry}`];
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
return execCLI([
|
core.info(`AWS ECR detected with ${region} region`);
|
||||||
ecrCmd,
|
const ecr = new ECR({
|
||||||
'get-login',
|
customUserAgent: 'docker-login-action',
|
||||||
'--region',
|
credentials,
|
||||||
region,
|
region: region
|
||||||
'--registry-ids',
|
|
||||||
accountIDs.join(' '),
|
|
||||||
'--no-include-email'
|
|
||||||
]).then(dockerLoginCmds => {
|
|
||||||
return dockerLoginCmds.trim().split(`\n`);
|
|
||||||
});
|
});
|
||||||
|
const authTokenResponse = await ecr.getAuthorizationToken(authTokenRequest);
|
||||||
|
if (!Array.isArray(authTokenResponse.authorizationData) || !authTokenResponse.authorizationData.length) {
|
||||||
|
throw new Error('Could not retrieve an authorization token from AWS ECR');
|
||||||
|
}
|
||||||
|
const regDatas: RegistryData[] = [];
|
||||||
|
for (const authData of authTokenResponse.authorizationData) {
|
||||||
|
const authToken = Buffer.from(authData.authorizationToken || '', 'base64').toString('utf-8');
|
||||||
|
const creds = authToken.split(':', 2);
|
||||||
|
regDatas.push({
|
||||||
|
registry: authData.proxyEndpoint || '',
|
||||||
|
username: creds[0],
|
||||||
|
password: creds[1]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return regDatas;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -4,6 +4,7 @@ export interface Inputs {
|
|||||||
registry: string;
|
registry: string;
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
|
ecr: string;
|
||||||
logout: boolean;
|
logout: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -12,6 +13,7 @@ export function getInputs(): Inputs {
|
|||||||
registry: core.getInput('registry'),
|
registry: core.getInput('registry'),
|
||||||
username: core.getInput('username'),
|
username: core.getInput('username'),
|
||||||
password: core.getInput('password'),
|
password: core.getInput('password'),
|
||||||
|
ecr: core.getInput('ecr'),
|
||||||
logout: core.getBooleanInput('logout')
|
logout: core.getBooleanInput('logout')
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -2,8 +2,8 @@ import * as aws from './aws';
|
|||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as exec from '@actions/exec';
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
export async function login(registry: string, username: string, password: string): Promise<void> {
|
export async function login(registry: string, username: string, password: string, ecr: string): Promise<void> {
|
||||||
if (await aws.isECR(registry)) {
|
if (/true/i.test(ecr) || (ecr == 'auto' && aws.isECR(registry))) {
|
||||||
await loginECR(registry, username, password);
|
await loginECR(registry, username, password);
|
||||||
} else {
|
} else {
|
||||||
await loginStandard(registry, username, password);
|
await loginStandard(registry, username, password);
|
||||||
@@ -51,39 +51,21 @@ export async function loginStandard(registry: string, username: string, password
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function loginECR(registry: string, username: string, password: string): Promise<void> {
|
export async function loginECR(registry: string, username: string, password: string): Promise<void> {
|
||||||
const cliPath = await aws.getCLI();
|
core.info(`Retrieving registries data through AWS SDK...`);
|
||||||
const cliVersion = await aws.getCLIVersion();
|
const regDatas = await aws.getRegistriesData(registry, username, password);
|
||||||
const region = await aws.getRegion(registry);
|
for (const regData of regDatas) {
|
||||||
const accountIDs = await aws.getAccountIDs(registry);
|
core.info(`Logging into ${regData.registry}...`);
|
||||||
|
await exec
|
||||||
if (await aws.isPubECR(registry)) {
|
.getExecOutput('docker', ['login', '--password-stdin', '--username', regData.username, regData.registry], {
|
||||||
core.info(`AWS Public ECR detected with ${region} region`);
|
|
||||||
} else {
|
|
||||||
core.info(`AWS ECR detected with ${region} region`);
|
|
||||||
}
|
|
||||||
|
|
||||||
process.env.AWS_ACCESS_KEY_ID = username || process.env.AWS_ACCESS_KEY_ID;
|
|
||||||
process.env.AWS_SECRET_ACCESS_KEY = password || process.env.AWS_SECRET_ACCESS_KEY;
|
|
||||||
|
|
||||||
core.info(`Retrieving docker login command through AWS CLI ${cliVersion} (${cliPath})...`);
|
|
||||||
const loginCmds = await aws.getDockerLoginCmds(cliVersion, registry, region, accountIDs);
|
|
||||||
|
|
||||||
core.info(`Logging into ${registry}...`);
|
|
||||||
loginCmds.forEach((loginCmd, index) => {
|
|
||||||
exec
|
|
||||||
.getExecOutput(loginCmd, [], {
|
|
||||||
ignoreReturnCode: true,
|
ignoreReturnCode: true,
|
||||||
silent: true
|
silent: true,
|
||||||
|
input: Buffer.from(regData.password)
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||||
throw new Error(res.stderr.trim());
|
throw new Error(res.stderr.trim());
|
||||||
}
|
}
|
||||||
if (loginCmds.length > 1) {
|
core.info('Login Succeeded!');
|
||||||
core.info(`Login Succeeded! (${index}/${loginCmds.length})`);
|
|
||||||
} else {
|
|
||||||
core.info('Login Succeeded!');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,10 +5,10 @@ import * as stateHelper from './state-helper';
|
|||||||
|
|
||||||
export async function run(): Promise<void> {
|
export async function run(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const {registry, username, password, logout} = context.getInputs();
|
const input: context.Inputs = context.getInputs();
|
||||||
stateHelper.setRegistry(registry);
|
stateHelper.setRegistry(input.registry);
|
||||||
stateHelper.setLogout(logout);
|
stateHelper.setLogout(input.logout);
|
||||||
await docker.login(registry, username, password);
|
await docker.login(input.registry, input.username, input.password, input.ecr);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.setFailed(error.message);
|
core.setFailed(error.message);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user