mirror of
https://github.com/aws-actions/configure-aws-credentials.git
synced 2026-09-05 06:25:08 +09:00
chore: unstage devel changes (#1786)
* Revert "chore: Update dist" This reverts commite8614cfbf0. * Revert "chore(deps): bump @aws-sdk/client-sts from 3.1045.0 to 3.1049.0 (#1782)" This reverts commit4684f47f89. * Revert "chore: Update dist" This reverts commit48b8685c96. * Revert "chore(deps-dev): bump @smithy/property-provider from 4.3.1 to 4.3.3 (#1783)" This reverts commitfe6ad3af19. * Revert "chore: Update dist" This reverts commit2520c5e921. * Revert "chore(deps-dev): bump @aws-sdk/credential-provider-env (#1784)" This reverts commitbc1093db1d. * Revert "chore(deps-dev): bump @types/node from 25.7.0 to 25.9.0 (#1785)" This reverts commitffde832a1d. * Revert "chore: Update dist" This reverts commit707acd96f6. * Revert "chore(deps): bump @smithy/node-http-handler from 4.7.1 to 4.7.3 (#1781)" This reverts commita7c33ae483. * Revert "chore: update README for additional claim support (#1779)" This reverts commit713aaabfec. * Revert "chore: Update dist" This reverts commite6e8eba750. * Revert "fix: skip credential check on output-env-credentials: false (#1778)" This reverts commit58e7c47adf. * Revert "chore: document forgejo compatibility (#1776)" This reverts commitf35a7d7d7e. * Revert "chore: Update dist" This reverts commit3884f59ecd. * Revert "feat: add additional session tags by default (#1775)" This reverts commite0ba768507. * Revert "chore: Update dist" This reverts commit6795889618. * Revert "feat: expose run id in STS client user-agent (#1774)" This reverts commit29d1be3027. * Revert "chore(deps-dev): bump @types/node from 25.6.0 to 25.7.0 (#1773)" This reverts commitef734cca81. * Revert "chore(deps-dev): bump @biomejs/biome from 2.4.14 to 2.4.15 (#1772)" This reverts commit7521c55910. * Revert "chore: Update dist" This reverts commitc0e2737f14. * Revert "chore(deps): bump @smithy/node-http-handler from 4.6.1 to 4.7.1 (#1770)" This reverts commitdbd503f368. * Revert "chore: Update dist" This reverts commit18a236fbd1. * Revert "chore(deps-dev): bump @smithy/property-provider from 4.2.14 to 4.3.1 (#1771)" This reverts commit1ab31502aa. * Revert "chore(deps-dev): bump @vitest/coverage-v8 from 4.1.5 to 4.1.6 (#1768)" This reverts commit1fb495c4b2. * Revert "chore: Update dist" This reverts commit1e8fec8ea1. * Revert "chore(deps): bump @aws-sdk/client-sts from 3.1044.0 to 3.1045.0 (#1767)" This reverts commita388f23f7d. * Revert "chore: update documentation for environment workflows (#1766)" This reverts commit3f7e1b63d7. * Revert "feat: add regex validation to role-session-name (#1765)" This reverts commite35449909c. * Revert "chore: Update dist" This reverts commit958a80fc34. * Revert "feat: add more retry logic and better logging (#1764)" This reverts commit540d0c13ae. * Revert "chore: automate README version bumping (#1763)" This reverts commit07ada0fe07. * Revert "chore: Update dist" This reverts commitf8d4eb68a9. * Revert "feat: support custom STS endpoints (#1762)" This reverts commit8d52d05d7a. * Revert "chore: Update dist" This reverts commit681892c11b. * Revert "chore: configure codeql to ignore generated code (#1760)" This reverts commitdc2353e57a. * Revert "feat: Allow custom session tags to be passed when assuming a role (#1759)" This reverts commit61f50f630f. * Revert "chore: automatic major version tagging (#1565)" This reverts commitc36525a567. * Revert "chore: bump unit test node version (#1758)" This reverts commit39d1702721. * Revert "chore(deps): bump @aws-sdk/client-sts from 3.1043.0 to 3.1044.0 (#1754)" This reverts commit4cfda40a13. * Revert "chore(deps-dev): bump @biomejs/biome from 2.4.13 to 2.4.14 (#1756)" This reverts commit8856e12f3a. * Revert "chore(deps): bump @actions/core from 2.0.3 to 3.0.1 (#1746)" This reverts commit64d8e82527. * Revert "chore(deps-dev): bump vitest from 3.2.4 to 4.1.5 (#1748)" This reverts commit78f374f6d1.
This commit is contained in:
@@ -1,5 +0,0 @@
|
|||||||
name: "CodeQL config"
|
|
||||||
|
|
||||||
paths-ignore:
|
|
||||||
- dist
|
|
||||||
- node_modules
|
|
||||||
@@ -36,7 +36,6 @@
|
|||||||
${{ secrets.OSDS_PACKAGING_ROLE }}
|
${{ secrets.OSDS_PACKAGING_ROLE }}
|
||||||
|
|
||||||
- name: Run release-please
|
- name: Run release-please
|
||||||
id: release
|
|
||||||
uses: googleapis/release-please-action@v4
|
uses: googleapis/release-please-action@v4
|
||||||
with:
|
with:
|
||||||
release-type: node
|
release-type: node
|
||||||
@@ -44,33 +43,3 @@
|
|||||||
config-file: release-please-config.json
|
config-file: release-please-config.json
|
||||||
manifest-file: .release-please-manifest.json
|
manifest-file: .release-please-manifest.json
|
||||||
|
|
||||||
- name: Checkout Again
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Tag Major Version
|
|
||||||
if: ${{ steps.release.outputs.release_created }}
|
|
||||||
run: |
|
|
||||||
git config user.name "GitHub Actions"
|
|
||||||
git config user.email "github-aws-sdk-osds-automation@amazon.com"
|
|
||||||
if git rev-parse "v${{ steps.release.outputs.major }}" >/dev/null 2>&1; then
|
|
||||||
git tag -d "v${{ steps.release.outputs.major }}"
|
|
||||||
git push origin ":v${{ steps.release.outputs.major }}"
|
|
||||||
fi
|
|
||||||
git tag -a "v${{ steps.release.outputs.major }}" -m "Release v${{ steps.release.outputs.major }}"
|
|
||||||
git push origin "v${{ steps.release.outputs.major }}"
|
|
||||||
|
|
||||||
- name: Update README version references
|
|
||||||
if: ${{ steps.release.outputs.release_created }}
|
|
||||||
run: |
|
|
||||||
sed -i 's|configure-aws-credentials@v[0-9]*\.[0-9]*\.[0-9]*|configure-aws-credentials@${{ steps.release.outputs.tag_name }}|g' README.md
|
|
||||||
if git diff --quiet README.md; then
|
|
||||||
echo "README already up to date"
|
|
||||||
else
|
|
||||||
echo "::add-mask::${{ env.OSDS_ACCESS_TOKEN }}"
|
|
||||||
git remote set-url origin https://${{ env.OSDS_ACCESS_TOKEN }}@github.com/aws-actions/configure-aws-credentials.git
|
|
||||||
git add README.md
|
|
||||||
git commit -m "docs: update README version references to ${{ steps.release.outputs.tag_name }}"
|
|
||||||
git push --force origin
|
|
||||||
fi
|
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ jobs:
|
|||||||
- name: "Checkout repository"
|
- name: "Checkout repository"
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v5
|
||||||
- name: "Setup node"
|
- name: "Setup node"
|
||||||
uses: actions/setup-node@v6.4.0
|
uses: actions/setup-node@v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 20
|
||||||
- name: "Install dependencies"
|
- name: "Install dependencies"
|
||||||
run: npm ci
|
run: npm ci
|
||||||
- name: "Run tests"
|
- name: "Run tests"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
.history
|
|
||||||
node_modules
|
node_modules
|
||||||
coverage
|
coverage
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
# Configure AWS Credentials
|
# Configure AWS Credentials
|
||||||
|
|
||||||
Authenticate to AWS in GitHub Actions (and others)! Works especially well with
|
Authenticate to AWS in GitHub Actions! Works especially well with
|
||||||
[AWS Secrets Manager][secretsmanager].
|
[AWS Secrets Manager][secretsmanager].
|
||||||
|
|
||||||
[secretsmanager]: https://github.com/aws-actions/aws-secretsmanager-get-secrets
|
[secretsmanager]:
|
||||||
|
https://github.com/aws-actions/aws-secretsmanager-get-secrets
|
||||||
|
|
||||||
## Quick Start (OIDC, recommended)
|
## Quick Start (OIDC, recommended)
|
||||||
|
|
||||||
1. Create an IAM Identity Provider in your AWS account for GitHub OIDC. (See
|
1. Create an IAM Identity Provider in your AWS account for GitHub OIDC. (See
|
||||||
[OIDC configuration](#oidc-configuration-details) below for details.)
|
[OIDC configuration](#oidc-configuration-details) below for details.)
|
||||||
2. Create an IAM Role in your AWS account with a trust policy that allows GitHub
|
2. Create an IAM Role in your AWS account with a trust policy that allows
|
||||||
Actions to assume it. (Expand the sections below) <details>
|
GitHub Actions to assume it. (Expand the sections below) <details>
|
||||||
<summary>GitHub OIDC Trust Policy</summary>
|
<summary>GitHub OIDC Trust Policy</summary>
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -36,12 +37,6 @@ Authenticate to AWS in GitHub Actions (and others)! Works especially well with
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
Note: if you are running in a GitHub environment based workflow, the value
|
|
||||||
for the Sub claim will be different, in the form of
|
|
||||||
`repo:<GITHUB_ORG>/<GITHUB_REPOSITORY>:environment:<ENVIRONMENT_NAME>`.
|
|
||||||
Adjust the trust policy accordingly if you are using environment-based
|
|
||||||
workflows.
|
|
||||||
|
|
||||||
3. Attach permissions to the IAM Role that allow it to access the AWS resources
|
3. Attach permissions to the IAM Role that allow it to access the AWS resources
|
||||||
you need.
|
you need.
|
||||||
4. Add the following to your GitHub Actions workflow: <details>
|
4. Add the following to your GitHub Actions workflow: <details>
|
||||||
@@ -68,9 +63,9 @@ Authenticate to AWS in GitHub Actions (and others)! Works especially well with
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
That's it! Your GitHub Actions workflow can now access AWS resources using the
|
That's it! Your GitHub Actions workflow can now access AWS resources using
|
||||||
IAM Role you created. Other authentication scenarios are also supported (see
|
the IAM Role you created. Other authentication scenarios are also supported
|
||||||
below).
|
(see below).
|
||||||
|
|
||||||
## Security Recommendations
|
## Security Recommendations
|
||||||
|
|
||||||
@@ -86,8 +81,8 @@ below).
|
|||||||
of the credentials used in workflows.
|
of the credentials used in workflows.
|
||||||
- Periodically rotate any long-lived credentials that you use.
|
- Periodically rotate any long-lived credentials that you use.
|
||||||
- Store sensitive information in a secure way, such as using
|
- Store sensitive information in a secure way, such as using
|
||||||
[AWS Secrets Manager](https://aws.amazon.com/secrets-manager/) or [GitHub
|
[AWS Secrets Manager](https://aws.amazon.com/secrets-manager/) or
|
||||||
Secrets][gh-secrets].
|
[GitHub Secrets][gh-secrets].
|
||||||
- Be especially careful about running Actions in non-ephemeral environments, or
|
- Be especially careful about running Actions in non-ephemeral environments, or
|
||||||
[triggering workflows on `pull_request_target`](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#pull_request_target)
|
[triggering workflows on `pull_request_target`](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#pull_request_target)
|
||||||
events.
|
events.
|
||||||
@@ -110,12 +105,11 @@ by specifying different inputs.
|
|||||||
5. Use credentials stored in the Action environment to fetch temporary
|
5. Use credentials stored in the Action environment to fetch temporary
|
||||||
credentials via STS AssumeRole.
|
credentials via STS AssumeRole.
|
||||||
|
|
||||||
Because we use the AWS JavaScript SDK, we always will use the [credential
|
Because we use the AWS JavaScript SDK, we always will use the
|
||||||
resolution flow for Node.js][cred-resolution].
|
[credential resolution flow for Node.js][cred-resolution].
|
||||||
|
|
||||||
[cred-resolution]:
|
[cred-resolution]:
|
||||||
https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html
|
https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html
|
||||||
|
|
||||||
Depending on your inputs, the action might override parts of this flow.
|
Depending on your inputs, the action might override parts of this flow.
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
@@ -137,8 +131,8 @@ enabling this option._
|
|||||||
|
|
||||||
Additionally, **`aws-region`** is always required.
|
Additionally, **`aws-region`** is always required.
|
||||||
|
|
||||||
_Note: If you use GitHub Enterprise Server, you may need to adjust examples here
|
_Note: If you use GitHub Enterprise Server, you may need to adjust examples
|
||||||
to match your environment._
|
here to match your environment._
|
||||||
|
|
||||||
## Additional Options
|
## Additional Options
|
||||||
|
|
||||||
@@ -151,7 +145,7 @@ detail.
|
|||||||
<summary>Options list and descriptions</summary>
|
<summary>Options list and descriptions</summary>
|
||||||
|
|
||||||
| Option | Description | Required |
|
| Option | Description | Required |
|
||||||
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
|
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
|
||||||
| aws-region | Which AWS region to use | Yes |
|
| aws-region | Which AWS region to use | Yes |
|
||||||
| aws-profile | Name of the AWS profile to configure. When provided, credentials are written to `~/.aws/credentials` and `~/.aws/config` files. This enables configuring multiple profiles in a single workflow. Name cannot contain whitespace, square brackets, or slashes. When set, credentials will not be exported as environment variables unless `output-env-credentials` is manually set to true. | No |
|
| aws-profile | Name of the AWS profile to configure. When provided, credentials are written to `~/.aws/credentials` and `~/.aws/config` files. This enables configuring multiple profiles in a single workflow. Name cannot contain whitespace, square brackets, or slashes. When set, credentials will not be exported as environment variables unless `output-env-credentials` is manually set to true. | No |
|
||||||
| overwrite-aws-profile | Overwrite the given AWS profile if it already exists. When set to false or not set, an error will be thrown if the profile already exists. | No |
|
| overwrite-aws-profile | Overwrite the given AWS profile if it already exists. When set to false or not set, an error will be thrown if the profile already exists. | No |
|
||||||
@@ -216,8 +210,8 @@ Profile names may not contain whitespace, square brackets, or forward or
|
|||||||
backslashes.
|
backslashes.
|
||||||
|
|
||||||
Writing to a profile will prevent credentials being written to the environment
|
Writing to a profile will prevent credentials being written to the environment
|
||||||
by default. Use `output-env-credentials: true` if you would like the credentials
|
by default. Use `output-env-credentials: true` if you would like the
|
||||||
to also be exported as environment variables.
|
credentials to also be exported as environment variables.
|
||||||
|
|
||||||
By default, the action will not overwrite existing profiles. If you would like
|
By default, the action will not overwrite existing profiles. If you would like
|
||||||
to overwrite a profile, set the `overwrite-aws-profile` input to `true`.
|
to overwrite a profile, set the `overwrite-aws-profile` input to `true`.
|
||||||
@@ -232,8 +226,8 @@ extreme care to ensure that this is safe in your environment and you do not leak
|
|||||||
valid credentials unintentionally. Writing to configuration files is intended
|
valid credentials unintentionally. Writing to configuration files is intended
|
||||||
for unusual authentication scenarios._
|
for unusual authentication scenarios._
|
||||||
|
|
||||||
For using profiles with static IAM User Credentials or when using one role to
|
For using profiles with static IAM User Credentials or when using one
|
||||||
assume another, role chaining is needed:
|
role to assume another, role chaining is needed:
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
|
|
||||||
@@ -254,9 +248,9 @@ specify the profile name as an environment variable in the job step:
|
|||||||
AWS_PROFILE: MyProfile1
|
AWS_PROFILE: MyProfile1
|
||||||
```
|
```
|
||||||
|
|
||||||
If you are using one role to assume another while using profiles, the subsequent
|
If you are using one role to assume another while using profiles, the
|
||||||
steps must set `role-chaining: true` and specify the prior profile's name as
|
subsequent steps must set `role-chaining: true` and specify the prior profile's
|
||||||
step environment variables:
|
name as step environment variables:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Configure AWS credentials
|
- name: Configure AWS credentials
|
||||||
@@ -289,7 +283,7 @@ environment variable to `true`:
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
env:
|
env:
|
||||||
AWS_SKIP_CLEANUP_STEP: "true"
|
AWS_SKIP_CLEANUP_STEP: 'true'
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Use an HTTP proxy
|
#### Use an HTTP proxy
|
||||||
@@ -322,12 +316,11 @@ HTTP_PROXY="http://companydomain.com:3128"
|
|||||||
#### Special characters in AWS_SECRET_ACCESS_KEY
|
#### Special characters in AWS_SECRET_ACCESS_KEY
|
||||||
|
|
||||||
Some edge cases are unable to properly parse an `AWS_SECRET_ACCESS_KEY` if it
|
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
|
contains special characters. For more information, please see the
|
||||||
documentation][aws-cli-troubleshooting].
|
[AWS CLI documentation][aws-cli-troubleshooting].
|
||||||
|
|
||||||
[aws-cli-troubleshooting]:
|
[aws-cli-troubleshooting]:
|
||||||
https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-troubleshooting.html#tshoot-signature-does-not-match
|
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
|
If you set the `special-characters-workaround` option, this action will
|
||||||
continually retry fetching credentials until we get one that does not have
|
continually retry fetching credentials until we get one that does not have
|
||||||
special characters. This option overrides the `disable-retry` and
|
special characters. This option overrides the `disable-retry` and
|
||||||
@@ -344,15 +337,13 @@ _Note: you might find it helpful to set the `role-session-name` to
|
|||||||
`${{ github.run_id }}` so as to clarify in audit logs which AWS actions were
|
`${{ github.run_id }}` so as to clarify in audit logs which AWS actions were
|
||||||
performed by which workflow run._
|
performed by which workflow run._
|
||||||
|
|
||||||
The session will be tagged with the following tags: (Refer to [GitHub's
|
The session will be tagged with the following tags: (Refer to
|
||||||
documentation for `GITHUB_` environment variable definitions][gh-env-vars])
|
[GitHub's documentation for `GITHUB_` environment variable
|
||||||
|
definitions][gh-env-vars])
|
||||||
|
|
||||||
[gh-env-vars]:
|
[gh-env-vars]:
|
||||||
https://docs.github.com/en/actions/reference/workflows-and-actions/variables#default-environment-variables
|
https://docs.github.com/en/actions/reference/workflows-and-actions/variables#default-environment-variables
|
||||||
|
|
||||||
**Protected tags** are always emitted when session tags are used, and cannot be
|
|
||||||
overridden via `custom-tags`:
|
|
||||||
|
|
||||||
| Key | Value |
|
| Key | Value |
|
||||||
| ---------- | ----------------- |
|
| ---------- | ----------------- |
|
||||||
| GitHub | "Actions" |
|
| GitHub | "Actions" |
|
||||||
@@ -360,43 +351,21 @@ overridden via `custom-tags`:
|
|||||||
| Workflow | GITHUB_WORKFLOW |
|
| Workflow | GITHUB_WORKFLOW |
|
||||||
| Action | GITHUB_ACTION |
|
| Action | GITHUB_ACTION |
|
||||||
| Actor | GITHUB_ACTOR |
|
| Actor | GITHUB_ACTOR |
|
||||||
| Commit | GITHUB_SHA |
|
|
||||||
| Branch | GITHUB_REF |
|
| Branch | GITHUB_REF |
|
||||||
|
| Commit | GITHUB_SHA |
|
||||||
**Overrideable tags** are automatically added to the set of default session tags
|
|
||||||
but may be overridden via `custom-tags`. AWS has a maximum limit of 50 session
|
|
||||||
tags; tags from this list are dropped in reverse priority order if your
|
|
||||||
`custom-tags` set plus the protected set exceeds this limit.
|
|
||||||
|
|
||||||
| Key | Value | Priority |
|
|
||||||
| --------------- | ----------------------- | -------- |
|
|
||||||
| EventName | GITHUB_EVENT_NAME | 1 |
|
|
||||||
| BaseRef | GITHUB_BASE_REF | 2 |
|
|
||||||
| HeadRef | GITHUB_HEAD_REF | 3 |
|
|
||||||
| RefName | GITHUB_REF_NAME | 4 |
|
|
||||||
| RunId | GITHUB_RUN_ID | 5 |
|
|
||||||
| RefType | GITHUB_REF_TYPE | 6 |
|
|
||||||
| Job | GITHUB_JOB | 7 |
|
|
||||||
| TriggeringActor | GITHUB_TRIGGERING_ACTOR | 8 |
|
|
||||||
|
|
||||||
Tags whose source environment variable is unset are omitted (e.g., `BaseRef` and
|
|
||||||
`HeadRef` are only set on `pull_request` events).
|
|
||||||
|
|
||||||
_Note: all tag values must conform to
|
_Note: all tag values must conform to
|
||||||
[the tag requirements][sts-tag-requirements].
|
[the tag requirements](https://docs.aws.amazon.com/STS/latest/APIReference/API_Tag.html).
|
||||||
Values longer than 256 characters will be truncated, and characters outside the
|
Particularly, `GITHUB_WORKFLOW` will be truncated if it's too long. If
|
||||||
allowed set will be replaced with an underscore (`_`).\_
|
`GITHUB_ACTOR` or `GITHUB_WORKFLOW` contain invalid characters, the characters
|
||||||
|
will be replaced with an '\*'._
|
||||||
[sts-tag-requirements]:
|
|
||||||
https://docs.aws.amazon.com/STS/latest/APIReference/API_Tag.html
|
|
||||||
|
|
||||||
The action will use session tagging by default unless you are using OIDC.
|
The action will use session tagging by default unless you are using OIDC.
|
||||||
|
|
||||||
To [forward session tags to subsequent sessions in a role
|
To [forward session tags to subsequent sessions in a role
|
||||||
chain][session-tag-chaining], you can use
|
chain][session-tag-chaining], you can use
|
||||||
|
|
||||||
[session-tag-chaining]:
|
[session-tag-chaining]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining
|
||||||
https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining
|
|
||||||
|
|
||||||
the `transitive-tag-keys` input to specify the keys of the tags to be passed.
|
the `transitive-tag-keys` input to specify the keys of the tags to be passed.
|
||||||
|
|
||||||
@@ -413,23 +382,6 @@ with:
|
|||||||
Actor
|
Actor
|
||||||
```
|
```
|
||||||
|
|
||||||
### Custom session tags
|
|
||||||
|
|
||||||
You can add custom session tags using the `custom-tags` input, which accepts a
|
|
||||||
JSON object. Custom tags cannot override protected tags, but they can override
|
|
||||||
overrideable tags (in which case the overrideable tag's slot is freed for the
|
|
||||||
next overrideable tag in the priority list, if any).
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
uses: aws-actions/configure-aws-credentials@v6
|
|
||||||
with:
|
|
||||||
custom-tags: '{"Environment": "Production", "Team": "Platform"}'
|
|
||||||
```
|
|
||||||
|
|
||||||
_Note: custom tags are not supported when using OIDC or web identity token
|
|
||||||
authentication. In those flows, session tags are controlled by the identity
|
|
||||||
provider's token claims._
|
|
||||||
|
|
||||||
### Session policies
|
### Session policies
|
||||||
|
|
||||||
Session policies are not required, but they allow you to limit the scope of the
|
Session policies are not required, but they allow you to limit the scope of the
|
||||||
@@ -500,12 +452,6 @@ with:
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### Custom STS endpoint
|
|
||||||
|
|
||||||
Use the `sts-endpoint` input to override the AWS STS endpoint URL. Most users
|
|
||||||
should not set this option and instead let the SDK derive the correct endpoint
|
|
||||||
from the specified region.
|
|
||||||
|
|
||||||
## OIDC Configuration Details
|
## OIDC Configuration Details
|
||||||
|
|
||||||
We recommend using
|
We recommend using
|
||||||
@@ -570,42 +516,41 @@ aws iam create-open-id-connect-provider \
|
|||||||
|
|
||||||
### Claims and scoping permissions
|
### Claims and scoping permissions
|
||||||
|
|
||||||
To align with the Amazon IAM best practice of [granting least
|
To align with the Amazon IAM best practice of
|
||||||
privilege][least-privilege], the assume role policy document should contain a
|
[granting least privilege][least-privilege],
|
||||||
[`Condition`](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html)
|
|
||||||
that restricts which workflows can assume the role. Without any condition, any
|
|
||||||
GitHub user or repository could potentially assume the role.
|
|
||||||
|
|
||||||
GitHub provides a number of additional claims in the OIDC token that you can use
|
|
||||||
in your IAM policies to scope down permissions. Early versions of this action
|
|
||||||
only supported the `sub` and `aud` claims, but AWS IAM and GitHub have since
|
|
||||||
added support for `sub` claim customization and a variety of additional
|
|
||||||
claims ([1][gh-blog-oidc], [2][sub-claim-custom]).
|
|
||||||
|
|
||||||
> **Warning:** Avoid `ForAllValues:` in `Allow` statements. These operators
|
|
||||||
> return true when the claim is absent or misspelled, which can lead to
|
|
||||||
> uninended access. Instead, use `StringEquals` or `StringLike` operators to
|
|
||||||
> check for specific claim values.
|
|
||||||
|
|
||||||
[least-privilege]:
|
[least-privilege]:
|
||||||
https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege
|
https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege
|
||||||
[gh-blog-oidc]:
|
the assume role policy document should contain a
|
||||||
https://aws.amazon.com/about-aws/whats-new/2026/01/aws-sts-supports-validation-identity-provider-claims/
|
[`Condition`](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html)
|
||||||
[sub-claim-custom]:
|
that specifies a subject (`sub`) allowed to assume the role.
|
||||||
https://docs.github.com/en/rest/actions/oidc?apiVersion=2026-03-10
|
[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.
|
||||||
|
|
||||||
#### Inspecting the token
|
Without a subject (`sub`) condition, any GitHub user or repository could
|
||||||
|
potentially assume the role. The subject can be scoped to a GitHub organization
|
||||||
If you aren't sure what claim values your workflow is producing, the
|
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/reference/security/oidc#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/reference/security/oidc#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)
|
[`actions-oidc-debugger`](https://github.com/github/actions-oidc-debugger)
|
||||||
action will print the decoded JWT payload. Run it in a private repository
|
action to your workflow to see the value of the subject (`sub`) key, as well as
|
||||||
only — the token itself is short-lived but the claim values may be sensitive.
|
other claims.
|
||||||
|
|
||||||
See the GitHub [security-hardening guide][gh-oidc-hardening] for further
|
Additional claim conditions can be added for higher specificity as explained in
|
||||||
discussion of trust conditions and threat modeling.
|
the
|
||||||
|
[GitHub documentation][gh-oidc-hardening].
|
||||||
|
|
||||||
[gh-oidc-hardening]:
|
[gh-oidc-hardening]:
|
||||||
https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect
|
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 information about OIDC
|
### Further information about OIDC
|
||||||
|
|
||||||
@@ -617,28 +562,6 @@ 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 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/)
|
- [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/)
|
||||||
|
|
||||||
## Compatibility with non-GitHub Actions environments
|
|
||||||
|
|
||||||
This action has been sucessfully tested with
|
|
||||||
Codeberg/[Forgejo Actions](https://forgejo.org/docs/next/user/actions/overview/)
|
|
||||||
and should be generally compatible with any CI/CD environment that sets the
|
|
||||||
correct `GITHUB_` environment variables. For use with Foregejo, please review
|
|
||||||
the
|
|
||||||
[runner differences with GitHub's action runners][forgejo-gh-differences].
|
|
||||||
|
|
||||||
[forgejo-gh-differences]:
|
|
||||||
https://forgejo.org/docs/next/user/actions/github-actions/#known-list-of-differences
|
|
||||||
The main difference to be aware of is that Forgejo uses the
|
|
||||||
`enable-openid-connect` flag to enable OIDC instad of GitHub's `id-token: write`
|
|
||||||
permission. Forgejo also uses a slightly different syntax for the workflow
|
|
||||||
definition file, omitting some subkeys.
|
|
||||||
|
|
||||||
For OIDC use, the issuer name for the IAM IdP for GitHub Actions is
|
|
||||||
`token.actions.githubusercontent.com`. For Forgejo Actions it is
|
|
||||||
`[foregejo instance url]/api/actions`. As an example, Codeberg would use
|
|
||||||
`codeberg.org/api/actions` as the issuer URL when configuring the IAM Identity
|
|
||||||
Provider. The audience would still be `sts.amazonaws.com` by default.
|
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
### AssumeRoleWithWebIdentity
|
### AssumeRoleWithWebIdentity
|
||||||
@@ -736,13 +659,6 @@ This example shows that you can reference the fetched credentials as outputs if
|
|||||||
the `aws-session-token` input in a situation where session tokens are fetched
|
the `aws-session-token` input in a situation where session tokens are fetched
|
||||||
and passed to this action.
|
and passed to this action.
|
||||||
|
|
||||||
If you only want the credentials available as _step outputs_ and not exported to
|
|
||||||
the environment (for example, on a self-hosted runner where you do not want the
|
|
||||||
assumed-role credentials to shadow an existing EC2 instance profile), pair
|
|
||||||
`output-credentials: true` with `output-env-credentials: false`. In that mode,
|
|
||||||
the action does not run its post-credential SDK-pickup validation step, since
|
|
||||||
the credentials were never written to the environment.
|
|
||||||
|
|
||||||
### Configure multiple AWS profiles in a single workflow
|
### Configure multiple AWS profiles in a single workflow
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@@ -775,8 +691,8 @@ the credentials were never written to the environment.
|
|||||||
This example shows how to configure multiple named AWS profiles in a single
|
This example shows how to configure multiple named AWS profiles in a single
|
||||||
workflow. When using the `aws-profile` input, credentials are written to
|
workflow. When using the `aws-profile` input, credentials are written to
|
||||||
`~/.aws/credentials` and `~/.aws/config` files, allowing you to reference
|
`~/.aws/credentials` and `~/.aws/config` files, allowing you to reference
|
||||||
different profiles using the `--profile` flag with AWS CLI, SDKs, CDK, and other
|
different profiles using the `--profile` flag with AWS CLI, SDKs, CDK, and
|
||||||
tools.
|
other tools.
|
||||||
|
|
||||||
Each profile is independent and can authenticate to different AWS accounts or
|
Each profile is independent and can authenticate to different AWS accounts or
|
||||||
use different roles. This is particularly useful for multi-account deployments
|
use different roles. This is particularly useful for multi-account deployments
|
||||||
@@ -789,7 +705,6 @@ Starting with version 5.0.0, this action uses semantic-style release tags and
|
|||||||
|
|
||||||
[immutable-releases]:
|
[immutable-releases]:
|
||||||
https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/immutable-releases
|
https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/immutable-releases
|
||||||
|
|
||||||
A floating version tag (vN) is also provided for convenience: this tag will move
|
A floating version tag (vN) is also provided for convenience: this tag will move
|
||||||
to the latest major version (vN -> vN.2.1, vM -> vM.0.0, etc.).
|
to the latest major version (vN -> vN.2.1, vM -> vM.0.0, etc.).
|
||||||
|
|
||||||
|
|||||||
+497
-67
@@ -431,12 +431,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
The following npm packages may be included in this product:
|
The following npm package may be included in this product:
|
||||||
|
|
||||||
- @aws-crypto/crc32@5.2.0
|
|
||||||
- @aws-crypto/util@5.2.0
|
- @aws-crypto/util@5.2.0
|
||||||
|
|
||||||
These packages each contain the following license:
|
This package contains the following license:
|
||||||
|
|
||||||
Apache License
|
Apache License
|
||||||
Version 2.0, January 2004
|
Version 2.0, January 2004
|
||||||
@@ -642,11 +641,20 @@ Apache License
|
|||||||
|
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
The following npm package may be included in this product:
|
The following npm packages may be included in this product:
|
||||||
|
|
||||||
- @aws-sdk/client-sts@3.1049.0
|
- @aws-sdk/client-sts@3.1038.0
|
||||||
|
- @aws-sdk/util-user-agent-browser@3.972.10
|
||||||
|
- @aws-sdk/util-user-agent-node@3.973.22
|
||||||
|
- @smithy/middleware-retry@4.5.6
|
||||||
|
- @smithy/querystring-builder@4.2.14
|
||||||
|
- @smithy/querystring-parser@4.2.14
|
||||||
|
- @smithy/service-error-classification@4.3.1
|
||||||
|
- @smithy/url-parser@4.2.14
|
||||||
|
- @smithy/util-defaults-mode-browser@4.3.49
|
||||||
|
- @smithy/util-defaults-mode-node@4.2.54
|
||||||
|
|
||||||
This package contains the following license:
|
These packages each contain the following license:
|
||||||
|
|
||||||
Apache License
|
Apache License
|
||||||
Version 2.0, January 2004
|
Version 2.0, January 2004
|
||||||
@@ -854,9 +862,17 @@ Apache License
|
|||||||
|
|
||||||
The following npm packages may be included in this product:
|
The following npm packages may be included in this product:
|
||||||
|
|
||||||
- @aws-sdk/signature-v4-multi-region@3.996.27
|
- @aws-sdk/middleware-host-header@3.972.10
|
||||||
- @smithy/core@3.24.3
|
- @aws-sdk/middleware-recursion-detection@3.972.11
|
||||||
- @smithy/types@4.14.2
|
- @aws-sdk/middleware-sdk-s3@3.972.35
|
||||||
|
- @aws-sdk/middleware-user-agent@3.972.36
|
||||||
|
- @aws-sdk/signature-v4-multi-region@3.996.23
|
||||||
|
- @smithy/core@3.23.17
|
||||||
|
- @smithy/invalid-dependency@4.2.14
|
||||||
|
- @smithy/middleware-serde@4.2.20
|
||||||
|
- @smithy/protocol-http@5.3.14
|
||||||
|
- @smithy/smithy-client@4.12.13
|
||||||
|
- @smithy/types@4.14.1
|
||||||
|
|
||||||
These packages each contain the following license:
|
These packages each contain the following license:
|
||||||
|
|
||||||
@@ -1224,7 +1240,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||||||
|
|
||||||
The following npm package may be included in this product:
|
The following npm package may be included in this product:
|
||||||
|
|
||||||
- @actions/http-client@4.0.1
|
- @actions/http-client@3.0.2
|
||||||
|
|
||||||
This package contains the following license:
|
This package contains the following license:
|
||||||
|
|
||||||
@@ -1254,7 +1270,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||||||
|
|
||||||
The following npm package may be included in this product:
|
The following npm package may be included in this product:
|
||||||
|
|
||||||
- @aws-sdk/core@3.974.12
|
- @aws-sdk/core@3.974.6
|
||||||
|
|
||||||
This package contains the following license:
|
This package contains the following license:
|
||||||
|
|
||||||
@@ -1674,20 +1690,40 @@ Apache License
|
|||||||
|
|
||||||
The following npm packages may be included in this product:
|
The following npm packages may be included in this product:
|
||||||
|
|
||||||
- @aws-sdk/credential-provider-env@3.972.38
|
- @aws-sdk/credential-provider-env@3.972.32
|
||||||
- @aws-sdk/credential-provider-ini@3.972.42
|
- @aws-sdk/credential-provider-ini@3.972.36
|
||||||
- @aws-sdk/credential-provider-node@3.972.43
|
- @aws-sdk/credential-provider-node@3.972.37
|
||||||
- @aws-sdk/token-providers@3.1049.0
|
- @aws-sdk/region-config-resolver@3.972.13
|
||||||
|
- @aws-sdk/token-providers@3.1038.0
|
||||||
- @aws-sdk/types@3.973.8
|
- @aws-sdk/types@3.973.8
|
||||||
|
- @aws-sdk/util-arn-parser@3.972.3
|
||||||
|
- @aws-sdk/util-endpoints@3.996.8
|
||||||
- @aws-sdk/util-locate-window@3.965.5
|
- @aws-sdk/util-locate-window@3.965.5
|
||||||
- @aws-sdk/xml-builder@3.972.24
|
- @aws-sdk/xml-builder@3.972.21
|
||||||
- @smithy/credential-provider-imds@4.3.3
|
- @smithy/config-resolver@4.4.17
|
||||||
- @smithy/fetch-http-handler@5.4.3
|
- @smithy/credential-provider-imds@4.2.14
|
||||||
|
- @smithy/fetch-http-handler@5.3.17
|
||||||
|
- @smithy/hash-node@4.2.14
|
||||||
- @smithy/is-array-buffer@2.2.0
|
- @smithy/is-array-buffer@2.2.0
|
||||||
- @smithy/node-http-handler@4.7.3
|
- @smithy/is-array-buffer@4.2.2
|
||||||
- @smithy/signature-v4@5.4.3
|
- @smithy/middleware-content-length@4.2.14
|
||||||
|
- @smithy/middleware-endpoint@4.4.32
|
||||||
|
- @smithy/middleware-stack@4.2.14
|
||||||
|
- @smithy/node-http-handler@4.6.1
|
||||||
|
- @smithy/property-provider@4.2.14
|
||||||
|
- @smithy/shared-ini-file-loader@4.4.9
|
||||||
|
- @smithy/signature-v4@5.3.14
|
||||||
|
- @smithy/util-base64@4.3.2
|
||||||
|
- @smithy/util-body-length-browser@4.2.2
|
||||||
|
- @smithy/util-body-length-node@4.2.3
|
||||||
- @smithy/util-buffer-from@2.2.0
|
- @smithy/util-buffer-from@2.2.0
|
||||||
|
- @smithy/util-buffer-from@4.2.2
|
||||||
|
- @smithy/util-hex-encoding@4.2.2
|
||||||
|
- @smithy/util-stream@4.5.25
|
||||||
|
- @smithy/util-uri-escape@4.2.2
|
||||||
- @smithy/util-utf8@2.3.0
|
- @smithy/util-utf8@2.3.0
|
||||||
|
- @smithy/util-utf8@4.2.2
|
||||||
|
- @smithy/uuid@1.1.2
|
||||||
|
|
||||||
These packages each contain the following license:
|
These packages each contain the following license:
|
||||||
|
|
||||||
@@ -1897,9 +1933,9 @@ Apache License
|
|||||||
|
|
||||||
The following npm packages may be included in this product:
|
The following npm packages may be included in this product:
|
||||||
|
|
||||||
- @aws-sdk/credential-provider-process@3.972.38
|
- @aws-sdk/credential-provider-process@3.972.32
|
||||||
- @aws-sdk/credential-provider-sso@3.972.42
|
- @aws-sdk/credential-provider-sso@3.972.36
|
||||||
- @aws-sdk/credential-provider-web-identity@3.972.42
|
- @aws-sdk/credential-provider-web-identity@3.972.36
|
||||||
|
|
||||||
These packages each contain the following license:
|
These packages each contain the following license:
|
||||||
|
|
||||||
@@ -2109,9 +2145,433 @@ Apache License
|
|||||||
|
|
||||||
The following npm packages may be included in this product:
|
The following npm packages may be included in this product:
|
||||||
|
|
||||||
- @aws-sdk/credential-provider-http@3.972.40
|
- @aws-sdk/middleware-logger@3.972.10
|
||||||
- @aws-sdk/credential-provider-login@3.972.42
|
- @smithy/node-config-provider@4.3.14
|
||||||
- @aws-sdk/nested-clients@3.997.10
|
- @smithy/util-config-provider@4.2.2
|
||||||
|
|
||||||
|
These packages each contain the following license:
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
-----------
|
||||||
|
|
||||||
|
The following npm packages may be included in this product:
|
||||||
|
|
||||||
|
- @smithy/util-endpoints@3.4.2
|
||||||
|
- @smithy/util-middleware@4.2.14
|
||||||
|
- @smithy/util-retry@4.3.5
|
||||||
|
|
||||||
|
These packages each contain the following license:
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
-----------
|
||||||
|
|
||||||
|
The following npm packages may be included in this product:
|
||||||
|
|
||||||
|
- @aws-sdk/credential-provider-http@3.972.34
|
||||||
|
- @aws-sdk/credential-provider-login@3.972.36
|
||||||
|
- @aws-sdk/nested-clients@3.997.4
|
||||||
|
|
||||||
These packages each contain the following license:
|
These packages each contain the following license:
|
||||||
|
|
||||||
@@ -2121,7 +2581,7 @@ Apache-2.0
|
|||||||
|
|
||||||
The following npm package may be included in this product:
|
The following npm package may be included in this product:
|
||||||
|
|
||||||
- ip-address@10.2.0
|
- ip-address@10.0.1
|
||||||
|
|
||||||
This package contains the following license:
|
This package contains the following license:
|
||||||
|
|
||||||
@@ -2208,7 +2668,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||||||
|
|
||||||
The following npm package may be included in this product:
|
The following npm package may be included in this product:
|
||||||
|
|
||||||
- basic-ftp@5.3.1
|
- basic-ftp@5.3.0
|
||||||
|
|
||||||
This package contains the following license:
|
This package contains the following license:
|
||||||
|
|
||||||
@@ -2336,8 +2796,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
The following npm packages may be included in this product:
|
The following npm packages may be included in this product:
|
||||||
|
|
||||||
- @nodable/entities@2.1.0
|
- @nodable/entities@2.1.0
|
||||||
|
- netmask@2.1.0
|
||||||
- quickjs-wasi@2.2.0
|
- quickjs-wasi@2.2.0
|
||||||
- xml-naming@0.1.0
|
|
||||||
|
|
||||||
These packages each contain the following license:
|
These packages each contain the following license:
|
||||||
|
|
||||||
@@ -2347,37 +2807,7 @@ MIT
|
|||||||
|
|
||||||
The following npm package may be included in this product:
|
The following npm package may be included in this product:
|
||||||
|
|
||||||
- netmask@2.1.1
|
- fast-xml-parser@5.7.2
|
||||||
|
|
||||||
This package contains the following license:
|
|
||||||
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2011 Olivier Poitrey rs@rhapsodyk.net
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
||||||
-----------
|
|
||||||
|
|
||||||
The following npm package may be included in this product:
|
|
||||||
|
|
||||||
- fast-xml-parser@5.7.3
|
|
||||||
|
|
||||||
This package contains the following license:
|
This package contains the following license:
|
||||||
|
|
||||||
@@ -2407,7 +2837,7 @@ SOFTWARE.
|
|||||||
|
|
||||||
The following npm package may be included in this product:
|
The following npm package may be included in this product:
|
||||||
|
|
||||||
- strnum@2.3.0
|
- strnum@2.2.3
|
||||||
|
|
||||||
This package contains the following license:
|
This package contains the following license:
|
||||||
|
|
||||||
@@ -2467,7 +2897,7 @@ SOFTWARE.
|
|||||||
|
|
||||||
The following npm package may be included in this product:
|
The following npm package may be included in this product:
|
||||||
|
|
||||||
- fast-xml-builder@1.2.0
|
- fast-xml-builder@1.1.5
|
||||||
|
|
||||||
This package contains the following license:
|
This package contains the following license:
|
||||||
|
|
||||||
@@ -2497,7 +2927,7 @@ SOFTWARE.
|
|||||||
|
|
||||||
The following npm package may be included in this product:
|
The following npm package may be included in this product:
|
||||||
|
|
||||||
- undici@6.25.0
|
- undici@6.24.0
|
||||||
|
|
||||||
This package contains the following license:
|
This package contains the following license:
|
||||||
|
|
||||||
@@ -2639,7 +3069,7 @@ THE SOFTWARE.
|
|||||||
|
|
||||||
The following npm package may be included in this product:
|
The following npm package may be included in this product:
|
||||||
|
|
||||||
- socks@2.8.8
|
- socks@2.8.7
|
||||||
|
|
||||||
This package contains the following license:
|
This package contains the following license:
|
||||||
|
|
||||||
@@ -2727,9 +3157,9 @@ SOFTWARE.
|
|||||||
|
|
||||||
The following npm packages may be included in this product:
|
The following npm packages may be included in this product:
|
||||||
|
|
||||||
- @actions/core@3.0.1
|
- @actions/core@2.0.2
|
||||||
- @actions/exec@3.0.0
|
- @actions/exec@2.0.0
|
||||||
- @actions/io@3.0.2
|
- @actions/io@2.0.0
|
||||||
|
|
||||||
These packages each contain the following license:
|
These packages each contain the following license:
|
||||||
|
|
||||||
|
|||||||
+1
-6
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
name: '"Configure AWS Credentials" Action for GitHub Actions'
|
name: '"Configure AWS Credentials" Action for GitHub Actions'
|
||||||
description: Configures AWS credentials for use in subsequent steps in a GitHub Action workflow
|
description: Configures AWS credentials for use in subsequent steps in a GitHub Action workflow
|
||||||
runs:
|
runs:
|
||||||
@@ -100,12 +101,6 @@ inputs:
|
|||||||
action-timeout-s:
|
action-timeout-s:
|
||||||
required: false
|
required: false
|
||||||
description: A global timeout in seconds for the action. When the timeout is reached, the action immediately exits. The default is to run without a timeout.
|
description: A global timeout in seconds for the action. When the timeout is reached, the action immediately exits. The default is to run without a timeout.
|
||||||
custom-tags:
|
|
||||||
description: Additional tags to apply to the assumed role session. Must be a JSON object provided as a string.
|
|
||||||
required: false
|
|
||||||
sts-endpoint:
|
|
||||||
description: Custom STS endpoint URL. Use this to point to an STS-compatible API (e.g. MinIO, LocalStack) instead of the default AWS STS endpoint for the region.
|
|
||||||
required: false
|
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
aws-account-id:
|
aws-account-id:
|
||||||
|
|||||||
+2835
-369
File diff suppressed because it is too large
Load Diff
+15544
-17214
File diff suppressed because one or more lines are too long
Generated
+4653
-1769
File diff suppressed because it is too large
Load Diff
+11
-11
@@ -4,8 +4,8 @@
|
|||||||
"version": "6.1.1",
|
"version": "6.1.1",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"lint": "biome check --error-on-warnings ./src ./test && markdownlint -i node_modules -i CHANGELOG.md '**/*.md'",
|
"lint": "biome check --error-on-warnings ./src && markdownlint -i node_modules -i CHANGELOG.md '**/*.md'",
|
||||||
"lint:fix": "biome check --write ./src ./test && markdownlint -i node_modules -i CHANGELOG.md -f '**/*.md'",
|
"lint:fix": "biome check --write ./src && markdownlint -i node_modules -i CHANGELOG.md -f '**/*.md'",
|
||||||
"package": "esbuild src/index.ts --bundle --platform=node --target=node24 --outfile=dist/index.js && esbuild src/cleanup/index.ts --bundle --platform=node --target=node24 --outfile=dist/cleanup/index.js && npm run license",
|
"package": "esbuild src/index.ts --bundle --platform=node --target=node24 --outfile=dist/index.js && esbuild src/cleanup/index.ts --bundle --platform=node --target=node24 --outfile=dist/cleanup/index.js && npm run license",
|
||||||
"test": "npm run lint && vitest run && npm run build",
|
"test": "npm run lint && vitest run && npm run build",
|
||||||
"clean": "del-cli coverage test-reports node_modules",
|
"clean": "del-cli coverage test-reports node_modules",
|
||||||
@@ -17,11 +17,11 @@
|
|||||||
"organization": true
|
"organization": true
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@aws-sdk/credential-provider-env": "^3.972.38",
|
"@aws-sdk/credential-provider-env": "^3.972.32",
|
||||||
"@biomejs/biome": "2.4.15",
|
"@biomejs/biome": "2.4.13",
|
||||||
"@smithy/property-provider": "^4.3.3",
|
"@smithy/property-provider": "^4.2.14",
|
||||||
"@types/node": "^25.9.0",
|
"@types/node": "^25.6.0",
|
||||||
"@vitest/coverage-v8": "^4.1.6",
|
"@vitest/coverage-v8": "^3.2.4",
|
||||||
"aws-sdk-client-mock": "^4.1.0",
|
"aws-sdk-client-mock": "^4.1.0",
|
||||||
"esbuild": "^0.28.0",
|
"esbuild": "^0.28.0",
|
||||||
"generate-license-file": "^4.1.1",
|
"generate-license-file": "^4.1.1",
|
||||||
@@ -30,12 +30,12 @@
|
|||||||
"memfs": "^4.57.2",
|
"memfs": "^4.57.2",
|
||||||
"standard-version": "^9.5.0",
|
"standard-version": "^9.5.0",
|
||||||
"typescript": "^6.0.3",
|
"typescript": "^6.0.3",
|
||||||
"vitest": "^4.1.5"
|
"vitest": "^3.2.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^3.0.1",
|
"@actions/core": "^2.0.2",
|
||||||
"@aws-sdk/client-sts": "^3.1049.0",
|
"@aws-sdk/client-sts": "^3.1038.0",
|
||||||
"@smithy/node-http-handler": "^4.7.3",
|
"@smithy/node-http-handler": "^4.6.1",
|
||||||
"proxy-agent": "^8.0.1"
|
"proxy-agent": "^8.0.1"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|||||||
+10
-15
@@ -3,18 +3,15 @@ import { STSClient } from '@aws-sdk/client-sts';
|
|||||||
import type { AwsCredentialIdentity } from '@aws-sdk/types';
|
import type { AwsCredentialIdentity } from '@aws-sdk/types';
|
||||||
import { NodeHttpHandler } from '@smithy/node-http-handler';
|
import { NodeHttpHandler } from '@smithy/node-http-handler';
|
||||||
import { ProxyAgent } from 'proxy-agent';
|
import { ProxyAgent } from 'proxy-agent';
|
||||||
import { buildCustomUserAgent, errorMessage, getCallerIdentity } from './helpers';
|
import { errorMessage, getCallerIdentity } from './helpers';
|
||||||
import { ProxyResolver } from './ProxyResolver';
|
import { ProxyResolver } from './ProxyResolver';
|
||||||
|
|
||||||
if (!process.env.AWS_EXECUTION_ENV) {
|
const USER_AGENT = 'configure-aws-credentials-for-github-actions';
|
||||||
process.env.AWS_EXECUTION_ENV = 'GitHubActions';
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CredentialsClientProps {
|
export interface CredentialsClientProps {
|
||||||
region?: string;
|
region?: string;
|
||||||
proxyServer?: string;
|
proxyServer?: string;
|
||||||
noProxy?: string;
|
noProxy?: string;
|
||||||
stsEndpoint?: string;
|
|
||||||
roleChaining: boolean;
|
roleChaining: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,7 +19,6 @@ export class CredentialsClient {
|
|||||||
public region?: string;
|
public region?: string;
|
||||||
private _stsClient?: STSClient;
|
private _stsClient?: STSClient;
|
||||||
private readonly requestHandler?: NodeHttpHandler;
|
private readonly requestHandler?: NodeHttpHandler;
|
||||||
private readonly stsEndpoint?: string;
|
|
||||||
private roleChaining?: boolean;
|
private roleChaining?: boolean;
|
||||||
|
|
||||||
constructor(props: CredentialsClientProps) {
|
constructor(props: CredentialsClientProps) {
|
||||||
@@ -45,20 +41,19 @@ export class CredentialsClient {
|
|||||||
httpAgent: handler,
|
httpAgent: handler,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (props.stsEndpoint) {
|
|
||||||
this.stsEndpoint = props.stsEndpoint;
|
|
||||||
}
|
|
||||||
this.roleChaining = props.roleChaining;
|
this.roleChaining = props.roleChaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get stsClient(): STSClient {
|
public get stsClient(): STSClient {
|
||||||
if (!this._stsClient || this.roleChaining) {
|
if (!this._stsClient || this.roleChaining) {
|
||||||
this._stsClient = new STSClient({
|
const config = { customUserAgent: USER_AGENT } as {
|
||||||
customUserAgent: buildCustomUserAgent(),
|
customUserAgent: string;
|
||||||
...(this.region !== undefined && { region: this.region }),
|
region?: string;
|
||||||
...(this.stsEndpoint !== undefined && { endpoint: this.stsEndpoint }),
|
requestHandler?: NodeHttpHandler;
|
||||||
...(this.requestHandler !== undefined && { requestHandler: this.requestHandler }),
|
};
|
||||||
});
|
if (this.region !== undefined) config.region = this.region;
|
||||||
|
if (this.requestHandler !== undefined) config.requestHandler = this.requestHandler;
|
||||||
|
this._stsClient = new STSClient(config);
|
||||||
}
|
}
|
||||||
return this._stsClient;
|
return this._stsClient;
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-119
@@ -78,98 +78,6 @@ export interface assumeRoleParams {
|
|||||||
webIdentityToken?: string;
|
webIdentityToken?: string;
|
||||||
inlineSessionPolicy?: string;
|
inlineSessionPolicy?: string;
|
||||||
managedSessionPolicies?: { arn: string }[];
|
managedSessionPolicies?: { arn: string }[];
|
||||||
customTags?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const TAG_KEY_REGEX = /^[\p{L}\p{Z}\p{N}_.:/=+\-@]+$/u;
|
|
||||||
const TAG_VALUE_REGEX = /^[\p{L}\p{Z}\p{N}_.:/=+\-@]*$/u;
|
|
||||||
const MAX_TAG_KEY_LENGTH = 128;
|
|
||||||
const MAX_TAG_VALUE_LENGTH = 256;
|
|
||||||
const MAX_SESSION_TAGS = 50;
|
|
||||||
|
|
||||||
// Identity/audit primitives. Always emitted and cannot be overridden by custom-tags.
|
|
||||||
const PROTECTED_TAG_SOURCES: ReadonlyArray<{ key: string; envVar: string }> = [
|
|
||||||
{ key: 'Repository', envVar: 'GITHUB_REPOSITORY' },
|
|
||||||
{ key: 'Workflow', envVar: 'GITHUB_WORKFLOW' },
|
|
||||||
{ key: 'Action', envVar: 'GITHUB_ACTION' },
|
|
||||||
{ key: 'Actor', envVar: 'GITHUB_ACTOR' },
|
|
||||||
{ key: 'Commit', envVar: 'GITHUB_SHA' },
|
|
||||||
{ key: 'Branch', envVar: 'GITHUB_REF' },
|
|
||||||
];
|
|
||||||
|
|
||||||
// Convenience metadata. Custom-tags may override (suppresses the default for that key).
|
|
||||||
// Listed in priority order; lower-priority entries are dropped first if the user's custom-tags
|
|
||||||
// would push the total above MAX_SESSION_TAGS.
|
|
||||||
const OVERRIDEABLE_TAG_SOURCES_BY_PRIORITY: ReadonlyArray<{ key: string; envVar: string }> = [
|
|
||||||
{ key: 'EventName', envVar: 'GITHUB_EVENT_NAME' },
|
|
||||||
{ key: 'BaseRef', envVar: 'GITHUB_BASE_REF' },
|
|
||||||
{ key: 'HeadRef', envVar: 'GITHUB_HEAD_REF' },
|
|
||||||
{ key: 'RefName', envVar: 'GITHUB_REF_NAME' },
|
|
||||||
{ key: 'RunId', envVar: 'GITHUB_RUN_ID' },
|
|
||||||
{ key: 'RefType', envVar: 'GITHUB_REF_TYPE' },
|
|
||||||
{ key: 'Job', envVar: 'GITHUB_JOB' },
|
|
||||||
{ key: 'TriggeringActor', envVar: 'GITHUB_TRIGGERING_ACTOR' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const PROTECTED_TAG_KEYS = new Set<string>(['GitHub', ...PROTECTED_TAG_SOURCES.map((s) => s.key)]);
|
|
||||||
|
|
||||||
export function parseAndValidateCustomTags(customTags: string, existingTags: Tag[]): Tag[] {
|
|
||||||
let parsed: unknown;
|
|
||||||
try {
|
|
||||||
parsed = JSON.parse(customTags);
|
|
||||||
} catch {
|
|
||||||
throw new Error('custom-tags: input is not valid JSON');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
||||||
throw new Error('custom-tags: input must be a JSON object (not an array or primitive)');
|
|
||||||
}
|
|
||||||
|
|
||||||
const newTags: Tag[] = [];
|
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(parsed)) {
|
|
||||||
if (typeof value === 'object') {
|
|
||||||
throw new Error(
|
|
||||||
`custom-tags: value for key '${key}' must be a string, number, or boolean (not an object or array)`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const stringValue = String(value);
|
|
||||||
|
|
||||||
if (key.length === 0 || key.length > MAX_TAG_KEY_LENGTH) {
|
|
||||||
throw new Error(`custom-tags: key '${key}' must be between 1 and ${MAX_TAG_KEY_LENGTH} characters`);
|
|
||||||
}
|
|
||||||
if (stringValue.length > MAX_TAG_VALUE_LENGTH) {
|
|
||||||
throw new Error(
|
|
||||||
`custom-tags: value for key '${key}' exceeds maximum length of ${MAX_TAG_VALUE_LENGTH} characters`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (!TAG_KEY_REGEX.test(key)) {
|
|
||||||
throw new Error(
|
|
||||||
`custom-tags: key '${key}' contains invalid characters. Allowed: unicode letters, digits, spaces, and _.:/=+-@`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (stringValue.length > 0 && !TAG_VALUE_REGEX.test(stringValue)) {
|
|
||||||
throw new Error(
|
|
||||||
`custom-tags: value for key '${key}' contains invalid characters. Allowed: unicode letters, digits, spaces, and _.:/=+-@`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (PROTECTED_TAG_KEYS.has(key)) {
|
|
||||||
throw new Error(
|
|
||||||
`custom-tags: key '${key}' conflicts with a protected session tag set by this action and cannot be overridden`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
newTags.push({ Key: key, Value: stringValue });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existingTags.length + newTags.length > MAX_SESSION_TAGS) {
|
|
||||||
throw new Error(
|
|
||||||
`custom-tags: total session tags (${existingTags.length + newTags.length}) would exceed the AWS limit of ${MAX_SESSION_TAGS}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newTags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function assumeRole(params: assumeRoleParams) {
|
export async function assumeRole(params: assumeRoleParams) {
|
||||||
@@ -186,7 +94,6 @@ export async function assumeRole(params: assumeRoleParams) {
|
|||||||
webIdentityToken,
|
webIdentityToken,
|
||||||
inlineSessionPolicy,
|
inlineSessionPolicy,
|
||||||
managedSessionPolicies,
|
managedSessionPolicies,
|
||||||
customTags,
|
|
||||||
} = { ...params };
|
} = { ...params };
|
||||||
|
|
||||||
// Load GitHub environment variables
|
// Load GitHub environment variables
|
||||||
@@ -195,37 +102,26 @@ export async function assumeRole(params: assumeRoleParams) {
|
|||||||
throw new Error('Missing required environment variables. Are you running in GitHub Actions?');
|
throw new Error('Missing required environment variables. Are you running in GitHub Actions?');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build session tags. Values are sanitized because the AWS tag value spec is more
|
// Load role session tags
|
||||||
// restrictive than permissible characters in environment variables.
|
const tagArray: Tag[] = [
|
||||||
const protectedTags: Tag[] = [{ Key: 'GitHub', Value: 'Actions' }];
|
{ Key: 'GitHub', Value: 'Actions' },
|
||||||
for (const { key, envVar } of PROTECTED_TAG_SOURCES) {
|
{ Key: 'Repository', Value: GITHUB_REPOSITORY },
|
||||||
const value = process.env[envVar];
|
{ Key: 'Workflow', Value: sanitizeGitHubVariables(GITHUB_WORKFLOW) },
|
||||||
if (value) {
|
{ Key: 'Action', Value: GITHUB_ACTION },
|
||||||
protectedTags.push({ Key: key, Value: sanitizeGitHubVariables(value) });
|
{ 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 parsedCustomTags: Tag[] = customTags ? parseAndValidateCustomTags(customTags, protectedTags) : [];
|
|
||||||
const customTagKeys = new Set(parsedCustomTags.map((t) => t.Key));
|
|
||||||
|
|
||||||
const availableOverrideableSlots = MAX_SESSION_TAGS - protectedTags.length - parsedCustomTags.length;
|
|
||||||
const overrideableTags: Tag[] = [];
|
|
||||||
for (const { key, envVar } of OVERRIDEABLE_TAG_SOURCES_BY_PRIORITY) {
|
|
||||||
if (overrideableTags.length >= availableOverrideableSlots) break;
|
|
||||||
if (customTagKeys.has(key)) continue;
|
|
||||||
const value = process.env[envVar];
|
|
||||||
if (value) {
|
|
||||||
overrideableTags.push({ Key: key, Value: sanitizeGitHubVariables(value) });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const tagArray: Tag[] = [...protectedTags, ...overrideableTags, ...parsedCustomTags];
|
|
||||||
|
|
||||||
const tags = roleSkipSessionTagging ? undefined : tagArray;
|
const tags = roleSkipSessionTagging ? undefined : tagArray;
|
||||||
if (!tags) {
|
if (!tags) {
|
||||||
core.debug('Role session tagging has been skipped.');
|
core.debug('Role session tagging has been skipped.');
|
||||||
} else {
|
} else {
|
||||||
core.debug(`${tags.length} role session tags are being used:`);
|
core.debug(`${tags.length} role session tags are being used.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
//only populate transitiveTagKeys array if user is actually using session tagging
|
//only populate transitiveTagKeys array if user is actually using session tagging
|
||||||
|
|||||||
+4
-27
@@ -1,32 +1,11 @@
|
|||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import type { Credentials, STSClient } from '@aws-sdk/client-sts';
|
import type { Credentials, STSClient } from '@aws-sdk/client-sts';
|
||||||
import { GetCallerIdentityCommand } from '@aws-sdk/client-sts';
|
import { GetCallerIdentityCommand } from '@aws-sdk/client-sts';
|
||||||
import type { UserAgent } from '@smithy/types';
|
|
||||||
import type { CredentialsClient } from './CredentialsClient';
|
import type { CredentialsClient } from './CredentialsClient';
|
||||||
|
|
||||||
const MAX_TAG_VALUE_LENGTH = 256;
|
const MAX_TAG_VALUE_LENGTH = 256;
|
||||||
const SANITIZATION_CHARACTER = '_';
|
const SANITIZATION_CHARACTER = '_';
|
||||||
const SPECIAL_CHARS_REGEX = /[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]+/;
|
const SPECIAL_CHARS_REGEX = /[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]+/;
|
||||||
const USER_AGENT_PREFIX = 'configure-aws-credentials-for-github-actions';
|
|
||||||
const UA_FIELDS: ReadonlyArray<{ env: string; label: string; pattern: RegExp }> = [
|
|
||||||
{ env: 'GITHUB_ACTION', label: 'action', pattern: /^[A-Za-z0-9_-]{1,128}$/ },
|
|
||||||
{ env: 'GITHUB_RUN_ID', label: 'run_id', pattern: /^[0-9]{1,20}$/ },
|
|
||||||
{ env: 'GITHUB_RUN_ATTEMPT', label: 'attempt', pattern: /^[0-9]{1,10}$/ },
|
|
||||||
];
|
|
||||||
|
|
||||||
export function buildCustomUserAgent(): UserAgent {
|
|
||||||
const tokens: UserAgent = [[USER_AGENT_PREFIX]];
|
|
||||||
for (const { env, label, pattern } of UA_FIELDS) {
|
|
||||||
const value = process.env[env];
|
|
||||||
if (value === undefined) continue;
|
|
||||||
if (pattern.test(value)) {
|
|
||||||
tokens.push(['md', `${label}#${value}`]);
|
|
||||||
} else {
|
|
||||||
core.warning(`${env} has unexpected format; omitting from User-Agent`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tokens;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function translateEnvVariables() {
|
export function translateEnvVariables() {
|
||||||
const envVars = [
|
const envVars = [
|
||||||
@@ -210,7 +189,6 @@ export async function retryAndBackoff<T>(
|
|||||||
maxRetries = 12,
|
maxRetries = 12,
|
||||||
retries = 0,
|
retries = 0,
|
||||||
base = 50,
|
base = 50,
|
||||||
label?: string,
|
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
try {
|
try {
|
||||||
return await fn();
|
return await fn();
|
||||||
@@ -222,21 +200,20 @@ export async function retryAndBackoff<T>(
|
|||||||
// It's retryable, so sleep and retry.
|
// It's retryable, so sleep and retry.
|
||||||
const delay = Math.random() * (2 ** retries * base);
|
const delay = Math.random() * (2 ** retries * base);
|
||||||
const nextRetry = retries + 1;
|
const nextRetry = retries + 1;
|
||||||
const opName = label ? ` ${label}` : '';
|
|
||||||
|
|
||||||
core.info(
|
core.debug(
|
||||||
`Retry${opName}: attempt ${nextRetry} of ${maxRetries} failed: ${errorMessage(err)}. ` +
|
`retryAndBackoff: attempt ${nextRetry} of ${maxRetries} failed: ${errorMessage(err)}. ` +
|
||||||
`Retrying after ${Math.floor(delay)}ms.`,
|
`Retrying after ${Math.floor(delay)}ms.`,
|
||||||
);
|
);
|
||||||
|
|
||||||
await sleep(delay);
|
await sleep(delay);
|
||||||
|
|
||||||
if (nextRetry >= maxRetries) {
|
if (nextRetry >= maxRetries) {
|
||||||
core.info(`Retry${opName}: reached max retries (${maxRetries}); giving up.`);
|
core.debug('retryAndBackoff: reached max retries; giving up.');
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return await retryAndBackoff(fn, isRetryable, maxRetries, nextRetry, base, label);
|
return await retryAndBackoff(fn, isRetryable, maxRetries, nextRetry, base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+28
-70
@@ -19,7 +19,6 @@ import { writeProfileFiles } from './profileManager';
|
|||||||
const DEFAULT_ROLE_DURATION = 3600; // One hour (seconds)
|
const DEFAULT_ROLE_DURATION = 3600; // One hour (seconds)
|
||||||
const ROLE_SESSION_NAME = 'GitHubActions';
|
const ROLE_SESSION_NAME = 'GitHubActions';
|
||||||
const REGION_REGEX = /^[a-z0-9-]+$/g;
|
const REGION_REGEX = /^[a-z0-9-]+$/g;
|
||||||
const ROLE_SESSION_NAME_REGEX = /^[\w+=,.@-]*$/;
|
|
||||||
|
|
||||||
export async function run() {
|
export async function run() {
|
||||||
try {
|
try {
|
||||||
@@ -44,7 +43,6 @@ export async function run() {
|
|||||||
const roleSkipSessionTagging = getBooleanInput('role-skip-session-tagging', { required: false });
|
const roleSkipSessionTagging = getBooleanInput('role-skip-session-tagging', { required: false });
|
||||||
const transitiveTagKeys = core.getMultilineInput('transitive-tag-keys', { required: false });
|
const transitiveTagKeys = core.getMultilineInput('transitive-tag-keys', { required: false });
|
||||||
const proxyServer = core.getInput('http-proxy', { required: false }) || process.env.HTTP_PROXY;
|
const proxyServer = core.getInput('http-proxy', { required: false }) || process.env.HTTP_PROXY;
|
||||||
const customTags = core.getInput('custom-tags', { required: false });
|
|
||||||
const inlineSessionPolicy = core.getInput('inline-session-policy', { required: false });
|
const inlineSessionPolicy = core.getInput('inline-session-policy', { required: false });
|
||||||
const managedSessionPolicies = core.getMultilineInput('managed-session-policies', { required: false }).map((p) => {
|
const managedSessionPolicies = core.getMultilineInput('managed-session-policies', { required: false }).map((p) => {
|
||||||
return { arn: p };
|
return { arn: p };
|
||||||
@@ -65,7 +63,6 @@ export async function run() {
|
|||||||
.map((s) => s.trim());
|
.map((s) => s.trim());
|
||||||
const forceSkipOidc = getBooleanInput('force-skip-oidc', { required: false });
|
const forceSkipOidc = getBooleanInput('force-skip-oidc', { required: false });
|
||||||
const noProxy = core.getInput('no-proxy', { required: false });
|
const noProxy = core.getInput('no-proxy', { required: false });
|
||||||
const stsEndpoint = core.getInput('sts-endpoint', { required: false });
|
|
||||||
const globalTimeout = Number.parseInt(core.getInput('action-timeout-s', { required: false })) || 0;
|
const globalTimeout = Number.parseInt(core.getInput('action-timeout-s', { required: false })) || 0;
|
||||||
|
|
||||||
let timeoutId: NodeJS.Timeout | undefined;
|
let timeoutId: NodeJS.Timeout | undefined;
|
||||||
@@ -91,9 +88,6 @@ export async function run() {
|
|||||||
maxRetries = 1;
|
maxRetries = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const withRetry = <T>(fn: () => Promise<T>, label: string): Promise<T> =>
|
|
||||||
retryAndBackoff(fn, !disableRetry, maxRetries, 0, 50, label);
|
|
||||||
|
|
||||||
// Logic to decide whether to attempt to use OIDC or not
|
// Logic to decide whether to attempt to use OIDC or not
|
||||||
const useGitHubOIDCProvider = () => {
|
const useGitHubOIDCProvider = () => {
|
||||||
if (forceSkipOidc) return false;
|
if (forceSkipOidc) return false;
|
||||||
@@ -130,33 +124,15 @@ export async function run() {
|
|||||||
throw new Error(`Region is not valid: ${region}`);
|
throw new Error(`Region is not valid: ${region}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (roleSessionName.length < 2 || roleSessionName.length > 64) {
|
|
||||||
throw new Error(
|
|
||||||
`Role session name must be between 2 and 64 characters, got ${roleSessionName.length}: '${roleSessionName}'`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (!roleSessionName.match(ROLE_SESSION_NAME_REGEX)) {
|
|
||||||
throw new Error(
|
|
||||||
`Role session name is not valid: '${roleSessionName}'. Must satisfy regular expression pattern: [\\w+=,.@-]*`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
exportRegion(region, outputEnvCredentials);
|
exportRegion(region, outputEnvCredentials);
|
||||||
|
|
||||||
// Instantiate credentials client
|
// Instantiate credentials client
|
||||||
const clientProps: {
|
const clientProps: { region: string; proxyServer?: string; noProxy?: string; roleChaining: boolean } = {
|
||||||
region: string;
|
|
||||||
proxyServer?: string;
|
|
||||||
noProxy?: string;
|
|
||||||
stsEndpoint?: string;
|
|
||||||
roleChaining: boolean;
|
|
||||||
} = {
|
|
||||||
region,
|
region,
|
||||||
roleChaining,
|
roleChaining,
|
||||||
};
|
};
|
||||||
if (proxyServer) clientProps.proxyServer = proxyServer;
|
if (proxyServer) clientProps.proxyServer = proxyServer;
|
||||||
if (noProxy) clientProps.noProxy = noProxy;
|
if (noProxy) clientProps.noProxy = noProxy;
|
||||||
if (stsEndpoint) clientProps.stsEndpoint = stsEndpoint;
|
|
||||||
const credentialsClient = new CredentialsClient(clientProps);
|
const credentialsClient = new CredentialsClient(clientProps);
|
||||||
let sourceAccountId: string;
|
let sourceAccountId: string;
|
||||||
let webIdentityToken: string;
|
let webIdentityToken: string;
|
||||||
@@ -176,9 +152,13 @@ export async function run() {
|
|||||||
// Else, export credentials provided as input
|
// Else, export credentials provided as input
|
||||||
if (useGitHubOIDCProvider()) {
|
if (useGitHubOIDCProvider()) {
|
||||||
try {
|
try {
|
||||||
webIdentityToken = await withRetry(async () => {
|
webIdentityToken = await retryAndBackoff(
|
||||||
|
async () => {
|
||||||
return core.getIDToken(audience);
|
return core.getIDToken(audience);
|
||||||
}, 'getIDToken');
|
},
|
||||||
|
!disableRetry,
|
||||||
|
maxRetries,
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(`getIDToken call failed: ${errorMessage(error)}`);
|
throw new Error(`getIDToken call failed: ${errorMessage(error)}`);
|
||||||
}
|
}
|
||||||
@@ -199,40 +179,23 @@ export async function run() {
|
|||||||
}
|
}
|
||||||
} else if (!webIdentityTokenFile && !roleChaining) {
|
} else if (!webIdentityTokenFile && !roleChaining) {
|
||||||
// Proceed only if credentials can be picked up
|
// Proceed only if credentials can be picked up
|
||||||
await withRetry(
|
await credentialsClient.validateCredentials(undefined, roleChaining, expectedAccountIds);
|
||||||
() => credentialsClient.validateCredentials(undefined, roleChaining, expectedAccountIds),
|
sourceAccountId = await exportAccountId(credentialsClient, maskAccountId);
|
||||||
'validateCredentials',
|
|
||||||
);
|
|
||||||
sourceAccountId = await withRetry(() => exportAccountId(credentialsClient, maskAccountId), 'exportAccountId');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AccessKeyId || roleChaining) {
|
if (AccessKeyId || roleChaining) {
|
||||||
// Validate that the SDK can actually pick up credentials.
|
// Validate that the SDK can actually pick up credentials.
|
||||||
// This validates cases where this action is using existing environment 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.
|
// and cases where the user intended to provide input credentials but the secrets inputs resolved to empty strings.
|
||||||
// Skip when output-env-credentials is false: input IAM keys were not written to env, so
|
await credentialsClient.validateCredentials(AccessKeyId, roleChaining, expectedAccountIds);
|
||||||
// the default chain would resolve to ambient runner credentials and the access-key check
|
sourceAccountId = await exportAccountId(credentialsClient, maskAccountId);
|
||||||
// would spuriously fail (see #1554).
|
|
||||||
if (outputEnvCredentials) {
|
|
||||||
await withRetry(
|
|
||||||
() => credentialsClient.validateCredentials(AccessKeyId, roleChaining, expectedAccountIds),
|
|
||||||
'validateCredentials',
|
|
||||||
);
|
|
||||||
sourceAccountId = await withRetry(() => exportAccountId(credentialsClient, maskAccountId), 'exportAccountId');
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (customTags && (useGitHubOIDCProvider() || webIdentityTokenFile)) {
|
|
||||||
core.warning(
|
|
||||||
"'custom-tags' is set but will be ignored because session tags cannot be applied when using OIDC or web identity token authentication. " +
|
|
||||||
'Tags are controlled by the identity provider token claims in these authentication flows.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get role credentials if configured to do so
|
// Get role credentials if configured to do so
|
||||||
if (roleToAssume) {
|
if (roleToAssume) {
|
||||||
let roleCredentials: AssumeRoleCommandOutput;
|
let roleCredentials: AssumeRoleCommandOutput;
|
||||||
do {
|
do {
|
||||||
roleCredentials = await withRetry(async () => {
|
roleCredentials = await retryAndBackoff(
|
||||||
|
async () => {
|
||||||
return assumeRole({
|
return assumeRole({
|
||||||
credentialsClient,
|
credentialsClient,
|
||||||
sourceAccountId,
|
sourceAccountId,
|
||||||
@@ -246,30 +209,29 @@ export async function run() {
|
|||||||
webIdentityToken,
|
webIdentityToken,
|
||||||
inlineSessionPolicy,
|
inlineSessionPolicy,
|
||||||
managedSessionPolicies,
|
managedSessionPolicies,
|
||||||
customTags,
|
|
||||||
});
|
});
|
||||||
}, 'AssumeRole');
|
},
|
||||||
|
!disableRetry,
|
||||||
|
maxRetries,
|
||||||
|
);
|
||||||
} while (specialCharacterWorkaround && !verifyKeys(roleCredentials.Credentials));
|
} while (specialCharacterWorkaround && !verifyKeys(roleCredentials.Credentials));
|
||||||
core.info(`Authenticated as assumedRoleId ${roleCredentials.AssumedRoleUser?.AssumedRoleId}`);
|
core.info(`Authenticated as assumedRoleId ${roleCredentials.AssumedRoleUser?.AssumedRoleId}`);
|
||||||
exportCredentials(roleCredentials.Credentials, outputCredentials, outputEnvCredentials);
|
exportCredentials(roleCredentials.Credentials, outputCredentials, outputEnvCredentials);
|
||||||
// Validate that the SDK can pick up the assumed-role credentials from the environment.
|
// We need to validate the credentials in 2 of our use-cases
|
||||||
// Skip when output-env-credentials is false: the credentials were never written to env,
|
// First: self-hosted runners. If the GITHUB_ACTIONS environment variable
|
||||||
// so the default credential provider chain would resolve to ambient runner credentials
|
// is set to `true` then we are NOT in a self-hosted runner.
|
||||||
// (e.g. an EC2 instance profile) and the access-key-id check would spuriously fail.
|
// Second: Customer provided credentials manually (IAM User keys stored in GH Secrets)
|
||||||
// Skip when using a profile: validation runs after the profile file is written below.
|
// If we are using a profile, don't validate credentials yet (since they most likely won't be in the environment).
|
||||||
if ((!process.env.GITHUB_ACTIONS || AccessKeyId) && !awsProfile && outputEnvCredentials) {
|
// Wait until after creds are written to the profile file to try validation.
|
||||||
await withRetry(
|
if ((!process.env.GITHUB_ACTIONS || AccessKeyId) && !awsProfile) {
|
||||||
() =>
|
await credentialsClient.validateCredentials(
|
||||||
credentialsClient.validateCredentials(
|
|
||||||
roleCredentials.Credentials?.AccessKeyId,
|
roleCredentials.Credentials?.AccessKeyId,
|
||||||
roleChaining,
|
roleChaining,
|
||||||
expectedAccountIds,
|
expectedAccountIds,
|
||||||
),
|
|
||||||
'validateCredentials',
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (outputEnvCredentials) {
|
if (outputEnvCredentials) {
|
||||||
await withRetry(() => exportAccountId(credentialsClient, maskAccountId), 'exportAccountId');
|
await exportAccountId(credentialsClient, maskAccountId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write profile files if profile mode is enabled
|
// Write profile files if profile mode is enabled
|
||||||
@@ -282,14 +244,10 @@ export async function run() {
|
|||||||
// We then validate the credentials to make sure they work.
|
// We then validate the credentials to make sure they work.
|
||||||
if (AccessKeyId || !process.env.GITHUB_ACTIONS) {
|
if (AccessKeyId || !process.env.GITHUB_ACTIONS) {
|
||||||
writeProfileFiles(awsProfile, roleCredentials.Credentials, region, true);
|
writeProfileFiles(awsProfile, roleCredentials.Credentials, region, true);
|
||||||
await withRetry(
|
await credentialsClient.validateCredentials(
|
||||||
() =>
|
roleCredentials.Credentials.AccessKeyId,
|
||||||
credentialsClient.validateCredentials(
|
|
||||||
roleCredentials.Credentials?.AccessKeyId,
|
|
||||||
roleChaining,
|
roleChaining,
|
||||||
expectedAccountIds,
|
expectedAccountIds,
|
||||||
),
|
|
||||||
'validateCredentials',
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
writeProfileFiles(awsProfile, roleCredentials.Credentials, region, overwriteAwsProfile);
|
writeProfileFiles(awsProfile, roleCredentials.Credentials, region, overwriteAwsProfile);
|
||||||
|
|||||||
+13
-8
@@ -5,15 +5,20 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|||||||
import { cleanup } from '../src/cleanup';
|
import { cleanup } from '../src/cleanup';
|
||||||
import mocks from './mockinputs.test';
|
import mocks from './mockinputs.test';
|
||||||
|
|
||||||
vi.mock('@actions/core');
|
|
||||||
|
|
||||||
const mockedSTSClient = mockClient(STSClient);
|
const mockedSTSClient = mockClient(STSClient);
|
||||||
|
|
||||||
describe('Configure AWS Credentials cleanup', {}, () => {
|
describe('Configure AWS Credentials cleanup', {}, () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.resetAllMocks();
|
// Reset mock state
|
||||||
|
vi.restoreAllMocks();
|
||||||
mockedSTSClient.reset();
|
mockedSTSClient.reset();
|
||||||
vi.mocked(core.getInput).mockReturnValue('');
|
// Mock GitHub Actions core functions
|
||||||
|
vi.spyOn(core, 'exportVariable').mockImplementation((_n, _v) => {});
|
||||||
|
vi.spyOn(core, 'setSecret').mockImplementation((_s) => {});
|
||||||
|
vi.spyOn(core, 'setFailed').mockImplementation((_m) => {});
|
||||||
|
vi.spyOn(core, 'setOutput').mockImplementation((_n, _v) => {});
|
||||||
|
vi.spyOn(core, 'debug').mockImplementation((_m) => {});
|
||||||
|
vi.spyOn(core, 'info').mockImplementation((_m) => {});
|
||||||
process.env = {
|
process.env = {
|
||||||
...mocks.envs,
|
...mocks.envs,
|
||||||
AWS_ACCESS_KEY_ID: 'CLEANUPTEST',
|
AWS_ACCESS_KEY_ID: 'CLEANUPTEST',
|
||||||
@@ -34,7 +39,7 @@ describe('Configure AWS Credentials cleanup', {}, () => {
|
|||||||
expect(core.exportVariable).toHaveBeenCalledWith('AWS_REGION', '');
|
expect(core.exportVariable).toHaveBeenCalledWith('AWS_REGION', '');
|
||||||
});
|
});
|
||||||
it('also clears AWS_PROFILE when aws-profile was set', {}, () => {
|
it('also clears AWS_PROFILE when aws-profile was set', {}, () => {
|
||||||
vi.mocked(core.getInput).mockImplementation((name: string) => {
|
vi.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||||
if (name === 'aws-profile') return 'my-profile';
|
if (name === 'aws-profile') return 'my-profile';
|
||||||
if (name === 'output-env-credentials') return 'true';
|
if (name === 'output-env-credentials') return 'true';
|
||||||
return '';
|
return '';
|
||||||
@@ -45,7 +50,7 @@ describe('Configure AWS Credentials cleanup', {}, () => {
|
|||||||
expect(core.exportVariable).toHaveBeenCalledWith('AWS_PROFILE', '');
|
expect(core.exportVariable).toHaveBeenCalledWith('AWS_PROFILE', '');
|
||||||
});
|
});
|
||||||
it('skips env cleanup when aws-profile is set without output-env-credentials', {}, () => {
|
it('skips env cleanup when aws-profile is set without output-env-credentials', {}, () => {
|
||||||
vi.mocked(core.getInput).mockImplementation((name: string) => {
|
vi.spyOn(core, 'getInput').mockImplementation((name: string) => {
|
||||||
if (name === 'aws-profile') return 'my-profile';
|
if (name === 'aws-profile') return 'my-profile';
|
||||||
return '';
|
return '';
|
||||||
});
|
});
|
||||||
@@ -54,14 +59,14 @@ describe('Configure AWS Credentials cleanup', {}, () => {
|
|||||||
expect(core.exportVariable).toHaveBeenCalledTimes(0);
|
expect(core.exportVariable).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
it('handles errors', {}, () => {
|
it('handles errors', {}, () => {
|
||||||
vi.mocked(core.exportVariable).mockImplementationOnce(() => {
|
vi.spyOn(core, 'exportVariable').mockImplementationOnce(() => {
|
||||||
throw new Error('Test error');
|
throw new Error('Test error');
|
||||||
});
|
});
|
||||||
cleanup();
|
cleanup();
|
||||||
expect(core.setFailed).toHaveBeenCalled();
|
expect(core.setFailed).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
it(`doesn't export credentials as empty env variables if asked not to`, {}, () => {
|
it(`doesn't export credentials as empty env variables if asked not to`, {}, () => {
|
||||||
vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.NO_ENV_CREDS_INPUTS));
|
vi.spyOn(core, 'getInput').mockImplementation(mocks.getInput(mocks.NO_ENV_CREDS_INPUTS));
|
||||||
cleanup();
|
cleanup();
|
||||||
expect(core.exportVariable).toHaveBeenCalledTimes(0);
|
expect(core.exportVariable).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|||||||
+14
-30
@@ -2,11 +2,10 @@ import * as core from '@actions/core';
|
|||||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
import * as helpers from '../src/helpers';
|
import * as helpers from '../src/helpers';
|
||||||
|
|
||||||
vi.mock('@actions/core');
|
|
||||||
|
|
||||||
describe('Configure AWS Credentials helpers', {}, () => {
|
describe('Configure AWS Credentials helpers', {}, () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.resetAllMocks();
|
vi.restoreAllMocks();
|
||||||
|
vi.spyOn(core, 'debug').mockImplementation(() => {});
|
||||||
});
|
});
|
||||||
it('removes brackets from GitHub Actor', {}, () => {
|
it('removes brackets from GitHub Actor', {}, () => {
|
||||||
const actor = 'actor[bot]';
|
const actor = 'actor[bot]';
|
||||||
@@ -24,30 +23,10 @@ describe('Configure AWS Credentials helpers', {}, () => {
|
|||||||
await expect(helpers.retryAndBackoff(fn, false)).rejects.toMatch('i am not retryable');
|
await expect(helpers.retryAndBackoff(fn, false)).rejects.toMatch('i am not retryable');
|
||||||
expect(fn).toHaveBeenCalledTimes(1);
|
expect(fn).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
it('retries and logs with label at info level', {}, async () => {
|
|
||||||
helpers.withsleep(() => Promise.resolve());
|
|
||||||
const fn = vi.fn().mockRejectedValueOnce(new Error('transient')).mockResolvedValueOnce('success');
|
|
||||||
const result = await helpers.retryAndBackoff(fn, true, 3, 0, 50, 'TestOp');
|
|
||||||
expect(result).toBe('success');
|
|
||||||
expect(fn).toHaveBeenCalledTimes(2);
|
|
||||||
expect(core.info).toHaveBeenCalledWith(expect.stringContaining('Retry TestOp: attempt 1 of 3 failed'));
|
|
||||||
helpers.reset();
|
|
||||||
});
|
|
||||||
it('logs max retries reached with label', {}, async () => {
|
|
||||||
helpers.withsleep(() => Promise.resolve());
|
|
||||||
const fn = vi.fn().mockRejectedValue(new Error('persistent'));
|
|
||||||
await expect(helpers.retryAndBackoff(fn, true, 2, 0, 50, 'TestOp')).rejects.toThrow('persistent');
|
|
||||||
expect(core.info).toHaveBeenCalledWith(expect.stringContaining('Retry TestOp: reached max retries (2)'));
|
|
||||||
helpers.reset();
|
|
||||||
});
|
|
||||||
it('retries without a label (backward compat)', {}, async () => {
|
|
||||||
helpers.withsleep(() => Promise.resolve());
|
|
||||||
const fn = vi.fn().mockRejectedValueOnce(new Error('transient')).mockResolvedValueOnce('ok');
|
|
||||||
await helpers.retryAndBackoff(fn, true, 3);
|
|
||||||
expect(core.info).toHaveBeenCalledWith(expect.stringContaining('Retry: attempt 1 of 3 failed'));
|
|
||||||
helpers.reset();
|
|
||||||
});
|
|
||||||
it('can output creds when told to', {}, () => {
|
it('can output creds when told to', {}, () => {
|
||||||
|
vi.spyOn(core, 'setOutput').mockImplementation(() => {});
|
||||||
|
vi.spyOn(core, 'setSecret').mockImplementation(() => {});
|
||||||
|
vi.spyOn(core, 'exportVariable').mockImplementation(() => {});
|
||||||
helpers.exportCredentials(
|
helpers.exportCredentials(
|
||||||
{ AccessKeyId: 'test', SecretAccessKey: 'test', SessionToken: 'test', Expiration: new Date(8640000000000000) },
|
{ AccessKeyId: 'test', SecretAccessKey: 'test', SessionToken: 'test', Expiration: new Date(8640000000000000) },
|
||||||
true,
|
true,
|
||||||
@@ -68,6 +47,9 @@ describe('Configure AWS Credentials helpers', {}, () => {
|
|||||||
process.env = env;
|
process.env = env;
|
||||||
});
|
});
|
||||||
it(`won't output credentials to env if told not to`, {}, () => {
|
it(`won't output credentials to env if told not to`, {}, () => {
|
||||||
|
vi.spyOn(core, 'setOutput').mockImplementation(() => {});
|
||||||
|
vi.spyOn(core, 'setSecret').mockImplementation(() => {});
|
||||||
|
vi.spyOn(core, 'exportVariable').mockImplementation(() => {});
|
||||||
helpers.exportCredentials(
|
helpers.exportCredentials(
|
||||||
{ AccessKeyId: 'test', SecretAccessKey: 'test', SessionToken: 'test', Expiration: new Date(8640000000000000) },
|
{ AccessKeyId: 'test', SecretAccessKey: 'test', SessionToken: 'test', Expiration: new Date(8640000000000000) },
|
||||||
true,
|
true,
|
||||||
@@ -95,20 +77,22 @@ describe('Configure AWS Credentials helpers', {}, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('handles getBooleanInput correctly', {}, () => {
|
it('handles getBooleanInput correctly', {}, () => {
|
||||||
vi.mocked(core.getInput).mockReturnValue('true');
|
vi.spyOn(core, 'getInput').mockReturnValue('true');
|
||||||
expect(helpers.getBooleanInput('test')).toBe(true);
|
expect(helpers.getBooleanInput('test')).toBe(true);
|
||||||
|
|
||||||
vi.mocked(core.getInput).mockReturnValue('false');
|
vi.spyOn(core, 'getInput').mockReturnValue('false');
|
||||||
expect(helpers.getBooleanInput('test')).toBe(false);
|
expect(helpers.getBooleanInput('test')).toBe(false);
|
||||||
|
|
||||||
vi.mocked(core.getInput).mockReturnValue('');
|
vi.spyOn(core, 'getInput').mockReturnValue('');
|
||||||
expect(helpers.getBooleanInput('test', { default: true })).toBe(true);
|
expect(helpers.getBooleanInput('test', { default: true })).toBe(true);
|
||||||
|
|
||||||
vi.mocked(core.getInput).mockReturnValue('invalid');
|
vi.spyOn(core, 'getInput').mockReturnValue('invalid');
|
||||||
expect(() => helpers.getBooleanInput('test')).toThrow();
|
expect(() => helpers.getBooleanInput('test')).toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('clears session token when not provided', {}, () => {
|
it('clears session token when not provided', {}, () => {
|
||||||
|
vi.spyOn(core, 'setSecret').mockImplementation(() => {});
|
||||||
|
vi.spyOn(core, 'exportVariable').mockImplementation(() => {});
|
||||||
process.env.AWS_SESSION_TOKEN = 'old-token';
|
process.env.AWS_SESSION_TOKEN = 'old-token';
|
||||||
helpers.exportCredentials({ AccessKeyId: 'test', SecretAccessKey: 'test' }, false, true);
|
helpers.exportCredentials({ AccessKeyId: 'test', SecretAccessKey: 'test' }, false, true);
|
||||||
expect(core.exportVariable).toHaveBeenCalledWith('AWS_SESSION_TOKEN', '');
|
expect(core.exportVariable).toHaveBeenCalledWith('AWS_SESSION_TOKEN', '');
|
||||||
|
|||||||
+87
-624
File diff suppressed because it is too large
Load Diff
@@ -6,46 +6,6 @@ const inputs = {
|
|||||||
'aws-region': 'fake-region-1',
|
'aws-region': 'fake-region-1',
|
||||||
'special-characters-workaround': 'true',
|
'special-characters-workaround': 'true',
|
||||||
},
|
},
|
||||||
CUSTOM_TAGS_INVALID_JSON_INPUTS: {
|
|
||||||
'aws-access-key-id': 'MYAWSACCESSKEYID',
|
|
||||||
'aws-secret-access-key': 'MYAWSSECRETACCESSKEY',
|
|
||||||
'role-to-assume': 'arn:aws:iam::111111111111:role/MY-ROLE',
|
|
||||||
'aws-region': 'fake-region-1',
|
|
||||||
'retry-max-attempts': '1',
|
|
||||||
'custom-tags': 'not a json',
|
|
||||||
},
|
|
||||||
CUSTOM_TAGS_ARRAY_INPUTS: {
|
|
||||||
'aws-access-key-id': 'MYAWSACCESSKEYID',
|
|
||||||
'aws-secret-access-key': 'MYAWSSECRETACCESSKEY',
|
|
||||||
'role-to-assume': 'arn:aws:iam::111111111111:role/MY-ROLE',
|
|
||||||
'aws-region': 'fake-region-1',
|
|
||||||
'retry-max-attempts': '1',
|
|
||||||
'custom-tags': '[1, 2, 3]',
|
|
||||||
},
|
|
||||||
CUSTOM_TAGS_RESERVED_KEY_INPUTS: {
|
|
||||||
'aws-access-key-id': 'MYAWSACCESSKEYID',
|
|
||||||
'aws-secret-access-key': 'MYAWSSECRETACCESSKEY',
|
|
||||||
'role-to-assume': 'arn:aws:iam::111111111111:role/MY-ROLE',
|
|
||||||
'aws-region': 'fake-region-1',
|
|
||||||
'retry-max-attempts': '1',
|
|
||||||
'custom-tags': JSON.stringify({ Repository: 'evil-repo' }),
|
|
||||||
},
|
|
||||||
CUSTOM_TAGS_INVALID_KEY_CHARS_INPUTS: {
|
|
||||||
'aws-access-key-id': 'MYAWSACCESSKEYID',
|
|
||||||
'aws-secret-access-key': 'MYAWSSECRETACCESSKEY',
|
|
||||||
'role-to-assume': 'arn:aws:iam::111111111111:role/MY-ROLE',
|
|
||||||
'aws-region': 'fake-region-1',
|
|
||||||
'retry-max-attempts': '1',
|
|
||||||
'custom-tags': JSON.stringify({ 'invalid{key}': 'value' }),
|
|
||||||
},
|
|
||||||
CUSTOM_TAGS_OBJECT_INPUTS: {
|
|
||||||
'aws-access-key-id': 'MYAWSACCESSKEYID',
|
|
||||||
'aws-secret-access-key': 'MYAWSSECRETACCESSKEY',
|
|
||||||
'role-to-assume': 'arn:aws:iam::111111111111:role/MY-ROLE',
|
|
||||||
'aws-region': 'fake-region-1',
|
|
||||||
'retry-max-attempts': '1',
|
|
||||||
'custom-tags': JSON.stringify({ Environment: 'Production', Team: 'DevOps' }),
|
|
||||||
},
|
|
||||||
IAM_USER_INPUTS: {
|
IAM_USER_INPUTS: {
|
||||||
'aws-access-key-id': 'MYAWSACCESSKEYID',
|
'aws-access-key-id': 'MYAWSACCESSKEYID',
|
||||||
'aws-secret-access-key': 'MYAWSSECRETACCESSKEY',
|
'aws-secret-access-key': 'MYAWSSECRETACCESSKEY',
|
||||||
@@ -83,14 +43,6 @@ const inputs = {
|
|||||||
'output-env-credentials': 'false',
|
'output-env-credentials': 'false',
|
||||||
'output-credentials': 'true',
|
'output-credentials': 'true',
|
||||||
},
|
},
|
||||||
IAM_ASSUMEROLE_NO_ENV_INPUTS: {
|
|
||||||
'aws-access-key-id': 'MYAWSACCESSKEYID',
|
|
||||||
'aws-secret-access-key': 'MYAWSSECRETACCESSKEY',
|
|
||||||
'role-to-assume': 'arn:aws:iam::111111111111:role/MY-ROLE',
|
|
||||||
'aws-region': 'fake-region-1',
|
|
||||||
'output-env-credentials': 'false',
|
|
||||||
'output-credentials': 'true',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const envs = {
|
const envs = {
|
||||||
@@ -101,15 +53,6 @@ const envs = {
|
|||||||
GITHUB_SHA: 'MY-COMMIT-ID',
|
GITHUB_SHA: 'MY-COMMIT-ID',
|
||||||
GITHUB_WORKSPACE: '/home/github',
|
GITHUB_WORKSPACE: '/home/github',
|
||||||
GITHUB_ACTIONS: 'true',
|
GITHUB_ACTIONS: 'true',
|
||||||
GITHUB_REF: 'refs/pull/42/merge',
|
|
||||||
GITHUB_EVENT_NAME: 'pull_request',
|
|
||||||
GITHUB_RUN_ID: '16412345678',
|
|
||||||
GITHUB_JOB: 'build',
|
|
||||||
GITHUB_REF_NAME: 'feature-branch',
|
|
||||||
GITHUB_REF_TYPE: 'branch',
|
|
||||||
GITHUB_BASE_REF: 'main',
|
|
||||||
GITHUB_HEAD_REF: 'feature-branch',
|
|
||||||
GITHUB_TRIGGERING_ACTOR: 'MY-USERNAME[bot]',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const outputs = {
|
const outputs = {
|
||||||
|
|||||||
+84
-98
@@ -11,13 +11,13 @@ import {
|
|||||||
writeProfileFiles,
|
writeProfileFiles,
|
||||||
} from '../src/profileManager';
|
} from '../src/profileManager';
|
||||||
|
|
||||||
vi.mock('@actions/core');
|
|
||||||
vi.mock('node:fs');
|
|
||||||
|
|
||||||
describe('Profile Manager', {}, () => {
|
describe('Profile Manager', {}, () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.resetAllMocks();
|
vi.restoreAllMocks();
|
||||||
|
vi.mock('node:fs');
|
||||||
vol.reset();
|
vol.reset();
|
||||||
|
vi.spyOn(core, 'debug').mockImplementation(() => {});
|
||||||
|
vi.spyOn(core, 'info').mockImplementation(() => {});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('parseIni', {}, () => {
|
describe('parseIni', {}, () => {
|
||||||
@@ -95,10 +95,7 @@ describe('Profile Manager', {}, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('round-trips through parseIni', {}, () => {
|
it('round-trips through parseIni', {}, () => {
|
||||||
const data = {
|
const data = { dev: { aws_access_key_id: 'AKIA', aws_secret_access_key: 'secret' }, 'profile prod': { region: 'us-west-2' } };
|
||||||
dev: { aws_access_key_id: 'AKIA', aws_secret_access_key: 'secret' },
|
|
||||||
'profile prod': { region: 'us-west-2' },
|
|
||||||
};
|
|
||||||
const roundTripped = parseIni(stringifyIni(data));
|
const roundTripped = parseIni(stringifyIni(data));
|
||||||
expect(roundTripped).toEqual(data);
|
expect(roundTripped).toEqual(data);
|
||||||
});
|
});
|
||||||
@@ -199,15 +196,10 @@ describe('Profile Manager', {}, () => {
|
|||||||
const filePath = '/home/runner/.aws/credentials';
|
const filePath = '/home/runner/.aws/credentials';
|
||||||
fs.mkdirSync('/home/runner/.aws', { recursive: true });
|
fs.mkdirSync('/home/runner/.aws', { recursive: true });
|
||||||
|
|
||||||
mergeProfileSection(
|
mergeProfileSection(filePath, 'dev', {
|
||||||
filePath,
|
|
||||||
'dev',
|
|
||||||
{
|
|
||||||
aws_access_key_id: 'AKIAIOSFODNN7EXAMPLE',
|
aws_access_key_id: 'AKIAIOSFODNN7EXAMPLE',
|
||||||
aws_secret_access_key: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
|
aws_secret_access_key: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
|
||||||
},
|
}, false);
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
const content = fs.readFileSync(filePath, 'utf-8');
|
const content = fs.readFileSync(filePath, 'utf-8');
|
||||||
const parsed = parseIni(content);
|
const parsed = parseIni(content);
|
||||||
@@ -222,26 +214,16 @@ describe('Profile Manager', {}, () => {
|
|||||||
fs.mkdirSync('/home/runner/.aws', { recursive: true });
|
fs.mkdirSync('/home/runner/.aws', { recursive: true });
|
||||||
|
|
||||||
// Create initial profile
|
// Create initial profile
|
||||||
mergeProfileSection(
|
mergeProfileSection(filePath, 'dev', {
|
||||||
filePath,
|
|
||||||
'dev',
|
|
||||||
{
|
|
||||||
aws_access_key_id: 'AKIAIOSFODNN7EXAMPLE',
|
aws_access_key_id: 'AKIAIOSFODNN7EXAMPLE',
|
||||||
aws_secret_access_key: 'devSecretKey',
|
aws_secret_access_key: 'devSecretKey',
|
||||||
},
|
}, false);
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add second profile
|
// Add second profile
|
||||||
mergeProfileSection(
|
mergeProfileSection(filePath, 'prod', {
|
||||||
filePath,
|
|
||||||
'prod',
|
|
||||||
{
|
|
||||||
aws_access_key_id: 'AKIAPRODEXAMPLE',
|
aws_access_key_id: 'AKIAPRODEXAMPLE',
|
||||||
aws_secret_access_key: 'prodSecretKey',
|
aws_secret_access_key: 'prodSecretKey',
|
||||||
},
|
}, false);
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
const content = fs.readFileSync(filePath, 'utf-8');
|
const content = fs.readFileSync(filePath, 'utf-8');
|
||||||
const parsed = parseIni(content);
|
const parsed = parseIni(content);
|
||||||
@@ -257,28 +239,18 @@ describe('Profile Manager', {}, () => {
|
|||||||
fs.mkdirSync('/home/runner/.aws', { recursive: true });
|
fs.mkdirSync('/home/runner/.aws', { recursive: true });
|
||||||
|
|
||||||
// Create initial profile
|
// Create initial profile
|
||||||
mergeProfileSection(
|
mergeProfileSection(filePath, 'dev', {
|
||||||
filePath,
|
|
||||||
'dev',
|
|
||||||
{
|
|
||||||
aws_access_key_id: 'OLD_KEY',
|
aws_access_key_id: 'OLD_KEY',
|
||||||
aws_secret_access_key: 'oldSecretKey',
|
aws_secret_access_key: 'oldSecretKey',
|
||||||
aws_session_token: 'oldSessionToken',
|
aws_session_token: 'oldSessionToken'
|
||||||
},
|
}, false);
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Overwrite with new credentials
|
// Overwrite with new credentials
|
||||||
mergeProfileSection(
|
mergeProfileSection(filePath, 'dev', {
|
||||||
filePath,
|
|
||||||
'dev',
|
|
||||||
{
|
|
||||||
aws_access_key_id: 'NEW_KEY',
|
aws_access_key_id: 'NEW_KEY',
|
||||||
aws_secret_access_key: 'newSecretKey',
|
aws_secret_access_key: 'newSecretKey',
|
||||||
aws_session_token: 'newSessionToken',
|
aws_session_token: 'newSessionToken',
|
||||||
},
|
}, true);
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
const content = fs.readFileSync(filePath, 'utf-8');
|
const content = fs.readFileSync(filePath, 'utf-8');
|
||||||
const parsed = parseIni(content);
|
const parsed = parseIni(content);
|
||||||
@@ -293,27 +265,17 @@ describe('Profile Manager', {}, () => {
|
|||||||
fs.mkdirSync('/home/runner/.aws', { recursive: true });
|
fs.mkdirSync('/home/runner/.aws', { recursive: true });
|
||||||
|
|
||||||
// Create profile with session token
|
// Create profile with session token
|
||||||
mergeProfileSection(
|
mergeProfileSection(filePath, 'dev', {
|
||||||
filePath,
|
|
||||||
'dev',
|
|
||||||
{
|
|
||||||
aws_access_key_id: 'AKIA',
|
aws_access_key_id: 'AKIA',
|
||||||
aws_secret_access_key: 'secret',
|
aws_secret_access_key: 'secret',
|
||||||
aws_session_token: 'old-token',
|
aws_session_token: 'old-token',
|
||||||
},
|
}, false);
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Overwrite without session token
|
// Overwrite without session token
|
||||||
mergeProfileSection(
|
mergeProfileSection(filePath, 'dev', {
|
||||||
filePath,
|
|
||||||
'dev',
|
|
||||||
{
|
|
||||||
aws_access_key_id: 'AKIA2',
|
aws_access_key_id: 'AKIA2',
|
||||||
aws_secret_access_key: 'secret2',
|
aws_secret_access_key: 'secret2',
|
||||||
},
|
}, true);
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
const content = fs.readFileSync(filePath, 'utf-8');
|
const content = fs.readFileSync(filePath, 'utf-8');
|
||||||
const parsed = parseIni(content);
|
const parsed = parseIni(content);
|
||||||
@@ -328,15 +290,10 @@ describe('Profile Manager', {}, () => {
|
|||||||
fs.mkdirSync('/home/runner/.aws', { recursive: true });
|
fs.mkdirSync('/home/runner/.aws', { recursive: true });
|
||||||
fs.writeFileSync(filePath, '', { mode: 0o600 });
|
fs.writeFileSync(filePath, '', { mode: 0o600 });
|
||||||
|
|
||||||
mergeProfileSection(
|
mergeProfileSection(filePath, 'dev', {
|
||||||
filePath,
|
|
||||||
'dev',
|
|
||||||
{
|
|
||||||
aws_access_key_id: 'AKIA',
|
aws_access_key_id: 'AKIA',
|
||||||
aws_secret_access_key: 'secret',
|
aws_secret_access_key: 'secret',
|
||||||
},
|
}, false);
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
const content = fs.readFileSync(filePath, 'utf-8');
|
const content = fs.readFileSync(filePath, 'utf-8');
|
||||||
const parsed = parseIni(content);
|
const parsed = parseIni(content);
|
||||||
@@ -350,31 +307,17 @@ describe('Profile Manager', {}, () => {
|
|||||||
fs.mkdirSync('/home/runner/.aws', { recursive: true });
|
fs.mkdirSync('/home/runner/.aws', { recursive: true });
|
||||||
|
|
||||||
// Create initial profile
|
// Create initial profile
|
||||||
mergeProfileSection(
|
mergeProfileSection(filePath, 'dev', {
|
||||||
filePath,
|
|
||||||
'dev',
|
|
||||||
{
|
|
||||||
aws_access_key_id: 'OLD_KEY',
|
aws_access_key_id: 'OLD_KEY',
|
||||||
aws_secret_access_key: 'oldSecretKey',
|
aws_secret_access_key: 'oldSecretKey',
|
||||||
},
|
}, false);
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Overwrite with new credentials
|
// Overwrite with new credentials
|
||||||
expect(() =>
|
expect(() => mergeProfileSection(filePath, 'dev', {
|
||||||
mergeProfileSection(
|
|
||||||
filePath,
|
|
||||||
'dev',
|
|
||||||
{
|
|
||||||
aws_access_key_id: 'NEW_KEY',
|
aws_access_key_id: 'NEW_KEY',
|
||||||
aws_secret_access_key: 'newSecretKey',
|
aws_secret_access_key: 'newSecretKey',
|
||||||
aws_session_token: 'sessionToken',
|
aws_session_token: 'sessionToken',
|
||||||
},
|
}, false)).toThrow(`Profile with name "dev" already exists. Please use the overwrite-aws-profile input if you want to overwrite existing profiles.`);
|
||||||
false,
|
|
||||||
),
|
|
||||||
).toThrow(
|
|
||||||
`Profile with name "dev" already exists. Please use the overwrite-aws-profile input if you want to overwrite existing profiles.`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const content = fs.readFileSync(filePath, 'utf-8');
|
const content = fs.readFileSync(filePath, 'utf-8');
|
||||||
const parsed = parseIni(content);
|
const parsed = parseIni(content);
|
||||||
@@ -525,7 +468,7 @@ describe('Profile Manager', {}, () => {
|
|||||||
SecretAccessKey: 'secret',
|
SecretAccessKey: 'secret',
|
||||||
},
|
},
|
||||||
'us-east-1',
|
'us-east-1',
|
||||||
false,
|
false
|
||||||
),
|
),
|
||||||
).toThrow('whitespace');
|
).toThrow('whitespace');
|
||||||
});
|
});
|
||||||
@@ -543,7 +486,7 @@ describe('Profile Manager', {}, () => {
|
|||||||
SecretAccessKey: 'secret',
|
SecretAccessKey: 'secret',
|
||||||
},
|
},
|
||||||
'us-east-1',
|
'us-east-1',
|
||||||
false,
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(fs.existsSync('/custom/credentials')).toBe(true);
|
expect(fs.existsSync('/custom/credentials')).toBe(true);
|
||||||
@@ -558,7 +501,7 @@ describe('Profile Manager', {}, () => {
|
|||||||
SecretAccessKey: 'secret',
|
SecretAccessKey: 'secret',
|
||||||
},
|
},
|
||||||
'us-east-1',
|
'us-east-1',
|
||||||
false,
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(core.info).toHaveBeenCalledWith('Writing credentials to profile: dev');
|
expect(core.info).toHaveBeenCalledWith('Writing credentials to profile: dev');
|
||||||
@@ -574,7 +517,12 @@ describe('Profile Manager', {}, () => {
|
|||||||
'[personal]\naws_access_key_id=AKIAPERSONAL\naws_secret_access_key=personalSecret\naws_session_token=personalToken\n',
|
'[personal]\naws_access_key_id=AKIAPERSONAL\naws_secret_access_key=personalSecret\naws_session_token=personalToken\n',
|
||||||
);
|
);
|
||||||
|
|
||||||
writeProfileFiles('dev', { AccessKeyId: 'AKIADEV', SecretAccessKey: 'devSecret' }, 'us-east-1', false);
|
writeProfileFiles(
|
||||||
|
'dev',
|
||||||
|
{ AccessKeyId: 'AKIADEV', SecretAccessKey: 'devSecret' },
|
||||||
|
'us-east-1',
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
const content = fs.readFileSync(credsPath, 'utf-8');
|
const content = fs.readFileSync(credsPath, 'utf-8');
|
||||||
const parsed = parseIni(content);
|
const parsed = parseIni(content);
|
||||||
@@ -592,9 +540,17 @@ describe('Profile Manager', {}, () => {
|
|||||||
it('preserves pre-existing config with extra keys', {}, () => {
|
it('preserves pre-existing config with extra keys', {}, () => {
|
||||||
const configPath = getProfileFilePaths().config;
|
const configPath = getProfileFilePaths().config;
|
||||||
fs.mkdirSync(require('node:path').dirname(configPath), { recursive: true });
|
fs.mkdirSync(require('node:path').dirname(configPath), { recursive: true });
|
||||||
fs.writeFileSync(configPath, '[profile personal]\nregion=eu-west-1\noutput=json\ncli_pager=\n');
|
fs.writeFileSync(
|
||||||
|
configPath,
|
||||||
|
'[profile personal]\nregion=eu-west-1\noutput=json\ncli_pager=\n',
|
||||||
|
);
|
||||||
|
|
||||||
writeProfileFiles('dev', { AccessKeyId: 'AKIA', SecretAccessKey: 'secret' }, 'us-east-1', false);
|
writeProfileFiles(
|
||||||
|
'dev',
|
||||||
|
{ AccessKeyId: 'AKIA', SecretAccessKey: 'secret' },
|
||||||
|
'us-east-1',
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
const content = fs.readFileSync(configPath, 'utf-8');
|
const content = fs.readFileSync(configPath, 'utf-8');
|
||||||
const parsed = parseIni(content);
|
const parsed = parseIni(content);
|
||||||
@@ -610,9 +566,17 @@ describe('Profile Manager', {}, () => {
|
|||||||
it('preserves pre-existing default profile when writing a named profile', {}, () => {
|
it('preserves pre-existing default profile when writing a named profile', {}, () => {
|
||||||
const credsPath = getProfileFilePaths().credentials;
|
const credsPath = getProfileFilePaths().credentials;
|
||||||
fs.mkdirSync(require('node:path').dirname(credsPath), { recursive: true });
|
fs.mkdirSync(require('node:path').dirname(credsPath), { recursive: true });
|
||||||
fs.writeFileSync(credsPath, '[default]\naws_access_key_id=AKIADEFAULT\naws_secret_access_key=defaultSecret\n');
|
fs.writeFileSync(
|
||||||
|
credsPath,
|
||||||
|
'[default]\naws_access_key_id=AKIADEFAULT\naws_secret_access_key=defaultSecret\n',
|
||||||
|
);
|
||||||
|
|
||||||
writeProfileFiles('dev', { AccessKeyId: 'AKIADEV', SecretAccessKey: 'devSecret' }, 'us-west-2', false);
|
writeProfileFiles(
|
||||||
|
'dev',
|
||||||
|
{ AccessKeyId: 'AKIADEV', SecretAccessKey: 'devSecret' },
|
||||||
|
'us-west-2',
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
const content = fs.readFileSync(credsPath, 'utf-8');
|
const content = fs.readFileSync(credsPath, 'utf-8');
|
||||||
const parsed = parseIni(content);
|
const parsed = parseIni(content);
|
||||||
@@ -632,7 +596,12 @@ describe('Profile Manager', {}, () => {
|
|||||||
'# My important comment\n[personal]\naws_access_key_id=AKIA\naws_secret_access_key=secret\n',
|
'# My important comment\n[personal]\naws_access_key_id=AKIA\naws_secret_access_key=secret\n',
|
||||||
);
|
);
|
||||||
|
|
||||||
writeProfileFiles('dev', { AccessKeyId: 'AKIADEV', SecretAccessKey: 'devSecret' }, 'us-east-1', false);
|
writeProfileFiles(
|
||||||
|
'dev',
|
||||||
|
{ AccessKeyId: 'AKIADEV', SecretAccessKey: 'devSecret' },
|
||||||
|
'us-east-1',
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
const content = fs.readFileSync(credsPath, 'utf-8') as string;
|
const content = fs.readFileSync(credsPath, 'utf-8') as string;
|
||||||
|
|
||||||
@@ -666,7 +635,12 @@ describe('Profile Manager', {}, () => {
|
|||||||
|
|
||||||
fs.mkdirSync('/custom-creds', { recursive: true });
|
fs.mkdirSync('/custom-creds', { recursive: true });
|
||||||
|
|
||||||
writeProfileFiles('dev', { AccessKeyId: 'AKIA', SecretAccessKey: 'secret' }, 'us-east-1', false);
|
writeProfileFiles(
|
||||||
|
'dev',
|
||||||
|
{ AccessKeyId: 'AKIA', SecretAccessKey: 'secret' },
|
||||||
|
'us-east-1',
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
expect(fs.existsSync('/custom-creds/credentials')).toBe(true);
|
expect(fs.existsSync('/custom-creds/credentials')).toBe(true);
|
||||||
// Config file should be at the default path (under homedir)
|
// Config file should be at the default path (under homedir)
|
||||||
@@ -683,7 +657,7 @@ describe('Profile Manager', {}, () => {
|
|||||||
SessionToken: 'FwoGZXIvYXdzEBYaDEXAMPLE',
|
SessionToken: 'FwoGZXIvYXdzEBYaDEXAMPLE',
|
||||||
},
|
},
|
||||||
'us-east-1',
|
'us-east-1',
|
||||||
false,
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
const credsPath = getProfileFilePaths().credentials;
|
const credsPath = getProfileFilePaths().credentials;
|
||||||
@@ -702,16 +676,24 @@ describe('Profile Manager', {}, () => {
|
|||||||
'aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\n' +
|
'aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\n' +
|
||||||
'aws_session_token = FwoGZXIvYXdzEBYaDEXAMPLE\n',
|
'aws_session_token = FwoGZXIvYXdzEBYaDEXAMPLE\n',
|
||||||
);
|
);
|
||||||
expect(configContent).toBe('[profile dev]\n' + 'region = us-east-1\n');
|
expect(configContent).toBe(
|
||||||
|
'[profile dev]\n' +
|
||||||
|
'region = us-east-1\n',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('golden file for multi-profile output', {}, () => {
|
it('golden file for multi-profile output', {}, () => {
|
||||||
writeProfileFiles('dev', { AccessKeyId: 'AKIADEV', SecretAccessKey: 'devSecret' }, 'us-east-1', false);
|
writeProfileFiles(
|
||||||
|
'dev',
|
||||||
|
{ AccessKeyId: 'AKIADEV', SecretAccessKey: 'devSecret' },
|
||||||
|
'us-east-1',
|
||||||
|
false
|
||||||
|
);
|
||||||
writeProfileFiles(
|
writeProfileFiles(
|
||||||
'prod',
|
'prod',
|
||||||
{ AccessKeyId: 'AKIAPROD', SecretAccessKey: 'prodSecret', SessionToken: 'prodToken' },
|
{ AccessKeyId: 'AKIAPROD', SecretAccessKey: 'prodSecret', SessionToken: 'prodToken' },
|
||||||
'us-west-2',
|
'us-west-2',
|
||||||
false,
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
const credsPath = getProfileFilePaths().credentials;
|
const credsPath = getProfileFilePaths().credentials;
|
||||||
@@ -731,7 +713,11 @@ describe('Profile Manager', {}, () => {
|
|||||||
'aws_session_token = prodToken\n',
|
'aws_session_token = prodToken\n',
|
||||||
);
|
);
|
||||||
expect(configContent).toBe(
|
expect(configContent).toBe(
|
||||||
'[profile dev]\n' + 'region = us-east-1\n' + '\n' + '[profile prod]\n' + 'region = us-west-2\n',
|
'[profile dev]\n' +
|
||||||
|
'region = us-east-1\n' +
|
||||||
|
'\n' +
|
||||||
|
'[profile prod]\n' +
|
||||||
|
'region = us-west-2\n',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user