Compare commits

..

134 Commits

Author SHA1 Message Date
CrazyMax
6af3c118c8 Merge pull request #152 from crazy-max/aws-sdk-proxy
handle proxy settings for aws-sdk
2022-02-17 11:30:34 +01:00
CrazyMax
caca3368ce handle proxy settings for aws-sdk
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2022-02-16 13:53:16 +01:00
CrazyMax
17f28ab24d Merge pull request #112 from dineshba/workload-identity-gcr-gar
Update readme with workload identity based authentication for GCR and GAR
2022-02-03 17:48:36 +01:00
Dinesh B
a875dd0e21 Update readme with workload identity based authentication for GCR and GAR
Signed-off-by: Dinesh B <dineshudt17@gmail.com>
Signed-off-by: Dinesh <dineshb@thoughtworks.com>
2022-02-03 20:57:42 +05:30
CrazyMax
7948fffc49 Merge pull request #49 from crazy-max/e2e-acr
Test login against ACR
2022-01-27 13:07:02 +01:00
CrazyMax
5fcefb941d Merge pull request #131 from docker/dependabot/npm_and_yarn/aws-sdk/client-ecr-public-3.45.0
Bump @aws-sdk/client-ecr-public from 3.43.0 to 3.45.0
2021-12-30 20:49:49 +01:00
CrazyMax
3bb2d084df Update generated content
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-12-30 20:43:44 +01:00
dependabot[bot]
242fb9a356 Bump @aws-sdk/client-ecr-public from 3.43.0 to 3.45.0
Bumps [@aws-sdk/client-ecr-public](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-ecr-public) from 3.43.0 to 3.45.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-ecr-public/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.45.0/clients/client-ecr-public)

---
updated-dependencies:
- dependency-name: "@aws-sdk/client-ecr-public"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-30 19:41:46 +00:00
CrazyMax
fa72313bc3 Merge pull request #132 from docker/dependabot/npm_and_yarn/aws-sdk/client-ecr-3.45.0
Bump @aws-sdk/client-ecr from 3.44.0 to 3.45.0
2021-12-30 20:39:56 +01:00
CrazyMax
088f62a4f2 Update generated content
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-12-30 19:35:40 +01:00
dependabot[bot]
7929ac7647 Bump @aws-sdk/client-ecr from 3.44.0 to 3.45.0
Bumps [@aws-sdk/client-ecr](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-ecr) from 3.44.0 to 3.45.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-ecr/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.45.0/clients/client-ecr)

---
updated-dependencies:
- dependency-name: "@aws-sdk/client-ecr"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-24 05:13:23 +00:00
CrazyMax
42d299face Merge pull request #130 from crazy-max/ci-workflow
Update ci workflow
2021-12-20 14:29:48 +01:00
CrazyMax
4858b0b5ea Update ci workflow
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-12-20 14:27:18 +01:00
CrazyMax
1d7d8649e7 Merge pull request #128 from Flydiverny/aws-sdk-v3
fix(ecr): only set credentials if username & password if specified, refactor to use aws-sdk v3
2021-12-20 14:25:33 +01:00
Markus Maga
58855695bb refactor: use v3 sdk
Signed-off-by: Markus Maga <markus@maga.se>
2021-12-20 13:46:08 +01:00
CrazyMax
d9927c4142 Merge pull request #123 from crazy-max/ecr-input
ecr input to specify whether the given registry is ECR
2021-12-20 11:05:56 +01:00
CrazyMax
b9a4d91ee5 ecr input to specify whether the given registry is ECR
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-12-20 10:59:20 +01:00
CrazyMax
b20b9f5e31 Merge pull request #126 from crazy-max/aws-sdk
ecr: switch implementation to use the AWS SDK
2021-12-20 10:51:10 +01:00
CrazyMax
cb21399f71 ci: test against windows runner
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-12-20 10:43:27 +01:00
CrazyMax
faae4d6665 ecr: switch implementation to use the AWS SDK
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-12-20 10:43:26 +01:00
CrazyMax
4d84a3c20f Merge pull request #127 from crazy-max/carry-124
Update instructions for Google registry
2021-12-19 22:47:40 +01:00
CrazyMax
6f7ca8828b Update instructions for Google registry
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-12-19 22:44:48 +01:00
CrazyMax
b776a64ec0 Merge pull request #114 from Flydiverny/fix-ec2-instance-credentials
fix(ecr): use ec2 instance credentials when no credentials are provided
2021-12-16 13:31:05 +01:00
Markus Maga
f6476db6e9 chore: update dist
Signed-off-by: Markus Maga <markus@maga.se>
2021-12-14 14:39:35 +01:00
Markus Maga
46ab6d5c3c fix(ecr): use ec2 instance credentials when no credentials are provided
Signed-off-by: Markus Maga <markus@maga.se>
2021-12-06 11:28:43 +01:00
CrazyMax
1cce1654e0 Merge pull request #111 from crazy-max/update-wrokflow
dev: update workflow
2021-11-16 21:47:03 +01:00
CrazyMax
9537342dee dev: update workflow
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-11-16 21:40:03 +01:00
CrazyMax
7f47463f56 Merge pull request #103 from docker/dependabot/npm_and_yarn/actions/core-1.6.0
Bump @actions/core from 1.5.0 to 1.6.0
2021-10-04 13:16:56 +02:00
CrazyMax
8807319764 Update generated content
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-10-04 13:14:44 +02:00
CrazyMax
ebac4bd30d Merge pull request #84 from crazy-max/depre-ubuntu-1604
Ubuntu 16.04 runner deprecated
2021-10-03 19:48:27 +02:00
dependabot[bot]
499663a42c Bump @actions/core from 1.5.0 to 1.6.0
Bumps [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) from 1.5.0 to 1.6.0.
- [Release notes](https://github.com/actions/toolkit/releases)
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/core/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/core)

