Compare commits

..

80 Commits

Author SHA1 Message Date
GitHub Actions 023daa7fe5 chore: Update dist 2023-02-28 04:08:41 +00:00
dependabot[bot] f586cc8d6c chore: Bump aws-sdk from 2.1319.0 to 2.1324.0 (#678)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1319.0 to 2.1324.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1319.0...v2.1324.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-28 04:07:50 +00:00
dependabot[bot] 5726671b7e chore: Bump axios from 1.3.3 to 1.3.4 (#676)
Bumps [axios](https://github.com/axios/axios) from 1.3.3 to 1.3.4.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.3.3...v1.3.4)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-02-28 03:59:33 +00:00
dependabot[bot] 682539baa7 chore: Bump eslint from 8.34.0 to 8.35.0 (#674)
Bumps [eslint](https://github.com/eslint/eslint) from 8.34.0 to 8.35.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.34.0...v8.35.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-28 03:58:18 +00:00
Tom Keller 186395a864 fix!: proxy changes to v1-node16 (runtime failures 2023-02-24 16:00:06 -08:00
Tom Keller a19d847176 Merge branch 'master' into v1-node16 2023-02-24 14:36:52 -08:00
Tom Keller afbf093795 Revert "Merge branch 'master' into v1-node16"
This reverts commit df03f9f89e, reversing
changes made to 5f641521a3.
2023-02-24 14:28:16 -08:00
Tom Keller df03f9f89e Merge branch 'master' into v1-node16 2023-02-24 14:04:51 -08:00
GitHub Actions 5f641521a3 chore: Update dist 2023-02-21 04:01:43 +00:00
dependabot[bot] cf1ab7af03 chore: Bump aws-sdk from 2.1314.0 to 2.1319.0 (#664)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1314.0 to 2.1319.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1314.0...v2.1319.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-02-21 04:00:52 +00:00
dependabot[bot] feaa7fa4a6 chore: Bump jest from 29.4.2 to 29.4.3 (#662)
Bumps [jest](https://github.com/facebook/jest/tree/HEAD/packages/jest) from 29.4.2 to 29.4.3.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v29.4.3/packages/jest)

---
updated-dependencies:
- dependency-name: jest
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-21 03:59:32 +00:00
dependabot[bot] 4f2f92e5ab chore: Bump jest from 29.4.1 to 29.4.2 (#657)
Bumps [jest](https://github.com/facebook/jest/tree/HEAD/packages/jest) from 29.4.1 to 29.4.2.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v29.4.2/packages/jest)

---
updated-dependencies:
- dependency-name: jest
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-02-14 04:05:29 +00:00
GitHub Actions 63c92be916 chore: Update dist 2023-02-14 04:04:16 +00:00
dependabot[bot] d57f6a99b2 chore: Bump aws-sdk from 2.1310.0 to 2.1314.0 (#656)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1310.0 to 2.1314.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1310.0...v2.1314.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-14 04:03:21 +00:00
dependabot[bot] b10102e8c0 chore: Bump axios from 1.3.2 to 1.3.3 (#652)
Bumps [axios](https://github.com/axios/axios) from 1.3.2 to 1.3.3.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.3.2...v1.3.3)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-02-14 04:00:13 +00:00
dependabot[bot] 329c87d69e chore: Bump eslint from 8.33.0 to 8.34.0 (#654)
Bumps [eslint](https://github.com/eslint/eslint) from 8.33.0 to 8.34.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.33.0...v8.34.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-14 03:59:24 +00:00
GitHub Actions 7c78a8afc0 chore: Update dist 2023-02-07 03:05:41 +00:00
dependabot[bot] bfc885690a chore: Bump aws-sdk from 2.1305.0 to 2.1310.0 (#649)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1305.0 to 2.1310.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1305.0...v2.1310.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-07 03:04:53 +00:00
dependabot[bot] b8843be31a chore: Bump axios from 1.2.6 to 1.3.2 (#647)
Bumps [axios](https://github.com/axios/axios) from 1.2.6 to 1.3.2.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.2.6...v1.3.2)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-07 03:02:30 +00:00
dependabot[bot] 07c2f971ba chore: Bump eslint from 8.32.0 to 8.33.0 (#644)
Bumps [eslint](https://github.com/eslint/eslint) from 8.32.0 to 8.33.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.32.0...v8.33.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-01-31 03:09:14 +00:00
GitHub Actions afaecf5658 chore: Update dist 2023-01-31 03:07:50 +00:00
dependabot[bot] 9395f54576 chore: Bump aws-sdk from 2.1300.0 to 2.1305.0 (#646)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1300.0 to 2.1305.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1300.0...v2.1305.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-31 03:07:04 +00:00
dependabot[bot] 15bf15ef24 chore: Bump jest from 29.3.1 to 29.4.1 (#642)
Bumps [jest](https://github.com/facebook/jest/tree/HEAD/packages/jest) from 29.3.1 to 29.4.1.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v29.4.1/packages/jest)

---
updated-dependencies:
- dependency-name: jest
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-01-31 03:04:46 +00:00
dependabot[bot] 0bb734a034 chore: Bump @vercel/ncc from 0.36.0 to 0.36.1 (#641)
Bumps [@vercel/ncc](https://github.com/vercel/ncc) from 0.36.0 to 0.36.1.
- [Release notes](https://github.com/vercel/ncc/releases)
- [Commits](https://github.com/vercel/ncc/compare/0.36.0...0.36.1)

---
updated-dependencies:
- dependency-name: "@vercel/ncc"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-01-31 03:03:53 +00:00
dependabot[bot] 104814938c chore: Bump axios from 1.2.3 to 1.2.6 (#638)
Bumps [axios](https://github.com/axios/axios) from 1.2.3 to 1.2.6.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.2.3...v1.2.6)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-31 03:02:35 +00:00
dependabot[bot] 8203047ce9 chore: Bump axios from 1.2.2 to 1.2.3 (#631)
Bumps [axios](https://github.com/axios/axios) from 1.2.2 to 1.2.3.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/1.2.2...v1.2.3)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-24 03:07:20 +00:00
GitHub Actions a3d672ff77 chore: Update dist 2023-01-24 03:04:23 +00:00
dependabot[bot] 3c5e8d9305 chore: Bump aws-sdk from 2.1295.0 to 2.1300.0 (#629)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1295.0 to 2.1300.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1295.0...v2.1300.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-24 03:03:37 +00:00
GitHub Actions 26c46c2ae7 chore: Update dist 2023-01-17 03:06:51 +00:00
dependabot[bot] 011701cc1b chore: Bump aws-sdk from 2.1291.0 to 2.1295.0 (#626)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1291.0 to 2.1295.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1291.0...v2.1295.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-01-17 03:06:06 +00:00
dependabot[bot] b9e6c47506 chore: Bump eslint from 8.31.0 to 8.32.0 (#624)
Bumps [eslint](https://github.com/eslint/eslint) from 8.31.0 to 8.32.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.31.0...v8.32.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-17 03:04:52 +00:00
GitHub Actions 9727186006 chore: Update dist 2023-01-10 03:03:21 +00:00
dependabot[bot] 8c40159721 chore: Bump aws-sdk from 2.1286.0 to 2.1291.0 (#623)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1286.0 to 2.1291.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1286.0...v2.1291.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-10 03:02:30 +00:00
dependabot[bot] ada05fa00e chore: Bump axios from 1.2.1 to 1.2.2 (#617)
Bumps [axios](https://github.com/axios/axios) from 1.2.1 to 1.2.2.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.2.1...1.2.2)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-01-03 03:06:18 +00:00
dependabot[bot] 90be1075bb chore: Bump eslint from 8.30.0 to 8.31.0 (#618)
Bumps [eslint](https://github.com/eslint/eslint) from 8.30.0 to 8.31.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.30.0...v8.31.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-01-03 03:04:37 +00:00
GitHub Actions b1e291fd46 chore: Update dist 2023-01-03 03:03:12 +00:00
dependabot[bot] 5bf8e889ef chore: Bump aws-sdk from 2.1282.0 to 2.1286.0 (#615)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1282.0 to 2.1286.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1282.0...v2.1286.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-03 03:02:24 +00:00
GitHub Actions 8fd75be9bb chore: Update dist 2022-12-27 03:03:20 +00:00
dependabot[bot] 65cd794383 chore: Bump aws-sdk from 2.1278.0 to 2.1282.0 (#614)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1278.0 to 2.1282.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1278.0...v2.1282.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-27 03:02:29 +00:00
GitHub Actions 56320524c9 chore: Update dist 2022-12-20 03:04:22 +00:00
dependabot[bot] 4a10c382ea chore: Bump aws-sdk from 2.1273.0 to 2.1278.0 (#609)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1273.0 to 2.1278.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1273.0...v2.1278.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-20 03:03:44 +00:00
dependabot[bot] d4fb44140f chore: Bump eslint from 8.29.0 to 8.30.0 (#607)
Bumps [eslint](https://github.com/eslint/eslint) from 8.29.0 to 8.30.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.29.0...v8.30.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-20 03:03:30 +00:00
GitHub Actions 95bc17402b chore: Update dist 2022-12-13 03:06:02 +00:00
dependabot[bot] b016bfd40a chore: Bump aws-sdk from 2.1268.0 to 2.1273.0 (#602)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1268.0 to 2.1273.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1268.0...v2.1273.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-13 03:05:06 +00:00
dependabot[bot] abcf4fe216 chore: Bump axios from 1.2.0 to 1.2.1 (#595)
Bumps [axios](https://github.com/axios/axios) from 1.2.0 to 1.2.1.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.2.0...v1.2.1)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2022-12-06 03:08:30 +00:00
dependabot[bot] 6a502811f6 chore: Bump @vercel/ncc from 0.34.0 to 0.36.0 (#593)
Bumps [@vercel/ncc](https://github.com/vercel/ncc) from 0.34.0 to 0.36.0.
- [Release notes](https://github.com/vercel/ncc/releases)
- [Commits](https://github.com/vercel/ncc/compare/0.34.0...0.36.0)

---
updated-dependencies:
- dependency-name: "@vercel/ncc"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2022-12-06 03:07:00 +00:00
GitHub Actions fc10f5e66c chore: Update dist 2022-12-06 03:05:42 +00:00
dependabot[bot] 2fbb264794 chore: Bump aws-sdk from 2.1262.0 to 2.1268.0 (#597)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1262.0 to 2.1268.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1262.0...v2.1268.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2022-12-06 03:04:54 +00:00
dependabot[bot] 7704dba423 chore: Bump eslint from 8.28.0 to 8.29.0 (#591)
Bumps [eslint](https://github.com/eslint/eslint) from 8.28.0 to 8.29.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.28.0...v8.29.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-06 03:02:38 +00:00
dependabot[bot] 495fc37803 chore: Bump axios from 1.1.3 to 1.2.0 (#589)
Bumps [axios](https://github.com/axios/axios) from 1.1.3 to 1.2.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.1.3...v1.2.0)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-29 03:08:57 +00:00
GitHub Actions c44e4cd308 chore: Update dist 2022-11-29 03:05:00 +00:00
dependabot[bot] 5db0c4b245 chore: Bump aws-sdk from 2.1259.0 to 2.1262.0 (#588)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1259.0 to 2.1262.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1259.0...v2.1262.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-29 03:04:09 +00:00
dependabot[bot] 8962602b76 chore: Bump eslint from 8.27.0 to 8.28.0 (#583)
Bumps [eslint](https://github.com/eslint/eslint) from 8.27.0 to 8.28.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.27.0...v8.28.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2022-11-22 03:34:04 +00:00
GitHub Actions 996af9a61b chore: Update dist 2022-11-22 03:31:45 +00:00
dependabot[bot] 70f70f3d01 chore: Bump aws-sdk from 2.1254.0 to 2.1259.0 (#582)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1254.0 to 2.1259.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1254.0...v2.1259.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-22 03:30:55 +00:00
GitHub Actions 40d50e0dc7 chore: Update dist 2022-11-15 03:05:40 +00:00
dependabot[bot] d70ae8a9b8 chore: Bump aws-sdk from 2.1249.0 to 2.1254.0 (#577)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1249.0 to 2.1254.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1249.0...v2.1254.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2022-11-15 03:04:55 +00:00
dependabot[bot] 29858782df chore: Bump jest from 29.3.0 to 29.3.1 (#575)
Bumps [jest](https://github.com/facebook/jest/tree/HEAD/packages/jest) from 29.3.0 to 29.3.1.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v29.3.1/packages/jest)

---
updated-dependencies:
- dependency-name: jest
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-15 03:03:35 +00:00
dependabot[bot] daed12437b chore: Bump eslint from 8.26.0 to 8.27.0 (#573)
Bumps [eslint](https://github.com/eslint/eslint) from 8.26.0 to 8.27.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.26.0...v8.27.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-08 03:20:41 +00:00
dependabot[bot] 3d0ec8cfd7 chore: Bump jest from 29.2.2 to 29.3.0 (#571)
Bumps [jest](https://github.com/facebook/jest/tree/HEAD/packages/jest) from 29.2.2 to 29.3.0.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v29.3.0/packages/jest)

---
updated-dependencies:
- dependency-name: jest
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2022-11-08 03:08:29 +00:00
GitHub Actions 89d6bf8b63 chore: Update dist 2022-11-08 03:07:25 +00:00
dependabot[bot] 89d9dc8901 chore: Bump aws-sdk from 2.1244.0 to 2.1249.0 (#569)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1244.0 to 2.1249.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1244.0...v2.1249.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-08 03:06:39 +00:00
Tom Keller 59775fae63 Merge branch 'master' into v1-node16 2022-11-04 17:45:19 -07:00
dependabot[bot] 8461db48ce chore: Bump aws-sdk from 2.1239.0 to 2.1244.0 (#559)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1239.0 to 2.1244.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1239.0...v2.1244.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-01 03:41:45 +00:00
Tom Keller 1c6d3132e1 Merge branch 'master' into v1-node16 2022-10-26 13:16:25 -07:00
Peter Woodworth 77b504aefa update package lock with node 14 (#556) 2022-10-26 13:15:51 -07:00
Peter Woodworth 993b6a062d update package lock (#555) 2022-10-26 13:15:50 -07:00
Tom Keller 1fee7bbf94 Merge branch 'master' into v1-node16 2022-10-25 17:33:46 -07:00
Tom Keller 096a34b527 Merge branch 'master' into v1-node16 2022-10-25 16:56:51 -07:00
Tom Keller 036f9c6a9f Merge branch 'master' into v1-node16 2022-10-25 09:48:37 -07:00
dependabot[bot] 1908557210 chore: Bump eslint from 8.25.0 to 8.26.0 (#544)
Bumps [eslint](https://github.com/eslint/eslint) from 8.25.0 to 8.26.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.25.0...v8.26.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-25 03:38:47 +00:00
dependabot[bot] 7be15a02d9 chore: Bump aws-sdk from 2.1234.0 to 2.1239.0 (#545)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1234.0 to 2.1239.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1234.0...v2.1239.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2022-10-25 03:37:17 +00:00
dependabot[bot] 7289c29462 chore: Bump jest from 29.2.0 to 29.2.2 (#547)
Bumps [jest](https://github.com/facebook/jest/tree/HEAD/packages/jest) from 29.2.0 to 29.2.2.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v29.2.2/packages/jest)

---
updated-dependencies:
- dependency-name: jest
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-25 03:36:23 +00:00
Tom Keller a485a1e9a4 Merge branch 'master' into v1-node16 2022-10-18 21:11:25 -07:00
dependabot[bot] c3748b7f3f chore: Bump axios from 1.1.2 to 1.1.3 (#533)
Bumps [axios](https://github.com/axios/axios) from 1.1.2 to 1.1.3.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.1.2...v1.1.3)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-18 03:25:50 +00:00
dependabot[bot] 2db6cd9a80 chore: Bump aws-sdk from 2.1232.0 to 2.1234.0 (#538)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1232.0 to 2.1234.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1232.0...v2.1234.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2022-10-18 03:24:23 +00:00
dependabot[bot] d90b587a73 chore: Bump jest from 29.1.2 to 29.2.0 (#536)
Bumps [jest](https://github.com/facebook/jest/tree/HEAD/packages/jest) from 29.1.2 to 29.2.0.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v29.2.0/packages/jest)

---
updated-dependencies:
- dependency-name: jest
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-18 03:22:49 +00:00
dependabot[bot] 2aed65ee75 chore: Bump aws-sdk from 2.1231.0 to 2.1232.0 (#527)
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1231.0 to 2.1232.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1231.0...v2.1232.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-13 20:52:46 +00:00
Peter Woodworth cdfc29bebf Merge pull request #524 from kellertk/v1-node16
fix: temporarily bump node version to 16
2022-10-13 13:17:15 -07:00
Tom Keller a30b23eed5 fix: temporarily bump node version to 16 2022-10-13 13:09:41 -07:00
54 changed files with 45290 additions and 69696 deletions
-19
View File
@@ -1,19 +0,0 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab
indent_size = 4
-2
View File
@@ -1,2 +0,0 @@
build
dist
+18
View File
@@ -0,0 +1,18 @@
{
"env": {
"commonjs": true,
"es6": true,
"node": true,
"jest": true
},
"extends": "eslint:recommended",
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaVersion": 2018
},
"rules": {
}
}
-168
View File
@@ -1,168 +0,0 @@
env:
jest: true
node: true
root: true
plugins:
- import
- prettier
parserOptions:
ecmaVersion: 2021
sourceType: module
extends:
- plugin:prettier/recommended
- prettier
rules:
prettier/prettier: [error]
import/no-extraneous-dependencies:
- error
- devDependencies:
- "**/test/**"
- "**/build-tools/**"
optionalDependencies: false
peerDependencies: true
import/no-unresolved: [error]
import/order:
- warn
- groups:
- builtin
- external
alphabetize:
order: asc
caseInsensitive: true
array-callback-return: [warn]
no-await-in-loop: [warn]
no-constant-binary-expression: [error]
no-constructor-return: [error]
no-duplicate-imports: [error]
no-self-compare: [warn]
no-template-curly-in-string: [error]
no-unmodified-loop-condition: [error]
no-unreachable-loop: [error]
no-unused-private-class-members: [error]
no-use-before-define: [error]
require-atomic-updates: [error]
block-scoped-var: [warn]
camelcase: [warn]
class-methods-use-this: [error]
consistent-return: [warn]
consistent-this: [warn]
default-case-last: [warn]
default-param-last: [warn]
dot-notation: [error]
eqeqeq: [error]
guard-for-in: [warn]
logical-assignment-operators:
- error
- always
- enforceForIfStatements: false
no-array-constructor: [error]
no-bitwise: [error]
no-console: [warn]
no-empty-function: [warn]
no-eval: [error]
no-extra-bind: [error]
no-labels: [error]
no-implicit-globals: [error]
no-invalid-this: [error]
key-spacing: [error]
no-multiple-empty-lines: [error]
no-return-await: [warn]
no-trailing-spaces: [error]
no-lonely-if: [error]
no-nested-ternary: [warn]
no-mixed-operators: [warn]
no-proto: [error]
no-sequences: [error]
no-throw-literal: [error]
no-useless-call: [error]
no-useless-concat: [warn]
no-var: [error]
one-var-declaration-per-line: [error]
prefer-const: [warn]
prefer-arrow-callback: [warn]
prefer-regex-literals: [warn]
prefer-promise-reject-errors: [warn]
prefer-spread: [warn]
prefer-template: [warn]
require-await: [error]
overrides:
- files:
- '**/*.ts'
parser: '@typescript-eslint/parser'
parserOptions:
ecmaVersion: 2021
sourceType: module
project: ./tsconfig.json
extends:
- plugin:@typescript-eslint/recommended
- plugin:@typescript-eslint/recommended-requiring-type-checking
- plugin:import/typescript
rules:
'@typescript-eslint/array-type':
- warn
- default: array-simple
'@typescript-eslint/ban-tslint-comment': [error]
'@typescript-eslint/consistent-indexed-object-style': [warn]
'@typescript-eslint/consistent-type-assertions': [warn]
'@typescript-eslint/prefer-includes': [warn]
dot-notation: [off]
'@typescript-eslint/dot-notation': [error]
'@typescript-eslint/no-explicit-any': [off]
'@typescript-eslint/consistent-type-exports': [warn]
'@typescript-eslint/consistent-type-imports': [warn]
'@typescript-eslint/no-base-to-string': [error]
'@typescript-eslint/no-confusing-non-null-assertion': [warn]
'@typescript-eslint/no-invalid-void-type': [error]
'@typescript-eslint/no-meaningless-void-operator': [warn]
'@typescript-eslint/no-redundant-type-constituents': [warn]
'@typescript-eslint/no-unnecessary-boolean-literal-compare': [warn]
'@typescript-eslint/no-unnecessary-condition': [warn]
'@typescript-eslint/no-unnecessary-qualifier': [warn]
'@typescript-eslint/no-unnecessary-type-arguments': [warn]
'@typescript-eslint/non-nullable-type-assertion-style': [warn]
'@typescript-eslint/prefer-for-of': [error]
'@typescript-eslint/prefer-literal-enum-member': [warn]
'@typescript-eslint/prefer-optional-chain': [warn]
'@typescript-eslint/prefer-readonly': [warn]
'@typescript-eslint/prefer-regexp-exec': [warn]
'@typescript-eslint/prefer-string-starts-ends-with': [warn]
'@typescript-eslint/prefer-ts-expect-error': [error]
'@typescript-eslint/promise-function-async': [warn]
'@typescript-eslint/require-array-sort-compare': [error]
default-param-last: [off]
'@typescript-eslint/default-param-last': [warn]
no-array-constructor: [off]
'@typescript-eslint/no-array-constructor': [error]
no-dupe-class-members: [off]
'@typescript-eslint/no-dupe-class-members': [warn]
no-invalid-this: [off]
'@typescript-eslint/no-invalid-this': [warn]
no-unused-vars: [off]
'@typescript-eslint/no-unused-vars':
- error
- varsIgnorePattern: '^_'
argsIgnorePattern: '^_'
caughtErrorsIgnorePattern: '^_'
'@typescript-eslint/no-non-null-assertion': [off]
'@typescript-eslint/no-require-imports':
- error
no-return-await: [off]
'@typescript-eslint/return-await': [error]
no-shadow: [off]
'@typescript-eslint/no-shadow': [error]
'@typescript-eslint/no-floating-promises': [error]
"@typescript-eslint/member-ordering":
- error
- default:
- public-static-field
- public-static-method
- protected-static-field
- protected-static-method
- private-static-field
- private-static-method
- field
- constructor
- method
no-use-before-define: [off]
'@typescript-eslint/no-use-before-define': [error]
no-duplicate-imports: [off]
-7
View File
@@ -1,7 +0,0 @@
/dist/** linguist-generated
/package-lock.json linguist-generated
*.json text eol=lf
*.js text eol=lf
*.jsx text eol=lf
*.ts text eol=lf
*.tsx text eol=lf
+1 -1
View File
@@ -4,6 +4,6 @@
---
* [ ] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws-actions/configure-aws-credentials/blob/main/CONTRIBUTING.md)
* [ ] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws-actions/configure-aws-credentials/blob/master/CONTRIBUTING.md)
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
+8 -1
View File
@@ -6,4 +6,11 @@ updates:
interval: weekly
day: tuesday
open-pull-requests-limit: 10
target-branch: 'main'
target-branch: 'master'
- package-ecosystem: npm
directory: "/"
schedule:
interval: weekly
day: tuesday
open-pull-requests-limit: 10
target-branch: 'v1-node16'
+16
View File
@@ -0,0 +1,16 @@
on:
[pull_request]
name: Check
jobs:
check:
name: Run Unit Tests
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Run tests
run: |
npm ci
npm test
+3 -3
View File
@@ -22,7 +22,7 @@ jobs:
ancient-issue-message: This issue has not received any attention in 1 year. If you want to keep this issue open, please leave a comment below and auto-close will be canceled.
stale-issue-message: This issue has not received a response in a while. If you want to keep this issue open, please leave a comment below and auto-close will be canceled.
stale-pr-message: This PR has not received a response in a while. If you want to keep this issue open, please leave a comment below and auto-close will be canceled.
# These labels are required
stale-issue-label: closing-soon
exempt-issue-labels: no-autoclose
@@ -37,7 +37,7 @@ jobs:
# Issue timing
days-before-stale: 5
days-before-close: 2
days-before-ancient: 36500
days-before-ancient: 365
# If you don't want to mark a issue as being ancient based on a
# threshold of "upvotes", you can set this here. An "upvote" is
@@ -48,4 +48,4 @@ jobs:
repo-token: ${{ secrets.GITHUB_TOKEN }}
loglevel: DEBUG
# Set dry-run to true to not perform label or close actions.
dry-run: false
dry-run: false
+3 -1
View File
@@ -13,5 +13,7 @@ jobs:
# These inputs are both required
repo-token: "${{ secrets.GITHUB_TOKEN }}"
message: |
Comments on closed issues are hard for our team to see.
### ⚠️Comment Visibility Warning⚠️
Comments on closed issues are hard for our team to see.
If you need more assistance, please either tag a team member or open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.
+71
View File
@@ -0,0 +1,71 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
name: "CodeQL"
on:
push:
branches: [master]
pull_request:
# The branches below must be a subset of the branches above
branches: [master]
schedule:
- cron: '0 0 * * 2'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Override automatic language detection by changing the below list
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
language: ['javascript']
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
@@ -1,18 +0,0 @@
name: HandleStaleDiscussions
on:
schedule:
- cron: '0 */4 * * *'
discussion_comment:
types: [created]
jobs:
handle-stale-discussions:
name: Handle stale discussions
runs-on: ubuntu-latest
permissions:
discussions: write
steps:
- name: Stale discussions action
uses: aws-github-ops/handle-stale-discussions@v1
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
+8 -8
View File
@@ -1,12 +1,12 @@
name: Update dist files on main branch
name: Update dist files on
on:
push:
branches:
- main
- master
- v1-node16
paths-ignore:
- 'dist/**'
workflow_dispatch:
jobs:
package:
@@ -28,10 +28,10 @@ jobs:
npm test
npm run package
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
uses: aws-actions/configure-aws-credentials@v1-node16
with:
aws-region: us-west-2
role-to-assume: ${{ secrets.SECRETS_AWS_PACKAGING_ROLE_TO_ASSUME }}
role-to-assume: ${{ secrets.SECRETS_AWS_ROLE_TO_ASSUME }}
role-duration-seconds: 900
role-session-name: SecretsManagerFetch
- name: Get bot user token
@@ -39,13 +39,13 @@ jobs:
with:
parse-json-secrets: true
secret-ids: |
OSDS,arn:aws:secretsmanager:us-west-2:206735643321:secret:github-aws-sdk-osds-automation-gebs9n
OSDS,arn:aws:secretsmanager:us-west-2:294535624312:secret:github-aws-sdk-osds-automation-ZHNalp
- name: Commit
run: |
echo "::add-mask::${{ env.OSDS_ACCESS_TOKEN }}"
echo "::add-mask::${{ env.OSDS_ACCESS_TOKEN }}}"
git config user.name "GitHub Actions"
git config user.email "github-aws-sdk-osds-automation@amazon.com"
git remote set-url origin https://${{ env.OSDS_ACCESS_TOKEN }}@github.com/aws-actions/configure-aws-credentials.git
git remote set-url origin https://x-access-token:${{ env.OSDS_ACCESS_TOKEN }}@github.com/aws-actions/configure-aws-credentials.git
git add dist
git commit -m "chore: Update dist" || echo "No changes to commit"
git push origin
-27
View File
@@ -1,27 +0,0 @@
name: pull-request-lint
on:
pull_request_target:
types:
- labeled
- opened
- synchronize
- reopened
- ready_for_review
- edited
jobs:
validate:
name: Validate PR title
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: amannn/action-semantic-pull-request@v4.5.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
types: |-
feat
fix
chore
requireScope: false
-112
View File
@@ -1,112 +0,0 @@
name: Run Integ tests
on:
workflow_dispatch:
jobs:
integ-oidc:
permissions:
contents: read
id-token: write
strategy:
fail-fast: false
matrix:
os: [[self-hosted, linux-fargate], windows-latest, ubuntu-latest, macos-latest]
name: Run OIDC integ tests
runs-on: ${{ matrix.os }}
timeout-minutes: 30
steps:
- name: "Checkout repository"
uses: actions/checkout@v3
- name: Integ test for OIDC
uses: ./
with:
aws-region: us-west-2
role-to-assume: ${{ secrets.SECRETS_OIDC_AWS_ROLE_TO_ASSUME }}
role-duration-seconds: 900
role-session-name: IntegOidcAssumeRole
role-external-id: ${{ secrets.SECRETS_OIDC_AWS_ROLE_EXTERNAL_ID }}
integ-oidc-env:
permissions:
contents: read
id-token: write
strategy:
fail-fast: false
matrix:
os: [[self-hosted, linux-fargate], windows-latest, ubuntu-latest, macos-latest]
name: Run OIDC integ tests with existing invalid env vars
runs-on: ${{ matrix.os }}
env:
AWS_ACCESS_KEY_ID: dummyaccesskeyid
AWS_SECRET_ACCESS_KEY: dummysecretkey
AWS_SESSION_TOKEN: dummytoken
timeout-minutes: 30
steps:
- name: "Checkout repository"
uses: actions/checkout@v3
- name: Integ test for OIDC
uses: ./
with:
aws-region: us-west-2
role-to-assume: ${{ secrets.SECRETS_OIDC_AWS_ROLE_TO_ASSUME }}
role-duration-seconds: 900
role-session-name: IntegOidcAssumeRole
role-external-id: ${{ secrets.SECRETS_OIDC_AWS_ROLE_EXTERNAL_ID }}
integ-access-keys:
strategy:
fail-fast: false
matrix:
os: [[self-hosted, linux-fargate], windows-latest, ubuntu-latest, macos-latest]
name: Run access key integ tests
runs-on: ${{ matrix.os }}
timeout-minutes: 30
steps:
- name: "Checkout repository"
uses: actions/checkout@v3
- name: Integ test for access keys
uses: ./
with:
aws-region: us-west-2
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
role-to-assume: ${{ secrets.SECRETS_AWS_ROLE_TO_ASSUME }}
role-session-name: IntegAccessKeysAssumeRole
role-external-id: ${{ secrets.SECRETS_AWS_ROLE_EXTERNAL_ID }}
integ-access-keys-env:
strategy:
fail-fast: false
matrix:
os: [[self-hosted, linux-fargate], windows-latest, ubuntu-latest, macos-latest]
name: Run access key from env integ tests
runs-on: ${{ matrix.os }}
timeout-minutes: 30
steps:
- name: "Checkout repository"
uses: actions/checkout@v3
- name: Integ test for access keys
uses: ./
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
with:
aws-region: us-west-2
role-to-assume: ${{ secrets.SECRETS_AWS_ROLE_TO_ASSUME }}
role-session-name: IntegAccessKeysAssumeRole
role-external-id: ${{ secrets.SECRETS_AWS_ROLE_EXTERNAL_ID }}
integ-iam-user:
strategy:
fail-fast: false
matrix:
os: [[self-hosted, linux-fargate], windows-latest, ubuntu-latest, macos-latest]
name: Run IAM User integ tests
runs-on: ${{ matrix.os }}
timeout-minutes: 30
steps:
- name: "Checkout repository"
uses: actions/checkout@v3
- name: Integ test for IAM user
uses: ./
with:
aws-region: us-west-2
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
-40
View File
@@ -1,40 +0,0 @@
on:
[pull_request]
name: Run unit tests
jobs:
unit-test:
strategy:
fail-fast: false
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
name: Run unit tests
runs-on: ${{ matrix.os }}
timeout-minutes: 5
steps:
- name: "Checkout repository"
uses: actions/checkout@v3
- name: "Setup node"
uses: actions/setup-node@v3
with:
node-version: 20
- name: "Install dependencies"
uses: bahmutov/npm-install@v1
- name: "Run tests"
run: npm run test --if-present
lint:
name: Ensure code standards
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: "Checkout repostiory"
uses: actions/checkout@v3
- name: "Setup node"
uses: actions/setup-node@v3
with:
node-version: 20
- name: "Install dependencies"
uses: bahmutov/npm-install@v1
- name: "Lint code"
run: npm run lint --if-present
+65 -5
View File
@@ -1,6 +1,66 @@
node_modules
node_modules/
# Editors
.vscode
.idea
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
.DS_Store
Thumbs.db
build
test-reports
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Other Dependency directories
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# next.js build output
.next
+7 -14
View File
@@ -1,22 +1,17 @@
queue_rules:
- name: default
conditions:
# Conditions to merge a queued PR
- check-success=Run unit tests (windows-latest)
- check-success=Run unit tests (ubuntu-latest)
- check-success=Run unit tests (macos-latest)
- "#approved-reviews-by>=1"
- -approved-reviews-by~=author
# Conditions to get out of the queue (= merged)
- status-success=Run Unit Tests
pull_request_rules:
- name: Automatically merge on CI success and review approval
conditions:
- base~=main|integ-tests
- base~=master|v1-node16|integ-tests
- "#approved-reviews-by>=1"
- -approved-reviews-by~=author
- check-success=Run unit tests (windows-latest)
- check-success=Run unit tests (ubuntu-latest)
- check-success=Run unit tests (macos-latest)
- status-success=Run Unit Tests
- label!=work-in-progress
- -title~=(WIP|wip)
- -merged
@@ -29,11 +24,9 @@ pull_request_rules:
- name: Automatically approve and merge Dependabot PRs
conditions:
- base~=main
- base~=master|v1-node16
- author=dependabot[bot]
- check-success=Run unit tests (windows-latest)
- check-success=Run unit tests (ubuntu-latest)
- check-success=Run unit tests (macos-latest)
- status-success=Run Unit Tests
- -title~=(WIP|wip)
- -label~=(blocked|do-not-merge)
- -merged
-8
View File
@@ -1,8 +0,0 @@
{
"printWidth": 120,
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"bracketSpacing": true,
"overrides": []
}
-63
View File
@@ -2,69 +2,6 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## [4.0.1](https://github.com/aws-actions/configure-aws-credentials/compare/v4.0.0...v4.0.1) (2023-10-03)
### Documentation
* Throw a warning when customers use long-term credentials.
## [4.0.0](https://github.com/aws-actions/configure-aws-credentials/compare/v3.0.2...v4.0.0) (2023-09-11)
* Upgraded runtime to `node20` from `node16`
## [3.0.2](https://github.com/aws-actions/configure-aws-credentials/compare/v3.0.1...v3.0.2) (2023-09-07)
### Bug Fixes
* fixes #817 #819: validation logic throwing unwanted errors [d78f55b](https://github.com/aws-actions/configure-aws-credentials/commit/d78f55b1db65186cb251a8504ae9527af06fc5fd)
## [3.0.1](https://github.com/aws-actions/configure-aws-credentials/compare/v3.0.0...v3.0.1) (2023-08-24)
### Features
* Can configure `special-characters-workaround` to keep retrying credentials if the returned
credentials have special characters (Fixes #599)
### Bug Fixes
* Fixes #792: Action fails when intending to use existing credentials
* Minor typo fix from @ubaid-ansari21
### Changes to existing functionality
* Special characters are now allowed in returned credential variables unless you configure the
`special-characters-workaround` option
## [3.0.0](https://github.com/aws-actions/configure-aws-credentials/compare/v2.2.0...v3.0.0) (2023-08-21)
### Features
* Can configure `max-retries` and `disable-retry` to modify retry functionality when the assume role call fails
* Set returned credentials as step outputs with `output-credentials`
* Clear AWS related environment variables at the start of the action with `unset-current-credentials`
* Unique role identifier is now printed in the workflow logs
### Bug Fixes
* Can't use credentials if they contain a special character
* Retry functionality added when generating the JWT fails
* Can now use `webIdentityTokenFile` option
* Branch name validation too strict
* JS SDK v2 deprecation warning in workflow logs
### Changes to existing functionality
* Default session duration is now 1 hour in all cases (from 6 hours in some cases)
* Account ID will not be masked by default in logs
## [2.2.0](https://github.com/aws-actions/configure-aws-credentials/compare/v2.1.0...v2.2.0) (2023-05-31)
### Features
* `inline-session-policy` prop enables assuming a role with inline session policies ([d00f6c6](https://github.com/aws-actions/configure-aws-credentials/commit/d00f6c6f41fde02a9fd0d469040be6ed0df69e73))
* `managed-session-policies` prop enables assuming a role with managed policy arns ([d00f6c6](https://github.com/aws-actions/configure-aws-credentials/commit/d00f6c6f41fde02a9fd0d469040be6ed0df69e73))
## [2.1.0](https://github.com/aws-actions/configure-aws-credentials/compare/v2.0.0...v2.1.0) (2023-05-31)
### Features
* `role-chaining` prop enables role chaining use case ([6fbd316](https://github.com/aws-actions/configure-aws-credentials/commit/6fbd316fd15f52c3d9f68e7aa06eae4f5699a518))
## [2.0.0](https://github.com/aws-actions/configure-aws-credentials/compare/v1.7.0...v2.0.0) (2023-03-06)
### Features
* Version bump to use Node 16 by default.
## [1.7.0](https://github.com/aws-actions/configure-aws-credentials/compare/v1.6.1...v1.7.0) (2022-08-03)
+2 -2
View File
@@ -23,7 +23,7 @@ reported the issue. Please try to include as much information as you can. Detail
## Contributing via Pull Requests
Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:
1. You are working against the latest source on the *main* branch.
1. You are working against the latest source on the *master* branch.
2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.
3. You open an issue to discuss any significant work - we would hate for your time to be wasted.
@@ -56,6 +56,6 @@ If you discover a potential security issue in this project we ask that you notif
## Licensing
See the [LICENSE](https://github.com/aws-actions/configure-aws-credentials/blob/main/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution.
See the [LICENSE](https://github.com/aws-actions/configure-aws-credentials/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution.
We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes.
+3 -1
View File
@@ -1,4 +1,6 @@
Copyright (c) 2019-2022 Amazon.com, Inc. or its affiliates
MIT License
Copyright 2019 Amazon.com, Inc. or its affiliates.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+115 -400
View File
@@ -1,118 +1,39 @@
## Configure AWS Credentials for GitHub Actions
Configure your AWS credentials and region environment variables for use in other
GitHub Actions. This action implements the AWS SDK credential resolution chain
and exports environment variables for your other Actions to use. Environment
variable exports are detected by both the AWS SDKs and the AWS CLI for AWS API
calls.
## "Configure AWS Credentials" Action For GitHub Actions
---
Configure AWS credential and region environment variables for use in other GitHub Actions. The environment variables will be detected by both the AWS SDKs and the AWS CLI to determine the credentials and region to use for AWS API calls.
### Recent News
## NOTICE: node12 deprecation warning
GitHub actions has recently started throwing warning messages regarding the deprecation of Node 12. If you would like to stop seeing this warning, configure your action to use `aws-actions/configure-aws-credentials@v1-node16`. Both the `v1` branch and the `v1-node16` branch will receive the same updates moving forward. See [this issue](https://github.com/aws-actions/configure-aws-credentials/issues/489) for more information on this topic.
#### Long-term credentials warning (10/3/23)
**Table of Contents**
We have added a warning when using long-term credentials to access AWS
(IAM access keys and secret keys). Using long-term credentials requires you
to create IAM users and properly secure the access keys to prevent their disclosure.
A better approach is to use [GitHub's support for OpenID Connect](#OIDC) to authenticate
using an IAM role to generate temporary security credentials.
#### v4 Announcement (9/11/23)
We have just released `v4` of Configure AWS Credentials. The only thing that
changed from `v3` is that the action now runs on `node20` instead of `node16`.
You can still see the `v3` announcement below, as it is still recent.
#### v3 Announcement (8/23/23)
We have recently released `v3` of Configure AWS Credentials! With this new
release we have migrated the code to TypeScript, and have also migrated away
from using `v2` of the JavaScript AWS SDK. This should eliminate the warning you
have seen in your workflow logs about `v2` deprecation.
In addition to the refactored codebase, we have also introduced some changes to
existing functionality, added some new features, and fixed some bugs. These
changes should be backwards compatible with your existing workflows.
**Notable changes to existing functionality**
- By default, the assumed role credentials will only be valid for one hour in
_all_ use cases. This is changed from 6 hours in `v2`. You can adjust this value
with the `role-duration-seconds` input.
- By default, your account ID will not be masked in workflow logs. This was
changed from being masked by default in the previous version. AWS does not consider
account IDs as sensitive information, so this change reflects that stance. You
can revert to the old default and mask your account ID in workflow logs by
setting the `mask-aws-account-id` input to `true`.
**New features**
- You can now configure retry settings in case your STS call fails. By default,
we retry with exponential backoff twelve times. You can disable this behavior
altogether by setting the `disable-retry` input to `true`, or you can configure
the number of times the action will retry with the `retry-max-attempts` input.
- You can now set the returned credentials as action step outputs. To do this,
you can set the `output-credentials` prop to `true`.
- There's now an option to clear the AWS-related environment variables at the
start of the action. Clearing these variables is often a workaround for
problems, so enabling this can be helpful if existing credentials or environment
variables are interfering with the action. You can enable this by setting the
`unset-current-credentials` input to `true`.
**Bug fixes**
You can find a list of bugs that have been fixed in v3 in the
[changelog](./CHANGELOG.md).
---
### Table of Contents
<!-- toc -->
- [Overview](#overview)
- [Security recommendations](#security-recommendations)
- [Using this action](#using-this-action)
+ [Credential Lifetime](#credential-lifetime)
+ [External ID](#external-id)
+ [Session tagging](#session-tagging-and-name)
- [Usage](#usage)
- [Credentials](#credentials)
- [Assuming a Role](#assuming-a-role)
+ [Session tagging](#session-tagging)
+ [Sample IAM Role Permissions](#sample-iam-role-cloudformation-template)
+ [Misc](#misc)
- [OIDC](#OIDC)
+ [Audience](#audience)
+ [Sample IAM OIDC CloudFormation Template](#sample-iam-oidc-cloudformation-template)
+ [Claims and scoping permissions](#claims-and-scoping-permissions)
+ [Further info](#further-info)
- [Self-Hosted Runners](#self-hosted-runners)
+ [Proxy Configuration](#proxy-configuration)
+ [Use with the AWS CLI](#use-with-the-aws-cli)
- [Examples](#examples)
- [License Summary](#license-summary)
- [Security Disclosures](#security-disclosures)
<!-- tocstop -->
## Overview
We support five methods for fetching credentials from AWS, but we recommend that
you use GitHub's OIDC provider in conjunction with a configured AWS IAM
Identity Provider endpoint.
## Usage
To do that, you would add the following step to your workflow:
Add the following step to your workflow:
```yaml
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: arn:aws:iam::123456789100:role/my-github-actions-role
aws-region: us-east-2
```
This will cause the action to perform an [`AssumeRoleWithWebIdentity`](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html) call and
return temporary security credentials for use by other steps in your workflow. In order for
this to work, you'll need to preconfigure the IAM Identity Provider in your AWS account
(see [Assuming a Role](#assuming-a-role) for details).
You can use this action with the AWS CLI available in
[GitHub's hosted virtual environments](https://help.github.com/en/actions/reference/software-installed-on-github-hosted-runners) or run this action multiple times
to use different AWS accounts, regions, or IAM roles in the same GitHub Actions
workflow. As an example, here is a complete workflow file that uploads artifacts
to Amazon S3.
For example, you can use this action with the AWS CLI available in [GitHub's hosted virtual environments](https://help.github.com/en/actions/reference/software-installed-on-github-hosted-runners).
You can also run this action multiple times to use different AWS accounts, regions, or IAM roles in the same GitHub Actions workflow job.
```yaml
jobs:
@@ -125,230 +46,109 @@ jobs:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Configure AWS credentials from Test account
uses: aws-actions/configure-aws-credentials@v4
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: arn:aws:iam::111111111111:role/my-github-actions-role-test
aws-region: us-east-1
- name: Copy files to the test website with the AWS CLI
run: |
aws s3 sync . s3://my-s3-test-website-bucket
- name: Configure AWS credentials from Production account
uses: aws-actions/configure-aws-credentials@v4
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: arn:aws:iam::222222222222:role/my-github-actions-role-prod
aws-region: us-west-2
- name: Copy files to the production website with the AWS CLI
run: |
aws s3 sync . s3://my-s3-prod-website-bucket
```
See [action.yml](action.yml) for the full documentation for this action's inputs
and outputs.
See [action.yml](action.yml) for the full documentation for this action's inputs and outputs.
### Note about GHES
## Credentials
Some of this documentation may be inaccurate if you are using GHES (GitHub Enterprise Servers), please take note to review the GitHub documentation when relevant.
We recommend following [Amazon IAM best practices](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html) for the AWS credentials used in GitHub Actions workflows, including:
* Do not store credentials in your repository's code.
* [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege) to the credentials used in GitHub Actions workflows. Grant only the permissions required to perform the actions in your GitHub Actions workflows.
* [Monitor the activity](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#keep-a-log) of the credentials used in GitHub Actions workflows.
For example, the URL that the OIDC JWT is issued from is different than the usual `tokens.actions.githubusercontent.com`, and will be unique to your enterprise server. As a result, you will need to configure this differently when you create the Identity Provider.
## Assuming a Role
We recommend using [GitHub's OIDC provider](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services) to get short-lived credentials needed for your actions.
Specifying `role-to-assume` **without** providing an `aws-access-key-id` or a `web-identity-token-file` will signal to the action that you wish to use the OIDC provider.
## Security recommendations
The default session duration is **1 hour** when using the OIDC provider to directly assume an IAM Role or when an `aws-session-token` is directly provided.
We recommend following
[Amazon IAM best practices](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html)
for the AWS credentials used in GitHub Actions workflows, including:
* Do not store credentials in your repository's code.
* [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege) to the credentials used in GitHub Actions
workflows. Grant only the permissions required to perform the actions in your
GitHub Actions workflows.
* [Monitor the activity](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#keep-a-log) of the credentials used in GitHub Actions workflows.
## Using this action
There are five different supported ways to retrieve credentials:
- Using GitHub's OIDC provider (`AssumeRoleWithWebIdentity`)
- Proceeding as an IAM user (No STS call is made)
- Using access keys as action input (`AssumeRole`)
- Using a WebIdentity Token File (`AssumeRoleWithWebIdentity`)
- Using existing credentials in your runner (`AssumeRole`)
We recommend using [GitHub's OIDC provider](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services) to get short-lived AWS credentials needed for your actions. See [OIDC](#OIDC) for more information on how to setup your AWS account to assume a role with OIDC.
The following table describes which method is used based on which values are supplied to the Action:
| **Identity Used** | `aws-access-key-id` | `role-to-assume` | `web-identity-token-file` | `role-chaining` | `id-token` permission
| --------------------------------------------------------------- | ------------------- | ---------------- | ------------------------- | - | - |
| [✅ Recommended] Assume Role directly using GitHub OIDC provider | | ✔ | | | ✔ |
| IAM User | ✔ | | | | |
| Assume Role using IAM User credentials | ✔ | ✔ | | | |
| Assume Role using WebIdentity Token File credentials | | ✔ | ✔ | | |
| Assume Role using existing credentials | | ✔ | | ✔ | |
*Note: `role-chaining` is not necessary to use existing credentials in every use case. If you're getting a "Credentials loaded by the SDK do not match" error, try enabling this prop.
### Credential Lifetime
The default session duration is **1 hour**.
The default session duration is **6 hours** when using an IAM User to assume an IAM Role (by providing an `aws-access-key-id`, `aws-secret-access-key`, and a `role-to-assume`) .
If you would like to adjust this you can pass a duration to `role-duration-seconds`, but the duration cannot exceed the maximum that was defined when the IAM Role was created.
The default session name is GitHubActions, and you can modify it by specifying the desired name in `role-session-name`.
The default audience is `sts.amazonaws.com` which you can replace by specifying the desired audience name in `audience`.
### External ID
If your role requires an external ID to assume, you can provide the external ID with the `role-external-id` input
The following table describes which identity is used based on which values are supplied to the Action:
### Session tagging and name
The default session name is "GitHubActions", and you can modify it by specifying the desired name in `role-session-name`.
The session will be tagged with the following tags: (`GITHUB_` environment variable definitions can be
[found here](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/using-environment-variables#default-environment-variables))
| **Identity Used** | `aws-access-key-id` | `role-to-assume` | `web-identity-token-file` |
|------------------------------------------------------------------|---------------------|------------------|---------------------------|
| [✅ Recommended] Assume Role directly using GitHub OIDC provider | | ✔ | |
| IAM User | ✔ | | |
| Assume Role using IAM User credentials | ✔ | ✔ | |
| Assume Role using WebIdentity Token File credentials | | ✔ | ✔ |
| Key | Value |
| ---------- | ----------------- |
| GitHub | "Actions" |
| Repository | GITHUB_REPOSITORY |
| Workflow | GITHUB_WORKFLOW |
| Action | GITHUB_ACTION |
| Actor | GITHUB_ACTOR |
| Branch | GITHUB_REF |
| Commit | GITHUB_SHA |
### Examples
_Note: all tag values must conform to
[the requirements](https://docs.aws.amazon.com/STS/latest/APIReference/API_Tag.html).
Particularly, `GITHUB_WORKFLOW` will be truncated if it's too long. If
`GITHUB_ACTOR` or `GITHUB_WORKFLOW` contain invalid characters, the characters
will be replaced with an '*'._
The action will use session tagging by default during role assumption, unless you are assuming a role with a WebIdentity.
For WebIdentity role assumption, the session tags have to be included
in the encoded WebIdentity token. This means that Tags can only be supplied by
the OIDC provider, and they cannot set during the AssumeRoleWithWebIdentity API call
within the Action. See [issue 419](https://github.com/aws-actions/configure-aws-credentials/issues/419) for more info
You can skip this session tagging by providing
`role-skip-session-tagging` as true in the action's inputs:
```yaml
uses: aws-actions/configure-aws-credentials@v4
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
role-skip-session-tagging: true
aws-region: us-east-2
role-to-assume: arn:aws:iam::123456789100:role/my-github-actions-role
role-session-name: MySessionName
```
In this example, the Action will load the OIDC token from the GitHub-provided environment variable and use it to assume the role `arn:aws:iam::123456789100:role/my-github-actions-role` with the session name `MySessionName`.
### Session policies
#### Inline session policies
An IAM policy in stringified JSON format that you want to use as an inline session policy.
Depending on preferences, the JSON could be written on a single line like this:
```yaml
uses: aws-actions/configure-aws-credentials@v4
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
inline-session-policy: '{"Version":"2012-10-17","Statement":[{"Sid":"Stmt1","Effect":"Allow","Action":"s3:List*","Resource":"*"}]}'
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-2
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
role-external-id: ${{ secrets.AWS_ROLE_EXTERNAL_ID }}
role-duration-seconds: 1200
role-session-name: MySessionName
```
Or we can have a nicely formatted JSON as well:
In this example, the secret `AWS_ROLE_TO_ASSUME` contains a string like `arn:aws:iam::123456789100:role/my-github-actions-role`. To assume a role in the same account as the static credentials, you can simply specify the role name, like `role-to-assume: my-github-actions-role`.
```yaml
uses: aws-actions/configure-aws-credentials@v4
- name: Configure AWS Credentials for Beta Customers
uses: aws-actions/configure-aws-credentials@v1
with:
inline-session-policy: >-
{
"Version": "2012-10-17",
"Statement": [
{
"Sid":"Stmt1",
"Effect":"Allow",
"Action":"s3:List*",
"Resource":"*"
}
]
}
```
#### Managed session policies
The Amazon Resource Names (ARNs) of the IAM managed policies that you want to use as managed session policies.
The policies must exist in the same account as the role. You can pass a single managed policy like this:
```yaml
uses: aws-actions/configure-aws-credentials@v4
with:
managed-session-policies: arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
```
And we can pass multiple managed policies likes this:
```yaml
uses: aws-actions/configure-aws-credentials@v4
with:
managed-session-policies: |
arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
arn:aws:iam::aws:policy/AmazonS3OutpostsReadOnlyAccess
```
### Misc
#### Adjust the retry mechanism
You can now configure retry settings for when the STS call fails. By default, we retry with exponential backoff `12` times. You can disable this behavior altogether by setting the `disable-retry` input to `true`, or you can configure the number of times it retries with the `retry-max-attempts` input.
#### Mask account ID
Your account ID is not masked by default in workflow logs since it's not considered sensitive information. However, you can set the `mask-aws-account-id` input to `true` to mask your account ID in workflow logs if desired.
#### Unset current credentials
Sometimes, existing credentials in your runner can get in the way of the intended outcome, and the recommended solution is to include another step in your workflow which unsets the environment variables set by this action. Now if you set the `unset-current-credentials` input to `true`, the workaround is made eaiser
#### Special characters in AWS_SECRET_ACCESS_KEY
Some edge cases are unable to properly parse an `AWS_SECRET_ACCESS_KEY` if it
contains special characters. For more information, please see the
[AWS CLI documentation](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-troubleshooting.html#tshoot-signature-does-not-match).
If you set the `special-characters-workaround` option, this action will
continually retry fetching credentials until we get one that does not have
special characters. This option overrides the `disable-retry` and
`retry-max-attempts` options.
## OIDC
We recommend using [GitHub's OIDC provider](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services) to get short-lived AWS credentials needed for your actions. When using OIDC, this action will create a JWT unique to the workflow run, and it will use this JWT to assume the role. For this action to create the JWT, it is required for your workflow to have the `id-token: write` permission:
```yaml
permissions:
id-token: write
contents: read
```
### Audience
When the JWT is created, an audience needs to be specified. By default, the audience is `sts.amazonaws.com` and this will work for most cases. Changing the default audience may be necessary when using non-default AWS partitions. You can specify the audience through the `audience` input:
```yaml
- name: Configure AWS Credentials for China region audience
uses: aws-actions/configure-aws-credentials@v4
with:
audience: sts.amazonaws.com.cn
audience: beta-customers
aws-region: us-east-3
role-to-assume: arn:aws:iam::123456789100:role/my-github-actions-role
role-session-name: MySessionName
```
In this example, the audience has been changed from the default to use a different audience name `beta-customers`. This can help ensure that the role can only affect those AWS accounts whose GitHub OIDC providers have explicitly opted in to the `beta-customers` label.
### Sample IAM OIDC CloudFormation Template
To use GitHub's OIDC provider, you must first set up federation
with the provider in as an IAM IdP. The GitHub OIDC provider only needs to be
created once per account (i.e. multiple IAM Roles that can be assumed by the
GitHub's OIDC can share a single OIDC Provider).
Note that the thumbprint has been set to all F's because the thumbprint is not
used when authenticating `tokens.actions.githubusercontent.com`. Instead, IAM
uses its library of trusted CAs to authenticate. However, this value is still
required by the API.
This CloudFormation template will configure the IdP for you. You can copy the
template below, or load it from here:
https://d38mtn6aq9zhn6.cloudfront.net/configure-aws-credentials-latest.yml
Changing the default audience may be necessary when using non-default [AWS partitions](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html).
### Sample IAM Role CloudFormation Template
```yaml
Parameters:
GitHubOrg:
Description: Name of GitHub organization/user (case sensitive)
Type: String
RepositoryName:
Description: Name of GitHub repository (case sensitive)
Type: String
OIDCProviderArn:
Description: Arn for the GitHub OIDC Provider.
Default: ""
Type: String
OIDCAudience:
Description: Audience supplied to configure-aws-credentials.
Default: "sts.amazonaws.com"
Type: String
Conditions:
CreateOIDCProvider: !Equals
@@ -369,8 +169,6 @@ Resources:
- !Ref GithubOidc
- !Ref OIDCProviderArn
Condition:
StringEquals:
token.actions.githubusercontent.com:aud: !Ref OIDCAudience
StringLike:
token.actions.githubusercontent.com:sub: !Sub repo:${GitHubOrg}/${RepositoryName}:*
@@ -382,21 +180,16 @@ Resources:
ClientIdList:
- sts.amazonaws.com
ThumbprintList:
- ffffffffffffffffffffffffffffffffffffffff
- 6938fd4d98bab03faadb97b34396831e3780aea1
Outputs:
Role:
Value: !GetAtt Role.Arn
```
### Claims and scoping permissions
To align with the Amazon IAM best practice of [granting least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege), the assume role policy document should contain a [`Condition`](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html) that specifies a subject (`sub`) allowed to assume the role. [GitHub also recommends](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#defining-trust-conditions-on-cloud-roles-using-oidc-claims) filtering for the correct audience (`aud`). See [AWS IAM documentation](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_iam-condition-keys.html#condition-keys-wif) on which claims you can filter for in your trust policies.
The GitHub OIDC Provider only needs to be created once per account (i.e. multiple IAM Roles that can be assumed by the GitHub's OIDC can share a single OIDC Provider).
Without a subject (`sub`) condition, any GitHub user or repository could potentially assume the role. The subject can be scoped to a GitHub organization and repository as shown in the CloudFormation template. However, scoping it down to your org and repo may cause the role assumption to fail in some cases. See [Example subject claims](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#example-subject-claims) for specific details on what the subject value will be depending on your workflow. You can also [customize your subject claim](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#customizing-the-token-claims) if you want full control over the information you can filter for in your trust policy. If you aren't sure what your subject (`sub`) key is, you can add the [`actions-oidc-debugger`](https://github.com/github/actions-oidc-debugger) action to your workflow to see the value of the subject (`sub`) key, as well as other claims.
Additional claim conditions can be added for higher specificity as explained in the [GitHub documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect). Due to implementation details, not every OIDC claim is presently supported by IAM.
### Further info
To align with the Amazon IAM best practice of [granting least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege), the assume role policy document should contain a [`Condition`](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html) that specifies a subject allowed to assume the role. Without a subject condition, any GitHub user or repository could potentially assume the role. The subject can be scoped to a GitHub organization and repository as shown in the CloudFormation template. Additional claim conditions can be added for higher specificity as explained in the [GitHub docs](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect).
For further information on OIDC and GitHub Actions, please see:
@@ -406,155 +199,77 @@ For further information on OIDC and GitHub Actions, please see:
* [GitHub docs: Configuring OpenID Connect in Amazon Web Services](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services)
* [GitHub changelog: GitHub Actions: Secure cloud deployments with OpenID Connect](https://github.blog/changelog/2021-10-27-github-actions-secure-cloud-deployments-with-openid-connect/)
### Session tagging
The session will have the name "GitHubActions" and be tagged with the following tags:
(`GITHUB_` environment variable definitions can be [found here](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/using-environment-variables#default-environment-variables))
| Key | Value|
| --- | --- |
| GitHub | "Actions" |
| Repository | GITHUB_REPOSITORY |
| Workflow | GITHUB_WORKFLOW |
| Action | GITHUB_ACTION |
| Actor | GITHUB_ACTOR |
| Branch | GITHUB_REF |
| Commit | GITHUB_SHA |
_Note: all tag values must conform to [the requirements](https://docs.aws.amazon.com/STS/latest/APIReference/API_Tag.html). Particularly, `GITHUB_WORKFLOW` will be truncated if it's too long. If `GITHUB_ACTOR` or `GITHUB_WORKFLOW` contain invalid characters, the characters will be replaced with an '*'._
The action will use session tagging by default during role assumption.
Note that for WebIdentity role assumption, the session tags have to be included in the encoded WebIdentity token.
This means that Tags can only be supplied by the OIDC provider and not set during the AssumeRoleWithWebIdentity API call within the Action.
You can skip this session tagging by providing `role-skip-session-tagging` as true in the action's inputs:
```yaml
uses: aws-actions/configure-aws-credentials@v1
with:
role-skip-session-tagging: true
```
## Self-Hosted Runners
If you run your GitHub Actions in a
[self-hosted runner](https://help.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners) that already has access to AWS credentials, such as
an EC2 instance, then you do not need to provide IAM user access key credentials
to this action. We will use the standard AWS JavaScript SDK credential
resolution methods to find your credentials, so if the AWS JS SDK can
authenticate on your runner, this Action will as well.
If you run your GitHub Actions in a [self-hosted runner](https://help.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners) that already has access to AWS credentials, such as an EC2 instance, then you do not need to provide IAM user access key credentials to this action.
If no access key credentials are given in the action inputs, this action will
use credentials from the runner environment using the
[default methods for the AWS SDK for Javascript](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html).
If no access key credentials are given in the action inputs, this action will use credentials from the runner environment using the [default methods for the AWS SDK for Javascript](https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-credentials-node.html).
You can use this action to simply configure the region and account ID in the
environment, and then use the runner's credentials for all AWS API calls made by
your Actions workflow:
You can use this action to simply configure the region and account ID in the environment, and then use the runner's credentials for all AWS API calls made by your Actions workflow:
```yaml
uses: aws-actions/configure-aws-credentials@v4
uses: aws-actions/configure-aws-credentials@v1
with:
aws-region: us-east-2
```
In this case, your runner's credentials must have permissions to call any AWS
APIs called by your Actions workflow.
In this case, your runner's credentials must have permissions to call any AWS APIs called by your Actions workflow.
Or, you can use this action to assume a role, and then use the role credentials
for all AWS API calls made by your Actions workflow:
Or, you can use this action to assume a role, and then use the role credentials for all AWS API calls made by your Actions workflow:
```yaml
uses: aws-actions/configure-aws-credentials@v4
uses: aws-actions/configure-aws-credentials@v1
with:
aws-region: us-east-2
role-to-assume: my-github-actions-role
```
In this case, your runner's credentials must have permissions to assume the
role.
In this case, your runner's credentials must have permissions to assume the role.
You can also assume a role using a web identity token file, such as if using
[Amazon EKS IRSA](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts-technical-overview.html). Pods running in EKS
worker nodes that do not run as root can use this file to assume a role with a
web identity.
You can also assume a role using a web identity token file, such as if using [Amazon EKS IRSA](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts-technical-overview.html).
Pods running in EKS worker nodes that do not run as root can use this file to assume a role with a web identity.
### Proxy Configuration
If you run in self-hosted environments and in secured environment where you need
use a specific proxy you can set it in the action manually.
Additionally this action will always consider already configured proxy in the
environment.
Manually configured proxy:
You can configure your workflow as follows in order to use this file:
```yaml
uses: aws-actions/configure-aws-credentials@v4
uses: aws-actions/configure-aws-credentials@v1
with:
aws-region: us-east-2
role-to-assume: my-github-actions-role
http-proxy: "http://companydomain.com:3128"
web-identity-token-file: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
```
Proxy configured in the environment variable:
```bash
# Your environment configuration
HTTP_PROXY="http://companydomain.com:3128"
```
The action will read the underlying proxy configuration from the environment and
you don't need to configure it in the action.
### Use with the AWS CLI
This workflow does _not_ install the [AWS CLI](https://aws.amazon.com/cli/)
into your environment. Self-hosted runners that intend to run this action prior
to executing `aws` commands need to have the AWS CLI
[installed](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html)
if it's not already present.
Most [GitHub hosted runner environments](https://github.com/actions/virtual-environments)
should include the AWS CLI by default.
## Examples
### AssumeRoleWithWebIdentity (recommended)
```yaml
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: us-east-2
role-to-assume: arn:aws:iam::123456789100:role/my-github-actions-role
role-session-name: MySessionName
```
In this example, the Action will load the OIDC token from the GitHub-provided environment variable and use it to assume the role `arn:aws:iam::123456789100:role/my-github-actions-role` with the session name `MySessionName`.
### AssumeRole with role previously assumed by action in same workflow
```yaml
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: us-east-2
role-to-assume: arn:aws:iam::123456789100:role/my-github-actions-role
role-session-name: MySessionName
- name: Configure other AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: us-east-2
role-to-assume: arn:aws:iam::987654321000:role/my-second-role
role-session-name: MySessionName
role-chaining: true
```
In this two-step example, the first step will use OIDC to assume the role `arn:aws:iam::123456789100:role/my-github-actions-role` just as in the prior example. Following that, a second step will use this role to assume a different role, `arn:aws:iam::987654321000:role/my-second-role`.
### AssumeRole with static IAM credentials in repository secrets
```yaml
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-2
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
role-external-id: ${{ secrets.AWS_ROLE_EXTERNAL_ID }}
role-duration-seconds: 1200
role-session-name: MySessionName
```
In this example, the secret `AWS_ROLE_TO_ASSUME` contains a string like `arn:aws:iam::123456789100:role/my-github-actions-role`. To assume a role in the same account as the static credentials, you can simply specify the role name, like `role-to-assume: my-github-actions-role`.
### Retrieving credentials from step output, AssumeRole with temporary credentials
```yaml
- name: Configure AWS Credentials 1
id: creds
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: us-east-2
role-to-assume: arn:aws:iam::123456789100:role/my-github-actions-role
output-credentials: true
- name: get caller identity 1
run: |
aws sts get-caller-identity
- name: Configure AWS Credentials 2
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: us-east-2
aws-access-key-id: ${{ steps.creds.outputs.aws-access-key-id }}
aws-secret-access-key: ${{ steps.creds.outputs.aws-secret-access-key }}
aws-session-token: ${{ steps.creds.outputs.aws-session-token }}
role-to-assume: arn:aws:iam::123456789100:role/my-other-github-actions-role
- name: get caller identity2
run: |
aws sts get-caller-identity
```
This example shows that you can reference the fetched credentials as outputs if `output-credentials` is set to true. This example also shows that you can use the `aws-session-token` input in a situation where session tokens are fetched and passed to this action.
This workflow does _not_ install the [AWS CLI](https://aws.amazon.com/cli/) into your environment. Self-hosted runners that intend to run this action prior to executing `aws` commands need to have the AWS CLI [installed](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html) if it's not already present.
Most [GitHub hosted runner environments](https://github.com/actions/virtual-environments) should include the AWS CLI by default.
## License Summary
This code is made available under the MIT license.
## Security Disclosures
If you would like to report a potential security issue in this project, please do not create a GitHub issue. Instead, please follow the instructions [here](https://aws.amazon.com/security/vulnerability-reporting/) or [email AWS security directly](mailto:aws-security@amazon.com).
+215 -11453
View File
File diff suppressed because it is too large Load Diff
+45 -65
View File
@@ -1,84 +1,64 @@
name: '"Configure AWS Credentials" Action for GitHub Actions'
description: Configures AWS credentials for use in subsequent steps in a GitHub Action workflow
runs:
using: node20
main: dist/index.js
post: dist/cleanup/index.js
name: '"Configure AWS Credentials" Action For GitHub Actions'
description: 'Configure AWS credential and region environment variables for use with the AWS CLI and AWS SDKs'
branding:
color: orange
icon: cloud
icon: 'cloud'
color: 'orange'
inputs:
aws-region:
description: AWS Region, e.g. us-east-2
required: true
role-to-assume:
description: The Amazon Resource Name (ARN) of the role to assume. Use the provided credentials to assume an IAM role and configure the Actions environment with the assumed role credentials rather than with the provided credentials.
audience:
default: 'sts.amazonaws.com'
description: 'The audience to use for the OIDC provider'
required: false
aws-access-key-id:
description: AWS Access Key ID. Provide this key if you want to assume a role using access keys rather than a web identity token.
description: >-
AWS Access Key ID. This input is required if running in the GitHub hosted environment.
It is optional if running in a self-hosted environment that already has AWS credentials,
for example on an EC2 instance.
required: false
aws-secret-access-key:
description: AWS Secret Access Key. Required if aws-access-key-id is provided.
description: >-
AWS Secret Access Key. This input is required if running in the GitHub hosted environment.
It is optional if running in a self-hosted environment that already has AWS credentials,
for example on an EC2 instance.
required: false
aws-session-token:
description: AWS Session Token.
description: 'AWS Session Token'
required: false
aws-region:
description: 'AWS Region, e.g. us-east-2'
required: true
mask-aws-account-id:
description: >-
Whether to set the AWS account ID for these credentials as a secret value,
so that it is masked in logs. Valid values are 'true' and 'false'.
Defaults to true
required: false
role-to-assume:
description: >-
Use the provided credentials to assume an IAM role and configure the Actions
environment with the assumed role credentials rather than with the provided
credentials
required: false
web-identity-token-file:
description: Use the web identity token file from the provided file system path in order to assume an IAM role using a web identity, e.g. from within an Amazon EKS worker node.
required: false
role-chaining:
description: Use existing credentials from the environment to assume a new role, rather than providing credentials as input.
required: false
audience:
description: The audience to use for the OIDC provider
required: false
default: sts.amazonaws.com
http-proxy:
description: Proxy to use for the AWS SDK agent
required: false
mask-aws-account-id:
description: Whether to mask the AWS account ID for these credentials as a secret value. By default the account ID will not be masked
description: >-
Use the web identity token file from the provided file system path in order to
assume an IAM role using a web identity. E.g., from within an Amazon EKS worker node
required: false
role-duration-seconds:
description: Role duration in seconds. Default is one hour.
required: false
role-external-id:
description: The external ID of the role to assume.
description: "Role duration in seconds (default: 6 hours, 1 hour for OIDC/specified aws-session-token)"
required: false
role-session-name:
description: "Role session name (default: GitHubActions)"
description: 'Role session name (default: GitHubActions)'
required: false
role-external-id:
description: 'The external ID of the role to assume'
required: false
role-skip-session-tagging:
description: Skip session tagging during role assumption
required: false
inline-session-policy:
description: Define an inline session policy to use when assuming a role
required: false
managed-session-policies:
description: Define a list of managed session policies to use when assuming a role
required: false
output-credentials:
description: Whether to set credentials as step output
required: false
unset-current-credentials:
description: Whether to unset the existing credentials in your runner. May be useful if you run this action multiple times in the same job
required: false
disable-retry:
description: Whether to disable the retry and backoff mechanism when the assume role call fails. By default the retry mechanism is enabled
required: false
retry-max-attempts:
description: The maximum number of attempts it will attempt to retry the assume role call. By default it will retry 12 times
required: false
special-characters-workaround:
description: Some environments do not support special characters in AWS_SECRET_ACCESS_KEY. This option will retry fetching credentials until the secret access key does not contain special characters. This option overrides disable-retry and retry-max-attempts. This option is disabled by default
description: 'Skip session tagging during role assumption'
required: false
outputs:
aws-account-id:
description: The AWS account ID for the provided credentials
aws-access-key-id:
description: The AWS access key ID for the provided credentials
aws-secret-access-key:
description: The AWS secret access key for the provided credentials
aws-session-token:
description: The AWS session token for the provided credentials
description: 'The AWS account ID for the provided credentials'
runs:
using: 'node16'
main: 'dist/index.js'
post: 'dist/cleanup/index.js'
+10 -11
View File
@@ -1,5 +1,4 @@
import * as core from '@actions/core';
import { errorMessage } from '../helpers';
const core = require('@actions/core');
/**
* When the GitHub Actions job is done, clean up any environment variables that
@@ -12,7 +11,7 @@ import { errorMessage } from '../helpers';
* with any other jobs.
*/
export function cleanup() {
async function cleanup() {
try {
// The GitHub Actions toolkit does not have an option to completely unset
// environment variables, so we overwrite the current value with an empty
@@ -23,15 +22,15 @@ export function cleanup() {
core.exportVariable('AWS_SESSION_TOKEN', '');
core.exportVariable('AWS_DEFAULT_REGION', '');
core.exportVariable('AWS_REGION', '');
} catch (error) {
core.setFailed(errorMessage(error));
}
catch (error) {
core.setFailed(error.message);
}
}
/* c8 ignore start */
module.exports = cleanup;
/* istanbul ignore next */
if (require.main === module) {
try {
cleanup();
} catch (error) {
core.setFailed(errorMessage(error));
}
cleanup();
}
+51
View File
@@ -0,0 +1,51 @@
const core = require('@actions/core');
const cleanup = require('./cleanup.js');
jest.mock('@actions/core');
const FAKE_ACCESS_KEY_ID = 'MY-AWS-ACCESS-KEY-ID';
const FAKE_SECRET_ACCESS_KEY = 'MY-AWS-SECRET-ACCESS-KEY';
const FAKE_SESSION_TOKEN = 'MY-AWS-SESSION-TOKEN';
const FAKE_REGION = 'fake-region-1';
const ACTION_ENVIRONMENT_VARIABLES = {
AWS_ACCESS_KEY_ID: FAKE_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY: FAKE_SECRET_ACCESS_KEY,
AWS_SESSION_TOKEN: FAKE_SESSION_TOKEN,
AWS_DEFAULT_REGION: FAKE_REGION,
AWS_REGION: FAKE_REGION,
};
describe('Configure AWS Credentials', () => {
const OLD_ENV = process.env;
beforeEach(() => {
jest.resetModules();
process.env = {...OLD_ENV, ...ACTION_ENVIRONMENT_VARIABLES};
});
afterEach(() => {
process.env = OLD_ENV;
});
test('replaces AWS credential and region env vars with empty strings', async () => {
await cleanup();
expect(core.setFailed).toHaveBeenCalledTimes(0);
expect(core.exportVariable).toHaveBeenCalledTimes(5);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_ACCESS_KEY_ID', '');
expect(core.exportVariable).toHaveBeenCalledWith('AWS_SECRET_ACCESS_KEY', '');
expect(core.exportVariable).toHaveBeenCalledWith('AWS_SESSION_TOKEN', '');
expect(core.exportVariable).toHaveBeenCalledWith('AWS_DEFAULT_REGION', '');
expect(core.exportVariable).toHaveBeenCalledWith('AWS_REGION', '');
});
test('error is caught and fails the action', async () => {
core.exportVariable.mockReset();
core.exportVariable.mockImplementation(() => {
throw new Error();
});
await cleanup();
expect(core.setFailed).toBeCalled();
});
});
+142 -18881
View File
File diff suppressed because it is too large Load Diff
-14
View File
@@ -1,14 +0,0 @@
import { STSClient } from '@aws-sdk/client-sts';
export interface CredentialsClientProps {
region?: string;
proxyServer?: string;
}
export declare class CredentialsClient {
region?: string;
private _stsClient?;
private readonly requestHandler?;
constructor(props: CredentialsClientProps);
get stsClient(): STSClient;
validateCredentials(expectedAccessKeyId?: string, roleChaining?: boolean): Promise<void>;
private loadCredentials;
}
-15
View File
@@ -1,15 +0,0 @@
import type { CredentialsClient } from './CredentialsClient';
export interface assumeRoleParams {
credentialsClient: CredentialsClient;
roleToAssume: string;
roleDuration: number;
roleSessionName: string;
roleSkipSessionTagging?: boolean;
sourceAccountId?: string;
roleExternalId?: string;
webIdentityTokenFile?: string;
webIdentityToken?: string;
inlineSessionPolicy?: string;
managedSessionPolicies?: any[];
}
export declare function assumeRole(params: assumeRoleParams): Promise<import("@aws-sdk/client-sts").AssumeRoleCommandOutput>;
-11
View File
@@ -1,11 +0,0 @@
/**
* When the GitHub Actions job is done, clean up any environment variables that
* may have been set by the configure-aws-credentials steps in the job.
*
* Environment variables are not intended to be shared across different jobs in
* the same GitHub Actions workflow: GitHub Actions documentation states that
* each job runs in a fresh instance. However, doing our own cleanup will
* give us additional assurance that these environment variables are not shared
* with any other jobs.
*/
export declare function cleanup(): void;
-16
View File
@@ -1,16 +0,0 @@
import type { Credentials } from '@aws-sdk/client-sts';
import type { CredentialsClient } from './CredentialsClient';
export declare function exportCredentials(creds?: Partial<Credentials>, outputCredentials?: boolean): void;
export declare function unsetCredentials(): void;
export declare function exportRegion(region: string): void;
export declare function exportAccountId(credentialsClient: CredentialsClient, maskAccountId?: boolean): Promise<string>;
export declare function sanitizeGitHubVariables(name: string): string;
export declare function defaultSleep(ms: number): Promise<unknown>;
declare let sleep: typeof defaultSleep;
export declare function withsleep(s: typeof sleep): void;
export declare function reset(): void;
export declare function verifyKeys(creds: Partial<Credentials> | undefined): boolean;
export declare function retryAndBackoff<T>(fn: () => Promise<T>, isRetryable: boolean, maxRetries?: number, retries?: number, base?: number): Promise<T>;
export declare function errorMessage(error: unknown): string;
export declare function isDefined<T>(i: T | undefined | null): i is T;
export {};
-1
View File
@@ -1 +0,0 @@
export declare function run(): Promise<void>;
-1
View File
@@ -1 +0,0 @@
export {};
-1
View File
@@ -1 +0,0 @@
export {};
-1
View File
@@ -1 +0,0 @@
export {};
+42372 -20148
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
uses: aws-actions/configure-aws-credentials@v1-node16
with:
aws-region: us-east-1
## the following creates an ARN based on the values entered into github secrets
+1 -1
View File
@@ -1,6 +1,6 @@
# federated-setup
## [github-action-oidc-federation](./github-actions-oidc-federation.yml)
## [github-action-oidc-federation](./github-actions-odic-federation.yml)
Setup of the OIDC federation between your GitHub Organization/repository and your AWS account.
+380
View File
@@ -0,0 +1,380 @@
const core = require('@actions/core');
const aws = require('aws-sdk');
const assert = require('assert');
const fs = require('fs');
const path = require('path');
// Use 1hr as role duration when using session token or OIDC
// Otherwise, use the max duration of GitHub action (6hr)
const MAX_ACTION_RUNTIME = 6 * 3600;
const SESSION_ROLE_DURATION = 3600;
const DEFAULT_ROLE_DURATION_FOR_OIDC_ROLES = 3600;
const USER_AGENT = 'configure-aws-credentials-for-github-actions';
const MAX_TAG_VALUE_LENGTH = 256;
const SANITIZATION_CHARACTER = '_';
const ROLE_SESSION_NAME = 'GitHubActions';
const REGION_REGEX = /^[a-z0-9-]+$/g;
async function assumeRole(params) {
// Assume a role to get short-lived credentials using longer-lived credentials.
const isDefined = i => !!i;
const {
sourceAccountId,
roleToAssume,
roleExternalId,
roleDurationSeconds,
roleSessionName,
region,
roleSkipSessionTagging,
webIdentityTokenFile,
webIdentityToken
} = params;
assert(
[roleToAssume, roleDurationSeconds, roleSessionName, region].every(isDefined),
"Missing required input when assuming a Role."
);
const {GITHUB_REPOSITORY, GITHUB_WORKFLOW, GITHUB_ACTION, GITHUB_ACTOR, GITHUB_SHA} = process.env;
assert(
[GITHUB_REPOSITORY, GITHUB_WORKFLOW, GITHUB_ACTION, GITHUB_ACTOR, GITHUB_SHA].every(isDefined),
'Missing required environment value. Are you running in GitHub Actions?'
);
const sts = getStsClient(region);
let roleArn = roleToAssume;
if (!roleArn.startsWith('arn:aws')) {
// Supports only 'aws' partition. Customers in other partitions ('aws-cn') will need to provide full ARN
assert(
isDefined(sourceAccountId),
"Source Account ID is needed if the Role Name is provided and not the Role Arn."
);
roleArn = `arn:aws:iam::${sourceAccountId}:role/${roleArn}`;
}
const tagArray = [
{Key: 'GitHub', Value: 'Actions'},
{Key: 'Repository', Value: GITHUB_REPOSITORY},
{Key: 'Workflow', Value: sanitizeGithubWorkflowName(GITHUB_WORKFLOW)},
{Key: 'Action', Value: GITHUB_ACTION},
{Key: 'Actor', Value: sanitizeGithubActor(GITHUB_ACTOR)},
{Key: 'Commit', Value: GITHUB_SHA},
];
if (isDefined(process.env.GITHUB_REF)) {
tagArray.push({Key: 'Branch', Value: process.env.GITHUB_REF});
}
const roleSessionTags = roleSkipSessionTagging ? undefined : tagArray;
if(roleSessionTags == undefined){
core.debug("Role session tagging has been skipped.")
} else {
core.debug(roleSessionTags.length + " role session tags are being used.")
}
const assumeRoleRequest = {
RoleArn: roleArn,
RoleSessionName: roleSessionName,
DurationSeconds: roleDurationSeconds,
Tags: roleSessionTags
};
if (roleExternalId) {
assumeRoleRequest.ExternalId = roleExternalId;
}
let assumeFunction = sts.assumeRole.bind(sts);
// These are customizations needed for the GH OIDC Provider
if(isDefined(webIdentityToken)) {
delete assumeRoleRequest.Tags;
assumeRoleRequest.WebIdentityToken = webIdentityToken;
assumeFunction = sts.assumeRoleWithWebIdentity.bind(sts);
} else if(isDefined(webIdentityTokenFile)) {
core.debug("webIdentityTokenFile provided. Will call sts:AssumeRoleWithWebIdentity and take session tags from token contents.");
delete assumeRoleRequest.Tags;
const webIdentityTokenFilePath = path.isAbsolute(webIdentityTokenFile) ?
webIdentityTokenFile :
path.join(process.env.GITHUB_WORKSPACE, webIdentityTokenFile);
if (!fs.existsSync(webIdentityTokenFilePath)) {
throw new Error(`Web identity token file does not exist: ${webIdentityTokenFilePath}`);
}
try {
assumeRoleRequest.WebIdentityToken = await fs.promises.readFile(webIdentityTokenFilePath, 'utf8');
assumeFunction = sts.assumeRoleWithWebIdentity.bind(sts);
} catch(error) {
throw new Error(`Web identity token file could not be read: ${error.message}`);
}
}
return assumeFunction(assumeRoleRequest)
.promise()
.then(function (data) {
return {
accessKeyId: data.Credentials.AccessKeyId,
secretAccessKey: data.Credentials.SecretAccessKey,
sessionToken: data.Credentials.SessionToken,
};
});
}
function sanitizeGithubActor(actor) {
// In some circumstances the actor may contain square brackets. For example, if they're a bot ('[bot]')
// Square brackets are not allowed in AWS session tags
return actor.replace(/\[|\]/g, SANITIZATION_CHARACTER)
}
function sanitizeGithubWorkflowName(name) {
// Workflow names can be almost any valid UTF-8 string, but tags are more restrictive.
// This replaces anything not conforming to the tag restrictions by inverting the regular expression.
// See the AWS documentation for constraint specifics https://docs.aws.amazon.com/STS/latest/APIReference/API_Tag.html.
const nameWithoutSpecialCharacters = name.replace(/[^\p{L}\p{Z}\p{N}_:/=+.-@-]/gu, SANITIZATION_CHARACTER);
const nameTruncated = nameWithoutSpecialCharacters.slice(0, MAX_TAG_VALUE_LENGTH)
return nameTruncated
}
function exportCredentials(params){
// Configure the AWS CLI and AWS SDKs using environment variables and set them as secrets.
// Setting the credentials as secrets masks them in Github Actions logs
const {accessKeyId, secretAccessKey, sessionToken} = params;
// AWS_ACCESS_KEY_ID:
// Specifies an AWS access key associated with an IAM user or role
core.setSecret(accessKeyId);
core.exportVariable('AWS_ACCESS_KEY_ID', accessKeyId);
// AWS_SECRET_ACCESS_KEY:
// Specifies the secret key associated with the access key. This is essentially the "password" for the access key.
core.setSecret(secretAccessKey);
core.exportVariable('AWS_SECRET_ACCESS_KEY', secretAccessKey);
// AWS_SESSION_TOKEN:
// Specifies the session token value that is required if you are using temporary security credentials.
if (sessionToken) {
core.setSecret(sessionToken);
core.exportVariable('AWS_SESSION_TOKEN', sessionToken);
} else if (process.env.AWS_SESSION_TOKEN) {
// clear session token from previous credentials action
core.exportVariable('AWS_SESSION_TOKEN', '');
}
}
function exportRegion(region) {
// AWS_DEFAULT_REGION and AWS_REGION:
// Specifies the AWS Region to send requests to
core.exportVariable('AWS_DEFAULT_REGION', region);
core.exportVariable('AWS_REGION', region);
}
async function exportAccountId(maskAccountId, region) {
// Get the AWS account ID
const sts = getStsClient(region);
const identity = await sts.getCallerIdentity().promise();
const accountId = identity.Account;
if (!maskAccountId || maskAccountId.toLowerCase() == 'true') {
core.setSecret(accountId);
}
core.setOutput('aws-account-id', accountId);
return accountId;
}
function loadCredentials() {
// Force the SDK to re-resolve credentials with the default provider chain.
//
// This action typically sets credentials in the environment via environment variables.
// The SDK never refreshes those env-var-based credentials after initial load.
// In case there were already env-var creds set in the actions environment when this action
// loaded, this action needs to refresh the SDK creds after overwriting those environment variables.
//
// The credentials object needs to be entirely recreated (instead of simply refreshed),
// because the credential object type could change when this action writes env var creds.
// For example, the first load could return EC2 instance metadata credentials
// in a self-hosted runner, and the second load could return environment credentials
// from an assume-role call in this action.
aws.config.credentials = null;
return new Promise((resolve, reject) => {
aws.config.getCredentials((err) => {
if (err) {
reject(err);
}
resolve(aws.config.credentials);
})
});
}
async function validateCredentials(expectedAccessKeyId) {
let credentials;
try {
credentials = await loadCredentials();
if (!credentials.accessKeyId) {
throw new Error('Access key ID empty after loading credentials');
}
} catch (error) {
throw new Error(`Credentials could not be loaded, please check your action inputs: ${error.message}`);
}
const actualAccessKeyId = credentials.accessKeyId;
if (expectedAccessKeyId && expectedAccessKeyId != actualAccessKeyId) {
throw new Error('Unexpected failure: Credentials loaded by the SDK do not match the access key ID configured by the action');
}
}
function getStsClient(region) {
return new aws.STS({
region,
stsRegionalEndpoints: 'regional',
customUserAgent: USER_AGENT
});
}
let defaultSleep = function (ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
};
let sleep = defaultSleep;
// retryAndBackoff retries with exponential backoff the promise if the error isRetryable upto maxRetries time.
const retryAndBackoff = async (fn, isRetryable, retries = 0, maxRetries = 12, base = 50) => {
try {
return await fn();
} catch (err) {
if (!isRetryable) {
throw err;
}
// It's retryable, so sleep and retry.
await sleep(Math.random() * (Math.pow(2, retries) * base) );
retries += 1;
if (retries === maxRetries) {
throw err;
}
return await retryAndBackoff(fn, isRetryable, retries, maxRetries, base);
}
}
async function run() {
try {
// Get inputs
const accessKeyId = core.getInput('aws-access-key-id', { required: false });
const audience = core.getInput('audience', { required: false });
const secretAccessKey = core.getInput('aws-secret-access-key', { required: false });
const region = core.getInput('aws-region', { required: true });
const sessionToken = core.getInput('aws-session-token', { required: false });
const maskAccountId = core.getInput('mask-aws-account-id', { required: false });
const roleToAssume = core.getInput('role-to-assume', {required: false});
const roleExternalId = core.getInput('role-external-id', { required: false });
let roleDurationSeconds = core.getInput('role-duration-seconds', {required: false})
|| (sessionToken && SESSION_ROLE_DURATION)
|| MAX_ACTION_RUNTIME;
const roleSessionName = core.getInput('role-session-name', { required: false }) || ROLE_SESSION_NAME;
const roleSkipSessionTaggingInput = core.getInput('role-skip-session-tagging', { required: false })|| 'false';
const roleSkipSessionTagging = roleSkipSessionTaggingInput.toLowerCase() === 'true';
const webIdentityTokenFile = core.getInput('web-identity-token-file', { required: false });
if (!region.match(REGION_REGEX)) {
throw new Error(`Region is not valid: ${region}`);
}
exportRegion(region);
// This wraps the logic for deciding if we should rely on the GH OIDC provider since we may need to reference
// the decision in a few differennt places. Consolidating it here makes the logic clearer elsewhere.
const useGitHubOIDCProvider = () => {
// The assumption here is that self-hosted runners won't be populating the `ACTIONS_ID_TOKEN_REQUEST_TOKEN`
// environment variable and they won't be providing a web idenity token file or access key either.
// V2 of the action might relax this a bit and create an explicit precedence for these so that customers
// can provide as much info as they want and we will follow the established credential loading precedence.
return roleToAssume && process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN && !accessKeyId && !webIdentityTokenFile
}
// Always export the source credentials and account ID.
// The STS client for calling AssumeRole pulls creds from the environment.
// Plus, in the assume role case, if the AssumeRole call fails, we want
// the source credentials and account ID to already be masked as secrets
// in any error messages.
if (accessKeyId) {
if (!secretAccessKey) {
throw new Error("'aws-secret-access-key' must be provided if 'aws-access-key-id' is provided");
}
exportCredentials({accessKeyId, secretAccessKey, sessionToken});
}
// Attempt to load credentials from the GitHub OIDC provider.
// If a user provides an IAM Role Arn and DOESN'T provide an Access Key Id
// The only way to assume the role is via GitHub's OIDC provider.
let sourceAccountId;
let webIdentityToken;
if(useGitHubOIDCProvider()) {
webIdentityToken = await core.getIDToken(audience);
roleDurationSeconds = core.getInput('role-duration-seconds', {required: false}) || DEFAULT_ROLE_DURATION_FOR_OIDC_ROLES;
// We don't validate the credentials here because we don't have them yet when using OIDC.
} else {
// Regardless of whether any source credentials were provided as inputs,
// validate that the SDK can actually pick up credentials. This validates
// cases where this action is on a self-hosted runner that doesn't have credentials
// configured correctly, and cases where the user intended to provide input
// credentials but the secrets inputs resolved to empty strings.
await validateCredentials(accessKeyId);
sourceAccountId = await exportAccountId(maskAccountId, region);
}
// Get role credentials if configured to do so
if (roleToAssume) {
const roleCredentials = await retryAndBackoff(
async () => { return await assumeRole({
sourceAccountId,
region,
roleToAssume,
roleExternalId,
roleDurationSeconds,
roleSessionName,
roleSkipSessionTagging,
webIdentityTokenFile,
webIdentityToken
}) }, true);
exportCredentials(roleCredentials);
// We need to validate the credentials in 2 of our use-cases
// First: self-hosted runners. If the GITHUB_ACTIONS environment variable
// is set to `true` then we are NOT in a self-hosted runner.
// Second: Customer provided credentials manually (IAM User keys stored in GH Secrets)
if (!process.env.GITHUB_ACTIONS || accessKeyId) {
await validateCredentials(roleCredentials.accessKeyId);
}
await exportAccountId(maskAccountId, region);
}
}
catch (error) {
core.setFailed(error.message);
const showStackTrace = process.env.SHOW_STACK_TRACE;
if (showStackTrace === 'true') {
throw(error)
}
}
}
exports.withSleep = function (s) {
sleep = s;
};
exports.reset = function () {
sleep = defaultSleep;
};
exports.run = run
/* istanbul ignore next */
if (require.main === module) {
run();
}
+807
View File
@@ -0,0 +1,807 @@
const core = require('@actions/core');
const assert = require('assert');
const aws = require('aws-sdk');
const { run, withSleep, reset } = require('./index.js');
jest.mock('@actions/core');
const FAKE_ACCESS_KEY_ID = 'MY-AWS-ACCESS-KEY-ID';
const FAKE_SECRET_ACCESS_KEY = 'MY-AWS-SECRET-ACCESS-KEY';
const FAKE_SESSION_TOKEN = 'MY-AWS-SESSION-TOKEN';
const FAKE_STS_ACCESS_KEY_ID = 'STS-AWS-ACCESS-KEY-ID';
const FAKE_STS_SECRET_ACCESS_KEY = 'STS-AWS-SECRET-ACCESS-KEY';
const FAKE_STS_SESSION_TOKEN = 'STS-AWS-SESSION-TOKEN';
const FAKE_REGION = 'fake-region-1';
const FAKE_ACCOUNT_ID = '123456789012';
const FAKE_ROLE_ACCOUNT_ID = '111111111111';
const ROLE_NAME = 'MY-ROLE';
const ROLE_ARN = 'arn:aws:iam::111111111111:role/MY-ROLE';
const ENVIRONMENT_VARIABLE_OVERRIDES = {
SHOW_STACK_TRACE: 'true',
GITHUB_REPOSITORY: 'MY-REPOSITORY-NAME',
GITHUB_WORKFLOW: 'MY-WORKFLOW-ID',
GITHUB_ACTION: 'MY-ACTION-NAME',
GITHUB_ACTOR: 'MY-USERNAME[bot]',
GITHUB_SHA: 'MY-COMMIT-ID',
GITHUB_REF: 'MY-BRANCH',
GITHUB_WORKSPACE: '/home/github'
};
const GITHUB_ACTOR_SANITIZED = 'MY-USERNAME_bot_'
function mockGetInput(requestResponse) {
return function (name, options) { // eslint-disable-line no-unused-vars
return requestResponse[name]
}
}
const CREDS_INPUTS = {
'aws-access-key-id': FAKE_ACCESS_KEY_ID,
'aws-secret-access-key': FAKE_SECRET_ACCESS_KEY
};
const DEFAULT_INPUTS = {
...CREDS_INPUTS,
'aws-session-token': FAKE_SESSION_TOKEN,
'aws-region': FAKE_REGION,
'mask-aws-account-id': 'TRUE'
};
const ASSUME_ROLE_INPUTS = {...CREDS_INPUTS, 'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION};
const mockStsCallerIdentity = jest.fn();
const mockStsAssumeRole = jest.fn();
const mockStsAssumeRoleWithWebIdentity = jest.fn();
jest.mock('aws-sdk', () => {
return {
config: {
getCredentials: jest.fn()
},
STS: jest.fn(() => ({
getCallerIdentity: mockStsCallerIdentity,
assumeRole: mockStsAssumeRole,
assumeRoleWithWebIdentity: mockStsAssumeRoleWithWebIdentity
}))
};
});
jest.mock('fs', () => {
return {
promises: {
readFile: jest.fn(() => Promise.resolve('testpayload')),
},
existsSync: jest.fn(() => true)
};
});
jest.mock('axios', () => ({
get: jest.fn(() => Promise.resolve({ data: { value: "testtoken" }})),
}));
describe('Configure AWS Credentials', () => {
beforeEach(() => {
jest.resetModules();
process.env = { ...ENVIRONMENT_VARIABLE_OVERRIDES };
jest.clearAllMocks();
core.getInput = jest
.fn()
.mockImplementation(mockGetInput(DEFAULT_INPUTS));
core.getIDToken = jest
.fn()
.mockImplementation(() => {
return "testtoken"
});
mockStsCallerIdentity.mockReset();
mockStsCallerIdentity
.mockReturnValueOnce({
promise() {
return Promise.resolve({ Account: FAKE_ACCOUNT_ID });
}
})
.mockReturnValueOnce({
promise() {
return Promise.resolve({ Account: FAKE_ROLE_ACCOUNT_ID });
}
});
aws.config.getCredentials.mockReset();
aws.config.getCredentials
.mockImplementationOnce(callback => {
if (!aws.config.credentials) {
aws.config.credentials = {
accessKeyId: FAKE_ACCESS_KEY_ID,
secretAccessKey: FAKE_SECRET_ACCESS_KEY
}
}
callback(null);
})
.mockImplementationOnce(callback => {
if (!aws.config.credentials) {
aws.config.credentials = {
accessKeyId: FAKE_STS_ACCESS_KEY_ID,
secretAccessKey: FAKE_STS_SECRET_ACCESS_KEY
}
}
callback(null);
});
mockStsAssumeRole.mockImplementation(() => {
return {
promise() {
return Promise.resolve({
Credentials: {
AccessKeyId: FAKE_STS_ACCESS_KEY_ID,
SecretAccessKey: FAKE_STS_SECRET_ACCESS_KEY,
SessionToken: FAKE_STS_SESSION_TOKEN
}
});
}
}
});
mockStsAssumeRoleWithWebIdentity.mockImplementation(() => {
return {
promise() {
return Promise.resolve({
Credentials: {
AccessKeyId: FAKE_STS_ACCESS_KEY_ID,
SecretAccessKey: FAKE_STS_SECRET_ACCESS_KEY,
SessionToken: FAKE_STS_SESSION_TOKEN
}
});
}
}
});
withSleep(() => {
return Promise.resolve();
});
});
afterEach(() => {
reset();
});
test('exports env vars', async () => {
await run();
expect(mockStsAssumeRole).toHaveBeenCalledTimes(0);
expect(core.exportVariable).toHaveBeenCalledTimes(5);
expect(core.setSecret).toHaveBeenCalledTimes(4);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_ACCESS_KEY_ID', FAKE_ACCESS_KEY_ID);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCESS_KEY_ID);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_SECRET_ACCESS_KEY', FAKE_SECRET_ACCESS_KEY);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_SECRET_ACCESS_KEY);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_SESSION_TOKEN', FAKE_SESSION_TOKEN);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_SESSION_TOKEN);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_DEFAULT_REGION', FAKE_REGION);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_REGION', FAKE_REGION);
expect(core.setOutput).toHaveBeenCalledWith('aws-account-id', FAKE_ACCOUNT_ID);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCOUNT_ID);
});
test('action fails when github env vars are not set', async () => {
process.env.SHOW_STACK_TRACE = 'false';
core.getInput = jest
.fn()
.mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS));
delete process.env.GITHUB_SHA;
await run();
expect(core.setFailed).toHaveBeenCalledWith('Missing required environment value. Are you running in GitHub Actions?');
});
test('action does not require GITHUB_REF env var', async () => {
core.getInput = jest
.fn()
.mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS));
delete process.env.GITHUB_REF;
await run();
});
test('hosted runners can pull creds from a self-hosted environment', async () => {
const mockInputs = {'aws-region': FAKE_REGION};
core.getInput = jest
.fn()
.mockImplementation(mockGetInput(mockInputs));
await run();
expect(mockStsAssumeRole).toHaveBeenCalledTimes(0);
expect(core.exportVariable).toHaveBeenCalledTimes(2);
expect(core.setSecret).toHaveBeenCalledTimes(1);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_DEFAULT_REGION', FAKE_REGION);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_REGION', FAKE_REGION);
expect(core.setOutput).toHaveBeenCalledWith('aws-account-id', FAKE_ACCOUNT_ID);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCOUNT_ID);
});
test('action with no accessible credentials fails', async () => {
process.env.SHOW_STACK_TRACE = 'false';
const mockInputs = {'aws-region': FAKE_REGION};
core.getInput = jest
.fn()
.mockImplementation(mockGetInput(mockInputs));
aws.config.getCredentials.mockReset();
aws.config.getCredentials.mockImplementation(callback => {
callback(new Error('No credentials to load'));
});
await run();
expect(core.setFailed).toHaveBeenCalledWith("Credentials could not be loaded, please check your action inputs: No credentials to load");
});
test('action with empty credentials fails', async () => {
process.env.SHOW_STACK_TRACE = 'false';
const mockInputs = {'aws-region': FAKE_REGION};
core.getInput = jest
.fn()
.mockImplementation(mockGetInput(mockInputs));
aws.config.getCredentials.mockReset();
aws.config.getCredentials.mockImplementation(callback => {
aws.config.credentials = {
accessKeyId: ''
}
callback(null);
});
await run();
expect(core.setFailed).toHaveBeenCalledWith("Credentials could not be loaded, please check your action inputs: Access key ID empty after loading credentials");
});
test('action fails when credentials are not set in the SDK correctly', async () => {
process.env.SHOW_STACK_TRACE = 'false';
core.getInput = jest
.fn()
.mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS));
aws.config.getCredentials.mockReset();
aws.config.getCredentials.mockImplementation(callback => {
aws.config.credentials = {
accessKeyId: FAKE_ACCESS_KEY_ID
}
callback(null);
});
await run();
expect(core.setFailed).toHaveBeenCalledWith("Unexpected failure: Credentials loaded by the SDK do not match the access key ID configured by the action");
});
test('session token is optional', async () => {
const mockInputs = {...CREDS_INPUTS, 'aws-region': 'eu-west-1'};
core.getInput = jest
.fn()
.mockImplementation(mockGetInput(mockInputs));
await run();
expect(mockStsAssumeRole).toHaveBeenCalledTimes(0);
expect(core.exportVariable).toHaveBeenCalledTimes(4);
expect(core.setSecret).toHaveBeenCalledTimes(3);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_ACCESS_KEY_ID', FAKE_ACCESS_KEY_ID);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCESS_KEY_ID);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_SECRET_ACCESS_KEY', FAKE_SECRET_ACCESS_KEY);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_SECRET_ACCESS_KEY);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_DEFAULT_REGION', 'eu-west-1');
expect(core.exportVariable).toHaveBeenCalledWith('AWS_REGION', 'eu-west-1');
expect(core.setOutput).toHaveBeenCalledWith('aws-account-id', FAKE_ACCOUNT_ID);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCOUNT_ID);
});
test('existing env var creds are cleared', async () => {
const mockInputs = {...CREDS_INPUTS, 'aws-region': 'eu-west-1'};
core.getInput = jest
.fn()
.mockImplementation(mockGetInput(mockInputs));
process.env.AWS_ACCESS_KEY_ID = 'foo';
process.env.AWS_SECRET_ACCESS_KEY = 'bar';
process.env.AWS_SESSION_TOKEN = 'helloworld';
aws.config.credentials = {
accessKeyId: 'foo',
secretAccessKey: 'bar',
sessionToken: 'helloworld'
};
await run();
expect(mockStsAssumeRole).toHaveBeenCalledTimes(0);
expect(core.exportVariable).toHaveBeenCalledTimes(5);
expect(core.setSecret).toHaveBeenCalledTimes(3);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_ACCESS_KEY_ID', FAKE_ACCESS_KEY_ID);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCESS_KEY_ID);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_SECRET_ACCESS_KEY', FAKE_SECRET_ACCESS_KEY);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_SECRET_ACCESS_KEY);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_SESSION_TOKEN', '');
expect(core.exportVariable).toHaveBeenCalledWith('AWS_DEFAULT_REGION', 'eu-west-1');
expect(core.exportVariable).toHaveBeenCalledWith('AWS_REGION', 'eu-west-1');
expect(core.setOutput).toHaveBeenCalledWith('aws-account-id', FAKE_ACCOUNT_ID);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCOUNT_ID);
expect(aws.config.credentials.accessKeyId).toBe(FAKE_ACCESS_KEY_ID);
expect(aws.config.credentials.secretAccessKey).toBe(FAKE_SECRET_ACCESS_KEY);
expect(aws.config.credentials.sessionToken).toBeUndefined();
});
test('validates region name', async () => {
process.env.SHOW_STACK_TRACE = 'false';
const mockInputs = {...CREDS_INPUTS, 'aws-region': '$AWS_REGION'};
core.getInput = jest
.fn()
.mockImplementation(mockGetInput(mockInputs));
await run();
expect(core.setFailed).toHaveBeenCalledWith('Region is not valid: $AWS_REGION');
});
test('throws error if access key id exists but missing secret access key', async () => {
process.env.SHOW_STACK_TRACE = 'false';
const inputsWIthoutSecretKey = {...ASSUME_ROLE_INPUTS}
inputsWIthoutSecretKey["aws-secret-access-key"] = undefined
core.getInput = jest
.fn()
.mockImplementation(mockGetInput(inputsWIthoutSecretKey));
await run();
expect(core.setFailed).toHaveBeenCalledWith("'aws-secret-access-key' must be provided if 'aws-access-key-id' is provided");
});
test('can opt out of masking account ID', async () => {
const mockInputs = {...CREDS_INPUTS, 'aws-region': 'us-east-1', 'mask-aws-account-id': 'false'};
core.getInput = jest
.fn()
.mockImplementation(mockGetInput(mockInputs));
await run();
expect(mockStsAssumeRole).toHaveBeenCalledTimes(0);
expect(core.exportVariable).toHaveBeenCalledTimes(4);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_ACCESS_KEY_ID', FAKE_ACCESS_KEY_ID);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCESS_KEY_ID);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_SECRET_ACCESS_KEY', FAKE_SECRET_ACCESS_KEY);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_SECRET_ACCESS_KEY);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_DEFAULT_REGION', 'us-east-1');
expect(core.exportVariable).toHaveBeenCalledWith('AWS_REGION', 'us-east-1');
expect(core.setOutput).toHaveBeenCalledWith('aws-account-id', FAKE_ACCOUNT_ID);
expect(core.setSecret).toHaveBeenCalledTimes(2);
});
test('error is caught by core.setFailed and caught', async () => {
process.env.SHOW_STACK_TRACE = 'false';
mockStsCallerIdentity.mockReset();
mockStsCallerIdentity.mockImplementation(() => {
throw new Error();
});
await run();
expect(core.setFailed).toBeCalled();
});
test('error is caught by core.setFailed and passed', async () => {
mockStsCallerIdentity.mockReset();
mockStsCallerIdentity.mockImplementation(() => {
throw new Error();
});
await assert.rejects(() => run());
expect(core.setFailed).toBeCalled();
});
test('basic role assumption exports', async () => {
core.getInput = jest
.fn()
.mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS));
await run();
expect(mockStsAssumeRole).toHaveBeenCalledTimes(1);
expect(core.exportVariable).toHaveBeenCalledTimes(7);
expect(core.setSecret).toHaveBeenCalledTimes(7);
expect(core.setOutput).toHaveBeenCalledTimes(2);
// first the source credentials are exported and masked
expect(core.setSecret).toHaveBeenNthCalledWith(1, FAKE_ACCESS_KEY_ID);
expect(core.setSecret).toHaveBeenNthCalledWith(2, FAKE_SECRET_ACCESS_KEY);
expect(core.setSecret).toHaveBeenNthCalledWith(3, FAKE_ACCOUNT_ID);
expect(core.exportVariable).toHaveBeenNthCalledWith(1, 'AWS_DEFAULT_REGION', FAKE_REGION);
expect(core.exportVariable).toHaveBeenNthCalledWith(2, 'AWS_REGION', FAKE_REGION);
expect(core.exportVariable).toHaveBeenNthCalledWith(3, 'AWS_ACCESS_KEY_ID', FAKE_ACCESS_KEY_ID);
expect(core.exportVariable).toHaveBeenNthCalledWith(4, 'AWS_SECRET_ACCESS_KEY', FAKE_SECRET_ACCESS_KEY);
expect(core.setOutput).toHaveBeenNthCalledWith(1, 'aws-account-id', FAKE_ACCOUNT_ID);
// then the role credentials are exported and masked
expect(core.setSecret).toHaveBeenNthCalledWith(4, FAKE_STS_ACCESS_KEY_ID);
expect(core.setSecret).toHaveBeenNthCalledWith(5, FAKE_STS_SECRET_ACCESS_KEY);
expect(core.setSecret).toHaveBeenNthCalledWith(6, FAKE_STS_SESSION_TOKEN);
expect(core.setSecret).toHaveBeenNthCalledWith(7, FAKE_ROLE_ACCOUNT_ID);
expect(core.exportVariable).toHaveBeenNthCalledWith(5, 'AWS_ACCESS_KEY_ID', FAKE_STS_ACCESS_KEY_ID);
expect(core.exportVariable).toHaveBeenNthCalledWith(6, 'AWS_SECRET_ACCESS_KEY', FAKE_STS_SECRET_ACCESS_KEY);
expect(core.exportVariable).toHaveBeenNthCalledWith(7, 'AWS_SESSION_TOKEN', FAKE_STS_SESSION_TOKEN);
expect(core.setOutput).toHaveBeenNthCalledWith(2, 'aws-account-id', FAKE_ROLE_ACCOUNT_ID);
});
test('assume role can pull source credentials from self-hosted environment', async () => {
core.getInput = jest
.fn()
.mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION}));
await run();
expect(mockStsAssumeRole).toHaveBeenCalledTimes(1);
expect(core.exportVariable).toHaveBeenCalledTimes(5);
expect(core.setSecret).toHaveBeenCalledTimes(5);
expect(core.setOutput).toHaveBeenCalledTimes(2);
// first the source account is exported and masked
expect(core.setSecret).toHaveBeenNthCalledWith(1, FAKE_ACCOUNT_ID);
expect(core.exportVariable).toHaveBeenNthCalledWith(1, 'AWS_DEFAULT_REGION', FAKE_REGION);
expect(core.exportVariable).toHaveBeenNthCalledWith(2, 'AWS_REGION', FAKE_REGION);
expect(core.setOutput).toHaveBeenNthCalledWith(1, 'aws-account-id', FAKE_ACCOUNT_ID);
// then the role credentials are exported and masked
expect(core.setSecret).toHaveBeenNthCalledWith(2, FAKE_STS_ACCESS_KEY_ID);
expect(core.setSecret).toHaveBeenNthCalledWith(3, FAKE_STS_SECRET_ACCESS_KEY);
expect(core.setSecret).toHaveBeenNthCalledWith(4, FAKE_STS_SESSION_TOKEN);
expect(core.setSecret).toHaveBeenNthCalledWith(5, FAKE_ROLE_ACCOUNT_ID);
expect(core.exportVariable).toHaveBeenNthCalledWith(3, 'AWS_ACCESS_KEY_ID', FAKE_STS_ACCESS_KEY_ID);
expect(core.exportVariable).toHaveBeenNthCalledWith(4, 'AWS_SECRET_ACCESS_KEY', FAKE_STS_SECRET_ACCESS_KEY);
expect(core.exportVariable).toHaveBeenNthCalledWith(5, 'AWS_SESSION_TOKEN', FAKE_STS_SESSION_TOKEN);
expect(core.setOutput).toHaveBeenNthCalledWith(2, 'aws-account-id', FAKE_ROLE_ACCOUNT_ID);
});
test('role assumption tags', async () => {
core.getInput = jest
.fn()
.mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS));
await run();
expect(mockStsAssumeRole).toHaveBeenCalledWith({
RoleArn: ROLE_ARN,
RoleSessionName: 'GitHubActions',
DurationSeconds: 6 * 3600,
Tags: [
{Key: 'GitHub', Value: 'Actions'},
{Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY},
{Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW},
{Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION},
{Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED},
{Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA},
{Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF},
]
})
});
test('role assumption duration provided', async () => {
core.getInput = jest
.fn()
.mockImplementation(mockGetInput({...ASSUME_ROLE_INPUTS, 'role-duration-seconds': 5}));
await run();
expect(mockStsAssumeRole).toHaveBeenCalledWith({
RoleArn: ROLE_ARN,
RoleSessionName: 'GitHubActions',
DurationSeconds: 5,
Tags: [
{Key: 'GitHub', Value: 'Actions'},
{Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY},
{Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW},
{Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION},
{Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED},
{Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA},
{Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF},
]
})
});
test('role assumption session name provided', async () => {
core.getInput = jest
.fn()
.mockImplementation(mockGetInput({...ASSUME_ROLE_INPUTS, 'role-session-name': 'MySessionName'}));
await run();
expect(mockStsAssumeRole).toHaveBeenCalledWith({
RoleArn: ROLE_ARN,
RoleSessionName: 'MySessionName',
DurationSeconds: 6 * 3600,
Tags: [
{Key: 'GitHub', Value: 'Actions'},
{Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY},
{Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW},
{Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION},
{Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED},
{Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA},
{Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF},
]
})
});
test('sets durationSeconds to one hour when session token provided and no duration is provided', async () => {
core.getInput = jest
.fn()
.mockImplementation(mockGetInput({...ASSUME_ROLE_INPUTS, 'aws-session-token': FAKE_SESSION_TOKEN}));
await run();
expect(mockStsAssumeRole).toHaveBeenCalledWith({
RoleArn: ROLE_ARN,
RoleSessionName: 'GitHubActions',
DurationSeconds: 3600,
Tags: [
{Key: 'GitHub', Value: 'Actions'},
{Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY},
{Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW},
{Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION},
{Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED},
{Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA},
{Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF},
]
})
});
test('sets durationSeconds to one 6 hours no session token or duration is provided', async () => {
core.getInput = jest
.fn()
.mockImplementation(mockGetInput({...ASSUME_ROLE_INPUTS}));
await run();
expect(mockStsAssumeRole).toHaveBeenCalledWith({
RoleArn: ROLE_ARN,
RoleSessionName: 'GitHubActions',
DurationSeconds: 6 * 3600,
Tags: [
{Key: 'GitHub', Value: 'Actions'},
{Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY},
{Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW},
{Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION},
{Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED},
{Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA},
{Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF},
]
})
});
test('role name provided instead of ARN', async () => {
core.getInput = jest
.fn()
.mockImplementation(mockGetInput({...CREDS_INPUTS, 'role-to-assume': ROLE_NAME, 'aws-region': FAKE_REGION}));
await run();
expect(mockStsAssumeRole).toHaveBeenCalledWith({
RoleArn: 'arn:aws:iam::123456789012:role/MY-ROLE',
RoleSessionName: 'GitHubActions',
DurationSeconds: 6 * 3600,
Tags: [
{Key: 'GitHub', Value: 'Actions'},
{Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY},
{Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW},
{Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION},
{Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED},
{Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA},
{Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF},
]
})
});
test('web identity token file provided with absolute path', async () => {
core.getInput = jest
.fn()
.mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION, 'web-identity-token-file': '/fake/token/file'}));
await run();
expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledWith({
RoleArn: 'arn:aws:iam::111111111111:role/MY-ROLE',
RoleSessionName: 'GitHubActions',
DurationSeconds: 6 * 3600,
WebIdentityToken: 'testpayload'
})
});
test('web identity token file provided with relative path', async () => {
core.getInput = jest
.fn()
.mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION, 'web-identity-token-file': 'fake/token/file'}));
await run();
expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledWith({
RoleArn: 'arn:aws:iam::111111111111:role/MY-ROLE',
RoleSessionName: 'GitHubActions',
DurationSeconds: 6 * 3600,
WebIdentityToken: 'testpayload'
})
});
test('only role arn and region provided to use GH OIDC Token', async () => {
process.env.GITHUB_ACTIONS = 'true';
process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token';
core.getInput = jest
.fn()
.mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION}));
await run();
expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledWith({
RoleArn: 'arn:aws:iam::111111111111:role/MY-ROLE',
RoleSessionName: 'GitHubActions',
DurationSeconds: 3600,
WebIdentityToken: 'testtoken'
});
expect(core.setSecret).toHaveBeenNthCalledWith(1, FAKE_STS_ACCESS_KEY_ID);
expect(core.setSecret).toHaveBeenNthCalledWith(2, FAKE_STS_SECRET_ACCESS_KEY);
expect(core.setSecret).toHaveBeenNthCalledWith(3, FAKE_STS_SESSION_TOKEN);
});
test('GH OIDC With custom role duration', async () => {
const CUSTOM_ROLE_DURATION = 1234;
process.env.GITHUB_ACTIONS = 'true';
process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token';
core.getInput = jest
.fn()
.mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION, 'role-duration-seconds': CUSTOM_ROLE_DURATION}));
await run();
expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledWith({
RoleArn: 'arn:aws:iam::111111111111:role/MY-ROLE',
RoleSessionName: 'GitHubActions',
DurationSeconds: CUSTOM_ROLE_DURATION,
WebIdentityToken: 'testtoken'
});
expect(core.setSecret).toHaveBeenNthCalledWith(1, FAKE_STS_ACCESS_KEY_ID);
expect(core.setSecret).toHaveBeenNthCalledWith(2, FAKE_STS_SECRET_ACCESS_KEY);
expect(core.setSecret).toHaveBeenNthCalledWith(3, FAKE_STS_SESSION_TOKEN);
});
test('role assumption fails after maximun trials using OIDC Provider', async () => {
process.env.GITHUB_ACTIONS = 'true';
process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token';
core.getInput = jest
.fn()
.mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION}));
mockStsAssumeRoleWithWebIdentity.mockReset();
mockStsAssumeRoleWithWebIdentity.mockImplementation(() => {
throw new Error();
});
await assert.rejects(() => run());
expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledTimes(12)
});
test('role external ID provided', async () => {
core.getInput = jest
.fn()
.mockImplementation(mockGetInput({...ASSUME_ROLE_INPUTS, 'role-external-id': 'abcdef'}));
await run();
expect(mockStsAssumeRole).toHaveBeenCalledWith({
RoleArn: ROLE_ARN,
RoleSessionName: 'GitHubActions',
DurationSeconds: 6 * 3600,
Tags: [
{Key: 'GitHub', Value: 'Actions'},
{Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY},
{Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW},
{Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION},
{Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED},
{Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA},
{Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF},
],
ExternalId: 'abcdef'
})
});
test('workflow name sanitized in role assumption tags', async () => {
core.getInput = jest
.fn()
.mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS));
process.env = {...process.env, GITHUB_WORKFLOW: 'Workflow!"#$%&\'()*+, -./:;<=>?@[]^_`{|}~🙂💥🍌1yFvMOeD3ZHYsHrGjCceOboMYzBPo0CRNFdcsVRG6UgR3A912a8KfcBtEVvkAS7kRBq80umGff8mux5IN1y55HQWPNBNyaruuVr4islFXte4FDQZexGJRUSMyHQpxJ8OmZnET84oDmbvmIjgxI6IBrdihX9PHMapT4gQvRYnLqNiKb18rEMWDNoZRy51UPX5sWK2GKPipgKSO9kqLckZai9D2AN2RlWCxtMqChNtxuxjqeqhoQZo0oaq39sjcRZgAAAAAAA'};
const sanitizedWorkflowName = 'Workflow__________+_ -./:;<=>?@____________1yFvMOeD3ZHYsHrGjCceOboMYzBPo0CRNFdcsVRG6UgR3A912a8KfcBtEVvkAS7kRBq80umGff8mux5IN1y55HQWPNBNyaruuVr4islFXte4FDQZexGJRUSMyHQpxJ8OmZnET84oDmbvmIjgxI6IBrdihX9PHMapT4gQvRYnLqNiKb18rEMWDNoZRy51UPX5sWK2GKPipgKSO9kqLckZa'
await run();
expect(mockStsAssumeRole).toHaveBeenCalledWith({
RoleArn: ROLE_ARN,
RoleSessionName: 'GitHubActions',
DurationSeconds: 6 * 3600,
Tags: [
{Key: 'GitHub', Value: 'Actions'},
{Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY},
{Key: 'Workflow', Value: sanitizedWorkflowName},
{Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION},
{Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED},
{Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA},
{Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF},
]
})
});
test('skip tagging provided as true', async () => {
core.getInput = jest
.fn()
.mockImplementation(mockGetInput({...ASSUME_ROLE_INPUTS, 'role-skip-session-tagging': 'true'}));
await run();
expect(mockStsAssumeRole).toHaveBeenCalledWith({
RoleArn: ROLE_ARN,
RoleSessionName: 'GitHubActions',
DurationSeconds: 21600,
Tags: undefined
})
});
test('skip tagging provided as false', async () => {
core.getInput = jest
.fn()
.mockImplementation(mockGetInput({...ASSUME_ROLE_INPUTS, 'role-skip-session-tagging': 'false'}));
await run();
expect(mockStsAssumeRole).toHaveBeenCalledWith({
RoleArn: ROLE_ARN,
RoleSessionName: 'GitHubActions',
DurationSeconds: 21600,
Tags: [
{Key: 'GitHub', Value: 'Actions'},
{Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY},
{Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW},
{Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION},
{Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED},
{Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA},
{Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF},
]
})
});
test('skip tagging not provided', async () => {
core.getInput = jest
.fn()
.mockImplementation(mockGetInput({...ASSUME_ROLE_INPUTS}));
await run();
expect(mockStsAssumeRole).toHaveBeenCalledWith({
RoleArn: ROLE_ARN,
RoleSessionName: 'GitHubActions',
DurationSeconds: 21600,
Tags: [
{Key: 'GitHub', Value: 'Actions'},
{Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY},
{Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW},
{Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION},
{Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED},
{Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA},
{Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF},
]
})
});
test('masks variables before exporting', async () => {
let maskedValues = [];
const publicFields = ['AWS_REGION', 'AWS_DEFAULT_REGION'];
core.setSecret.mockReset();
core.setSecret.mockImplementation((secret) => {
maskedValues.push(secret);
});
core.exportVariable.mockReset();
core.exportVariable.mockImplementation((name, value) => {
if (!maskedValues.includes(value) && !publicFields.includes(name)) {
throw new Error(value + " for variable " + name + " is not masked yet!");
}
});
core.getInput = jest
.fn()
.mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS));
await run();
});
});
-31
View File
@@ -1,31 +0,0 @@
/** @type {import('jest').Config} */
const config = {
verbose: true,
transform: {
'^.+\\.m?[tj]sx?$': ['ts-jest'],
},
testMatch: [
'<rootDir>/src/**/__tests__/**/*.ts?(x)',
'<rootDir>/(test|src)/**/*(*.)@(spec|test).ts?(x)',
'<rootDir>/test/**/*.(test|spec).(js|jsx|ts|tsx)',
],
clearMocks: true,
collectCoverage: true,
coverageReporters: ['json', 'lcov', 'clover', 'cobertura', 'text'],
coverageDirectory: 'coverage',
coveragePathIgnorePatterns: ['/node_modules/'],
testPathIgnorePatterns: ['/node_modules/'],
watchPathIgnorePatterns: ['/node_modules/'],
reporters: [
'default',
[
'jest-junit',
{
outputDirectory: 'test-reports',
},
],
],
preset: 'ts-jest/presets/default-legacy',
};
module.exports = config;
+920 -16488
View File
File diff suppressed because it is too large Load Diff
+26 -53
View File
@@ -1,64 +1,37 @@
{
"name": "configure-aws-credentials",
"description": "A GitHub Action to configure AWS credentials",
"name": "aws-actions-configure-aws-credentials",
"version": "1.7.0",
"description": "Configure AWS Credentials",
"main": "index.js",
"scripts": {
"build": "tsc --project tsconfig.build.json",
"lint": "eslint .",
"package": "npm run build && ncc build --license THIRD-PARTY -o dist && ncc build src/cleanup/index.ts -o dist/cleanup && copyup -E dist/THIRD-PARTY . && del-cli dist/THIRD-PARTY",
"test": "npm run lint && jest --verbose"
"lint": "eslint **.js",
"package": "ncc build index.js -o dist && ncc build cleanup.js -o dist/cleanup",
"test": "npm run lint && jest --coverage --verbose"
},
"author": {
"name": "Amazon.com, Inc. or its affiliates",
"url": "https://aws.amazon.com",
"organization": true
},
"devDependencies": {
"@aws-sdk/credential-provider-env": "^3.186.0",
"@smithy/property-provider": "^2.0.11",
"@jest/globals": "^29.7.0",
"@types/jest": "^29.5.5",
"@types/node": "^20",
"@typescript-eslint/eslint-plugin": "<=5.62.0",
"@typescript-eslint/parser": "<=5.62.0",
"@vercel/ncc": "^0.38.0",
"aws-sdk-client-mock": "^3.0.0",
"copyfiles": "^2.4.1",
"del-cli": "^5.1.0",
"eslint": "^8",
"eslint-config-prettier": "^9.0.0",
"eslint-import-resolver-node": "^0.3.6",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-prettier": "^5.0.0",
"jest": "^29.7.0",
"jest-junit": "^16",
"json-schema": "^0.4.0",
"prettier": "^3.0.3",
"standard-version": "^9",
"ts-jest": "^29.0.3",
"typescript": "^5.2.2"
},
"dependencies": {
"@actions/core": "^1.10.1",
"@aws-sdk/client-sts": "^3",
"@smithy/node-http-handler": "^2.1.6",
"https-proxy-agent": "^5.0.0"
"repository": {
"type": "git",
"url": "git+https://github.com/aws-actions/configure-aws-credentials.git"
},
"keywords": [
"aws",
"github",
"github-action"
"AWS",
"GitHub",
"Actions",
"JavaScript"
],
"engines": {
"node": ">= 14.0.0"
},
"main": "build/index.js",
"author": "AWS",
"license": "MIT",
"homepage": "https://github.com/aws-actions/configure-aws-credentials",
"version": "0.0.0",
"bugs": {
"url": "https://github.com/aws-actions/configure-aws-credentials/issues"
},
"types": "build/index.d.ts",
"private": true
"homepage": "https://github.com/aws-actions/configure-aws-credentials#readme",
"dependencies": {
"@actions/core": "^1.10.0",
"aws-sdk": "^2.1324.0",
"axios": "^1.3.4"
},
"devDependencies": {
"@vercel/ncc": "^0.36.1",
"eslint": "^8.35.0",
"jest": "^29.4.3"
}
}
-70
View File
@@ -1,70 +0,0 @@
import { info } from '@actions/core';
import { STSClient } from '@aws-sdk/client-sts';
import { NodeHttpHandler } from '@smithy/node-http-handler';
import { HttpsProxyAgent } from 'https-proxy-agent';
import { errorMessage } from './helpers';
const USER_AGENT = 'configure-aws-credentials-for-github-actions';
export interface CredentialsClientProps {
region?: string;
proxyServer?: string;
}
export class CredentialsClient {
public region?: string;
private _stsClient?: STSClient;
private readonly requestHandler?: NodeHttpHandler;
constructor(props: CredentialsClientProps) {
this.region = props.region;
if (props.proxyServer) {
info('Configuring proxy handler for STS client');
const handler = new HttpsProxyAgent(props.proxyServer);
this.requestHandler = new NodeHttpHandler({
httpAgent: handler,
httpsAgent: handler,
});
}
}
public get stsClient(): STSClient {
if (!this._stsClient) {
this._stsClient = new STSClient({
region: this.region,
customUserAgent: USER_AGENT,
requestHandler: this.requestHandler ? this.requestHandler : undefined,
});
}
return this._stsClient;
}
public async validateCredentials(expectedAccessKeyId?: string, roleChaining?: boolean) {
let credentials;
try {
credentials = await this.loadCredentials();
if (!credentials.accessKeyId) {
throw new Error('Access key ID empty after loading credentials');
}
} catch (error) {
throw new Error(`Credentials could not be loaded, please check your action inputs: ${errorMessage(error)}`);
}
if (!roleChaining) {
const actualAccessKeyId = credentials.accessKeyId;
if (expectedAccessKeyId && expectedAccessKeyId !== actualAccessKeyId) {
throw new Error(
'Unexpected failure: Credentials loaded by the SDK do not match the access key ID configured by the action'
);
}
}
}
private async loadCredentials() {
const client = new STSClient({
requestHandler: this.requestHandler ? this.requestHandler : undefined,
});
return client.config.credentials();
}
}
-172
View File
@@ -1,172 +0,0 @@
import assert from 'assert';
import fs from 'fs';
import path from 'path';
import * as core from '@actions/core';
import type { AssumeRoleCommandInput, STSClient, Tag } from '@aws-sdk/client-sts';
import { AssumeRoleCommand, AssumeRoleWithWebIdentityCommand } from '@aws-sdk/client-sts';
import type { CredentialsClient } from './CredentialsClient';
import { errorMessage, isDefined, sanitizeGitHubVariables } from './helpers';
async function assumeRoleWithOIDC(params: AssumeRoleCommandInput, client: STSClient, webIdentityToken: string) {
delete params.Tags;
core.info('Assuming role with OIDC');
try {
const creds = await client.send(
new AssumeRoleWithWebIdentityCommand({
...params,
WebIdentityToken: webIdentityToken,
})
);
return creds;
} catch (error) {
throw new Error(`Could not assume role with OIDC: ${errorMessage(error)}`);
}
}
async function assumeRoleWithWebIdentityTokenFile(
params: AssumeRoleCommandInput,
client: STSClient,
webIdentityTokenFile: string,
workspace: string
) {
core.debug(
'webIdentityTokenFile provided. Will call sts:AssumeRoleWithWebIdentity and take session tags from token contents.'
);
const webIdentityTokenFilePath = path.isAbsolute(webIdentityTokenFile)
? webIdentityTokenFile
: path.join(workspace, webIdentityTokenFile);
if (!fs.existsSync(webIdentityTokenFilePath)) {
throw new Error(`Web identity token file does not exist: ${webIdentityTokenFilePath}`);
}
core.info('Assuming role with web identity token file');
try {
const webIdentityToken = fs.readFileSync(webIdentityTokenFilePath, 'utf8');
delete params.Tags;
const creds = await client.send(
new AssumeRoleWithWebIdentityCommand({
...params,
WebIdentityToken: webIdentityToken,
})
);
return creds;
} catch (error) {
throw new Error(`Could not assume role with web identity token file: ${errorMessage(error)}`);
}
}
async function assumeRoleWithCredentials(params: AssumeRoleCommandInput, client: STSClient) {
core.info('Assuming role with user credentials');
if (!process.env['AWS_SESSION_TOKEN']) {
core.warning(
'To avoid using long-term AWS credentials, please update your workflows to authenticate using OpenID Connect.' +
' See https://s12d.com/gha-oidc-aws for more information.'
);
}
try {
const creds = await client.send(new AssumeRoleCommand({ ...params }));
return creds;
} catch (error) {
throw new Error(`Could not assume role with user credentials: ${errorMessage(error)}`);
}
}
export interface assumeRoleParams {
credentialsClient: CredentialsClient;
roleToAssume: string;
roleDuration: number;
roleSessionName: string;
roleSkipSessionTagging?: boolean;
sourceAccountId?: string;
roleExternalId?: string;
webIdentityTokenFile?: string;
webIdentityToken?: string;
inlineSessionPolicy?: string;
managedSessionPolicies?: any[];
}
export async function assumeRole(params: assumeRoleParams) {
const {
credentialsClient,
sourceAccountId,
roleToAssume,
roleExternalId,
roleDuration,
roleSessionName,
roleSkipSessionTagging,
webIdentityTokenFile,
webIdentityToken,
inlineSessionPolicy,
managedSessionPolicies,
} = { ...params };
// Load GitHub environment variables
const { GITHUB_REPOSITORY, GITHUB_WORKFLOW, GITHUB_ACTION, GITHUB_ACTOR, GITHUB_SHA, GITHUB_WORKSPACE } = process.env;
if (!GITHUB_REPOSITORY || !GITHUB_WORKFLOW || !GITHUB_ACTION || !GITHUB_ACTOR || !GITHUB_SHA || !GITHUB_WORKSPACE) {
throw new Error('Missing required environment variables. Are you running in GitHub Actions?');
}
// Load role session tags
const tagArray: Tag[] = [
{ Key: 'GitHub', Value: 'Actions' },
{ Key: 'Repository', Value: GITHUB_REPOSITORY },
{ Key: 'Workflow', Value: sanitizeGitHubVariables(GITHUB_WORKFLOW) },
{ Key: 'Action', Value: GITHUB_ACTION },
{ Key: 'Actor', Value: sanitizeGitHubVariables(GITHUB_ACTOR) },
{ Key: 'Commit', Value: GITHUB_SHA },
];
if (process.env['GITHUB_REF']) {
tagArray.push({ Key: 'Branch', Value: sanitizeGitHubVariables(process.env['GITHUB_REF']) });
}
const tags = roleSkipSessionTagging ? undefined : tagArray;
if (!tags) {
core.debug('Role session tagging has been skipped.');
} else {
core.debug(`${tags.length} role session tags are being used.`);
}
// Calculate role ARN from name and account ID (currently only supports `aws` partition)
let roleArn = roleToAssume;
if (!roleArn.startsWith('arn:aws')) {
assert(
isDefined(sourceAccountId),
'Source Account ID is needed if the Role Name is provided and not the Role Arn.'
);
roleArn = `arn:aws:iam::${sourceAccountId}:role/${roleArn}`;
}
// Ready common parameters to assume role
const commonAssumeRoleParams: AssumeRoleCommandInput = {
RoleArn: roleArn,
RoleSessionName: roleSessionName,
DurationSeconds: roleDuration,
Tags: tags ? tags : undefined,
ExternalId: roleExternalId ? roleExternalId : undefined,
Policy: inlineSessionPolicy ? inlineSessionPolicy : undefined,
PolicyArns: managedSessionPolicies?.length ? managedSessionPolicies : undefined,
};
const keys = Object.keys(commonAssumeRoleParams) as Array<keyof typeof commonAssumeRoleParams>;
keys.forEach((k) => commonAssumeRoleParams[k] === undefined && delete commonAssumeRoleParams[k]);
// Instantiate STS client
const stsClient = credentialsClient.stsClient;
// Assume role using one of three methods
switch (true) {
case !!webIdentityToken: {
return assumeRoleWithOIDC(commonAssumeRoleParams, stsClient, webIdentityToken!);
}
case !!webIdentityTokenFile: {
return assumeRoleWithWebIdentityTokenFile(
commonAssumeRoleParams,
stsClient,
webIdentityTokenFile!,
GITHUB_WORKSPACE
);
}
default: {
return assumeRoleWithCredentials(commonAssumeRoleParams, stsClient);
}
}
}
-145
View File
@@ -1,145 +0,0 @@
import * as core from '@actions/core';
import type { Credentials } from '@aws-sdk/client-sts';
import { GetCallerIdentityCommand } from '@aws-sdk/client-sts';
import type { CredentialsClient } from './CredentialsClient';
const MAX_TAG_VALUE_LENGTH = 256;
const SANITIZATION_CHARACTER = '_';
const SPECIAL_CHARS_REGEX = /[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]+/;
// Configure the AWS CLI and AWS SDKs using environment variables and set them as secrets.
// Setting the credentials as secrets masks them in Github Actions logs
export function exportCredentials(creds?: Partial<Credentials>, outputCredentials?: boolean) {
if (creds?.AccessKeyId) {
core.setSecret(creds.AccessKeyId);
core.exportVariable('AWS_ACCESS_KEY_ID', creds.AccessKeyId);
}
if (creds?.SecretAccessKey) {
core.setSecret(creds.SecretAccessKey);
core.exportVariable('AWS_SECRET_ACCESS_KEY', creds.SecretAccessKey);
}
if (creds?.SessionToken) {
core.setSecret(creds.SessionToken);
core.exportVariable('AWS_SESSION_TOKEN', creds.SessionToken);
} else if (process.env['AWS_SESSION_TOKEN']) {
// clear session token from previous credentials action
core.exportVariable('AWS_SESSION_TOKEN', '');
}
if (outputCredentials) {
if (creds?.AccessKeyId) {
core.setOutput('aws-access-key-id', creds.AccessKeyId);
}
if (creds?.SecretAccessKey) {
core.setOutput('aws-secret-access-key', creds.SecretAccessKey);
}
if (creds?.SessionToken) {
core.setOutput('aws-session-token', creds.SessionToken);
}
}
}
export function unsetCredentials() {
core.exportVariable('AWS_ACCESS_KEY_ID', '');
core.exportVariable('AWS_SECRET_ACCESS_KEY', '');
core.exportVariable('AWS_SESSION_TOKEN', '');
core.exportVariable('AWS_REGION', '');
core.exportVariable('AWS_DEFAULT_REGION', '');
}
export function exportRegion(region: string) {
core.exportVariable('AWS_DEFAULT_REGION', region);
core.exportVariable('AWS_REGION', region);
}
// Obtains account ID from STS Client and sets it as output
export async function exportAccountId(credentialsClient: CredentialsClient, maskAccountId?: boolean) {
const client = credentialsClient.stsClient;
const identity = await client.send(new GetCallerIdentityCommand({}));
const accountId = identity.Account;
if (!accountId) {
throw new Error('Could not get Account ID from STS. Did you set credentials?');
}
if (maskAccountId) {
core.setSecret(accountId);
}
core.setOutput('aws-account-id', accountId);
return accountId;
}
// Tags have a more restrictive set of acceptable characters than GitHub environment variables can.
// This replaces anything not conforming to the tag restrictions by inverting the regular expression.
// See the AWS documentation for constraint specifics https://docs.aws.amazon.com/STS/latest/APIReference/API_Tag.html.
export function sanitizeGitHubVariables(name: string) {
const nameWithoutSpecialCharacters = name.replace(/[^\p{L}\p{Z}\p{N}_.:/=+\-@]/gu, SANITIZATION_CHARACTER);
const nameTruncated = nameWithoutSpecialCharacters.slice(0, MAX_TAG_VALUE_LENGTH);
return nameTruncated;
}
export async function defaultSleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
let sleep = defaultSleep;
export function withsleep(s: typeof sleep) {
sleep = s;
}
export function reset() {
sleep = defaultSleep;
}
export function verifyKeys(creds: Partial<Credentials> | undefined) {
if (!creds) {
return false;
}
if (creds.AccessKeyId) {
if (SPECIAL_CHARS_REGEX.test(creds.AccessKeyId)) {
core.debug('AccessKeyId contains special characters.');
return false;
}
}
if (creds.SecretAccessKey) {
if (SPECIAL_CHARS_REGEX.test(creds.SecretAccessKey)) {
core.debug('SecretAccessKey contains special characters.');
return false;
}
}
return true;
}
// Retries the promise with exponential backoff if the error isRetryable up to maxRetries time.
export async function retryAndBackoff<T>(
fn: () => Promise<T>,
isRetryable: boolean,
maxRetries = 12,
retries = 0,
base = 50
): Promise<T> {
try {
return await fn();
} catch (err) {
if (!isRetryable) {
throw err;
}
// It's retryable, so sleep and retry.
await sleep(Math.random() * (Math.pow(2, retries) * base));
retries += 1;
if (retries >= maxRetries) {
throw err;
}
return await retryAndBackoff(fn, isRetryable, maxRetries, retries, base);
}
}
/* c8 ignore start */
export function errorMessage(error: unknown) {
return error instanceof Error ? error.message : String(error);
}
export function isDefined<T>(i: T | undefined | null): i is T {
return i !== undefined && i !== null;
}
/* c8 ignore stop */
-203
View File
@@ -1,203 +0,0 @@
import * as core from '@actions/core';
import type { AssumeRoleCommandOutput } from '@aws-sdk/client-sts';
import { assumeRole } from './assumeRole';
import { CredentialsClient } from './CredentialsClient';
import {
errorMessage,
retryAndBackoff,
exportRegion,
exportCredentials,
exportAccountId,
unsetCredentials,
verifyKeys,
} from './helpers';
const DEFAULT_ROLE_DURATION = 3600; // One hour (seconds)
const ROLE_SESSION_NAME = 'GitHubActions';
const REGION_REGEX = /^[a-z0-9-]+$/g;
export async function run() {
try {
// Get inputs
const AccessKeyId = core.getInput('aws-access-key-id', { required: false });
const SecretAccessKey = core.getInput('aws-secret-access-key', { required: false });
const sessionTokenInput = core.getInput('aws-session-token', { required: false });
const SessionToken = sessionTokenInput === '' ? undefined : sessionTokenInput;
const region = core.getInput('aws-region', { required: true });
const roleToAssume = core.getInput('role-to-assume', { required: false });
const audience = core.getInput('audience', { required: false });
const maskAccountIdInput = core.getInput('mask-aws-account-id', { required: false }) || 'false';
const maskAccountId = maskAccountIdInput.toLowerCase() === 'true';
const roleExternalId = core.getInput('role-external-id', { required: false });
const webIdentityTokenFile = core.getInput('web-identity-token-file', { required: false });
const roleDuration = parseInt(core.getInput('role-duration-seconds', { required: false })) || DEFAULT_ROLE_DURATION;
const roleSessionName = core.getInput('role-session-name', { required: false }) || ROLE_SESSION_NAME;
const roleSkipSessionTaggingInput = core.getInput('role-skip-session-tagging', { required: false }) || 'false';
const roleSkipSessionTagging = roleSkipSessionTaggingInput.toLowerCase() === 'true';
const proxyServer = core.getInput('http-proxy', { required: false });
const inlineSessionPolicy = core.getInput('inline-session-policy', { required: false });
const managedSessionPoliciesInput = core.getMultilineInput('managed-session-policies', { required: false });
const managedSessionPolicies: any[] = [];
const roleChainingInput = core.getInput('role-chaining', { required: false }) || 'false';
const roleChaining = roleChainingInput.toLowerCase() === 'true';
const outputCredentialsInput = core.getInput('output-credentials', { required: false }) || 'false';
const outputCredentials = outputCredentialsInput.toLowerCase() === 'true';
const unsetCurrentCredentialsInput = core.getInput('unset-current-credentials', { required: false }) || 'false';
const unsetCurrentCredentials = unsetCurrentCredentialsInput.toLowerCase() === 'true';
const disableRetryInput = core.getInput('disable-retry', { required: false }) || 'false';
let disableRetry = disableRetryInput.toLowerCase() === 'true';
const specialCharacterWorkaroundInput =
core.getInput('special-characters-workaround', { required: false }) || 'false';
const specialCharacterWorkaround = specialCharacterWorkaroundInput.toLowerCase() === 'true';
let maxRetries = parseInt(core.getInput('retry-max-attempts', { required: false })) || 12;
switch (true) {
case specialCharacterWorkaround:
// 😳
disableRetry = false;
maxRetries = 12;
break;
case maxRetries < 1:
maxRetries = 1;
break;
}
for (const managedSessionPolicy of managedSessionPoliciesInput) {
managedSessionPolicies.push({ arn: managedSessionPolicy });
}
// Logic to decide whether to attempt to use OIDC or not
const useGitHubOIDCProvider = () => {
// The `ACTIONS_ID_TOKEN_REQUEST_TOKEN` environment variable is set when the `id-token` permission is granted.
// This is necessary to authenticate with OIDC, but not strictly set just for OIDC. If it is not set and all other
// checks pass, it is likely but not guaranteed that the user needs but lacks this permission in their workflow.
// So, we will log a warning when it is the only piece absent
if (
!!roleToAssume &&
!webIdentityTokenFile &&
!AccessKeyId &&
!process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN'] &&
!roleChaining
) {
core.info(
'It looks like you might be trying to authenticate with OIDC. Did you mean to set the `id-token` permission? ' +
'If you are not trying to authenticate with OIDC and the action is working successfully, you can ignore this message.'
);
}
return (
!!roleToAssume &&
!!process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN'] &&
!AccessKeyId &&
!webIdentityTokenFile &&
!roleChaining
);
};
if (unsetCurrentCredentials) {
unsetCredentials();
}
if (!region.match(REGION_REGEX)) {
throw new Error(`Region is not valid: ${region}`);
}
exportRegion(region);
// Instantiate credentials client
const credentialsClient = new CredentialsClient({ region, proxyServer });
let sourceAccountId: string;
let webIdentityToken: string;
// If OIDC is being used, generate token
// Else, export credentials provided as input
if (useGitHubOIDCProvider()) {
try {
webIdentityToken = await retryAndBackoff(
async () => {
return core.getIDToken(audience);
},
!disableRetry,
maxRetries
);
} catch (error) {
throw new Error(`getIDToken call failed: ${errorMessage(error)}`);
}
} else if (AccessKeyId) {
if (!SecretAccessKey) {
throw new Error("'aws-secret-access-key' must be provided if 'aws-access-key-id' is provided");
}
// The STS client for calling AssumeRole pulls creds from the environment.
// Plus, in the assume role case, if the AssumeRole call fails, we want
// the source credentials to already be masked as secrets
// in any error messages.
exportCredentials({ AccessKeyId, SecretAccessKey, SessionToken });
} else if (!webIdentityTokenFile && !roleChaining) {
// Proceed only if credentials can be picked up
await credentialsClient.validateCredentials();
sourceAccountId = await exportAccountId(credentialsClient, maskAccountId);
}
if (AccessKeyId || roleChaining) {
// Validate that the SDK can actually pick up credentials.
// This validates cases where this action is using existing environment credentials,
// and cases where the user intended to provide input credentials but the secrets inputs resolved to empty strings.
await credentialsClient.validateCredentials(AccessKeyId, roleChaining);
sourceAccountId = await exportAccountId(credentialsClient, maskAccountId);
}
// Get role credentials if configured to do so
if (roleToAssume) {
let roleCredentials: AssumeRoleCommandOutput;
do {
// eslint-disable-next-line no-await-in-loop
roleCredentials = await retryAndBackoff(
async () => {
return assumeRole({
credentialsClient,
sourceAccountId,
roleToAssume,
roleExternalId,
roleDuration,
roleSessionName,
roleSkipSessionTagging,
webIdentityTokenFile,
webIdentityToken,
inlineSessionPolicy,
managedSessionPolicies,
});
},
!disableRetry,
maxRetries
);
// eslint-disable-next-line no-unmodified-loop-condition
} while (specialCharacterWorkaround && !verifyKeys(roleCredentials.Credentials));
core.info(`Authenticated as assumedRoleId ${roleCredentials.AssumedRoleUser!.AssumedRoleId!}`);
exportCredentials(roleCredentials.Credentials, outputCredentials);
// We need to validate the credentials in 2 of our use-cases
// First: self-hosted runners. If the GITHUB_ACTIONS environment variable
// is set to `true` then we are NOT in a self-hosted runner.
// Second: Customer provided credentials manually (IAM User keys stored in GH Secrets)
if (!process.env['GITHUB_ACTIONS'] || AccessKeyId) {
await credentialsClient.validateCredentials(roleCredentials.Credentials?.AccessKeyId);
}
await exportAccountId(credentialsClient, maskAccountId);
} else {
core.info('Proceeding with IAM user credentials');
}
} catch (error) {
core.setFailed(errorMessage(error));
const showStackTrace = process.env['SHOW_STACK_TRACE'];
if (showStackTrace === 'true') {
throw error;
}
}
}
/* c8 ignore start */
/* istanbul ignore next */
if (require.main === module) {
(async () => {
await run();
})().catch((error) => {
core.setFailed(errorMessage(error));
});
}
-52
View File
@@ -1,52 +0,0 @@
import * as core from '@actions/core';
import { cleanup } from '../src/cleanup';
const FAKE_ACCESS_KEY_ID = 'MY-AWS-ACCESS-KEY-ID';
const FAKE_SECRET_ACCESS_KEY = 'MY-AWS-SECRET-ACCESS-KEY';
const FAKE_SESSION_TOKEN = 'MY-AWS-SESSION-TOKEN';
const FAKE_REGION = 'fake-region-1';
const ACTION_ENVIRONMENT_VARIABLES = {
AWS_ACCESS_KEY_ID: FAKE_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY: FAKE_SECRET_ACCESS_KEY,
AWS_SESSION_TOKEN: FAKE_SESSION_TOKEN,
AWS_DEFAULT_REGION: FAKE_REGION,
AWS_REGION: FAKE_REGION,
};
describe('Configure AWS Credentials', () => {
const OLD_ENV = process.env;
beforeEach(() => {
jest.resetModules();
jest.spyOn(core, 'exportVariable').mockImplementation();
jest.spyOn(core, 'setSecret').mockImplementation();
jest.spyOn(core, 'setOutput').mockImplementation();
jest.spyOn(core, 'setFailed').mockImplementation();
process.env = { ...OLD_ENV, ...ACTION_ENVIRONMENT_VARIABLES };
});
afterEach(() => {
process.env = OLD_ENV;
});
test('replaces AWS credential and region env vars with empty strings', () => {
cleanup();
expect(core.setFailed).toHaveBeenCalledTimes(0);
expect(core.exportVariable).toHaveBeenCalledTimes(5);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_ACCESS_KEY_ID', '');
expect(core.exportVariable).toHaveBeenCalledWith('AWS_SECRET_ACCESS_KEY', '');
expect(core.exportVariable).toHaveBeenCalledWith('AWS_SESSION_TOKEN', '');
expect(core.exportVariable).toHaveBeenCalledWith('AWS_DEFAULT_REGION', '');
expect(core.exportVariable).toHaveBeenCalledWith('AWS_REGION', '');
});
test('error is caught and fails the action', () => {
jest.spyOn(core, 'exportVariable').mockImplementation(() => {
throw new Error();
});
cleanup();
expect(core.setFailed).toHaveBeenCalled();
});
});
-26
View File
@@ -1,26 +0,0 @@
import * as helpers from '../src/helpers';
describe('helpers', () => {
beforeEach(() => {
jest.resetModules();
jest.clearAllMocks();
});
test('removes brackets from GitHub Actor', () => {
expect(helpers.sanitizeGitHubVariables('foo[bot]')).toEqual('foo_bot_');
});
test('removes special characters from worflow names', () => {
expect(helpers.sanitizeGitHubVariables('sdf234@#$%$^&*()_+{}|:"<>?')).toEqual('sdf234@__________+___:____');
});
test('can sleep', () => {
const sleep = helpers.defaultSleep(10);
expect(Promise.race([sleep, new Promise((_res, rej) => setTimeout(rej, 20))])).resolves;
});
test("backoff function doesn't retry non-retryable errors", async () => {
const fn = jest.fn().mockRejectedValue('i am not retryable');
await expect(helpers.retryAndBackoff(fn, false)).rejects.toMatch('i am not retryable');
expect(fn).toHaveBeenCalledTimes(1);
});
});
-893
View File
@@ -1,893 +0,0 @@
import * as core from '@actions/core';
import {
AssumeRoleCommand,
AssumeRoleWithWebIdentityCommand,
GetCallerIdentityCommand,
STSClient,
} from '@aws-sdk/client-sts';
import { fromEnv } from '@aws-sdk/credential-provider-env';
import { CredentialsProviderError } from '@smithy/property-provider';
import { mockClient } from 'aws-sdk-client-mock';
import { withsleep, reset } from '../src/helpers';
import { run } from '../src/index';
// #region
const FAKE_ACCESS_KEY_ID = 'MYAWSACCESSKEYID';
const FAKE_SECRET_ACCESS_KEY = 'MYAWSSECRETACCESSKEY';
const FAKE_SESSION_TOKEN = 'MYAWSSESSIONTOKEN';
const FAKE_STS_ACCESS_KEY_ID = 'STSAWSACCESSKEYID';
const FAKE_STS_SECRET_ACCESS_KEY = 'STSAWSSECRETACCESSKEY';
const FAKE_STS_SESSION_TOKEN = 'STSAWSSESSIONTOKEN';
const FAKE_ASSUMED_ROLE_ID = 'AROAFAKEASSUMEDROLEID';
const FAKE_REGION = 'fake-region-1';
const FAKE_ACCOUNT_ID = '123456789012';
const FAKE_ROLE_ACCOUNT_ID = '111111111111';
const ROLE_NAME = 'MY-ROLE';
const ROLE_ARN = 'arn:aws:iam::111111111111:role/MY-ROLE';
const MANAGED_SESSION_POLICY_INPUT = [
'arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess',
'arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess',
];
const ENVIRONMENT_VARIABLE_OVERRIDES = {
SHOW_STACK_TRACE: 'false',
GITHUB_REPOSITORY: 'MY-REPOSITORY-NAME',
GITHUB_WORKFLOW: 'MY-WORKFLOW-ID',
GITHUB_ACTION: 'MY-ACTION-NAME',
GITHUB_ACTOR: 'MY-USERNAME[bot]',
GITHUB_SHA: 'MY-COMMIT-ID',
GITHUB_REF: 'MY-BRANCH',
GITHUB_WORKSPACE: '/home/github',
};
const GITHUB_ACTOR_SANITIZED = 'MY-USERNAME_bot_';
const CREDS_INPUTS = {
'aws-access-key-id': FAKE_ACCESS_KEY_ID,
'aws-secret-access-key': FAKE_SECRET_ACCESS_KEY,
};
const DEFAULT_INPUTS = {
...CREDS_INPUTS,
'aws-session-token': FAKE_SESSION_TOKEN,
'aws-region': FAKE_REGION,
};
const ASSUME_ROLE_INPUTS = { ...CREDS_INPUTS, 'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION };
// #endregion
const mockedSTS = mockClient(STSClient);
function mockGetInput(requestResponse: Record<string, string>) {
return function (name: string, _options: unknown): string {
return requestResponse[name]!;
};
}
function mockGetMultilineInput(requestResponse: Record<string, string[]>) {
return function (name: string, _options: unknown): string[] {
return requestResponse[name]!;
};
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
jest.mock('fs', () => ({
...jest.requireActual('fs'),
existsSync: jest.fn(() => true),
readFileSync: jest.fn(() => 'testpayload'),
}));
jest.mock('@aws-sdk/credential-provider-env', () => ({
// This is the actual implementation in the SDK ^_^
fromEnv: jest.fn().mockImplementation(() => () => {
const accessKeyId = process.env['AWS_ACCESS_KEY_ID'];
const secretAccessKey = process.env['AWS_SECRET_ACCESS_KEY'];
const sessionToken = process.env['AWS_SESSION_TOKEN'];
const expiration = process.env['AWS_CREDENTIAL_EXPIRATION'];
return {
accessKeyId,
secretAccessKey,
sessionToken,
expiration,
};
}),
}));
describe('Configure AWS Credentials', () => {
const OLD_ENV = process.env;
beforeEach(() => {
jest.resetModules();
process.env = { ...OLD_ENV, ...ENVIRONMENT_VARIABLE_OVERRIDES };
jest.clearAllMocks();
mockedSTS.reset();
(fromEnv as jest.Mock).mockReset();
jest.spyOn(core, 'getMultilineInput').mockImplementation(() => []);
jest.spyOn(core, 'getIDToken').mockImplementation(async () => Promise.resolve('testtoken'));
jest.spyOn(core, 'exportVariable').mockImplementation();
jest.spyOn(core, 'setSecret').mockImplementation();
jest.spyOn(core, 'setOutput').mockImplementation();
jest.spyOn(core, 'setFailed').mockImplementation();
jest.spyOn(core, 'debug').mockImplementation();
jest.spyOn(core, 'info').mockImplementation((string) => {
return string;
});
jest.spyOn(core, 'warning').mockImplementation((string) => {
return string;
});
(fromEnv as jest.Mock)
.mockImplementationOnce(() => () => ({
accessKeyId: FAKE_ACCESS_KEY_ID,
secretAccessKey: FAKE_SECRET_ACCESS_KEY,
}))
.mockImplementationOnce(() => () => ({
accessKeyId: FAKE_STS_ACCESS_KEY_ID,
secretAccessKey: FAKE_STS_SECRET_ACCESS_KEY,
}));
mockedSTS
.on(GetCallerIdentityCommand)
.resolvesOnce({ Account: FAKE_ACCOUNT_ID })
.resolvesOnce({ Account: FAKE_ROLE_ACCOUNT_ID });
mockedSTS.on(AssumeRoleCommand).resolves({
Credentials: {
AccessKeyId: FAKE_STS_ACCESS_KEY_ID,
SecretAccessKey: FAKE_STS_SECRET_ACCESS_KEY,
SessionToken: FAKE_STS_SESSION_TOKEN,
Expiration: new Date(8640000000000000),
},
AssumedRoleUser: {
AssumedRoleId: FAKE_ASSUMED_ROLE_ID,
Arn: ROLE_ARN,
},
});
mockedSTS.on(AssumeRoleWithWebIdentityCommand).resolves({
Credentials: {
AccessKeyId: FAKE_STS_ACCESS_KEY_ID,
SecretAccessKey: FAKE_STS_SECRET_ACCESS_KEY,
SessionToken: FAKE_STS_SESSION_TOKEN,
Expiration: new Date(8640000000000000),
},
AssumedRoleUser: {
AssumedRoleId: FAKE_ASSUMED_ROLE_ID,
Arn: ROLE_ARN,
},
});
withsleep(async () => {
return Promise.resolve();
});
});
afterEach(() => {
process.env = OLD_ENV;
reset();
});
test('exports env vars', async () => {
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(DEFAULT_INPUTS));
await run();
expect(mockedSTS.commandCalls(AssumeRoleCommand)).toHaveLength(0);
expect(core.exportVariable).toHaveBeenCalledTimes(5);
expect(core.setSecret).toHaveBeenCalledTimes(3);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_ACCESS_KEY_ID', FAKE_ACCESS_KEY_ID);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCESS_KEY_ID);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_SECRET_ACCESS_KEY', FAKE_SECRET_ACCESS_KEY);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_SECRET_ACCESS_KEY);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_SESSION_TOKEN', FAKE_SESSION_TOKEN);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_SESSION_TOKEN);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_DEFAULT_REGION', FAKE_REGION);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_REGION', FAKE_REGION);
expect(core.setOutput).toHaveBeenCalledWith('aws-account-id', FAKE_ACCOUNT_ID);
});
test('action fails when github env vars are not set', async () => {
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS));
delete process.env['GITHUB_SHA'];
await run();
expect(core.setFailed).toHaveBeenCalledWith(
'Missing required environment variables. Are you running in GitHub Actions?'
);
});
test('action does not require GITHUB_REF env var', async () => {
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(DEFAULT_INPUTS));
delete process.env['GITHUB_REF'];
await run();
expect(core.setFailed).toHaveBeenCalledTimes(0);
});
test('action with no accessible credentials fails', async () => {
const mockInputs = { 'aws-region': FAKE_REGION };
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(mockInputs));
(fromEnv as jest.Mock).mockReset();
(fromEnv as jest.Mock).mockImplementation(() => () => {
throw new CredentialsProviderError('test');
});
await run();
expect(core.setFailed).toHaveBeenCalledWith(
'Credentials could not be loaded, please check your action inputs: Could not load credentials from any providers'
);
});
test('action with empty credentials fails', async () => {
const mockInputs = { 'aws-region': FAKE_REGION };
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(mockInputs));
(fromEnv as jest.Mock).mockReset();
(fromEnv as jest.Mock).mockImplementation(
() => async () => Promise.resolve({ accessKeyId: '', secretAccessKey: '' })
);
await run();
expect(core.setFailed).toHaveBeenCalledWith(
'Credentials could not be loaded, please check your action inputs: Access key ID empty after loading credentials'
);
});
test('action fails when credentials are not set in the SDK correctly', async () => {
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(DEFAULT_INPUTS));
(fromEnv as jest.Mock).mockReset();
(fromEnv as jest.Mock).mockImplementationOnce(() => async () => Promise.resolve({ accessKeyId: '123' }));
await run();
expect(core.setFailed).toHaveBeenCalledWith(
'Unexpected failure: Credentials loaded by the SDK do not match the access key ID configured by the action'
);
});
test('session token is optional', async () => {
const mockInputs = { ...CREDS_INPUTS, 'aws-region': 'eu-west-1' };
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(mockInputs));
await run();
expect(mockedSTS.commandCalls(AssumeRoleCommand)).toHaveLength(0);
expect(core.exportVariable).toHaveBeenCalledTimes(4);
expect(core.setSecret).toHaveBeenCalledTimes(2);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_ACCESS_KEY_ID', FAKE_ACCESS_KEY_ID);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCESS_KEY_ID);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_SECRET_ACCESS_KEY', FAKE_SECRET_ACCESS_KEY);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_SECRET_ACCESS_KEY);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_DEFAULT_REGION', 'eu-west-1');
expect(core.exportVariable).toHaveBeenCalledWith('AWS_REGION', 'eu-west-1');
expect(core.setOutput).toHaveBeenCalledWith('aws-account-id', FAKE_ACCOUNT_ID);
});
test('existing env var creds are cleared', async () => {
const mockInputs = { ...CREDS_INPUTS, 'aws-region': 'eu-west-1' };
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(mockInputs));
process.env['AWS_ACCESS_KEY_ID'] = 'foo';
process.env['AWS_SECRET_ACCESS_KEY'] = 'bar';
process.env['AWS_SESSION_TOKEN'] = 'helloworld';
await run();
expect(mockedSTS.commandCalls(AssumeRoleCommand)).toHaveLength(0);
expect(core.exportVariable).toHaveBeenCalledTimes(5);
expect(core.setSecret).toHaveBeenCalledTimes(2);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_ACCESS_KEY_ID', FAKE_ACCESS_KEY_ID);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCESS_KEY_ID);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_SECRET_ACCESS_KEY', FAKE_SECRET_ACCESS_KEY);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_SECRET_ACCESS_KEY);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_SESSION_TOKEN', '');
expect(core.exportVariable).toHaveBeenCalledWith('AWS_DEFAULT_REGION', 'eu-west-1');
expect(core.exportVariable).toHaveBeenCalledWith('AWS_REGION', 'eu-west-1');
expect(core.setOutput).toHaveBeenCalledWith('aws-account-id', FAKE_ACCOUNT_ID);
});
test('validates region name', async () => {
const mockInputs = { ...CREDS_INPUTS, 'aws-region': '$AWS_REGION' };
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(mockInputs));
await run();
expect(core.setFailed).toHaveBeenCalledWith('Region is not valid: $AWS_REGION');
});
test('throws error if access key id exists but missing secret access key', async () => {
const inputsWIthoutSecretKey = { ...DEFAULT_INPUTS };
//@ts-expect-error deleting a required property to test failure condition
delete inputsWIthoutSecretKey['aws-secret-access-key'];
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(inputsWIthoutSecretKey));
await run();
expect(core.setFailed).toHaveBeenCalledWith(
"'aws-secret-access-key' must be provided if 'aws-access-key-id' is provided"
);
});
test('can opt into masking account ID', async () => {
const mockInputs = { ...CREDS_INPUTS, 'aws-region': 'us-east-1', 'mask-aws-account-id': 'true' };
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(mockInputs));
await run();
expect(mockedSTS.commandCalls(AssumeRoleCommand)).toHaveLength(0);
expect(core.exportVariable).toHaveBeenCalledTimes(4);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_ACCESS_KEY_ID', FAKE_ACCESS_KEY_ID);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCESS_KEY_ID);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_SECRET_ACCESS_KEY', FAKE_SECRET_ACCESS_KEY);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_SECRET_ACCESS_KEY);
expect(core.exportVariable).toHaveBeenCalledWith('AWS_DEFAULT_REGION', 'us-east-1');
expect(core.exportVariable).toHaveBeenCalledWith('AWS_REGION', 'us-east-1');
expect(core.setOutput).toHaveBeenCalledWith('aws-account-id', FAKE_ACCOUNT_ID);
expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCOUNT_ID);
expect(core.setSecret).toHaveBeenCalledTimes(3);
});
test('error is caught by core.setFailed and caught', async () => {
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(DEFAULT_INPUTS));
mockedSTS.reset();
mockedSTS.on(GetCallerIdentityCommand).rejects();
await run();
expect(core.setFailed).toHaveBeenCalled();
});
test('role assumption tags', async () => {
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS));
await run();
expect(mockedSTS.commandCalls(AssumeRoleCommand)[0]?.args[0].input).toEqual({
RoleArn: ROLE_ARN,
RoleSessionName: 'GitHubActions',
DurationSeconds: 3600,
Tags: [
{ Key: 'GitHub', Value: 'Actions' },
{ Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY },
{ Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW },
{ Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION },
{ Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED },
{ Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA },
{ Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF },
],
});
});
test('role assumption duration provided', async () => {
jest
.spyOn(core, 'getInput')
.mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS, 'role-duration-seconds': '5' }));
await run();
expect(mockedSTS.commandCalls(AssumeRoleCommand)[0]?.args[0].input).toEqual({
RoleArn: ROLE_ARN,
RoleSessionName: 'GitHubActions',
DurationSeconds: 5,
Tags: [
{ Key: 'GitHub', Value: 'Actions' },
{ Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY },
{ Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW },
{ Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION },
{ Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED },
{ Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA },
{ Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF },
],
});
});
test('role assumption session name provided', async () => {
jest
.spyOn(core, 'getInput')
.mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS, 'role-session-name': 'MySessionName' }));
await run();
expect(mockedSTS.commandCalls(AssumeRoleCommand)[0]?.args[0].input).toEqual({
RoleArn: ROLE_ARN,
RoleSessionName: 'MySessionName',
DurationSeconds: 3600,
Tags: [
{ Key: 'GitHub', Value: 'Actions' },
{ Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY },
{ Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW },
{ Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION },
{ Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED },
{ Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA },
{ Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF },
],
});
});
test('role name provided instead of ARN', async () => {
jest
.spyOn(core, 'getInput')
.mockImplementation(mockGetInput({ ...CREDS_INPUTS, 'role-to-assume': ROLE_NAME, 'aws-region': FAKE_REGION }));
await run();
expect(mockedSTS.commandCalls(AssumeRoleCommand)[0]?.args[0].input).toEqual({
RoleArn: 'arn:aws:iam::123456789012:role/MY-ROLE',
RoleSessionName: 'GitHubActions',
DurationSeconds: 3600,
Tags: [
{ Key: 'GitHub', Value: 'Actions' },
{ Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY },
{ Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW },
{ Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION },
{ Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED },
{ Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA },
{ Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF },
],
});
});
test('web identity token file provided with absolute path', async () => {
jest.spyOn(core, 'getInput').mockImplementation(
mockGetInput({
'role-to-assume': ROLE_ARN,
'aws-region': FAKE_REGION,
'web-identity-token-file': '/fake/token/file',
})
);
await run();
expect(mockedSTS.commandCalls(AssumeRoleWithWebIdentityCommand)[0]?.args[0].input).toEqual({
RoleArn: 'arn:aws:iam::111111111111:role/MY-ROLE',
RoleSessionName: 'GitHubActions',
DurationSeconds: 3600,
WebIdentityToken: 'testpayload',
});
});
test('web identity token file provided with relative path', async () => {
jest.spyOn(core, 'getInput').mockImplementation(
mockGetInput({
'role-to-assume': ROLE_ARN,
'aws-region': FAKE_REGION,
'web-identity-token-file': 'fake/token/file',
})
);
await run();
expect(mockedSTS.commandCalls(AssumeRoleWithWebIdentityCommand)[0]?.args[0].input).toEqual({
RoleArn: 'arn:aws:iam::111111111111:role/MY-ROLE',
RoleSessionName: 'GitHubActions',
DurationSeconds: 3600,
WebIdentityToken: 'testpayload',
});
});
test('only role arn and region provided to use GH OIDC Token', async () => {
process.env['GITHUB_ACTIONS'] = 'true';
process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN'] = 'test-token';
jest
.spyOn(core, 'getInput')
.mockImplementation(mockGetInput({ 'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION }));
await run();
expect(mockedSTS.commandCalls(AssumeRoleWithWebIdentityCommand)[0]?.args[0].input).toEqual({
RoleArn: 'arn:aws:iam::111111111111:role/MY-ROLE',
RoleSessionName: 'GitHubActions',
DurationSeconds: 3600,
WebIdentityToken: 'testtoken',
});
expect(core.getIDToken).toHaveBeenCalledTimes(1);
});
test('getIDToken call retries when failing', async () => {
process.env['GITHUB_ACTIONS'] = 'true';
process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN'] = 'test-token';
jest.spyOn(core, 'getIDToken').mockImplementation(() => {
throw new Error('test error');
});
jest
.spyOn(core, 'getInput')
.mockImplementation(mockGetInput({ 'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION }));
await run();
expect(core.getIDToken).toHaveBeenCalledTimes(12);
expect(core.setFailed).toHaveBeenCalledWith('getIDToken call failed: test error');
});
test('GH OIDC With custom role duration', async () => {
const CUSTOM_ROLE_DURATION = '1234';
process.env['GITHUB_ACTIONS'] = 'true';
process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN'] = 'test-token';
jest.spyOn(core, 'getInput').mockImplementation(
mockGetInput({
'role-to-assume': ROLE_ARN,
'aws-region': FAKE_REGION,
'role-duration-seconds': CUSTOM_ROLE_DURATION,
})
);
await run();
expect(mockedSTS.commandCalls(AssumeRoleWithWebIdentityCommand)[0]?.args[0].input).toEqual({
RoleArn: 'arn:aws:iam::111111111111:role/MY-ROLE',
RoleSessionName: 'GitHubActions',
DurationSeconds: parseInt(CUSTOM_ROLE_DURATION),
WebIdentityToken: 'testtoken',
});
});
test('GH OIDC check fails if token is not set', async () => {
(fromEnv as jest.Mock).mockReset();
process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN'] = undefined;
process.env['GITHUB_ACTIONS'] = 'true';
jest.spyOn(core, 'getInput').mockImplementation(
mockGetInput({
'role-to-assume': ROLE_ARN,
'aws-region': FAKE_REGION,
})
);
await run();
expect(core.info).toHaveBeenCalledWith(
'It looks like you might be trying to authenticate with OIDC. Did you mean to set the `id-token` permission?' +
' If you are not trying to authenticate with OIDC and the action is working successfully, you can ignore this message.'
);
expect(core.setFailed).toHaveBeenCalledWith(
'Credentials could not be loaded, please check your action inputs: provider is not a function'
);
});
test('Assume role with existing credentials if nothing else set', async () => {
process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN'] = undefined;
process.env['AWS_ACCESS_KEY_ID'] = FAKE_ACCESS_KEY_ID;
process.env['AWS_SECRET_ACCESS_KEY'] = FAKE_SECRET_ACCESS_KEY;
jest.spyOn(core, 'getInput').mockImplementation(
mockGetInput({
'role-to-assume': ROLE_ARN,
'aws-region': FAKE_REGION,
})
);
await run();
expect(core.info).toHaveBeenCalledWith(
'It looks like you might be trying to authenticate with OIDC. Did you mean to set the `id-token` permission?' +
' If you are not trying to authenticate with OIDC and the action is working successfully, you can ignore this message.'
);
expect(mockedSTS.commandCalls(AssumeRoleCommand).length).toEqual(1);
});
test('role assumption fails after maximum trials using OIDC provider', async () => {
process.env['GITHUB_ACTIONS'] = 'true';
process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN'] = 'test-token';
jest
.spyOn(core, 'getInput')
.mockImplementation(mockGetInput({ 'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION }));
mockedSTS.reset();
mockedSTS.on(AssumeRoleWithWebIdentityCommand).rejects();
await run();
expect(mockedSTS.commandCalls(AssumeRoleWithWebIdentityCommand).length).toEqual(12);
});
test('role assumption fails after one trial when disabling retry', async () => {
process.env['GITHUB_ACTIONS'] = 'true';
process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN'] = 'test-token';
jest
.spyOn(core, 'getInput')
.mockImplementation(
mockGetInput({ 'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION, 'disable-retry': 'true' })
);
mockedSTS.reset();
mockedSTS.on(AssumeRoleWithWebIdentityCommand).rejects();
await run();
expect(mockedSTS.commandCalls(AssumeRoleWithWebIdentityCommand).length).toEqual(1);
});
test('special character workaround works for AWS_ACCESS_KEY_ID', async () => {
jest
.spyOn(core, 'getInput')
.mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS, 'special-characters-workaround': 'true' }));
mockedSTS
.on(AssumeRoleCommand)
.resolvesOnce({
Credentials: {
AccessKeyId: FAKE_STS_ACCESS_KEY_ID,
SecretAccessKey: 'asdf+',
SessionToken: FAKE_STS_SESSION_TOKEN,
Expiration: new Date(8640000000000000),
},
})
.resolves({
Credentials: {
AccessKeyId: FAKE_STS_ACCESS_KEY_ID,
SecretAccessKey: 'asdf',
SessionToken: FAKE_STS_SESSION_TOKEN,
Expiration: new Date(8640000000000000),
},
});
await run();
expect(mockedSTS.commandCalls(AssumeRoleCommand).length).toEqual(2);
});
test('special character workaround works for AWS_SECRET_ACCESS_KEY', async () => {
jest
.spyOn(core, 'getInput')
.mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS, 'special-characters-workaround': 'true' }));
mockedSTS
.on(AssumeRoleCommand)
.resolvesOnce({
Credentials: {
AccessKeyId: FAKE_STS_ACCESS_KEY_ID,
SecretAccessKey: 'asdf+',
SessionToken: FAKE_STS_SESSION_TOKEN,
Expiration: new Date(8640000000000000),
},
})
.resolves({
Credentials: {
AccessKeyId: FAKE_STS_ACCESS_KEY_ID,
SecretAccessKey: 'asdf',
SessionToken: FAKE_STS_SESSION_TOKEN,
Expiration: new Date(8640000000000000),
},
});
await run();
expect(mockedSTS.commandCalls(AssumeRoleCommand).length).toEqual(2);
});
test('max retries is configurable', async () => {
process.env['GITHUB_ACTIONS'] = 'true';
process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN'] = 'test-token';
jest.spyOn(core, 'getInput').mockImplementation(
mockGetInput({
'role-to-assume': ROLE_ARN,
'aws-region': FAKE_REGION,
'retry-max-attempts': '15',
})
);
mockedSTS.reset();
mockedSTS.on(AssumeRoleWithWebIdentityCommand).rejects();
await run();
expect(mockedSTS.commandCalls(AssumeRoleWithWebIdentityCommand).length).toEqual(15);
expect(core.setFailed).toHaveBeenCalledWith('Could not assume role with OIDC: ');
});
test('max retries negative input does not retry', async () => {
process.env['GITHUB_ACTIONS'] = 'true';
process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN'] = 'test-token';
jest.spyOn(core, 'getInput').mockImplementation(
mockGetInput({
'role-to-assume': ROLE_ARN,
'aws-region': FAKE_REGION,
'retry-max-attempts': '-1',
})
);
mockedSTS.reset();
mockedSTS.on(AssumeRoleWithWebIdentityCommand).rejects();
await run();
expect(mockedSTS.commandCalls(AssumeRoleWithWebIdentityCommand).length).toEqual(1);
expect(core.setFailed).toHaveBeenCalledWith('Could not assume role with OIDC: ');
});
test('role external ID provided', async () => {
jest
.spyOn(core, 'getInput')
.mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS, 'role-external-id': 'abcdef' }));
await run();
expect(mockedSTS.commandCalls(AssumeRoleCommand)[0]?.args[0].input).toEqual({
RoleArn: ROLE_ARN,
RoleSessionName: 'GitHubActions',
DurationSeconds: 3600,
Tags: [
{ Key: 'GitHub', Value: 'Actions' },
{ Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY },
{ Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW },
{ Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION },
{ Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED },
{ Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA },
{ Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF },
],
ExternalId: 'abcdef',
});
});
test('workflow name sanitized in role assumption tags', async () => {
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS));
process.env = {
...process.env,
GITHUB_WORKFLOW:
'Workflow!"#$%&\'()*+, -./:;<=>?@[]^_`{|}~🙂💥🍌1yFvMOeD3ZHYsHrGjCceOboMYzBPo0CRNFdcsVRG6UgR3A912a8KfcBtEVvkAS7kRBq80umGff8mux5IN1y55HQWPNBNyaruuVr4islFXte4FDQZexGJRUSMyHQpxJ8OmZnET84oDmbvmIjgxI6IBrdihX9PHMapT4gQvRYnLqNiKb18rEMWDNoZRy51UPX5sWK2GKPipgKSO9kqLckZai9D2AN2RlWCxtMqChNtxuxjqeqhoQZo0oaq39sjcRZgAAAAAAA',
};
const sanitizedWorkflowName =
'Workflow__________+_ -./:__=__@____________1yFvMOeD3ZHYsHrGjCceOboMYzBPo0CRNFdcsVRG6UgR3A912a8KfcBtEVvkAS7kRBq80umGff8mux5IN1y55HQWPNBNyaruuVr4islFXte4FDQZexGJRUSMyHQpxJ8OmZnET84oDmbvmIjgxI6IBrdihX9PHMapT4gQvRYnLqNiKb18rEMWDNoZRy51UPX5sWK2GKPipgKSO9kqLckZa';
await run();
expect(mockedSTS.commandCalls(AssumeRoleCommand)[0]?.args[0].input).toEqual({
RoleArn: ROLE_ARN,
RoleSessionName: 'GitHubActions',
DurationSeconds: 3600,
Tags: [
{ Key: 'GitHub', Value: 'Actions' },
{ Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY },
{ Key: 'Workflow', Value: sanitizedWorkflowName },
{ Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION },
{ Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED },
{ Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA },
{ Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF },
],
});
});
test('skip tagging provided as true', async () => {
jest
.spyOn(core, 'getInput')
.mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS, 'role-skip-session-tagging': 'true' }));
await run();
expect(mockedSTS.commandCalls(AssumeRoleCommand)[0]?.args[0].input).toEqual({
RoleArn: ROLE_ARN,
RoleSessionName: 'GitHubActions',
DurationSeconds: 3600,
Tags: undefined,
});
});
test('skip tagging provided as false', async () => {
jest
.spyOn(core, 'getInput')
.mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS, 'role-skip-session-tagging': 'false' }));
await run();
expect(mockedSTS.commandCalls(AssumeRoleCommand)[0]?.args[0].input).toEqual({
RoleArn: ROLE_ARN,
RoleSessionName: 'GitHubActions',
DurationSeconds: 3600,
Tags: [
{ Key: 'GitHub', Value: 'Actions' },
{ Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY },
{ Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW },
{ Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION },
{ Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED },
{ Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA },
{ Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF },
],
});
});
test('skip tagging not provided', async () => {
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS }));
await run();
expect(mockedSTS.commandCalls(AssumeRoleCommand)[0]?.args[0].input).toEqual({
RoleArn: ROLE_ARN,
RoleSessionName: 'GitHubActions',
DurationSeconds: 3600,
Tags: [
{ Key: 'GitHub', Value: 'Actions' },
{ Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY },
{ Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW },
{ Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION },
{ Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED },
{ Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA },
{ Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF },
],
});
});
test('masks variables before exporting', async () => {
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS));
const maskedValues: string[] = [];
const publicFields = ['AWS_REGION', 'AWS_DEFAULT_REGION'];
jest.spyOn(core, 'setSecret').mockImplementation((secret) => {
maskedValues.push(secret);
});
jest.spyOn(core, 'exportVariable').mockImplementation((name, value) => {
const val = String(value);
if (!maskedValues.includes(val) && !publicFields.includes(name)) {
throw new Error(`{value} for variable ${name} is not masked yet!`);
}
process.env[name] = val;
});
await run();
expect(core.exportVariable).toReturn();
});
test('inline policy and managed session policies are provided in assume role calls', async () => {
jest
.spyOn(core, 'getInput')
.mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS, 'inline-session-policy': 'inline' }));
jest
.spyOn(core, 'getMultilineInput')
.mockImplementation(mockGetMultilineInput({ 'managed-session-policies': MANAGED_SESSION_POLICY_INPUT }));
await run();
expect(mockedSTS.commandCalls(AssumeRoleCommand)[0]?.args[0].input).toEqual({
RoleArn: ROLE_ARN,
RoleSessionName: 'GitHubActions',
DurationSeconds: 3600,
Tags: [
{ Key: 'GitHub', Value: 'Actions' },
{ Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY },
{ Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW },
{ Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION },
{ Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED },
{ Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA },
{ Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF },
],
Policy: 'inline',
PolicyArns: [
{ arn: 'arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess' },
{ arn: 'arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess' },
],
});
});
test('prints assumed role id', async () => {
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS));
await run();
expect(core.info).toHaveBeenCalledWith(`Authenticated as assumedRoleId ${FAKE_ASSUMED_ROLE_ID}`);
});
test('unsets credentials if enabled', async () => {
jest
.spyOn(core, 'getInput')
.mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS, 'unset-current-credentials': 'true' }));
await run();
expect(core.exportVariable).toHaveBeenCalledTimes(12);
});
test('sets credentials as output if enabled', async () => {
jest
.spyOn(core, 'getInput')
.mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS, 'output-credentials': 'true' }));
await run();
expect(core.setOutput).toHaveBeenCalledTimes(4);
});
test('prints warning for access key usage and no session token', async () => {
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS));
await run();
expect(core.warning).toHaveBeenCalledWith(
'To avoid using long-term AWS credentials, please update your workflows to authenticate using OpenID Connect.' +
' See https://s12d.com/gha-oidc-aws for more information.'
);
});
test('skips warning for access key usage with session token', async () => {
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(DEFAULT_INPUTS));
await run();
expect(core.warning).toHaveBeenCalledTimes(0);
});
});
-9
View File
@@ -1,9 +0,0 @@
{
"extends": "./tsconfig.json",
"exclude": [
"test/**/*.ts"
],
"compilerOptions": {
"rootDir": "src"
},
}
-34
View File
@@ -1,34 +0,0 @@
{
"compilerOptions": {
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"strict": true,
"exactOptionalPropertyTypes": false,
"noFallthroughCasesInSwitch": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noPropertyAccessFromIndexSignature": true,
"noUncheckedIndexedAccess": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"module": "CommonJS",
"resolveJsonModule": true,
"outDir": "build",
"declaration": true,
"newLine": "lf",
"noEmitOnError": true,
"sourceMap": true,
"disableSizeLimit": true,
"forceConsistentCasingInFileNames": true,
"lib": [ "ES2020" ],
"target": "ES2020",
"noErrorTruncation": true,
"esModuleInterop": true
},
"include": [
"src/**/*.ts",
"test/**/*.ts"
],
"exclude": [],
}