---
updated-dependencies:
- dependency-name: "@actions/core"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-29 05:09:54 +00:00
CrazyMax
70b0f7898e Merge pull request #101 from docker/dependabot/npm_and_yarn/ansi-regex-5.0.1
Bump ansi-regex from 5.0.0 to 5.0.1
2021-09-24 14:53:27 +02:00
dependabot[bot]
885923496b Bump ansi-regex from 5.0.0 to 5.0.1
Bumps [ansi-regex](https://github.com/chalk/ansi-regex) from 5.0.0 to 5.0.1.
- [Release notes](https://github.com/chalk/ansi-regex/releases)
- [Commits](https://github.com/chalk/ansi-regex/compare/v5.0.0...v5.0.1)

---
updated-dependencies:
- dependency-name: ansi-regex
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-24 12:07:37 +00:00
CrazyMax
ab92432d0b Merge pull request #100 from docker/dependabot/npm_and_yarn/tmpl-1.0.5
Bump tmpl from 1.0.4 to 1.0.5
2021-09-24 14:07:10 +02:00
dependabot[bot]
1828bf2d51 Bump tmpl from 1.0.4 to 1.0.5
Bumps [tmpl](https://github.com/daaku/nodejs-tmpl) from 1.0.4 to 1.0.5.
- [Release notes](https://github.com/daaku/nodejs-tmpl/releases)
- [Commits](https://github.com/daaku/nodejs-tmpl/commits/v1.0.5)

---
updated-dependencies:
- dependency-name: tmpl
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-22 01:49:39 +00:00
CrazyMax
25c0ca8bab Merge pull request #99 from crazy-max/fix-dep-labels
Fix Dependabot labels
2021-09-03 13:19:27 +02:00
CrazyMax
f11d2ba650 Fix Dependabot labels
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-09-03 13:17:39 +02:00
CrazyMax
3f83d7b89c Merge pull request #94 from docker/dependabot/npm_and_yarn/actions/core-1.5.0
Bump @actions/core from 1.4.0 to 1.5.0
2021-08-20 10:36:40 +02:00
CrazyMax
c9c0083563 Update generated content
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-08-20 10:34:52 +02:00
dependabot[bot]
f694e84504 Bump @actions/core from 1.4.0 to 1.5.0
Bumps [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) from 1.4.0 to 1.5.0.
- [Release notes](https://github.com/actions/toolkit/releases)
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/core/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/core)

---
updated-dependencies:
- dependency-name: "@actions/core"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-20 05:10:32 +00:00
CrazyMax
b30d77254f Merge pull request #91 from cs278/patch-1
Add link to GitHub documentation
2021-08-10 11:53:58 +02:00
Chris Smith
95778bc566 Replace GIF with link to GitHub documentation
Signed-off-by: Chris Smith <chris.smith@widerplan.com>
2021-08-10 10:45:00 +01:00
CrazyMax
2c6df6a22f Merge pull request #88 from docker/dependabot/github_actions/codecov/codecov-action-2.0.1
Bump codecov/codecov-action from 1 to 2.0.1
2021-07-23 12:57:07 +02:00
CrazyMax
c41c9a5c65 Use major
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-07-23 12:55:26 +02:00
CrazyMax
fc6fe565d2 Merge pull request #89 from crazy-max/update-deps
Use official images
2021-07-20 10:36:07 +02:00
CrazyMax
10428f39dc Use official images
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-07-20 10:27:09 +02:00
dependabot[bot]
1b4cf55146 Bump codecov/codecov-action from 1 to 2.0.1
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 1 to 2.0.1.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/master/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v1...v2.0.1)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-20 05:09:16 +00:00
CrazyMax
5bcefc987c Merge pull request #86 from crazy-max/ghrc-readme
Small changes for GHCR doc
2021-07-06 20:33:57 +02:00
CrazyMax
169057673d Small changes for GHCR doc
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-07-06 20:32:11 +02:00
CrazyMax
5d62c58fc3 Merge pull request #85 from crazy-max/dev-deps
Update dev deps
2021-07-06 20:26:29 +02:00
CrazyMax
73cda5dad9 Update dev deps
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-07-06 20:24:15 +02:00
CrazyMax
5ffec3343b Merge pull request #83 from docker/dependabot/npm_and_yarn/hosted-git-info-2.8.9
Bump hosted-git-info from 2.8.8 to 2.8.9
2021-06-23 14:08:18 +02:00
CrazyMax
305d960cac Merge pull request #82 from docker/dependabot/npm_and_yarn/node-notifier-8.0.2
Bump node-notifier from 8.0.0 to 8.0.2
2021-06-23 14:08:05 +02:00
CrazyMax
9a9ae26c89 Merge pull request #81 from docker/dependabot/npm_and_yarn/ws-7.5.0
Bump ws from 7.3.1 to 7.5.0
2021-06-23 14:07:50 +02:00
CrazyMax
48af9f2a97 Merge pull request #80 from docker/dependabot/npm_and_yarn/lodash-4.17.21
Bump lodash from 4.17.20 to 4.17.21
2021-06-23 14:07:37 +02:00
CrazyMax
c08e3a84a9 Merge pull request #79 from docker/dependabot/npm_and_yarn/y18n-4.0.3
Bump y18n from 4.0.0 to 4.0.3
2021-06-23 14:07:23 +02:00
CrazyMax
f12fe5c78d Ubuntu 16.04 runner deprecated
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-06-23 14:05:59 +02:00
dependabot[bot]
b566635cc9 Bump hosted-git-info from 2.8.8 to 2.8.9
Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.8.8 to 2.8.9.
- [Release notes](https://github.com/npm/hosted-git-info/releases)
- [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md)
- [Commits](https://github.com/npm/hosted-git-info/compare/v2.8.8...v2.8.9)

---
updated-dependencies:
- dependency-name: hosted-git-info
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-23 12:04:15 +00:00
dependabot[bot]
b8e54a5ea5 Bump node-notifier from 8.0.0 to 8.0.2
Bumps [node-notifier](https://github.com/mikaelbr/node-notifier) from 8.0.0 to 8.0.2.
- [Release notes](https://github.com/mikaelbr/node-notifier/releases)
- [Changelog](https://github.com/mikaelbr/node-notifier/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mikaelbr/node-notifier/compare/v8.0.0...v8.0.2)

---
updated-dependencies:
- dependency-name: node-notifier
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-23 12:04:11 +00:00
dependabot[bot]
d64238b93b Bump ws from 7.3.1 to 7.5.0
Bumps [ws](https://github.com/websockets/ws) from 7.3.1 to 7.5.0.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.3.1...7.5.0)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-23 12:03:59 +00:00
dependabot[bot]
763661a124 Bump lodash from 4.17.20 to 4.17.21
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.20 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.20...4.17.21)

---
updated-dependencies:
- dependency-name: lodash
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-23 12:03:56 +00:00
dependabot[bot]
41fba5a8c6 Bump y18n from 4.0.0 to 4.0.3
Bumps [y18n](https://github.com/yargs/y18n) from 4.0.0 to 4.0.3.
- [Release notes](https://github.com/yargs/y18n/releases)
- [Changelog](https://github.com/yargs/y18n/blob/y18n-v4.0.3/CHANGELOG.md)
- [Commits](https://github.com/yargs/y18n/compare/v4.0.0...y18n-v4.0.3)

---
updated-dependencies:
- dependency-name: y18n
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-23 12:03:51 +00:00
CrazyMax
f054a8b539 Merge pull request #78 from crazy-max/remove-github-pkg
Remove GitHub Packages Docker Registry
2021-06-22 12:40:38 +02:00
CrazyMax
0644d98afe Remove GitHub Packages Docker Registry
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-06-22 11:25:58 +02:00
CrazyMax
9e433e18cf Merge pull request #77 from crazy-max/exec-output
Use built-in `getExecOutput`
2021-06-22 11:18:22 +02:00
CrazyMax
39efbd2c12 Use built-in getExecOutput
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-06-22 11:09:31 +02:00
CrazyMax
4608add020 Merge pull request #76 from crazy-max/bool-input
Use `core.getBooleanInput`
2021-06-22 10:43:05 +02:00
CrazyMax
4fd5d8ead6 Use core.getBooleanInput
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-06-22 10:40:00 +02:00
CrazyMax
e2346b6971 Merge pull request #73 from docker/dependabot/npm_and_yarn/actions/exec-1.1.0
Bump @actions/exec from 1.0.4 to 1.1.0
2021-06-22 10:01:44 +02:00
CrazyMax
2051808c83 Update generated content
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-06-22 10:00:24 +02:00
dependabot[bot]
7c220e1b8d Bump @actions/exec from 1.0.4 to 1.1.0
Bumps [@actions/exec](https://github.com/actions/toolkit/tree/HEAD/packages/exec) from 1.0.4 to 1.1.0.
- [Release notes](https://github.com/actions/toolkit/releases)
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/exec/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/@actions/core@1.1.0/packages/exec)

---
updated-dependencies:
- dependency-name: "@actions/exec"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-22 07:57:42 +00:00
CrazyMax
f4cae19820 Merge pull request #75 from docker/dependabot/npm_and_yarn/actions/io-1.1.1
Bump @actions/io from 1.1.0 to 1.1.1
2021-06-22 09:54:39 +02:00
CrazyMax
e5ad366574 Update generated content
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-06-22 09:52:14 +02:00
dependabot[bot]
45bc0ebd6b Bump @actions/io from 1.1.0 to 1.1.1
Bumps [@actions/io](https://github.com/actions/toolkit/tree/HEAD/packages/io) from 1.1.0 to 1.1.1.
- [Release notes](https://github.com/actions/toolkit/releases)
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/io/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/@actions/tool-cache@1.1.1/packages/io)

---
updated-dependencies:
- dependency-name: "@actions/io"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-22 07:51:48 +00:00
CrazyMax
79068f5240 Merge pull request #74 from docker/dependabot/npm_and_yarn/actions/core-1.4.0
Bump @actions/core from 1.3.0 to 1.4.0
2021-06-22 09:49:46 +02:00
CrazyMax
8e670da7a1 Update generated content
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-06-22 09:47:22 +02:00
dependabot[bot]
76901a9025 Bump @actions/core from 1.3.0 to 1.4.0
Bumps [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) from 1.3.0 to 1.4.0.
- [Release notes](https://github.com/actions/toolkit/releases)
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/core/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/core)

---
updated-dependencies:
- dependency-name: "@actions/core"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-08 06:56:06 +00:00
CrazyMax
31f1bb4610 Merge pull request #70 from docker/dependabot/npm_and_yarn/actions/core-1.3.0
Bump @actions/core from 1.2.6 to 1.3.0
2021-05-25 01:10:03 +02:00
CrazyMax
28eb30dcb6 Update generated content
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-05-25 01:08:08 +02:00
dependabot[bot]
03b00fbeba Bump @actions/core from 1.2.6 to 1.3.0
Bumps [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) from 1.2.6 to 1.3.0.
- [Release notes](https://github.com/actions/toolkit/releases)
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/core/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/core)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-24 23:02:08 +00:00
CrazyMax
5934fe3407 Merge pull request #71 from docker/dependabot/npm_and_yarn/actions/io-1.1.0
Bump @actions/io from 1.0.2 to 1.1.0
2021-05-25 00:59:47 +02:00
CrazyMax
3cba154eb7 Update generated content
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-05-25 00:48:47 +02:00
dependabot[bot]
986a54f35b Bump @actions/io from 1.0.2 to 1.1.0
Bumps [@actions/io](https://github.com/actions/toolkit/tree/HEAD/packages/io) from 1.0.2 to 1.1.0.
- [Release notes](https://github.com/actions/toolkit/releases)
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/io/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/@actions/core@1.1.0/packages/io)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-24 22:47:36 +00:00
CrazyMax
fdb725ed4b Merge pull request #69 from docker/dependabot/npm_and_yarn/semver-7.3.5
Bump semver from 7.3.2 to 7.3.5
2021-05-25 00:45:34 +02:00
CrazyMax
bab7dcbf29 Update generated content
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-05-25 00:44:03 +02:00
dependabot[bot]
c0d23108f7 Bump semver from 7.3.2 to 7.3.5
Bumps [semver](https://github.com/npm/node-semver) from 7.3.2 to 7.3.5.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/master/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v7.3.2...v7.3.5)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-24 22:38:59 +00:00
CrazyMax
c902ecc709 Merge pull request #68 from crazy-max/dependabot-config
Update dependabot config
2021-05-25 00:37:20 +02:00
CrazyMax
b612a76a31 Update dependabot config
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-05-25 00:33:43 +02:00
CrazyMax
28218f9b04 Merge pull request #66 from crazy-max/remove-os-limitation
Remove os limitation
2021-04-28 00:38:38 +02:00
CrazyMax
7439f8b467 Remove os limitation
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-04-28 00:34:32 +02:00
CrazyMax
4b206288bd Merge pull request #61 from crazy-max/workflow
Enhance workflow
2021-03-31 18:49:11 +02:00
CrazyMax
4abf7e9de3 Enhance workflow
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-03-31 18:34:49 +02:00
CrazyMax
175e20ba61 Merge pull request #60 from syscll/docs-quay-io
Add Quay.io usage docs
2021-03-31 09:37:40 +02:00
Dan Bond
92a2593650 Update TOC 2021-03-26 14:58:30 -07:00
Dan Bond
957a8f0d4a README: add quay.io usage docs 2021-03-26 11:37:33 -07:00
CrazyMax
971b76aea9 Merge pull request #59 from crazy-max/ghcr-github-token
Use GITHUB_TOKEN with GHCR
2021-03-25 00:14:10 +01:00
CrazyMax
5b092cf2f7 Use GITHUB_TOKEN with GHCR
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-03-24 23:24:06 +01:00
CrazyMax
ab81ae06bb Merge pull request #58 from crazy-max/cleanup
Remove label workflow
2021-03-18 20:09:00 +01:00
CrazyMax
f4a3bbc2c6 Remove label workflow
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-03-18 20:07:30 +01:00
CrazyMax
e2302b10cc Merge pull request #55 from crazy-max/ghcr-doc
Improve GHCR doc
2021-02-16 13:30:19 +01:00
CrazyMax
c2c723b5d1 Improve GHCR doc
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2021-02-16 13:28:22 +01:00
CrazyMax
ab80d026d4 Merge pull request #48 from crazy-max/e2e-gar
Test login against GAR
2020-12-22 17:34:18 +01:00
CrazyMax
9376d24995 Test login against ACR
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-22 11:30:57 +01:00
CrazyMax
13fa0663e1 Test login against GAR
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-22 11:27:40 +01:00
CrazyMax
75e7be0db4 Merge pull request #42 from crazy-max/login-test-3
Test login against GCR
2020-12-22 11:12:35 +01:00
CrazyMax
d6f5c68835 Test login against GCR
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-22 11:11:31 +01:00
CrazyMax
f3364599c6 Merge pull request #40 from crazy-max/registry-ids
Handle Amazon ECR registries associated with other accounts
2020-12-18 07:41:31 +01:00
CrazyMax
24646ef465 Get AccountID from registry URL and handle ECR registry through regexp
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-17 20:22:02 +01:00
CrazyMax
9f189206e8 Merge pull request #44 from crazy-max/update-readme
Fix ci badge in README
2020-12-17 12:04:43 +01:00
CrazyMax
aed1d0c0c1 Fix ci badge in README
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-17 12:04:18 +01:00
CrazyMax
31722002f5 Merge pull request #43 from crazy-max/no-region-public-ecr
Keep default region for public ECR
2020-12-17 11:41:28 +01:00
CrazyMax
2a481b4109 Keep default region for public ECR
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-17 11:39:52 +01:00
CrazyMax
9bed62818a Merge pull request #27 from crazy-max/login-test-2
Test login against registries pt.2
2020-12-17 11:28:39 +01:00
CrazyMax
c718c795e7 Update for public ECR
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-17 11:06:21 +01:00
CrazyMax
7b79d7e834 Merge pull request #41 from crazy-max/fix-public-ecr
Fix public ECR login with AWS CLI v1
2020-12-17 07:52:03 +01:00
CrazyMax
f53ca527f7 Fix public ECR login with AWS CLI v1
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-17 07:49:50 +01:00
CrazyMax
d3160f671f Handle Amazon ECR registries associated with other accounts
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-16 21:53:24 +01:00
Chad Metcalf
3b14bab101 Merge pull request #37 from crazy-max/public-ecr
Add support for public ECR
2020-12-11 00:48:46 -08:00
CrazyMax
1e75de0e0e Add support for public ECR
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-11 07:15:35 +01:00
CrazyMax
7c9afe235c Merge pull request #35 from crazy-max/dind
Add example with DinD
2020-12-11 06:34:43 +01:00
CrazyMax
7dc3c3a70e Add example with DinD
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-08 19:12:44 +01:00
CrazyMax
b17cf6ab8f Merge branch 'master' into login-test-2 2020-11-18 18:49:20 +01:00
CrazyMax
27c3146301 Test login against registries part 2
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-11-18 18:47:53 +01:00
CrazyMax
12fd63324c Merge pull request #31 from crazy-max/master
Use major version of actions
2020-11-18 18:42:59 +01:00
CrazyMax
a3de3de177 Use major version of actions
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-11-18 18:41:33 +01:00
CrazyMax
9cbd4f95c4 Merge pull request #28 from pgressa/ocir
Extend documentation by OCI OCIR
2020-11-10 17:38:01 +01:00
Pavol Gressa
ad9eb3b250 Extend documentation by OCI OCIR 2020-11-10 17:24:49 +01:00
CrazyMax
71b3c789fa Merge pull request #23 from crazy-max/login-test
Test login against registries pt.1
2020-11-10 10:05:20 +01:00
CrazyMax
5e0bc83b38 Test login against registries
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-11-10 10:02:42 +01:00
CrazyMax
1f68ce02d7 Add workflow_dispatch event
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-10-28 17:03:42 +01:00
CrazyMax
767b2f4b7b Merge branch 'master' into login-test 2020-10-28 15:31:07 +01:00
Tõnis Tiigi
ddf06e1fed Merge pull request #22 from crazy-max/gar-example
Add example for Google Artifact Registry
2020-10-23 10:56:23 -07:00
CrazyMax
a5aa81adc8 Test login against registries
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-10-23 18:09:56 +02:00
CrazyMax
3b9e1f51cd Add example for Google Artifact Registry
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-10-23 16:30:05 +02:00
32 changed files with 87880 additions and 4931 deletions

2
.dockerignore Normal file
View File

@@ -0,0 +1,2 @@
/coverage
/node_modules

View File

@@ -2,20 +2,24 @@
Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great.
Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE). Contributions to this project are [released](https://docs.github.com/en/github/site-policy/github-terms-of-service#6-contributions-under-repository-license)
to the public under the [project's open source license](LICENSE).
## Submitting a pull request ## Submitting a pull request
1. [Fork](https://github.com/docker/login-action/fork) and clone the repository 1. [Fork](https://github.com/docker/login-action/fork) and clone the repository
2. Configure and install the dependencies: `yarn install` 2. Configure and install the dependencies: `yarn install`
4. Create a new branch: `git checkout -b my-branch-name` 3. Create a new branch: `git checkout -b my-branch-name`
5. Make your change 4. Make your changes
6. Run pre-checkin: `yarn run pre-checkin` 5. Make sure the tests pass: `docker buildx bake test`
7. Push to your fork and [submit a pull request](https://github.com/docker/login-action/compare) 6. Format code and build javascript artifacts: `docker buildx bake pre-checkin`
8. Pat your self on the back and wait for your pull request to be reviewed and merged. 7. Validate all code has correctly formatted and built: `docker buildx bake validate`
8. Push to your fork and [submit a pull request](https://github.com/docker/login-action/compare)
9. Pat your self on the back and wait for your pull request to be reviewed and merged.
Here are a few things you can do that will increase the likelihood of your pull request being accepted: Here are a few things you can do that will increase the likelihood of your pull request being accepted:
- Write tests.
- Make sure the `README.md` and any other relevant **documentation are kept up-to-date**. - Make sure the `README.md` and any other relevant **documentation are kept up-to-date**.
- We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option. - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option.
- Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as **separate pull requests**. - Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as **separate pull requests**.
@@ -24,5 +28,5 @@ Here are a few things you can do that will increase the likelihood of your pull
## Resources ## Resources
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) - [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/) - [Using Pull Requests](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests)
- [GitHub Help](https://help.github.com) - [GitHub Help](https://docs.github.com/en)

View File

@@ -30,4 +30,5 @@ about: Create a report to help us improve
### Logs ### Logs
> Download the [log file of your build](https://help.github.com/en/actions/configuring-and-managing-workflows/managing-a-workflow-run#downloading-logs) and [attach it](https://help.github.com/en/github/managing-your-work-on-github/file-attachments-on-issues-and-pull-requests) to this issue. > Download the [log file of your build](https://docs.github.com/en/actions/managing-workflow-runs/using-workflow-run-logs#downloading-logs)
> and [attach it](https://docs.github.com/en/github/managing-your-work-on-github/file-attachments-on-issues-and-pull-requests) to this issue.

View File

@@ -4,19 +4,15 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: "daily" interval: "daily"
time: "06:00"
timezone: "Europe/Paris"
labels: labels:
- ":game_die: dependencies" - "dependencies"
- ":robot: bot" - "bot"
- package-ecosystem: "npm" - package-ecosystem: "npm"
directory: "/" directory: "/"
schedule: schedule:
interval: "daily" interval: "daily"
time: "06:00"
timezone: "Europe/Paris"
allow: allow:
- dependency-type: "production" - dependency-type: "production"
labels: labels:
- ":game_die: dependencies" - "dependencies"
- ":robot: bot" - "bot"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

77
.github/labels.yml vendored
View File

@@ -1,77 +0,0 @@
## more info https://github.com/crazy-max/ghaction-github-labeler
- # automerge
name: ":bell: automerge"
color: "8f4fbc"
description: ""
- # bot
name: ":robot: bot"
color: "69cde9"
description: ""
- # bug
name: ":bug: bug"
color: "b60205"
description: ""
- # dependencies
name: ":game_die: dependencies"
color: "0366d6"
description: ""
- # documentation
name: ":memo: documentation"
color: "c5def5"
description: ""
- # duplicate
name: ":busts_in_silhouette: duplicate"
color: "cccccc"
description: ""
- # enhancement
name: ":sparkles: enhancement"
color: "0054ca"
description: ""
- # feature request
name: ":bulb: feature request"
color: "0e8a16"
description: ""
- # feedback
name: ":mega: feedback"
color: "03a9f4"
description: ""
- # future maybe
name: ":rocket: future maybe"
color: "fef2c0"
description: ""
- # good first issue
name: ":hatching_chick: good first issue"
color: "7057ff"
description: ""
- # help wanted
name: ":pray: help wanted"
color: "4caf50"
description: ""
- # hold
name: ":hand: hold"
color: "24292f"
description: ""
- # invalid
name: ":no_entry_sign: invalid"
color: "e6e6e6"
description: ""
- # maybe bug
name: ":interrobang: maybe bug"
color: "ff5722"
description: ""
- # needs more info
name: ":thinking: needs more info"
color: "795548"
description: ""
- # question
name: ":question: question"
color: "3f51b5"
description: ""
- # upstream
name: ":eyes: upstream"
color: "fbca04"
description: ""
- # wontfix
name: ":coffin: wontfix"
color: "ffffff"
description: ""

View File

@@ -1,150 +1,282 @@
name: ci name: ci
on: on:
workflow_dispatch:
schedule:
- cron: '0 10 * * *'
push: push:
branches: branches:
- master - 'master'
- releases/v* - 'releases/v*'
jobs: jobs:
# dockerhub: stop-docker:
# runs-on: ${{ matrix.os }} runs-on: ubuntu-latest
# strategy: steps:
# fail-fast: false -
# matrix: name: Checkout
# os: uses: actions/checkout@v2
# - ubuntu-20.04 -
# - ubuntu-18.04 name: Stop docker
# - ubuntu-16.04 run: |
# logout: sudo systemctl stop docker
# - true -
# - false name: Login to GitHub Container Registry
# steps: uses: ./
# - with:
# name: Checkout registry: ghcr.io
# uses: actions/checkout@v2.3.2 username: ${{ github.actor }}
# - password: ${{ secrets.GITHUB_TOKEN }}
# name: Login to DockerHub
# uses: ./
# with:
# username: ${{ secrets.DOCKERHUB_USERNAME_TEST }}
# password: ${{ secrets.DOCKERHUB_PASSWORD_TEST }}
# logout: ${{ matrix.logout }}
# -
# name: Clear
# if: always()
# run: |
# rm -f ${HOME}/.docker/config.json
gpr: logout:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
logout: logout:
- true
- false - false
- true
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v2.3.2 uses: actions/checkout@v2
- -
name: Login to GitHub Package Registry name: Login to GitHub Container Registry
uses: ./ uses: ./
with: with:
registry: docker.pkg.github.com registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
logout: ${{ matrix.logout }} logout: ${{ matrix.logout }}
-
name: Clear
if: always()
run: |
rm -f ${HOME}/.docker/config.json
# gitlab: dind:
# runs-on: ubuntu-latest runs-on: ubuntu-latest
# strategy: env:
# fail-fast: false DOCKER_CONFIG: $HOME/.docker
# matrix: steps:
# logout: -
# - true name: Checkout
# - false uses: actions/checkout@v2
# steps: -
# - name: Login to GitHub Container Registry
# name: Checkout uses: ./
# uses: actions/checkout@v2.3.2 with:
# - registry: ghcr.io
# name: Login to GitLab username: ${{ secrets.GHCR_USERNAME }}
# uses: ./ password: ${{ secrets.GHCR_PAT }}
# with: -
# registry: registry.gitlab.com name: DinD
# username: ${{ secrets.GITLAB_USERNAME_TEST }} uses: docker://docker
# password: ${{ secrets.GITLAB_PASSWORD_TEST }} with:
# logout: ${{ matrix.logout }} entrypoint: docker
# - args: pull ghcr.io/docker-ghactiontest/test
# name: Clear -
# if: always() name: Pull private image
# run: | run: |
# rm -f ${HOME}/.docker/config.json docker image prune -a -f >/dev/null 2>&1
# docker pull ghcr.io/docker-ghactiontest/test
# ecr:
# runs-on: ${{ matrix.os }} acr:
# strategy: runs-on: ubuntu-latest
# fail-fast: false steps:
# matrix: -
# os: name: Checkout
# - ubuntu-20.04 uses: actions/checkout@v2
# - ubuntu-18.04 -
# - ubuntu-16.04 name: Login to ACR
# logout: uses: ./
# - true with:
# - false registry: ${{ secrets.AZURE_REGISTRY_NAME }}.azurecr.io
# steps: username: ${{ secrets.AZURE_CLIENT_ID }}
# - password: ${{ secrets.AZURE_CLIENT_SECRET }}
# name: Checkout
# uses: actions/checkout@v2.3.1 dockerhub:
# - runs-on: ${{ matrix.os }}
# name: Login to ECR strategy:
# uses: ./ fail-fast: false
# with: matrix:
# registry: ${{ secrets.AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.AWS_REGION }}.amazonaws.com os:
# username: ${{ secrets.AWS_ACCESS_KEY_ID }} - ubuntu-latest
# password: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - windows-latest
# logout: ${{ matrix.logout }} steps:
# - -
# name: Clear name: Checkout
# if: always() uses: actions/checkout@v2
# run: | -
# rm -f ${HOME}/.docker/config.json name: Login to Docker Hub
# uses: ./
# ecr-aws-creds: with:
# runs-on: ${{ matrix.os }} username: ${{ secrets.DOCKERHUB_USERNAME }}
# strategy: password: ${{ secrets.DOCKERHUB_TOKEN }}
# fail-fast: false
# matrix: ecr:
# os: runs-on: ${{ matrix.os }}
# - ubuntu-20.04 strategy:
# - ubuntu-18.04 fail-fast: false
# - ubuntu-16.04 matrix:
# steps: os:
# - - ubuntu-latest
# name: Checkout - windows-latest
# uses: actions/checkout@v2.3.1 steps:
# - -
# name: Configure AWS Credentials name: Checkout
# uses: aws-actions/configure-aws-credentials@v1 uses: actions/checkout@v2
# with: -
# aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} name: Login to ECR
# aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} uses: ./
# aws-region: ${{ secrets.AWS_REGION }} with:
# - registry: ${{ secrets.AWS_ACCOUNT_NUMBER }}.dkr.ecr.us-east-1.amazonaws.com
# name: Login to ECR username: ${{ secrets.AWS_ACCESS_KEY_ID }}
# uses: ./ password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
# with:
# registry: ${{ secrets.AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.AWS_REGION }}.amazonaws.com ecr-aws-creds:
# - runs-on: ${{ matrix.os }}
# name: Clear strategy:
# if: always() fail-fast: false
# run: | matrix:
# rm -f ${HOME}/.docker/config.json 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: ${{ secrets.AWS_ACCOUNT_NUMBER }}.dkr.ecr.us-east-1.amazonaws.com
ecr-public:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Login to Public ECR
uses: ./
with:
registry: public.ecr.aws
username: ${{ secrets.AWS_ACCESS_KEY_ID }}
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:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Login to GitHub Container Registry
uses: ./
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
gitlab:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Login to GitLab
uses: ./
with:
registry: registry.gitlab.com
username: ${{ secrets.GITLAB_USERNAME }}
password: ${{ secrets.GITLAB_TOKEN }}
google-artifact:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Login to Google Artifact Registry
uses: ./
with:
registry: ${{ secrets.GAR_LOCATION }}-docker.pkg.dev
username: _json_key
password: ${{ secrets.GAR_JSON_KEY }}
google-container:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Login to Google Container Registry
uses: ./
with:
registry: gcr.io
username: _json_key
password: ${{ secrets.GCR_JSON_KEY }}

View File

@@ -1,20 +0,0 @@
name: labels
on:
push:
branches:
- 'master'
paths:
- '.github/labels.yml'
- '.github/workflows/labels.yml'
jobs:
labeler:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2.3.2
-
name: Run Labeler
uses: crazy-max/ghaction-github-labeler@v3.0.0

View File

@@ -3,38 +3,32 @@ name: test
on: on:
push: push:
branches: branches:
- master - 'master'
- releases/v* - 'releases/v*'
paths-ignore:
- '**.md'
pull_request: pull_request:
paths-ignore: branches:
- '**.md' - 'master'
- 'releases/v*'
jobs: jobs:
test: test:
runs-on: ${{ matrix.os }} runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
os:
- ubuntu-20.04
- ubuntu-18.04
- ubuntu-16.04
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v2.3.2 uses: actions/checkout@v2
- -
name: Install name: Validate
run: yarn install uses: docker/bake-action@v1
with:
targets: validate
- -
name: Test name: Test
run: yarn run test uses: docker/bake-action@v1
with:
targets: test
- -
name: Upload coverage name: Upload coverage
uses: codecov/codecov-action@v1.0.13 uses: codecov/codecov-action@v2
if: success()
with: with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage/clover.xml file: ./coverage/clover.xml

View File

@@ -1,5 +1,5 @@
{ {
"printWidth": 120, "printWidth": 240,
"tabWidth": 2, "tabWidth": 2,
"useTabs": false, "useTabs": false,
"semi": true, "semi": true,

324
README.md
View File

@@ -1,6 +1,6 @@
[![GitHub release](https://img.shields.io/github/release/docker/login-action.svg?style=flat-square)](https://github.com/docker/login-action/releases/latest) [![GitHub release](https://img.shields.io/github/release/docker/login-action.svg?style=flat-square)](https://github.com/docker/login-action/releases/latest)
[![GitHub marketplace](https://img.shields.io/badge/marketplace-docker--login-blue?logo=github&style=flat-square)](https://github.com/marketplace/actions/docker-login) [![GitHub marketplace](https://img.shields.io/badge/marketplace-docker--login-blue?logo=github&style=flat-square)](https://github.com/marketplace/actions/docker-login)
[![CI workflow](https://img.shields.io/github/workflow/status/docker/login-action/test?label=ci&logo=github&style=flat-square)](https://github.com/docker/login-action/actions?workflow=ci) [![CI workflow](https://img.shields.io/github/workflow/status/docker/login-action/ci?label=ci&logo=github&style=flat-square)](https://github.com/docker/login-action/actions?workflow=ci)
[![Test workflow](https://img.shields.io/github/workflow/status/docker/login-action/test?label=test&logo=github&style=flat-square)](https://github.com/docker/login-action/actions?workflow=test) [![Test workflow](https://img.shields.io/github/workflow/status/docker/login-action/test?label=test&logo=github&style=flat-square)](https://github.com/docker/login-action/actions?workflow=test)
[![Codecov](https://img.shields.io/codecov/c/github/docker/login-action?logo=codecov&style=flat-square)](https://codecov.io/gh/docker/login-action) [![Codecov](https://img.shields.io/codecov/c/github/docker/login-action?logo=codecov&style=flat-square)](https://codecov.io/gh/docker/login-action)
@@ -8,33 +8,30 @@
GitHub Action to login against a Docker registry. GitHub Action to login against a Docker registry.
> :bulb: See also:
> * [setup-buildx](https://github.com/docker/setup-buildx-action) action
> * [setup-qemu](https://github.com/docker/setup-qemu-action) action
> * [build-push](https://github.com/docker/build-push-action) action
![Screenshot](.github/docker-login.png) ![Screenshot](.github/docker-login.png)
___ ___
* [Usage](#usage) * [Usage](#usage)
* [DockerHub](#dockerhub) * [Docker Hub](#docker-hub)
* [GitHub Packages Docker Registry](#github-packages-docker-registry)
* [GitHub Container Registry](#github-container-registry) * [GitHub Container Registry](#github-container-registry)
* [GitLab](#gitlab) * [GitLab](#gitlab)
* [Azure Container Registry (ACR)](#azure-container-registry-acr) * [Azure Container Registry (ACR)](#azure-container-registry-acr)
* [Google Container Registry (GCR)](#google-container-registry-gcr) * [Google Container Registry (GCR)](#google-container-registry-gcr)
* [Google Artifact Registry (GAR)](#google-artifact-registry-gar)
* [AWS Elastic Container Registry (ECR)](#aws-elastic-container-registry-ecr) * [AWS Elastic Container Registry (ECR)](#aws-elastic-container-registry-ecr)
* [AWS Public Elastic Container Registry (ECR)](#aws-public-elastic-container-registry-ecr)
* [OCI Oracle Cloud Infrastructure Registry (OCIR)](#oci-oracle-cloud-infrastructure-registry-ocir)
* [Quay.io](#quayio)
* [Customizing](#customizing) * [Customizing](#customizing)
* [inputs](#inputs) * [inputs](#inputs)
* [Keep up-to-date with GitHub Dependabot](#keep-up-to-date-with-github-dependabot) * [Keep up-to-date with GitHub Dependabot](#keep-up-to-date-with-github-dependabot)
* [Limitation](#limitation)
## Usage ## Usage
### DockerHub ### Docker Hub
To authenticate against [DockerHub](https://hub.docker.com) it's strongly recommended to create a To authenticate against [Docker Hub](https://hub.docker.com) it's strongly recommended to create a
[personal access token](https://docs.docker.com/docker-hub/access-tokens/) as an alternative to your password. [personal access token](https://docs.docker.com/docker-hub/access-tokens/) as an alternative to your password.
```yaml ```yaml
@@ -42,60 +39,32 @@ name: ci
on: on:
push: push:
branches: master branches: main
jobs: jobs:
login: login:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- -
name: Login to DockerHub name: Login to Docker Hub
uses: docker/login-action@v1 uses: docker/login-action@v1
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
``` ```
### GitHub Packages Docker Registry
> :warning: GitHub Packages Docker Registry (aka `docker.pkg.github.com`) **is deprecated** and will sunset early next
> year. It's strongly advised to [migrate to GitHub Container Registry](https://docs.github.com/en/packages/getting-started-with-github-container-registry/migrating-to-github-container-registry-for-docker-images)
> instead.
You can configure the Docker client to use [GitHub Packages to publish and retrieve docker images](https://docs.github.com/en/packages/using-github-packages-with-your-projects-ecosystem/configuring-docker-for-use-with-github-packages).
```yaml
name: ci
on:
push:
branches: master
jobs:
login:
runs-on: ubuntu-latest
steps:
-
name: Login to GitHub Packages Docker Registry
uses: docker/login-action@v1
with:
registry: docker.pkg.github.com
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
```
### GitHub Container Registry ### GitHub Container Registry
To authenticate against 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 will need to create a new [personal access token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) use the [`GITHUB_TOKEN`](https://docs.github.com/en/actions/reference/authentication-in-a-workflow) for the best
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). security and experience.
```yaml ```yaml
name: ci name: ci
on: on:
push: push:
branches: master branches: main
jobs: jobs:
login: login:
@@ -106,10 +75,16 @@ 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.CR_PAT }} password: ${{ secrets.GITHUB_TOKEN }}
``` ```
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)
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).
### GitLab ### GitLab
```yaml ```yaml
@@ -117,7 +92,7 @@ name: ci
on: on:
push: push:
branches: master branches: main
jobs: jobs:
login: login:
@@ -143,7 +118,7 @@ name: ci
on: on:
push: push:
branches: master branches: main
jobs: jobs:
login: login:
@@ -162,17 +137,62 @@ jobs:
### Google Container Registry (GCR) ### Google Container Registry (GCR)
Use a service account with the ability to push to GCR and [configure access control](https://cloud.google.com/container-registry/docs/access-control). > [Google Artifact Registry](#google-artifact-registry-gar) is the evolution of Google Container Registry. As a
Then create and download the JSON key for this service account and save content of `.json` file > fully-managed service with support for both container images and non-container artifacts. If you currently use
[as a secret](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets-for-a-repository) > Google Container Registry, use the information [on this page](https://cloud.google.com/artifact-registry/docs/transition/transition-from-gcr)
called `GCR_JSON_KEY` in your GitHub repo. Ensure you set the username to `_json_key`. > 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 ```yaml
name: ci name: ci
on: on:
push: push:
branches: master 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).
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)
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
name: ci
on:
push:
branches: main
jobs: jobs:
login: login:
@@ -187,9 +207,81 @@ jobs:
password: ${{ secrets.GCR_JSON_KEY }} password: ${{ secrets.GCR_JSON_KEY }}
``` ```
### 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).
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)
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
name: ci
on:
push:
branches: main
jobs:
login:
runs-on: ubuntu-latest
steps:
-
name: Login to GAR
uses: docker/login-action@v1
with:
registry: <location>-docker.pkg.dev
username: _json_key
password: ${{ secrets.GAR_JSON_KEY }}
```
> 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.
### AWS Elastic Container Registry (ECR) ### AWS Elastic Container Registry (ECR)
Use an IAM user with the [ability to push to ECR](https://docs.aws.amazon.com/AmazonECR/latest/userguide/ecr_managed_policies.html). Use an IAM user with the ability to [push to ECR with `AmazonEC2ContainerRegistryPowerUser` managed policy for example](https://docs.aws.amazon.com/AmazonECR/latest/userguide/ecr_managed_policies.html#AmazonEC2ContainerRegistryPowerUser).
Then create and download access keys and save `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` [as secrets](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets-for-a-repository) Then create and download access keys and save `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` [as secrets](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets-for-a-repository)
in your GitHub repo. in your GitHub repo.
@@ -198,7 +290,7 @@ name: ci
on: on:
push: push:
branches: master branches: main
jobs: jobs:
login: login:
@@ -213,6 +305,33 @@ jobs:
password: ${{ secrets.AWS_SECRET_ACCESS_KEY }} password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
``` ```
If you need to log in to Amazon ECR registries associated with other accounts, you can use the `AWS_ACCOUNT_IDS`
environment variable:
```yaml
name: ci
on:
push:
branches: main
jobs:
login:
runs-on: ubuntu-latest
steps:
-
name: Login to ECR
uses: docker/login-action@v1
with:
registry: <aws-account-number>.dkr.ecr.<region>.amazonaws.com
username: ${{ secrets.AWS_ACCESS_KEY_ID }}
password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
env:
AWS_ACCOUNT_IDS: 012345678910,023456789012
```
> Only available with [AWS CLI version 1](https://docs.aws.amazon.com/cli/latest/reference/ecr/get-login.html)
You can also use the [Configure AWS Credentials](https://github.com/aws-actions/configure-aws-credentials) action in You can also use the [Configure AWS Credentials](https://github.com/aws-actions/configure-aws-credentials) action in
combination with this action: combination with this action:
@@ -221,7 +340,7 @@ name: ci
on: on:
push: push:
branches: master branches: main
jobs: jobs:
login: login:
@@ -243,6 +362,92 @@ jobs:
> Replace `<aws-account-number>` and `<region>` with their respective values. > Replace `<aws-account-number>` and `<region>` with their respective values.
### AWS Public Elastic Container Registry (ECR)
Use an IAM user with the ability to [push to ECR Public with `AmazonElasticContainerRegistryPublicPowerUser` managed policy for example](https://docs.aws.amazon.com/AmazonECR/latest/public/public-ecr-managed-policies.html#AmazonElasticContainerRegistryPublicPowerUser).
Then create and download access keys and save `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` [as secrets](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets-for-a-repository)
in your GitHub repo.
```yaml
name: ci
on:
push:
branches: main
jobs:
login:
runs-on: ubuntu-latest
steps:
-
name: Login to Public ECR
uses: docker/login-action@v1
with:
registry: public.ecr.aws
username: ${{ secrets.AWS_ACCESS_KEY_ID }}
password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
env:
AWS_REGION: <region>
```
> Replace `<region>` with its respective value (default `us-east-1`).
### OCI Oracle Cloud Infrastructure Registry (OCIR)
To push into OCIR in specific tenancy the [username](https://www.oracle.com/webfolder/technetwork/tutorials/obe/oci/registry/index.html#LogintoOracleCloudInfrastructureRegistryfromtheDockerCLI)
must be placed in format `<tenancy>/<username>` (in case of federated tenancy use the format
`<tenancy-namespace>/oracleidentitycloudservice/<username>`).
For password [create an auth token](https://www.oracle.com/webfolder/technetwork/tutorials/obe/oci/registry/index.html#GetanAuthToken).
Save username and token [as a secrets](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets-for-a-repository)
in your GitHub repo.
```yaml
name: ci
on:
push:
branches: main
jobs:
login:
runs-on: ubuntu-latest
steps:
-
name: Login to OCIR
uses: docker/login-action@v1
with:
registry: <region>.ocir.io
username: ${{ secrets.OCI_USERNAME }}
password: ${{ secrets.OCI_TOKEN }}
```
> Replace `<region>` with their respective values from [availability regions](https://docs.cloud.oracle.com/iaas/Content/Registry/Concepts/registryprerequisites.htm#Availab)
### Quay.io
Use a [Robot account](https://docs.quay.io/glossary/robot-accounts.html) with the ability to push to a public/private Quay.io repository.
```yaml
name: ci
on:
push:
branches: main
jobs:
login:
runs-on: ubuntu-latest
steps:
-
name: Login to Quay.io
uses: docker/login-action@v1
with:
registry: quay.io
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_ROBOT_TOKEN }}
```
## Customizing ## Customizing
### inputs ### inputs
@@ -254,6 +459,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
@@ -271,7 +477,3 @@ updates:
schedule: schedule:
interval: "daily" interval: "daily"
``` ```
## Limitation
This action is only available for Linux [virtual environments](https://help.github.com/en/articles/virtual-environments-for-github-actions#supported-virtual-environments-and-hardware-resources).

View File

@@ -1,54 +1,155 @@
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', () => {
test.each([ test.each([
['registry.gitlab.com', false], ['registry.gitlab.com', false],
['gcr.io', false], ['gcr.io', false],
['012345678901.dkr.ecr.eu-west-3.amazonaws.com', true] ['012345678901.dkr.ecr.eu-west-3.amazonaws.com', true],
['876820548815.dkr.ecr.cn-north-1.amazonaws.com.cn', true],
['390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn', 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);
}); });
}); });
describe('getCLI', () => { describe('isPubECR', () => {
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([ 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'], ['registry.gitlab.com', false],
['v2', 'aws-cli/2.0.41 Python/3.7.3 Linux/4.19.104-microsoft-standard exe/x86_64.ubuntu.18', '2.0.41'] ['gcr.io', false],
])('given aws %p', async (version, stdout, expected) => { ['012345678901.dkr.ecr.eu-west-3.amazonaws.com', false],
expect(await aws.parseCLIVersion(stdout)).toEqual(expected); ['876820548815.dkr.ecr.cn-north-1.amazonaws.com.cn', false],
['390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn', false],
['public.ecr.aws', true]
])('given registry %p', async (registry, expected) => {
expect(aws.isPubECR(registry)).toEqual(expected);
}); });
}); });
describe('getRegion', () => { describe('getRegion', () => {
test.each([['012345678901.dkr.ecr.eu-west-3.amazonaws.com', 'eu-west-3']])( test.each([
'given registry %p', ['012345678901.dkr.ecr.eu-west-3.amazonaws.com', 'eu-west-3'],
async (registry, expected) => { ['876820548815.dkr.ecr.cn-north-1.amazonaws.com.cn', 'cn-north-1'],
expect(await aws.getRegion(registry)).toEqual(expected); ['390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn', 'cn-northwest-1'],
} ['public.ecr.aws', 'us-east-1']
); ])('given registry %p', async (registry, expected) => {
expect(aws.getRegion(registry)).toEqual(expected);
});
});
describe('getAccountIDs', () => {
test.each([
['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,012345678910,023456789012', ['012345678901', '012345678910', '023456789012']],
['390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn', '012345678910,023456789012', ['390948362332', '012345678910', '023456789012']],
['public.ecr.aws', undefined, []]
])('given registry %p', async (registry, accountIDsEnv, expected) => {
if (accountIDsEnv) {
process.env.AWS_ACCOUNT_IDS = accountIDsEnv;
}
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);
});
}); });

View File

@@ -1,10 +1,9 @@
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 () => {
process.env['INPUT_USERNAME'] = 'dbowie'; process.env['INPUT_USERNAME'] = 'dbowie';
process.env['INPUT_PASSWORD'] = 'groundcontrol'; process.env['INPUT_PASSWORD'] = 'groundcontrol';
process.env['INPUT_LOGOUT'] = 'true';
expect(() => { expect(() => {
getInputs(); getInputs();
}).not.toThrowError(); }).not.toThrowError();

View File

@@ -7,9 +7,14 @@ 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, 'exec'); const execSpy: jest.SpyInstance = jest.spyOn(exec, 'getExecOutput');
// don't let exec try to actually run the commands execSpy.mockImplementation(() =>
execSpy.mockImplementation(() => {}); Promise.resolve({
exitCode: expect.any(Number),
stdout: expect.any(Function),
stderr: expect.any(Function)
})
);
const username: string = 'dbowie'; const username: string = 'dbowie';
const password: string = 'groundcontrol'; const password: string = 'groundcontrol';
@@ -20,30 +25,25 @@ test('loginStandard calls exec', async () => {
expect(execSpy).toHaveBeenCalledWith(`docker`, ['login', '--password-stdin', '--username', username, registry], { expect(execSpy).toHaveBeenCalledWith(`docker`, ['login', '--password-stdin', '--username', username, registry], {
input: Buffer.from(password), input: Buffer.from(password),
silent: true, silent: true,
ignoreReturnCode: true, ignoreReturnCode: true
listeners: expect.objectContaining({
stdout: expect.any(Function),
stderr: expect.any(Function)
})
}); });
}); });
test('logout calls exec', async () => { test('logout calls exec', async () => {
const execSpy: jest.SpyInstance = jest.spyOn(exec, 'exec'); const execSpy: jest.SpyInstance = jest.spyOn(exec, 'getExecOutput');
// don't let exec try to actually run the commands execSpy.mockImplementation(() =>
execSpy.mockImplementation(() => {}); Promise.resolve({
exitCode: expect.any(Number),
stdout: expect.any(Function),
stderr: expect.any(Function)
})
);
const registry: string = 'https://ghcr.io'; const registry: string = 'https://ghcr.io';
await logout(registry); await logout(registry);
expect(execSpy).toHaveBeenCalledWith(`docker`, ['logout', registry], { expect(execSpy).toHaveBeenCalledWith(`docker`, ['logout', registry], {
silent: false, ignoreReturnCode: true
ignoreReturnCode: true,
input: Buffer.from(''),
listeners: expect.objectContaining({
stdout: expect.any(Function),
stderr: expect.any(Function)
})
}); });
}); });

View File

@@ -6,21 +6,12 @@ import * as stateHelper from '../src/state-helper';
import * as core from '@actions/core'; import * as core from '@actions/core';
test('errors when not run on linux platform', async () => {
const platSpy = jest.spyOn(osm, 'platform');
platSpy.mockImplementation(() => 'netbsd');
const coreSpy: jest.SpyInstance = jest.spyOn(core, 'setFailed');
await run();
expect(coreSpy).toHaveBeenCalledWith('Only supported on linux platform');
});
test('errors without username and password', async () => { test('errors without username and password', async () => {
const platSpy = jest.spyOn(osm, 'platform'); const platSpy = jest.spyOn(osm, 'platform');
platSpy.mockImplementation(() => 'linux'); platSpy.mockImplementation(() => 'linux');
process.env['INPUT_LOGOUT'] = 'true'; // default value
const coreSpy: jest.SpyInstance = jest.spyOn(core, 'setFailed'); const coreSpy: jest.SpyInstance = jest.spyOn(core, 'setFailed');
await run(); await run();
@@ -43,11 +34,17 @@ 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;
process.env['INPUT_LOGOUT'] = String(logout);
await run(); await run();
expect(setRegistrySpy).toHaveBeenCalledWith(''); expect(setRegistrySpy).toHaveBeenCalledWith('');
expect(setLogoutSpy).toHaveBeenCalledWith(''); 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 () => {
@@ -68,12 +65,15 @@ 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 logout: string = 'true'; const ecr: string = 'auto';
process.env['INPUT_LOGOUT'] = logout; process.env['INPUT_ECR'] = ecr;
const logout: boolean = true;
process.env['INPUT_LOGOUT'] = String(logout);
await run(); await run();
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);
}); });

View File

@@ -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
View File

@@ -0,0 +1,3 @@
comment: false
github_checks:
annotations: false

984
dist/bridge.js generated vendored Normal file
View File

@@ -0,0 +1,984 @@
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ 989:
/***/ ((__unused_webpack_module, exports) => {
/**
* __ ___ ____ _ _ ___ _ _ ____
* \ \ / / \ | _ \| \ | |_ _| \ | |/ ___|
* \ \ /\ / / _ \ | |_) | \| || || \| | | _
* \ V V / ___ \| _ <| |\ || || |\ | |_| |
* \_/\_/_/ \_\_| \_\_| \_|___|_| \_|\____|
*
* This file is critical for vm2. It implements the bridge between the host and the sandbox.
* If you do not know exactly what you are doing, you should NOT edit this file.
*
* The file is loaded in the host and sandbox to handle objects in both directions.
* This is done to ensure that RangeErrors are from the correct context.
* The boundary between the sandbox and host might throw RangeErrors from both contexts.
* Therefore, thisFromOther and friends can handle objects from both domains.
*
* Method parameters have comments to tell from which context they came.
*
*/
const globalsList = [
'Number',
'String',
'Boolean',
'Date',
'RegExp',
'Map',
'WeakMap',
'Set',
'WeakSet',
'Promise',
'Function'
];
const errorsList = [
'RangeError',
'ReferenceError',
'SyntaxError',
'TypeError',
'EvalError',
'URIError',
'Error'
];
const OPNA = 'Operation not allowed on contextified object.';
const thisGlobalPrototypes = {
__proto__: null,
Object: Object.prototype,
Array: Array.prototype
};
for (let i = 0; i < globalsList.length; i++) {
const key = globalsList[i];
const g = global[key];
if (g) thisGlobalPrototypes[key] = g.prototype;
}
for (let i = 0; i < errorsList.length; i++) {
const key = errorsList[i];
const g = global[key];
if (g) thisGlobalPrototypes[key] = g.prototype;
}
const {
getPrototypeOf: thisReflectGetPrototypeOf,
setPrototypeOf: thisReflectSetPrototypeOf,
defineProperty: thisReflectDefineProperty,
deleteProperty: thisReflectDeleteProperty,
getOwnPropertyDescriptor: thisReflectGetOwnPropertyDescriptor,
isExtensible: thisReflectIsExtensible,
preventExtensions: thisReflectPreventExtensions,
apply: thisReflectApply,
construct: thisReflectConstruct,
set: thisReflectSet,
get: thisReflectGet,
has: thisReflectHas,
ownKeys: thisReflectOwnKeys,
enumerate: thisReflectEnumerate,
} = Reflect;
const thisObject = Object;
const {
freeze: thisObjectFreeze,
prototype: thisObjectPrototype
} = thisObject;
const thisObjectHasOwnProperty = thisObjectPrototype.hasOwnProperty;
const ThisProxy = Proxy;
const ThisWeakMap = WeakMap;
const {
get: thisWeakMapGet,
set: thisWeakMapSet
} = ThisWeakMap.prototype;
const ThisMap = Map;
const thisMapGet = ThisMap.prototype.get;
const thisMapSet = ThisMap.prototype.set;
const thisFunction = Function;
const thisFunctionBind = thisFunction.prototype.bind;
const thisArrayIsArray = Array.isArray;
const thisErrorCaptureStackTrace = Error.captureStackTrace;
const thisSymbolToString = Symbol.prototype.toString;
const thisSymbolToStringTag = Symbol.toStringTag;
/**
* VMError.
*
* @public
* @extends {Error}
*/
class VMError extends Error {
/**
* Create VMError instance.
*
* @public
* @param {string} message - Error message.
* @param {string} code - Error code.
*/
constructor(message, code) {
super(message);
this.name = 'VMError';
this.code = code;
thisErrorCaptureStackTrace(this, this.constructor);
}
}
thisGlobalPrototypes['VMError'] = VMError.prototype;
function thisUnexpected() {
return new VMError('Unexpected');
}
if (!thisReflectSetPrototypeOf(exports, null)) throw thisUnexpected();
function thisSafeGetOwnPropertyDescriptor(obj, key) {
const desc = thisReflectGetOwnPropertyDescriptor(obj, key);
if (!desc) return desc;
if (!thisReflectSetPrototypeOf(desc, null)) throw thisUnexpected();
return desc;
}
function thisThrowCallerCalleeArgumentsAccess(key) {
'use strict';
thisThrowCallerCalleeArgumentsAccess[key];
return thisUnexpected();
}
function thisIdMapping(factory, other) {
return other;
}
const thisThrowOnKeyAccessHandler = thisObjectFreeze({
__proto__: null,
get(target, key, receiver) {
if (typeof key === 'symbol') {
key = thisReflectApply(thisSymbolToString, key, []);
}
throw new VMError(`Unexpected access to key '${key}'`);
}
});
const emptyForzenObject = thisObjectFreeze({
__proto__: null
});
const thisThrowOnKeyAccess = new ThisProxy(emptyForzenObject, thisThrowOnKeyAccessHandler);
function SafeBase() {}
if (!thisReflectDefineProperty(SafeBase, 'prototype', {
__proto__: null,
value: thisThrowOnKeyAccess
})) throw thisUnexpected();
function SHARED_FUNCTION() {}
const TEST_PROXY_HANDLER = thisObjectFreeze({
__proto__: thisThrowOnKeyAccess,
construct() {
return this;
}
});
function thisIsConstructor(obj) {
// Note: obj@any(unsafe)
const Func = new ThisProxy(obj, TEST_PROXY_HANDLER);
try {
// eslint-disable-next-line no-new
new Func();
return true;
} catch (e) {
return false;
}
}
function thisCreateTargetObject(obj, proto) {
// Note: obj@any(unsafe) proto@any(unsafe) returns@this(unsafe) throws@this(unsafe)
let base;
if (typeof obj === 'function') {
if (thisIsConstructor(obj)) {
// Bind the function since bound functions do not have a prototype property.
base = thisReflectApply(thisFunctionBind, SHARED_FUNCTION, [null]);
} else {
base = () => {};
}
} else if (thisArrayIsArray(obj)) {
base = [];
} else {
return {__proto__: proto};
}
if (!thisReflectSetPrototypeOf(base, proto)) throw thisUnexpected();
return base;
}
function createBridge(otherInit, registerProxy) {
const mappingOtherToThis = new ThisWeakMap();
const protoMappings = new ThisMap();
const protoName = new ThisMap();
function thisAddProtoMapping(proto, other, name) {
// Note: proto@this(unsafe) other@other(unsafe) name@this(unsafe) throws@this(unsafe)
thisReflectApply(thisMapSet, protoMappings, [proto, thisIdMapping]);
thisReflectApply(thisMapSet, protoMappings, [other,
(factory, object) => thisProxyOther(factory, object, proto)]);
if (name) thisReflectApply(thisMapSet, protoName, [proto, name]);
}
function thisAddProtoMappingFactory(protoFactory, other, name) {
// Note: protoFactory@this(unsafe) other@other(unsafe) name@this(unsafe) throws@this(unsafe)
let proto;
thisReflectApply(thisMapSet, protoMappings, [other,
(factory, object) => {
if (!proto) {
proto = protoFactory();
thisReflectApply(thisMapSet, protoMappings, [proto, thisIdMapping]);
if (name) thisReflectApply(thisMapSet, protoName, [proto, name]);
}
return thisProxyOther(factory, object, proto);
}]);
}
const result = {
__proto__: null,
globalPrototypes: thisGlobalPrototypes,
safeGetOwnPropertyDescriptor: thisSafeGetOwnPropertyDescriptor,
fromArguments: thisFromOtherArguments,
from: thisFromOther,
fromWithFactory: thisFromOtherWithFactory,
ensureThis: thisEnsureThis,
mapping: mappingOtherToThis,
connect: thisConnect,
reflectSet: thisReflectSet,
reflectGet: thisReflectGet,
reflectDefineProperty: thisReflectDefineProperty,
reflectDeleteProperty: thisReflectDeleteProperty,
reflectApply: thisReflectApply,
reflectConstruct: thisReflectConstruct,
reflectHas: thisReflectHas,
reflectOwnKeys: thisReflectOwnKeys,
reflectEnumerate: thisReflectEnumerate,
reflectGetPrototypeOf: thisReflectGetPrototypeOf,
reflectIsExtensible: thisReflectIsExtensible,
reflectPreventExtensions: thisReflectPreventExtensions,
objectHasOwnProperty: thisObjectHasOwnProperty,
weakMapSet: thisWeakMapSet,
addProtoMapping: thisAddProtoMapping,
addProtoMappingFactory: thisAddProtoMappingFactory,
defaultFactory,
protectedFactory,
readonlyFactory,
VMError
};
const isHost = typeof otherInit !== 'object';
if (isHost) {
otherInit = otherInit(result, registerProxy);
}
result.other = otherInit;
const {
globalPrototypes: otherGlobalPrototypes,
safeGetOwnPropertyDescriptor: otherSafeGetOwnPropertyDescriptor,
fromArguments: otherFromThisArguments,
from: otherFromThis,
mapping: mappingThisToOther,
reflectSet: otherReflectSet,
reflectGet: otherReflectGet,
reflectDefineProperty: otherReflectDefineProperty,
reflectDeleteProperty: otherReflectDeleteProperty,
reflectApply: otherReflectApply,
reflectConstruct: otherReflectConstruct,
reflectHas: otherReflectHas,
reflectOwnKeys: otherReflectOwnKeys,
reflectEnumerate: otherReflectEnumerate,
reflectGetPrototypeOf: otherReflectGetPrototypeOf,
reflectIsExtensible: otherReflectIsExtensible,
reflectPreventExtensions: otherReflectPreventExtensions,
objectHasOwnProperty: otherObjectHasOwnProperty,
weakMapSet: otherWeakMapSet
} = otherInit;
function thisOtherHasOwnProperty(object, key) {
// Note: object@other(safe) key@prim throws@this(unsafe)
try {
return otherReflectApply(otherObjectHasOwnProperty, object, [key]) === true;
} catch (e) { // @other(unsafe)
throw thisFromOther(e);
}
}
function thisDefaultGet(handler, object, key, desc) {
// Note: object@other(unsafe) key@prim desc@other(safe)
let ret; // @other(unsafe)
if (desc.get || desc.set) {
const getter = desc.get;
if (!getter) return undefined;
try {
ret = otherReflectApply(getter, object, [key]);
} catch (e) {
throw thisFromOther(e);
}
} else {
ret = desc.value;
}
return handler.fromOtherWithContext(ret);
}
function otherFromThisIfAvailable(to, from, key) {
// Note: to@other(safe) from@this(safe) key@prim throws@this(unsafe)
if (!thisReflectApply(thisObjectHasOwnProperty, from, [key])) return false;
try {
to[key] = otherFromThis(from[key]);
} catch (e) { // @other(unsafe)
throw thisFromOther(e);
}
return true;
}
class BaseHandler extends SafeBase {
constructor(object) {
// Note: object@other(unsafe) throws@this(unsafe)
super();
this.object = object;
}
getFactory() {
return defaultFactory;
}
fromOtherWithContext(other) {
// Note: other@other(unsafe) throws@this(unsafe)
return thisFromOtherWithFactory(this.getFactory(), other);
}
doPreventExtensions(target, object, factory) {
// Note: target@this(unsafe) object@other(unsafe) throws@this(unsafe)
let keys; // @other(safe-array-of-prim)
try {
keys = otherReflectOwnKeys(object);
} catch (e) { // @other(unsafe)
throw thisFromOther(e);
}
for (let i = 0; i < keys.length; i++) {
const key = keys[i]; // @prim
let desc;
try {
desc = otherSafeGetOwnPropertyDescriptor(object, key);
} catch (e) { // @other(unsafe)
throw thisFromOther(e);
}
if (!desc) continue;
if (!desc.configurable) {
const current = thisSafeGetOwnPropertyDescriptor(target, key);
if (current && !current.configurable) continue;
if (desc.get || desc.set) {
desc.get = this.fromOtherWithContext(desc.get);
desc.set = this.fromOtherWithContext(desc.set);
} else if (typeof object === 'function' && (key === 'caller' || key === 'callee' || key === 'arguments')) {
desc.value = null;
} else {
desc.value = this.fromOtherWithContext(desc.value);
}
} else {
if (desc.get || desc.set) {
desc = {
__proto__: null,
configurable: true,
enumerable: desc.enumerable,
writable: true,
value: null
};
} else {
desc.value = null;
}
}
if (!thisReflectDefineProperty(target, key, desc)) throw thisUnexpected();
}
if (!thisReflectPreventExtensions(target)) throw thisUnexpected();
}
get(target, key, receiver) {
// Note: target@this(unsafe) key@prim receiver@this(unsafe) throws@this(unsafe)
const object = this.object; // @other(unsafe)
switch (key) {
case 'constructor': {
const desc = otherSafeGetOwnPropertyDescriptor(object, key);
if (desc) return thisDefaultGet(this, object, key, desc);
const proto = thisReflectGetPrototypeOf(target);
return proto === null ? undefined : proto.constructor;
}
case '__proto__': {
const desc = otherSafeGetOwnPropertyDescriptor(object, key);
if (desc) return thisDefaultGet(this, object, key, desc);
return thisReflectGetPrototypeOf(target);
}
case thisSymbolToStringTag:
if (!thisOtherHasOwnProperty(object, thisSymbolToStringTag)) {
const proto = thisReflectGetPrototypeOf(target);
const name = thisReflectApply(thisMapGet, protoName, [proto]);
if (name) return name;
}
break;
case 'arguments':
case 'caller':
case 'callee':
if (thisOtherHasOwnProperty(object, key)) throw thisThrowCallerCalleeArgumentsAccess(key);
break;
}
let ret; // @other(unsafe)
try {
ret = otherReflectGet(object, key);
} catch (e) { // @other(unsafe)
throw thisFromOther(e);
}
return this.fromOtherWithContext(ret);
}
set(target, key, value, receiver) {
// Note: target@this(unsafe) key@prim value@this(unsafe) receiver@this(unsafe) throws@this(unsafe)
const object = this.object; // @other(unsafe)
if (key === '__proto__' && !thisOtherHasOwnProperty(object, key)) {
return this.setPrototypeOf(target, value);
}
try {
value = otherFromThis(value);
return otherReflectSet(object, key, value) === true;
} catch (e) { // @other(unsafe)
throw thisFromOther(e);
}
}
getPrototypeOf(target) {
// Note: target@this(unsafe)
return thisReflectGetPrototypeOf(target);
}
setPrototypeOf(target, value) {
// Note: target@this(unsafe) throws@this(unsafe)
throw new VMError(OPNA);
}
apply(target, context, args) {
// Note: target@this(unsafe) context@this(unsafe) args@this(safe-array) throws@this(unsafe)
const object = this.object; // @other(unsafe)
let ret; // @other(unsafe)
try {
context = otherFromThis(context);
args = otherFromThisArguments(args);
ret = otherReflectApply(object, context, args);
} catch (e) { // @other(unsafe)
throw thisFromOther(e);
}
return thisFromOther(ret);
}
construct(target, args, newTarget) {
// Note: target@this(unsafe) args@this(safe-array) newTarget@this(unsafe) throws@this(unsafe)
const object = this.object; // @other(unsafe)
let ret; // @other(unsafe)
try {
args = otherFromThisArguments(args);
ret = otherReflectConstruct(object, args);
} catch (e) { // @other(unsafe)
throw thisFromOther(e);
}
return thisFromOtherWithFactory(this.getFactory(), ret, thisFromOther(object));
}
getOwnPropertyDescriptorDesc(target, prop, desc) {
// Note: target@this(unsafe) prop@prim desc@other{safe} throws@this(unsafe)
const object = this.object; // @other(unsafe)
if (desc && typeof object === 'function' && (prop === 'arguments' || prop === 'caller' || prop === 'callee')) desc.value = null;
return desc;
}
getOwnPropertyDescriptor(target, prop) {
// Note: target@this(unsafe) prop@prim throws@this(unsafe)
const object = this.object; // @other(unsafe)
let desc; // @other(safe)
try {
desc = otherSafeGetOwnPropertyDescriptor(object, prop);
} catch (e) { // @other(unsafe)
throw thisFromOther(e);
}
desc = this.getOwnPropertyDescriptorDesc(target, prop, desc);
if (!desc) return undefined;
let thisDesc;
if (desc.get || desc.set) {
thisDesc = {
__proto__: null,
get: this.fromOtherWithContext(desc.get),
set: this.fromOtherWithContext(desc.set),
enumerable: desc.enumerable === true,
configurable: desc.configurable === true
};
} else {
thisDesc = {
__proto__: null,
value: this.fromOtherWithContext(desc.value),
writable: desc.writable === true,
enumerable: desc.enumerable === true,
configurable: desc.configurable === true
};
}
if (!thisDesc.configurable) {
const oldDesc = thisSafeGetOwnPropertyDescriptor(target, prop);
if (!oldDesc || oldDesc.configurable || oldDesc.writable !== thisDesc.writable) {
if (!thisReflectDefineProperty(target, prop, thisDesc)) throw thisUnexpected();
}
}
return thisDesc;
}
definePropertyDesc(target, prop, desc) {
// Note: target@this(unsafe) prop@prim desc@this(safe) throws@this(unsafe)
return desc;
}
defineProperty(target, prop, desc) {
// Note: target@this(unsafe) prop@prim desc@this(unsafe) throws@this(unsafe)
const object = this.object; // @other(unsafe)
if (!thisReflectSetPrototypeOf(desc, null)) throw thisUnexpected();
desc = this.definePropertyDesc(target, prop, desc);
if (!desc) return false;
let otherDesc = {__proto__: null};
let hasFunc = true;
let hasValue = true;
let hasBasic = true;
hasFunc &= otherFromThisIfAvailable(otherDesc, desc, 'get');
hasFunc &= otherFromThisIfAvailable(otherDesc, desc, 'set');
hasValue &= otherFromThisIfAvailable(otherDesc, desc, 'value');
hasValue &= otherFromThisIfAvailable(otherDesc, desc, 'writable');
hasBasic &= otherFromThisIfAvailable(otherDesc, desc, 'enumerable');
hasBasic &= otherFromThisIfAvailable(otherDesc, desc, 'configurable');
try {
if (!otherReflectDefineProperty(object, prop, otherDesc)) return false;
if (otherDesc.configurable !== true && (!hasBasic || !(hasFunc || hasValue))) {
otherDesc = otherSafeGetOwnPropertyDescriptor(object, prop);
}
} catch (e) { // @other(unsafe)
throw thisFromOther(e);
}
if (!otherDesc.configurable) {
let thisDesc;
if (otherDesc.get || otherDesc.set) {
thisDesc = {
__proto__: null,
get: this.fromOtherWithContext(otherDesc.get),
set: this.fromOtherWithContext(otherDesc.set),
enumerable: otherDesc.enumerable,
configurable: otherDesc.configurable
};
} else {
thisDesc = {
__proto__: null,
value: this.fromOtherWithContext(otherDesc.value),
writable: otherDesc.writable,
enumerable: otherDesc.enumerable,
configurable: otherDesc.configurable
};
}
if (!thisReflectDefineProperty(target, prop, thisDesc)) throw thisUnexpected();
}
return true;
}
deleteProperty(target, prop) {
// Note: target@this(unsafe) prop@prim throws@this(unsafe)
const object = this.object; // @other(unsafe)
try {
return otherReflectDeleteProperty(object, prop) === true;
} catch (e) { // @other(unsafe)
throw thisFromOther(e);
}
}
has(target, key) {
// Note: target@this(unsafe) key@prim throws@this(unsafe)
const object = this.object; // @other(unsafe)
try {
return otherReflectHas(object, key) === true;
} catch (e) { // @other(unsafe)
throw thisFromOther(e);
}
}
isExtensible(target) {
// Note: target@this(unsafe) throws@this(unsafe)
const object = this.object; // @other(unsafe)
try {
if (otherReflectIsExtensible(object)) return true;
} catch (e) { // @other(unsafe)
throw thisFromOther(e);
}
if (thisReflectIsExtensible(target)) {
this.doPreventExtensions(target, object, this);
}
return false;
}
ownKeys(target) {
// Note: target@this(unsafe) throws@this(unsafe)
const object = this.object; // @other(unsafe)
let res; // @other(unsafe)
try {
res = otherReflectOwnKeys(object);
} catch (e) { // @other(unsafe)
throw thisFromOther(e);
}
return thisFromOther(res);
}
preventExtensions(target) {
// Note: target@this(unsafe) throws@this(unsafe)
const object = this.object; // @other(unsafe)
try {
if (!otherReflectPreventExtensions(object)) return false;
} catch (e) { // @other(unsafe)
throw thisFromOther(e);
}
if (thisReflectIsExtensible(target)) {
this.doPreventExtensions(target, object, this);
}
return true;
}
enumerate(target) {
// Note: target@this(unsafe) throws@this(unsafe)
const object = this.object; // @other(unsafe)
let res; // @other(unsafe)
try {
res = otherReflectEnumerate(object);
} catch (e) { // @other(unsafe)
throw thisFromOther(e);
}
return this.fromOtherWithContext(res);
}
}
function defaultFactory(object) {
// Note: other@other(unsafe) returns@this(unsafe) throws@this(unsafe)
return new BaseHandler(object);
}
class ProtectedHandler extends BaseHandler {
getFactory() {
return protectedFactory;
}
set(target, key, value, receiver) {
// Note: target@this(unsafe) key@prim value@this(unsafe) receiver@this(unsafe) throws@this(unsafe)
if (typeof value === 'function') {
return thisReflectDefineProperty(receiver, key, {
__proto__: null,
value: value,
writable: true,
enumerable: true,
configurable: true
}) === true;
}
return super.set(target, key, value, receiver);
}
definePropertyDesc(target, prop, desc) {
// Note: target@this(unsafe) prop@prim desc@this(safe) throws@this(unsafe)
if (desc && (desc.set || desc.get || typeof desc.value === 'function')) return undefined;
return desc;
}
}
function protectedFactory(object) {
// Note: other@other(unsafe) returns@this(unsafe) throws@this(unsafe)
return new ProtectedHandler(object);
}
class ReadOnlyHandler extends BaseHandler {
getFactory() {
return readonlyFactory;
}
set(target, key, value, receiver) {
// Note: target@this(unsafe) key@prim value@this(unsafe) receiver@this(unsafe) throws@this(unsafe)
return thisReflectDefineProperty(receiver, key, {
__proto__: null,
value: value,
writable: true,
enumerable: true,
configurable: true
});
}
setPrototypeOf(target, value) {
// Note: target@this(unsafe) throws@this(unsafe)
return false;
}
defineProperty(target, prop, desc) {
// Note: target@this(unsafe) prop@prim desc@this(unsafe) throws@this(unsafe)
return false;
}
deleteProperty(target, prop) {
// Note: target@this(unsafe) prop@prim throws@this(unsafe)
return false;
}
isExtensible(target) {
// Note: target@this(unsafe) throws@this(unsafe)
return false;
}
preventExtensions(target) {
// Note: target@this(unsafe) throws@this(unsafe)
return false;
}
}
function readonlyFactory(object) {
// Note: other@other(unsafe) returns@this(unsafe) throws@this(unsafe)
return new ReadOnlyHandler(object);
}
class ReadOnlyMockHandler extends ReadOnlyHandler {
constructor(object, mock) {
// Note: object@other(unsafe) mock:this(unsafe) throws@this(unsafe)
super(object);
this.mock = mock;
}
get(target, key, receiver) {
// Note: target@this(unsafe) key@prim receiver@this(unsafe) throws@this(unsafe)
const object = this.object; // @other(unsafe)
const mock = this.mock;
if (thisReflectApply(thisObjectHasOwnProperty, mock, key) && !thisOtherHasOwnProperty(object, key)) {
return mock[key];
}
return super.get(target, key, receiver);
}
}
function thisFromOther(other) {
// Note: other@other(unsafe) returns@this(unsafe) throws@this(unsafe)
return thisFromOtherWithFactory(defaultFactory, other);
}
function thisProxyOther(factory, other, proto) {
const target = thisCreateTargetObject(other, proto);
const handler = factory(other);
const proxy = new ThisProxy(target, handler);
try {
otherReflectApply(otherWeakMapSet, mappingThisToOther, [proxy, other]);
registerProxy(proxy, handler);
} catch (e) {
throw new VMError('Unexpected error');
}
if (!isHost) {
thisReflectApply(thisWeakMapSet, mappingOtherToThis, [other, proxy]);
return proxy;
}
const proxy2 = new ThisProxy(proxy, emptyForzenObject);
try {
otherReflectApply(otherWeakMapSet, mappingThisToOther, [proxy2, other]);
registerProxy(proxy2, handler);
} catch (e) {
throw new VMError('Unexpected error');
}
thisReflectApply(thisWeakMapSet, mappingOtherToThis, [other, proxy2]);
return proxy2;
}
function thisEnsureThis(other) {
const type = typeof other;
switch (type) {
case 'object':
case 'function':
if (other === null) {
return null;
} else {
let proto = thisReflectGetPrototypeOf(other);
if (!proto) {
return other;
}
while (proto) {
const mapping = thisReflectApply(thisMapGet, protoMappings, [proto]);
if (mapping) {
const mapped = thisReflectApply(thisWeakMapGet, mappingOtherToThis, [other]);
if (mapped) return mapped;
return mapping(defaultFactory, other);
}
proto = thisReflectGetPrototypeOf(proto);
}
return other;
}
case 'undefined':
case 'string':
case 'number':
case 'boolean':
case 'symbol':
case 'bigint':
return other;
default: // new, unknown types can be dangerous
throw new VMError(`Unknown type '${type}'`);
}
}
function thisFromOtherWithFactory(factory, other, proto) {
for (let loop = 0; loop < 10; loop++) {
const type = typeof other;
switch (type) {
case 'object':
case 'function':
if (other === null) {
return null;
} else {
const mapped = thisReflectApply(thisWeakMapGet, mappingOtherToThis, [other]);
if (mapped) return mapped;
if (proto) {
return thisProxyOther(factory, other, proto);
}
try {
proto = otherReflectGetPrototypeOf(other);
} catch (e) { // @other(unsafe)
other = e;
break;
}
if (!proto) {
return thisProxyOther(factory, other, null);
}
while (proto) {
const mapping = thisReflectApply(thisMapGet, protoMappings, [proto]);
if (mapping) return mapping(factory, other);
try {
proto = otherReflectGetPrototypeOf(proto);
} catch (e) { // @other(unsafe)
other = e;
break;
}
}
return thisProxyOther(factory, other, thisObjectPrototype);
}
case 'undefined':
case 'string':
case 'number':
case 'boolean':
case 'symbol':
case 'bigint':
return other;
default: // new, unknown types can be dangerous
throw new VMError(`Unknown type '${type}'`);
}
factory = defaultFactory;
proto = undefined;
}
throw new VMError('Exception recursion depth');
}
function thisFromOtherArguments(args) {
// Note: args@other(safe-array) returns@this(safe-array) throws@this(unsafe)
const arr = [];
for (let i = 0; i < args.length; i++) {
const value = thisFromOther(args[i]);
thisReflectDefineProperty(arr, i, {
__proto__: null,
value: value,
writable: true,
enumerable: true,
configurable: true
});
}
return arr;
}
function thisConnect(obj, other) {
// Note: obj@this(unsafe) other@other(unsafe) throws@this(unsafe)
try {
otherReflectApply(otherWeakMapSet, mappingThisToOther, [obj, other]);
} catch (e) {
throw new VMError('Unexpected error');
}
thisReflectApply(thisWeakMapSet, mappingOtherToThis, [other, obj]);
}
thisAddProtoMapping(thisGlobalPrototypes.Object, otherGlobalPrototypes.Object);
thisAddProtoMapping(thisGlobalPrototypes.Array, otherGlobalPrototypes.Array);
for (let i = 0; i < globalsList.length; i++) {
const key = globalsList[i];
const tp = thisGlobalPrototypes[key];
const op = otherGlobalPrototypes[key];
if (tp && op) thisAddProtoMapping(tp, op, key);
}
for (let i = 0; i < errorsList.length; i++) {
const key = errorsList[i];
const tp = thisGlobalPrototypes[key];
const op = otherGlobalPrototypes[key];
if (tp && op) thisAddProtoMapping(tp, op, 'Error');
}
thisAddProtoMapping(thisGlobalPrototypes.VMError, otherGlobalPrototypes.VMError, 'Error');
result.BaseHandler = BaseHandler;
result.ProtectedHandler = ProtectedHandler;
result.ReadOnlyHandler = ReadOnlyHandler;
result.ReadOnlyMockHandler = ReadOnlyMockHandler;
return result;
}
exports.createBridge = createBridge;
exports.VMError = VMError;
/***/ })
/******/ });
/************************************************************************/
/******/ /* webpack/runtime/compat */
/******/
/******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/";/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module is referenced by other modules so it can't be inlined
/******/ var __webpack_exports__ = {};
/******/ __webpack_modules__[989](0, __webpack_exports__);
/******/ module.exports = __webpack_exports__;
/******/
/******/ })()
;

1033
dist/events.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

85201
dist/index.js generated vendored

File diff suppressed because one or more lines are too long

473
dist/setup-node-sandbox.js generated vendored Normal file
View File

@@ -0,0 +1,473 @@
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ /* webpack/runtime/compat */
/******/
/******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/";/************************************************************************/
var __webpack_exports__ = {};
/* global host, data, VMError */
const LocalError = Error;
const LocalTypeError = TypeError;
const LocalWeakMap = WeakMap;
const {
apply: localReflectApply,
defineProperty: localReflectDefineProperty
} = Reflect;
const {
set: localWeakMapSet,
get: localWeakMapGet
} = LocalWeakMap.prototype;
const {
isArray: localArrayIsArray
} = Array;
function uncurryThis(func) {
return (thiz, ...args) => localReflectApply(func, thiz, args);
}
const localArrayPrototypeSlice = uncurryThis(Array.prototype.slice);
const localArrayPrototypeIncludes = uncurryThis(Array.prototype.includes);
const localArrayPrototypePush = uncurryThis(Array.prototype.push);
const localArrayPrototypeIndexOf = uncurryThis(Array.prototype.indexOf);
const localArrayPrototypeSplice = uncurryThis(Array.prototype.splice);
const localStringPrototypeStartsWith = uncurryThis(String.prototype.startsWith);
const localStringPrototypeSlice = uncurryThis(String.prototype.slice);
const localStringPrototypeIndexOf = uncurryThis(String.prototype.indexOf);
const {
argv: optionArgv,
env: optionEnv,
console: optionConsole,
vm,
resolver,
extensions
} = data;
function ensureSandboxArray(a) {
return localArrayPrototypeSlice(a);
}
const globalPaths = ensureSandboxArray(resolver.globalPaths);
class Module {
constructor(id, path, parent) {
this.id = id;
this.filename = id;
this.path = path;
this.parent = parent;
this.loaded = false;
this.paths = path ? ensureSandboxArray(resolver.genLookupPaths(path)) : [];
this.children = [];
this.exports = {};
}
_updateChildren(child, isNew) {
const children = this.children;
if (children && (isNew || !localArrayPrototypeIncludes(children, child))) {
localArrayPrototypePush(children, child);
}
}
require(id) {
return requireImpl(this, id, false);
}
}
const originalRequire = Module.prototype.require;
const cacheBuiltins = {__proto__: null};
function requireImpl(mod, id, direct) {
if (direct && mod.require !== originalRequire) {
return mod.require(id);
}
const filename = resolver.resolve(mod, id, undefined, Module._extensions, direct);
if (localStringPrototypeStartsWith(filename, 'node:')) {
id = localStringPrototypeSlice(filename, 5);
let nmod = cacheBuiltins[id];
if (!nmod) {
nmod = resolver.loadBuiltinModule(vm, id);
if (!nmod) throw new VMError(`Cannot find module '${filename}'`, 'ENOTFOUND');
cacheBuiltins[id] = nmod;
}
return nmod;
}
const cachedModule = Module._cache[filename];
if (cachedModule !== undefined) {
mod._updateChildren(cachedModule, false);
return cachedModule.exports;
}
let nmod = cacheBuiltins[id];
if (nmod) return nmod;
nmod = resolver.loadBuiltinModule(vm, id);
if (nmod) {
cacheBuiltins[id] = nmod;
return nmod;
}
const path = resolver.pathDirname(filename);
const module = new Module(filename, path, mod);
resolver.registerModule(module, filename, path, mod, direct);
mod._updateChildren(module, true);
try {
Module._cache[filename] = module;
const handler = findBestExtensionHandler(filename);
handler(module, filename);
module.loaded = true;
} catch (e) {
delete Module._cache[filename];
const children = mod.children;
if (localArrayIsArray(children)) {
const index = localArrayPrototypeIndexOf(children, module);
if (index !== -1) {
localArrayPrototypeSplice(children, index, 1);
}
}
throw e;
}
return module.exports;
}
Module.builtinModules = ensureSandboxArray(resolver.getBuiltinModulesList());
Module.globalPaths = globalPaths;
Module._extensions = {__proto__: null};
Module._cache = {__proto__: null};
{
const keys = Object.getOwnPropertyNames(extensions);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const handler = extensions[key];
Module._extensions[key] = (mod, filename) => handler(mod, filename);
}
}
function findBestExtensionHandler(filename) {
const name = resolver.pathBasename(filename);
for (let i = 0; (i = localStringPrototypeIndexOf(name, '.', i + 1)) !== -1;) {
const ext = localStringPrototypeSlice(name, i + 1);
const handler = Module._extensions[ext];
if (handler) return handler;
}
const js = Module._extensions['.js'];
if (js) return js;
const keys = Object.getOwnPropertyNames(Module._extensions);
if (keys.length === 0) throw new VMError(`Failed to load '${filename}': Unknown type.`, 'ELOADFAIL');
return Module._extensions[keys[0]];
}
function createRequireForModule(mod) {
// eslint-disable-next-line no-shadow
function require(id) {
return requireImpl(mod, id, true);
}
function resolve(id, options) {
return resolver.resolve(mod, id, options, Module._extensions, true);
}
require.resolve = resolve;
function paths(id) {
return ensureSandboxArray(resolver.lookupPaths(mod, id));
}
resolve.paths = paths;
require.extensions = Module._extensions;
require.cache = Module._cache;
return require;
}
/**
* Prepare sandbox.
*/
const TIMERS = new LocalWeakMap();
class Timeout {
}
class Interval {
}
class Immediate {
}
function clearTimer(timer) {
const obj = localReflectApply(localWeakMapGet, TIMERS, [timer]);
if (obj) {
obj.clear(obj.value);
}
}
// This is a function and not an arrow function, since the original is also a function
// eslint-disable-next-line no-shadow
global.setTimeout = function setTimeout(callback, delay, ...args) {
if (typeof callback !== 'function') throw new LocalTypeError('"callback" argument must be a function');
const obj = new Timeout(callback, args);
const cb = () => {
localReflectApply(callback, null, args);
};
const tmr = host.setTimeout(cb, delay);
const ref = {
__proto__: null,
clear: host.clearTimeout,
value: tmr
};
localReflectApply(localWeakMapSet, TIMERS, [obj, ref]);
return obj;
};
// eslint-disable-next-line no-shadow
global.setInterval = function setInterval(callback, interval, ...args) {
if (typeof callback !== 'function') throw new LocalTypeError('"callback" argument must be a function');
const obj = new Interval();
const cb = () => {
localReflectApply(callback, null, args);
};
const tmr = host.setInterval(cb, interval);
const ref = {
__proto__: null,
clear: host.clearInterval,
value: tmr
};
localReflectApply(localWeakMapSet, TIMERS, [obj, ref]);
return obj;
};
// eslint-disable-next-line no-shadow
global.setImmediate = function setImmediate(callback, ...args) {
if (typeof callback !== 'function') throw new LocalTypeError('"callback" argument must be a function');
const obj = new Immediate();
const cb = () => {
localReflectApply(callback, null, args);
};
const tmr = host.setImmediate(cb);
const ref = {
__proto__: null,
clear: host.clearImmediate,
value: tmr
};
localReflectApply(localWeakMapSet, TIMERS, [obj, ref]);
return obj;
};
// eslint-disable-next-line no-shadow
global.clearTimeout = function clearTimeout(timeout) {
clearTimer(timeout);
};
// eslint-disable-next-line no-shadow
global.clearInterval = function clearInterval(interval) {
clearTimer(interval);
};
// eslint-disable-next-line no-shadow
global.clearImmediate = function clearImmediate(immediate) {
clearTimer(immediate);
};
const localProcess = host.process;
function vmEmitArgs(event, args) {
const allargs = [event];
for (let i = 0; i < args.length; i++) {
if (!localReflectDefineProperty(allargs, i + 1, {
__proto__: null,
value: args[i],
writable: true,
enumerable: true,
configurable: true
})) throw new LocalError('Unexpected');
}
return localReflectApply(vm.emit, vm, allargs);
}
const LISTENERS = new LocalWeakMap();
const LISTENER_HANDLER = new LocalWeakMap();
/**
*
* @param {*} name
* @param {*} handler
* @this process
* @return {this}
*/
function addListener(name, handler) {
if (name !== 'beforeExit' && name !== 'exit') {
throw new LocalError(`Access denied to listen for '${name}' event.`);
}
let cb = localReflectApply(localWeakMapGet, LISTENERS, [handler]);
if (!cb) {
cb = () => {
handler();
};
localReflectApply(localWeakMapSet, LISTENER_HANDLER, [cb, handler]);
localReflectApply(localWeakMapSet, LISTENERS, [handler, cb]);
}
localProcess.on(name, cb);
return this;
}
/**
*
* @this process
* @return {this}
*/
// eslint-disable-next-line no-shadow
function process() {
return this;
}
// FIXME wrong class structure
global.process = {
__proto__: process.prototype,
argv: optionArgv !== undefined ? optionArgv : [],
title: localProcess.title,
version: localProcess.version,
versions: localProcess.versions,
arch: localProcess.arch,
platform: localProcess.platform,
env: optionEnv !== undefined ? optionEnv : {},
pid: localProcess.pid,
features: localProcess.features,
nextTick: function nextTick(callback, ...args) {
if (typeof callback !== 'function') {
throw new LocalError('Callback must be a function.');
}
localProcess.nextTick(()=>{
localReflectApply(callback, null, args);
});
},
hrtime: function hrtime(time) {
return localProcess.hrtime(time);
},
cwd: function cwd() {
return localProcess.cwd();
},
addListener,
on: addListener,
once: function once(name, handler) {
if (name !== 'beforeExit' && name !== 'exit') {
throw new LocalError(`Access denied to listen for '${name}' event.`);
}
let triggered = false;
const cb = () => {
if (triggered) return;
triggered = true;
localProcess.removeListener(name, cb);
handler();
};
localReflectApply(localWeakMapSet, LISTENER_HANDLER, [cb, handler]);
localProcess.on(name, cb);
return this;
},
listeners: function listeners(name) {
if (name !== 'beforeExit' && name !== 'exit') {
// Maybe add ({__proto__:null})[name] to throw when name fails in https://tc39.es/ecma262/#sec-topropertykey.
return [];
}
// Filter out listeners, which were not created in this sandbox
const all = localProcess.listeners(name);
const filtered = [];
let j = 0;
for (let i = 0; i < all.length; i++) {
const h = localReflectApply(localWeakMapGet, LISTENER_HANDLER, [all[i]]);
if (h) {
if (!localReflectDefineProperty(filtered, j, {
__proto__: null,
value: h,
writable: true,
enumerable: true,
configurable: true
})) throw new LocalError('Unexpected');
j++;
}
}
return filtered;
},
removeListener: function removeListener(name, handler) {
if (name !== 'beforeExit' && name !== 'exit') {
return this;
}
const cb = localReflectApply(localWeakMapGet, LISTENERS, [handler]);
if (cb) localProcess.removeListener(name, cb);
return this;
},
umask: function umask() {
if (arguments.length) {
throw new LocalError('Access denied to set umask.');
}
return localProcess.umask();
}
};
if (optionConsole === 'inherit') {
global.console = host.console;
} else if (optionConsole === 'redirect') {
global.console = {
debug(...args) {
vmEmitArgs('console.debug', args);
},
log(...args) {
vmEmitArgs('console.log', args);
},
info(...args) {
vmEmitArgs('console.info', args);
},
warn(...args) {
vmEmitArgs('console.warn', args);
},
error(...args) {
vmEmitArgs('console.error', args);
},
dir(...args) {
vmEmitArgs('console.dir', args);
},
time() {},
timeEnd() {},
trace(...args) {
vmEmitArgs('console.trace', args);
}
};
}
return {
__proto__: null,
Module,
jsonParse: JSON.parse,
createRequireForModule
};
module.exports = __webpack_exports__;
/******/ })()
;

462
dist/setup-sandbox.js generated vendored Normal file
View File

@@ -0,0 +1,462 @@
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ /* webpack/runtime/compat */
/******/
/******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/";/************************************************************************/
var __webpack_exports__ = {};
/* global host, bridge, data, context */
const {
Object: localObject,
Array: localArray,
Error: LocalError,
Reflect: localReflect,
Proxy: LocalProxy,
WeakMap: LocalWeakMap,
Function: localFunction,
Promise: localPromise,
eval: localEval
} = global;
const {
freeze: localObjectFreeze
} = localObject;
const {
getPrototypeOf: localReflectGetPrototypeOf,
apply: localReflectApply,
deleteProperty: localReflectDeleteProperty,
has: localReflectHas,
defineProperty: localReflectDefineProperty,
setPrototypeOf: localReflectSetPrototypeOf,
getOwnPropertyDescriptor: localReflectGetOwnPropertyDescriptor
} = localReflect;
const {
isArray: localArrayIsArray
} = localArray;
const {
ensureThis,
ReadOnlyHandler,
from,
fromWithFactory,
readonlyFactory,
connect,
addProtoMapping,
VMError,
ReadOnlyMockHandler
} = bridge;
const {
allowAsync,
GeneratorFunction,
AsyncFunction,
AsyncGeneratorFunction
} = data;
const localWeakMapGet = LocalWeakMap.prototype.get;
function localUnexpected() {
return new VMError('Should not happen');
}
// global is originally prototype of host.Object so it can be used to climb up from the sandbox.
if (!localReflectSetPrototypeOf(context, localObject.prototype)) throw localUnexpected();
Object.defineProperties(global, {
global: {value: global, writable: true, configurable: true, enumerable: true},
globalThis: {value: global, writable: true, configurable: true},
GLOBAL: {value: global, writable: true, configurable: true},
root: {value: global, writable: true, configurable: true}
});
if (!localReflectDefineProperty(global, 'VMError', {
__proto__: null,
value: VMError,
writable: true,
enumerable: false,
configurable: true
})) throw localUnexpected();
// Fixes buffer unsafe allocation
/* eslint-disable no-use-before-define */
class BufferHandler extends ReadOnlyHandler {
apply(target, thiz, args) {
if (args.length > 0 && typeof args[0] === 'number') {
return LocalBuffer.alloc(args[0]);
}
return localReflectApply(LocalBuffer.from, LocalBuffer, args);
}
construct(target, args, newTarget) {
if (args.length > 0 && typeof args[0] === 'number') {
return LocalBuffer.alloc(args[0]);
}
return localReflectApply(LocalBuffer.from, LocalBuffer, args);
}
}
/* eslint-enable no-use-before-define */
const LocalBuffer = fromWithFactory(obj => new BufferHandler(obj), host.Buffer);
if (!localReflectDefineProperty(global, 'Buffer', {
__proto__: null,
value: LocalBuffer,
writable: true,
enumerable: false,
configurable: true
})) throw localUnexpected();
addProtoMapping(LocalBuffer.prototype, host.Buffer.prototype, 'Uint8Array');
/**
*
* @param {*} size Size of new buffer
* @this LocalBuffer
* @return {LocalBuffer}
*/
function allocUnsafe(size) {
return LocalBuffer.alloc(size);
}
connect(allocUnsafe, host.Buffer.allocUnsafe);
/**
*
* @param {*} size Size of new buffer
* @this LocalBuffer
* @return {LocalBuffer}
*/
function allocUnsafeSlow(size) {
return LocalBuffer.alloc(size);
}
connect(allocUnsafeSlow, host.Buffer.allocUnsafeSlow);
/**
* Replacement for Buffer inspect
*
* @param {*} recurseTimes
* @param {*} ctx
* @this LocalBuffer
* @return {string}
*/
function inspect(recurseTimes, ctx) {
// Mimic old behavior, could throw but didn't pass a test.
const max = host.INSPECT_MAX_BYTES;
const actualMax = Math.min(max, this.length);
const remaining = this.length - max;
let str = this.hexSlice(0, actualMax).replace(/(.{2})/g, '$1 ').trim();
if (remaining > 0) str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`;
return `<${this.constructor.name} ${str}>`;
}
connect(inspect, host.Buffer.prototype.inspect);
connect(localFunction.prototype.bind, host.Function.prototype.bind);
connect(localObject.prototype.__defineGetter__, host.Object.prototype.__defineGetter__);
connect(localObject.prototype.__defineSetter__, host.Object.prototype.__defineSetter__);
connect(localObject.prototype.__lookupGetter__, host.Object.prototype.__lookupGetter__);
connect(localObject.prototype.__lookupSetter__, host.Object.prototype.__lookupSetter__);
/*
* PrepareStackTrace sanitization
*/
const oldPrepareStackTraceDesc = localReflectGetOwnPropertyDescriptor(LocalError, 'prepareStackTrace');
let currentPrepareStackTrace = LocalError.prepareStackTrace;
const wrappedPrepareStackTrace = new LocalWeakMap();
if (typeof currentPrepareStackTrace === 'function') {
wrappedPrepareStackTrace.set(currentPrepareStackTrace, currentPrepareStackTrace);
}
let OriginalCallSite;
LocalError.prepareStackTrace = (e, sst) => {
OriginalCallSite = sst[0].constructor;
};
new LocalError().stack;
if (typeof OriginalCallSite === 'function') {
LocalError.prepareStackTrace = undefined;
function makeCallSiteGetters(list) {
const callSiteGetters = [];
for (let i=0; i<list.length; i++) {
const name = list[i];
const func = OriginalCallSite.prototype[name];
callSiteGetters[i] = {__proto__: null,
name,
propName: '_' + name,
func: (thiz) => {
return localReflectApply(func, thiz, []);
}
};
}
return callSiteGetters;
}
function applyCallSiteGetters(thiz, callSite, getters) {
for (let i=0; i<getters.length; i++) {
const getter = getters[i];
localReflectDefineProperty(thiz, getter.propName, {
__proto__: null,
value: getter.func(callSite)
});
}
}
const callSiteGetters = makeCallSiteGetters([
'getTypeName',
'getFunctionName',
'getMethodName',
'getFileName',
'getLineNumber',
'getColumnNumber',
'getEvalOrigin',
'isToplevel',
'isEval',
'isNative',
'isConstructor',
'isAsync',
'isPromiseAll',
'getPromiseIndex'
]);
class CallSite {
constructor(callSite) {
applyCallSiteGetters(this, callSite, callSiteGetters);
}
getThis() {
return undefined;
}
getFunction() {
return undefined;
}
toString() {
return 'CallSite {}';
}
}
for (let i=0; i<callSiteGetters.length; i++) {
const name = callSiteGetters[i].name;
const funcProp = localReflectGetOwnPropertyDescriptor(OriginalCallSite.prototype, name);
if (!funcProp) continue;
const propertyName = callSiteGetters[i].propName;
const func = {func() {
return this[propertyName];
}}.func;
const nameProp = localReflectGetOwnPropertyDescriptor(func, 'name');
if (!nameProp) throw localUnexpected();
nameProp.value = name;
if (!localReflectDefineProperty(func, 'name', nameProp)) throw localUnexpected();
funcProp.value = func;
if (!localReflectDefineProperty(CallSite.prototype, name, funcProp)) throw localUnexpected();
}
if (!localReflectDefineProperty(LocalError, 'prepareStackTrace', {
configurable: false,
enumerable: false,
get() {
return currentPrepareStackTrace;
},
set(value) {
if (typeof(value) !== 'function') {
currentPrepareStackTrace = value;
return;
}
const wrapped = localReflectApply(localWeakMapGet, wrappedPrepareStackTrace, [value]);
if (wrapped) {
currentPrepareStackTrace = wrapped;
return;
}
const newWrapped = (error, sst) => {
if (localArrayIsArray(sst)) {
for (let i=0; i < sst.length; i++) {
const cs = sst[i];
if (typeof cs === 'object' && localReflectGetPrototypeOf(cs) === OriginalCallSite.prototype) {
sst[i] = new CallSite(cs);
}
}
}
return value(error, sst);
};
wrappedPrepareStackTrace.set(value, newWrapped);
wrappedPrepareStackTrace.set(newWrapped, newWrapped);
currentPrepareStackTrace = newWrapped;
}
})) throw localUnexpected();
} else if (oldPrepareStackTraceDesc) {
localReflectDefineProperty(LocalError, 'prepareStackTrace', oldPrepareStackTraceDesc);
} else {
localReflectDeleteProperty(LocalError, 'prepareStackTrace');
}
/*
* Exception sanitization
*/
const withProxy = localObjectFreeze({
__proto__: null,
has(target, key) {
if (key === host.INTERNAL_STATE_NAME) return false;
return localReflectHas(target, key);
}
});
const interanState = localObjectFreeze({
__proto__: null,
wrapWith(x) {
return new LocalProxy(x, withProxy);
},
handleException: ensureThis,
import(what) {
throw new VMError('Dynamic Import not supported');
}
});
if (!localReflectDefineProperty(global, host.INTERNAL_STATE_NAME, {
__proto__: null,
configurable: false,
enumerable: false,
writable: false,
value: interanState
})) throw localUnexpected();
/*
* Eval sanitization
*/
function throwAsync() {
return new VMError('Async not available');
}
function makeFunction(inputArgs, isAsync, isGenerator) {
const lastArgs = inputArgs.length - 1;
let code = lastArgs >= 0 ? `${inputArgs[lastArgs]}` : '';
let args = lastArgs > 0 ? `${inputArgs[0]}` : '';
for (let i = 1; i < lastArgs; i++) {
args += `,${inputArgs[i]}`;
}
try {
code = host.transformAndCheck(args, code, isAsync, isGenerator, allowAsync);
} catch (e) {
throw bridge.from(e);
}
return localEval(code);
}
const FunctionHandler = {
__proto__: null,
apply(target, thiz, args) {
return makeFunction(args, this.isAsync, this.isGenerator);
},
construct(target, args, newTarget) {
return makeFunction(args, this.isAsync, this.isGenerator);
}
};
const EvalHandler = {
__proto__: null,
apply(target, thiz, args) {
if (args.length === 0) return undefined;
let code = `${args[0]}`;
try {
code = host.transformAndCheck(null, code, false, false, allowAsync);
} catch (e) {
throw bridge.from(e);
}
return localEval(code);
}
};
const AsyncErrorHandler = {
__proto__: null,
apply(target, thiz, args) {
throw throwAsync();
},
construct(target, args, newTarget) {
throw throwAsync();
}
};
function makeCheckFunction(isAsync, isGenerator) {
if (isAsync && !allowAsync) return AsyncErrorHandler;
return {
__proto__: FunctionHandler,
isAsync,
isGenerator
};
}
function overrideWithProxy(obj, prop, value, handler) {
const proxy = new LocalProxy(value, handler);
if (!localReflectDefineProperty(obj, prop, {__proto__: null, value: proxy})) throw localUnexpected();
return proxy;
}
const proxiedFunction = overrideWithProxy(localFunction.prototype, 'constructor', localFunction, makeCheckFunction(false, false));
if (GeneratorFunction) {
if (!localReflectSetPrototypeOf(GeneratorFunction, proxiedFunction)) throw localUnexpected();
overrideWithProxy(GeneratorFunction.prototype, 'constructor', GeneratorFunction, makeCheckFunction(false, true));
}
if (AsyncFunction) {
if (!localReflectSetPrototypeOf(AsyncFunction, proxiedFunction)) throw localUnexpected();
overrideWithProxy(AsyncFunction.prototype, 'constructor', AsyncFunction, makeCheckFunction(true, false));
}
if (AsyncGeneratorFunction) {
if (!localReflectSetPrototypeOf(AsyncGeneratorFunction, proxiedFunction)) throw localUnexpected();
overrideWithProxy(AsyncGeneratorFunction.prototype, 'constructor', AsyncGeneratorFunction, makeCheckFunction(true, true));
}
global.Function = proxiedFunction;
global.eval = new LocalProxy(localEval, EvalHandler);
/*
* Promise sanitization
*/
if (localPromise && !allowAsync) {
const PromisePrototype = localPromise.prototype;
overrideWithProxy(PromisePrototype, 'then', PromisePrototype.then, AsyncErrorHandler);
// This seems not to work, and will produce
// UnhandledPromiseRejectionWarning: TypeError: Method Promise.prototype.then called on incompatible receiver [object Object].
// This is likely caused since the host.Promise.prototype.then cannot use the VM Proxy object.
// Contextify.connect(host.Promise.prototype.then, Promise.prototype.then);
if (PromisePrototype.finally) {
overrideWithProxy(PromisePrototype, 'finally', PromisePrototype.finally, AsyncErrorHandler);
// Contextify.connect(host.Promise.prototype.finally, Promise.prototype.finally);
}
if (Promise.prototype.catch) {
overrideWithProxy(PromisePrototype, 'catch', PromisePrototype.catch, AsyncErrorHandler);
// Contextify.connect(host.Promise.prototype.catch, Promise.prototype.catch);
}
}
function readonly(other, mock) {
// Note: other@other(unsafe) mock@other(unsafe) returns@this(unsafe) throws@this(unsafe)
if (!mock) return fromWithFactory(readonlyFactory, other);
const tmock = from(mock);
return fromWithFactory(obj=>new ReadOnlyMockHandler(obj, tmock), other);
}
return {
__proto__: null,
readonly,
global
};
module.exports = __webpack_exports__;
/******/ })()
;

70
docker-bake.hcl Normal file
View File

@@ -0,0 +1,70 @@
variable "NODE_VERSION" {
default = "12"
}
target "node-version" {
args = {
NODE_VERSION = NODE_VERSION
}
}
group "default" {
targets = ["build"]
}
group "pre-checkin" {
targets = ["vendor-update", "format", "build"]
}
group "validate" {
targets = ["format-validate", "build-validate", "vendor-validate"]
}
target "build" {
inherits = ["node-version"]
dockerfile = "./hack/build.Dockerfile"
target = "build-update"
output = ["."]
}
target "build-validate" {
inherits = ["node-version"]
dockerfile = "./hack/build.Dockerfile"
target = "build-validate"
output = ["type=cacheonly"]
}
target "format" {
inherits = ["node-version"]
dockerfile = "./hack/build.Dockerfile"
target = "format-update"
output = ["."]
}
target "format-validate" {
inherits = ["node-version"]
dockerfile = "./hack/build.Dockerfile"
target = "format-validate"
output = ["type=cacheonly"]
}
target "vendor-update" {
inherits = ["node-version"]
dockerfile = "./hack/build.Dockerfile"
target = "vendor-update"
output = ["."]
}
target "vendor-validate" {
inherits = ["node-version"]
dockerfile = "./hack/build.Dockerfile"
target = "vendor-validate"
output = ["type=cacheonly"]
}
target "test" {
inherits = ["node-version"]
dockerfile = "./hack/build.Dockerfile"
target = "test-coverage"
output = ["./coverage"]
}

78
hack/build.Dockerfile Normal file
View File

@@ -0,0 +1,78 @@
# syntax=docker/dockerfile:1.3-labs
ARG NODE_VERSION
ARG DOCKER_VERSION=20.10.10
ARG BUILDX_VERSION=0.7.0
FROM node:${NODE_VERSION}-alpine AS base
RUN apk add --no-cache cpio findutils git
WORKDIR /src
FROM base AS deps
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules \
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
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules \
yarn run build && mkdir /out && cp -Rf dist /out/
FROM scratch AS build-update
COPY --from=build /out /
FROM build AS build-validate
RUN --mount=type=bind,target=.,rw <<EOT
set -e
git add -A
cp -rf /out/* .
if [ -n "$(git status --porcelain -- dist)" ]; then
echo >&2 'ERROR: Build result differs. Please build first with "docker buildx bake build"'
git status --porcelain -- dist
exit 1
fi
EOT
FROM deps AS format
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules \
yarn run format \
&& mkdir /out && find . -name '*.ts' -not -path './node_modules/*' | cpio -pdm /out
FROM scratch AS format-update
COPY --from=format /out /
FROM deps AS format-validate
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules \
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 /

View File

@@ -27,22 +27,24 @@
], ],
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.2.6", "@actions/core": "^1.6.0",
"@actions/exec": "^1.0.4", "@actions/exec": "^1.1.0",
"@actions/io": "^1.0.2", "@actions/io": "^1.1.1",
"semver": "^7.3.2" "@aws-sdk/client-ecr": "^3.45.0",
"@aws-sdk/client-ecr-public": "^3.45.0",
"proxy-agent": "^5.0.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"
} }
} }

View File

@@ -1,51 +1,132 @@
import * as semver from 'semver'; import * as core from '@actions/core';
import * as io from '@actions/io'; import {ECR} from '@aws-sdk/client-ecr';
import * as execm from './exec'; import {ECRPUBLIC} from '@aws-sdk/client-ecr-public';
import {NodeHttpHandler} from '@aws-sdk/node-http-handler';
import ProxyAgent from 'proxy-agent';
export const isECR = async (registry: string): Promise<boolean> => { const ecrRegistryRegex = /^(([0-9]{12})\.dkr\.ecr\.(.+)\.amazonaws\.com(.cn)?)(\/([^:]+)(:.+)?)?$/;
return registry.includes('amazonaws');
export const isECR = (registry: string): boolean => {
return ecrRegistryRegex.test(registry) || isPubECR(registry);
}; };
export const getRegion = async (registry: string): Promise<string> => { export const isPubECR = (registry: string): boolean => {
return registry.substring(registry.indexOf('ecr.') + 4, registry.indexOf('.amazonaws')); return registry === 'public.ecr.aws';
}; };
export const getCLI = async (): Promise<string> => { export const getRegion = (registry: string): string => {
return io.which('aws', true); if (isPubECR(registry)) {
}; return process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || 'us-east-1';
}
export const execCLI = async (args: string[]): Promise<string> => { const matches = registry.match(ecrRegistryRegex);
return execm.exec(await getCLI(), args, true).then(res => {
if (res.stderr != '' && !res.success) {
throw new Error(res.stderr);
} else if (res.stderr != '') {
return res.stderr.trim();
} else {
return res.stdout.trim();
}
});
};
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) { if (!matches) {
throw new Error(`Cannot parse AWS CLI version`); return '';
} }
return semver.clean(matches[1]); return matches[3];
}; };
export const getDockerLoginCmd = async (cliVersion: string, registry: string, region: string): Promise<string> => { export const getAccountIDs = (registry: string): string[] => {
if (semver.satisfies(cliVersion, '>=2.0.0')) { if (isPubECR(registry)) {
return execCLI(['ecr', 'get-login-password', '--region', region]).then(pwd => { return [];
return `docker login --username AWS --password ${pwd} ${registry}`; }
const matches = registry.match(ecrRegistryRegex);
if (!matches) {
return [];
}
let accountIDs: Array<string> = [matches[2]];
if (process.env.AWS_ACCOUNT_IDS) {
accountIDs.push(...process.env.AWS_ACCOUNT_IDS.split(','));
}
return accountIDs.filter((item, index) => accountIDs.indexOf(item) === index);
};
export interface RegistryData {
registry: string;
username: string;
password: string;
}
export const getRegistriesData = async (registry: string, username?: string, password?: string): Promise<RegistryData[]> => {
const region = getRegion(registry);
const accountIDs = getAccountIDs(registry);
const authTokenRequest = {};
if (accountIDs.length > 0) {
core.debug(`Requesting AWS ECR auth token for ${accountIDs.join(', ')}`);
authTokenRequest['registryIds'] = accountIDs;
}
let httpProxyAgent: any = null;
const httpProxy = process.env.http_proxy || process.env.HTTP_PROXY || '';
if (httpProxy) {
core.debug(`Using http proxy ${httpProxy}`);
httpProxyAgent = new ProxyAgent(httpProxy);
}
let httpsProxyAgent: any = null;
const httpsProxy = process.env.https_proxy || process.env.HTTPS_PROXY || '';
if (httpsProxy) {
core.debug(`Using https proxy ${httpsProxy}`);
httpsProxyAgent = new ProxyAgent(httpsProxy);
}
const credentials =
username && password
? {
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,
requestHandler: new NodeHttpHandler({
httpAgent: httpProxyAgent,
httpsAgent: httpsProxyAgent
})
}); });
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]
}
];
} else { } else {
return execCLI(['ecr', 'get-login', '--region', region, '--no-include-email']).then(dockerLoginCmd => { core.info(`AWS ECR detected with ${region} region`);
return dockerLoginCmd; const ecr = new ECR({
customUserAgent: 'docker-login-action',
credentials,
region: region,
requestHandler: new NodeHttpHandler({
httpAgent: httpProxyAgent,
httpsAgent: httpsProxyAgent
})
}); });
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;
} }
}; };

View File

@@ -4,7 +4,8 @@ export interface Inputs {
registry: string; registry: string;
username: string; username: string;
password: string; password: string;
logout: string; ecr: string;
logout: boolean;
} }
export function getInputs(): Inputs { export function getInputs(): Inputs {
@@ -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'),
logout: core.getInput('logout') ecr: core.getInput('ecr'),
logout: core.getBooleanInput('logout')
}; };
} }

View File

@@ -1,9 +1,9 @@
import * as core from '@actions/core';
import * as aws from './aws'; import * as aws from './aws';
import * as execm from './exec'; import * as core from '@actions/core';
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);
@@ -11,11 +11,15 @@ export async function login(registry: string, username: string, password: string
} }
export async function logout(registry: string): Promise<void> { export async function logout(registry: string): Promise<void> {
await execm.exec('docker', ['logout', registry], false).then(res => { await exec
if (res.stderr != '' && !res.success) { .getExecOutput('docker', ['logout', registry], {
core.warning(res.stderr); ignoreReturnCode: true
} })
}); .then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
core.warning(res.stderr.trim());
}
});
} }
export async function loginStandard(registry: string, username: string, password: string): Promise<void> { export async function loginStandard(registry: string, username: string, password: string): Promise<void> {
@@ -28,35 +32,40 @@ export async function loginStandard(registry: string, username: string, password
loginArgs.push(registry); loginArgs.push(registry);
if (registry) { if (registry) {
core.info(`🔑 Logging into ${registry}...`); core.info(`Logging into ${registry}...`);
} else { } else {
core.info(`🔑 Logging into DockerHub...`); core.info(`Logging into Docker Hub...`);
} }
await execm.exec('docker', loginArgs, true, password).then(res => { await exec
if (res.stderr != '' && !res.success) { .getExecOutput('docker', loginArgs, {
throw new Error(res.stderr); ignoreReturnCode: true,
} silent: true,
core.info('🎉 Login Succeeded!'); input: Buffer.from(password)
}); })
.then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
throw new Error(res.stderr.trim());
}
core.info(`Login Succeeded!`);
});
} }
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) {
core.info(`💡 AWS ECR detected with ${region} region`); core.info(`Logging into ${regData.registry}...`);
await exec
process.env.AWS_ACCESS_KEY_ID = username || process.env.AWS_ACCESS_KEY_ID; .getExecOutput('docker', ['login', '--password-stdin', '--username', regData.username, regData.registry], {
process.env.AWS_SECRET_ACCESS_KEY = password || process.env.AWS_SECRET_ACCESS_KEY; ignoreReturnCode: true,
silent: true,
core.info(`⬇️ Retrieving docker login command through AWS CLI ${cliVersion} (${cliPath})...`); input: Buffer.from(regData.password)
const loginCmd = await aws.getDockerLoginCmd(cliVersion, registry, region); })
.then(res => {
core.info(`🔑 Logging into ${registry}...`); if (res.stderr.length > 0 && res.exitCode != 0) {
execm.exec(loginCmd, [], true).then(res => { throw new Error(res.stderr.trim());
if (res.stderr != '' && !res.success) { }
throw new Error(res.stderr); core.info('Login Succeeded!');
} });
core.info('🎉 Login Succeeded!'); }
});
} }

View File

@@ -1,40 +0,0 @@
import * as actionsExec from '@actions/exec';
import {ExecOptions} from '@actions/exec';
export interface ExecResult {
success: boolean;
stdout: string;
stderr: string;
}
export const exec = async (
command: string,
args: string[] = [],
silent: boolean,
stdin?: string
): Promise<ExecResult> => {
let stdout: string = '';
let stderr: string = '';
const options: ExecOptions = {
silent: silent,
ignoreReturnCode: true,
input: Buffer.from(stdin || '')
};
options.listeners = {
stdout: (data: Buffer) => {
stdout += data.toString();
},
stderr: (data: Buffer) => {
stderr += data.toString();
}
};
const returnCode: number = await actionsExec.exec(command, args, options);
return {
success: returnCode === 0,
stdout: stdout.trim(),
stderr: stderr.trim()
};
};

View File

@@ -1,19 +1,14 @@
import * as os from 'os';
import * as core from '@actions/core'; import * as core from '@actions/core';
import {getInputs, Inputs} from './context'; import * as context from './context';
import * as docker from './docker'; import * as docker from './docker';
import * as stateHelper from './state-helper'; import * as stateHelper from './state-helper';
export async function run(): Promise<void> { export async function run(): Promise<void> {
try { try {
if (os.platform() !== 'linux') { const input: context.Inputs = context.getInputs();
throw new Error('Only supported on linux platform'); stateHelper.setRegistry(input.registry);
} stateHelper.setLogout(input.logout);
await docker.login(input.registry, input.username, input.password, input.ecr);
const {registry, username, password, logout} = getInputs();
stateHelper.setRegistry(registry);
stateHelper.setLogout(logout);
await docker.login(registry, username, password);
} catch (error) { } catch (error) {
core.setFailed(error.message); core.setFailed(error.message);
} }

View File

@@ -8,7 +8,7 @@ export function setRegistry(registry: string) {
core.saveState('registry', registry); core.saveState('registry', registry);
} }
export function setLogout(logout: string) { export function setLogout(logout: boolean) {
core.saveState('logout', logout); core.saveState('logout', logout);
} }

3046
yarn.lock

File diff suppressed because it is too large Load Diff