diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..910b80407 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,8 @@ +{ + "singleQuote": false, + "arrowParens": "always", + "trailingComma": "all", + "printWidth": 120, + "bracketSpacing": true, + "semi": true +} diff --git a/README.md b/README.md index 471a9a8c6..90bcae14f 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ ## "Configure AWS Credentials" Action For GitHub Actions -Configure AWS credential and region environment variables for use in other GitHub Actions. The environment variables will be detected by both the AWS SDKs and the AWS CLI to determine the credentials and region to use for AWS API calls. +Configure AWS credential and region environment variables for use in other GitHub Actions. The environment variables will be detected by both the AWS SDKs and the AWS CLI to determine the credentials and region to use for AWS API calls. ## NOTICE: node12 deprecation warning + GitHub actions has recently started throwing warning messages regarding the deprecation of Node 12. If you would like to stop seeing this warning, configure your action to use `aws-actions/configure-aws-credentials@v1-node16`. Both the `v1` branch and the `v1-node16` branch will receive the same updates moving forward. See [this issue](https://github.com/aws-actions/configure-aws-credentials/issues/489) for more information on this topic. **Table of Contents** @@ -12,10 +13,10 @@ GitHub actions has recently started throwing warning messages regarding the depr - [Usage](#usage) - [Credentials](#credentials) - [Assuming a Role](#assuming-a-role) - + [Session tagging](#session-tagging) - + [Sample IAM Role Permissions](#sample-iam-role-cloudformation-template) + - [Session tagging](#session-tagging) + - [Sample IAM Role Permissions](#sample-iam-role-cloudformation-template) - [Self-Hosted Runners](#self-hosted-runners) - + [Proxy Configuration](#proxy-configuration) + - [Proxy Configuration](#proxy-configuration) - [License Summary](#license-summary) - [Security Disclosures](#security-disclosures) @@ -26,11 +27,11 @@ GitHub actions has recently started throwing warning messages regarding the depr Add the following step to your workflow: ```yaml - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - role-to-assume: arn:aws:iam::123456789100:role/my-github-actions-role - aws-region: us-east-2 +- name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + role-to-assume: arn:aws:iam::123456789100:role/my-github-actions-role + aws-region: us-east-2 ``` For example, you can use this action with the AWS CLI available in [GitHub's hosted virtual environments](https://help.github.com/en/actions/reference/software-installed-on-github-hosted-runners). @@ -46,28 +47,28 @@ jobs: id-token: write contents: read steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Configure AWS credentials from Test account - uses: aws-actions/configure-aws-credentials@v1 - with: - role-to-assume: arn:aws:iam::111111111111:role/my-github-actions-role-test - aws-region: us-east-1 - - - name: Copy files to the test website with the AWS CLI - run: | - aws s3 sync . s3://my-s3-test-website-bucket - - - name: Configure AWS credentials from Production account - uses: aws-actions/configure-aws-credentials@v1 - with: - role-to-assume: arn:aws:iam::222222222222:role/my-github-actions-role-prod - aws-region: us-west-2 - - - name: Copy files to the production website with the AWS CLI - run: | - aws s3 sync . s3://my-s3-prod-website-bucket + - name: Checkout + uses: actions/checkout@v2 + + - name: Configure AWS credentials from Test account + uses: aws-actions/configure-aws-credentials@v1 + with: + role-to-assume: arn:aws:iam::111111111111:role/my-github-actions-role-test + aws-region: us-east-1 + + - name: Copy files to the test website with the AWS CLI + run: | + aws s3 sync . s3://my-s3-test-website-bucket + + - name: Configure AWS credentials from Production account + uses: aws-actions/configure-aws-credentials@v1 + with: + role-to-assume: arn:aws:iam::222222222222:role/my-github-actions-role-prod + aws-region: us-west-2 + + - name: Copy files to the production website with the AWS CLI + run: | + aws s3 sync . s3://my-s3-prod-website-bucket ``` See [action.yml](action.yml) for the full documentation for this action's inputs and outputs. @@ -75,12 +76,14 @@ See [action.yml](action.yml) for the full documentation for this action's inputs ## Credentials We recommend following [Amazon IAM best practices](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html) for the AWS credentials used in GitHub Actions workflows, including: -* Do not store credentials in your repository's code. -* [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege) to the credentials used in GitHub Actions workflows. Grant only the permissions required to perform the actions in your GitHub Actions workflows. -* [Monitor the activity](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#keep-a-log) of the credentials used in GitHub Actions workflows. + +- Do not store credentials in your repository's code. +- [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege) to the credentials used in GitHub Actions workflows. Grant only the permissions required to perform the actions in your GitHub Actions workflows. +- [Monitor the activity](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#keep-a-log) of the credentials used in GitHub Actions workflows. ## Assuming a Role -We recommend using [GitHub's OIDC provider](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services) to get short-lived credentials needed for your actions. + +We recommend using [GitHub's OIDC provider](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services) to get short-lived credentials needed for your actions. Specifying `role-to-assume` **without** providing an `aws-access-key-id` or a `web-identity-token-file` will signal to the action that you wish to use the OIDC provider. The default session duration is **1 hour** when using the OIDC provider to directly assume an IAM Role or when an `aws-session-token` is directly provided. @@ -93,53 +96,76 @@ The default audience is `sts.amazonaws.com` which you can replace by specifying The following table describes which identity is used based on which values are supplied to the Action: -| **Identity Used** | `aws-access-key-id` | `role-to-assume` | `web-identity-token-file` | -| --------------------------------------------------------------- | ------------------- | ---------------- | ------------------------- | +| **Identity Used** | `aws-access-key-id` | `role-to-assume` | `web-identity-token-file` | +| ---------------------------------------------------------------- | ------------------- | ---------------- | ------------------------- | | [✅ Recommended] Assume Role directly using GitHub OIDC provider | | ✔ | | -| IAM User | ✔ | | | -| Assume Role using IAM User credentials | ✔ | ✔ | | -| Assume Role using WebIdentity Token File credentials | | ✔ | ✔ | +| IAM User | ✔ | | | +| Assume Role using IAM User credentials | ✔ | ✔ | | +| Assume Role using WebIdentity Token File credentials | | ✔ | ✔ | ### Examples ```yaml - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-region: us-east-2 - role-to-assume: arn:aws:iam::123456789100:role/my-github-actions-role - role-session-name: MySessionName +- name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-region: us-east-2 + role-to-assume: arn:aws:iam::123456789100:role/my-github-actions-role + role-session-name: MySessionName ``` + In this example, the Action will load the OIDC token from the GitHub-provided environment variable and use it to assume the role `arn:aws:iam::123456789100:role/my-github-actions-role` with the session name `MySessionName`. ```yaml - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: us-east-2 - role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} - role-external-id: ${{ secrets.AWS_ROLE_EXTERNAL_ID }} - role-duration-seconds: 1200 - role-session-name: MySessionName +- name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-east-2 + role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} + role-external-id: ${{ secrets.AWS_ROLE_EXTERNAL_ID }} + role-duration-seconds: 1200 + role-session-name: MySessionName ``` -In this example, the secret `AWS_ROLE_TO_ASSUME` contains a string like `arn:aws:iam::123456789100:role/my-github-actions-role`. To assume a role in the same account as the static credentials, you can simply specify the role name, like `role-to-assume: my-github-actions-role`. + +In this example, the secret `AWS_ROLE_TO_ASSUME` contains a string like `arn:aws:iam::123456789100:role/my-github-actions-role`. To assume a role in the same account as the static credentials, you can simply specify the role name, like `role-to-assume: my-github-actions-role`. ```yaml - - name: Configure AWS Credentials for Beta Customers - uses: aws-actions/configure-aws-credentials@v1 - with: - audience: beta-customers - aws-region: us-east-3 - role-to-assume: arn:aws:iam::123456789100:role/my-github-actions-role - role-session-name: MySessionName +- name: Configure AWS Credentials for Beta Customers + uses: aws-actions/configure-aws-credentials@v1 + with: + audience: beta-customers + aws-region: us-east-3 + role-to-assume: arn:aws:iam::123456789100:role/my-github-actions-role + role-session-name: MySessionName ``` + In this example, the audience has been changed from the default to use a different audience name `beta-customers`. This can help ensure that the role can only affect those AWS accounts whose GitHub OIDC providers have explicitly opted in to the `beta-customers` label. Changing the default audience may be necessary when using non-default [AWS partitions](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html). +```yaml +- name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-region: us-east-2 + role-to-assume: arn:aws:iam::109875432100:role/my-github-actions-role + role-session-name: MySessionName + aws-profile: us-profile +- name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-region: eu-central-1 + role-to-assume: arn:aws:iam::123456789100:role/my-github-actions-role + role-session-name: MySessionName + aws-profile: eu-profile +``` + +In this example, the Action will load the OIDC token from the GitHub-provided environment variable and use it to assume the role `arn:aws:iam::109875432100:role/my-github-actions-role` with the session name `MySessionName`. Additionaly we use multiple profiles further in the action so we can switch between an `eu-profile` and `us-profile`. + ### Sample IAM Role CloudFormation Template + ```yaml Parameters: GitHubOrg: @@ -152,7 +178,7 @@ Parameters: Type: String Conditions: - CreateOIDCProvider: !Equals + CreateOIDCProvider: !Equals - !Ref OIDCProviderArn - "" @@ -165,7 +191,7 @@ Resources: - Effect: Allow Action: sts:AssumeRoleWithWebIdentity Principal: - Federated: !If + Federated: !If - CreateOIDCProvider - !Ref GithubOidc - !Ref OIDCProviderArn @@ -178,14 +204,14 @@ Resources: Condition: CreateOIDCProvider Properties: Url: https://token.actions.githubusercontent.com - ClientIdList: + ClientIdList: - sts.amazonaws.com ThumbprintList: - 6938fd4d98bab03faadb97b34396831e3780aea1 Outputs: Role: - Value: !GetAtt Role.Arn + Value: !GetAtt Role.Arn ``` The GitHub OIDC Provider only needs to be created once per account (i.e. multiple IAM Roles that can be assumed by the GitHub's OIDC can share a single OIDC Provider). @@ -194,13 +220,14 @@ To align with the Amazon IAM best practice of [granting least privilege](https:/ For further information on OIDC and GitHub Actions, please see: -* [AWS docs: Creating OpenID Connect (OIDC) identity providers](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html) -* [AWS docs: IAM JSON policy elements: Condition](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html) -* [GitHub docs: About security hardening with OpenID Connect](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect) -* [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/) +- [AWS docs: Creating OpenID Connect (OIDC) identity providers](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html) +- [AWS docs: IAM JSON policy elements: Condition](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html) +- [GitHub docs: About security hardening with OpenID Connect](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect) +- [GitHub docs: Configuring OpenID Connect in Amazon Web Services](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services) +- [GitHub changelog: GitHub Actions: Secure cloud deployments with OpenID Connect](https://github.blog/changelog/2021-10-27-github-actions-secure-cloud-deployments-with-openid-connect/) ### Session tagging + The session will have the name "GitHubActions" and be tagged with the following tags: (`GITHUB_` environment variable definitions can be [found here](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/using-environment-variables#default-environment-variables)) @@ -214,17 +241,17 @@ The session will have the name "GitHubActions" and be tagged with the following | Branch | GITHUB_REF | | Commit | GITHUB_SHA | -_Note: all tag values must conform to [the requirements](https://docs.aws.amazon.com/STS/latest/APIReference/API_Tag.html). Particularly, `GITHUB_WORKFLOW` will be truncated if it's too long. If `GITHUB_ACTOR` or `GITHUB_WORKFLOW` contain invalid characters, the characters will be replaced with an '*'._ +_Note: all tag values must conform to [the requirements](https://docs.aws.amazon.com/STS/latest/APIReference/API_Tag.html). Particularly, `GITHUB_WORKFLOW` will be truncated if it's too long. If `GITHUB_ACTOR` or `GITHUB_WORKFLOW` contain invalid characters, the characters will be replaced with an '\*'._ -The action will use session tagging by default during role assumption. +The action will use session tagging by default during role assumption. Note that for WebIdentity role assumption, the session tags have to be included in the encoded WebIdentity token. This means that Tags can only be supplied by the OIDC provider and not set during the AssumeRoleWithWebIdentity API call within the Action. You can skip this session tagging by providing `role-skip-session-tagging` as true in the action's inputs: ```yaml - uses: aws-actions/configure-aws-credentials@v1 - with: - role-skip-session-tagging: true +uses: aws-actions/configure-aws-credentials@v1 +with: + role-skip-session-tagging: true ``` ## Self-Hosted Runners @@ -234,26 +261,31 @@ If you run your GitHub Actions in a [self-hosted runner](https://help.github.com If no access key credentials are given in the action inputs, this action will use credentials from the runner environment using the [default methods for the AWS SDK for Javascript](https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-credentials-node.html). You can use this action to simply configure the region and account ID in the environment, and then use the runner's credentials for all AWS API calls made by your Actions workflow: + ```yaml uses: aws-actions/configure-aws-credentials@v1 with: aws-region: us-east-2 ``` + In this case, your runner's credentials must have permissions to call any AWS APIs called by your Actions workflow. Or, you can use this action to assume a role, and then use the role credentials for all AWS API calls made by your Actions workflow: + ```yaml uses: aws-actions/configure-aws-credentials@v1 with: aws-region: us-east-2 role-to-assume: my-github-actions-role ``` + In this case, your runner's credentials must have permissions to assume the role. You can also assume a role using a web identity token file, such as if using [Amazon EKS IRSA](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts-technical-overview.html). Pods running in EKS worker nodes that do not run as root can use this file to assume a role with a web identity. You can configure your workflow as follows in order to use this file: + ```yaml uses: aws-actions/configure-aws-credentials@v1 with: @@ -269,6 +301,7 @@ If you run in self-hosted environments and in secured environment where you need Additionally this action will always consider already configured proxy in the environment. Manually configured proxy: + ```yaml uses: aws-actions/configure-aws-credentials@v1 with: @@ -288,13 +321,13 @@ The action will read the underlying proxy configuration from the environment and ### Use with the AWS CLI -This workflow does _not_ install the [AWS CLI](https://aws.amazon.com/cli/) into your environment. Self-hosted runners that intend to run this action prior to executing `aws` commands need to have the AWS CLI [installed](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html) if it's not already present. +This workflow does _not_ install the [AWS CLI](https://aws.amazon.com/cli/) into your environment. Self-hosted runners that intend to run this action prior to executing `aws` commands need to have the AWS CLI [installed](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html) if it's not already present. Most [GitHub hosted runner environments](https://github.com/actions/virtual-environments) should include the AWS CLI by default. - + ## License Summary This code is made available under the MIT license. ## Security Disclosures -If you would like to report a potential security issue in this project, please do not create a GitHub issue. Instead, please follow the instructions [here](https://aws.amazon.com/security/vulnerability-reporting/) or [email AWS security directly](mailto:aws-security@amazon.com). +If you would like to report a potential security issue in this project, please do not create a GitHub issue. Instead, please follow the instructions [here](https://aws.amazon.com/security/vulnerability-reporting/) or [email AWS security directly](mailto:aws-security@amazon.com). diff --git a/__snapshots__/index.test.js.snap b/__snapshots__/index.test.js.snap new file mode 100644 index 000000000..d6470fb73 --- /dev/null +++ b/__snapshots__/index.test.js.snap @@ -0,0 +1,74 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Configure AWS Credentials Profile Support add new profile if credentials file already exists 1`] = ` +"[profile default] +region=fake-region-1 + +[profile test-profile] +region=fake-region-1 +role_arn=arn:aws:iam::111111111111:role/MY-ROLE +role_session_name=GitHubActions +" +`; + +exports[`Configure AWS Credentials Profile Support add new profile if credentials file already exists 2`] = ` +"[default] +aws_access_key=STS-AWS-ACCESS-KEY-ID +aws_secret_access_key=STS-AWS-SECRET-ACCESS-KEY +aws_session_token=STS-AWS-SESSION-TOKEN + +[test-profile] +aws_access_key_id=STS-AWS-ACCESS-KEY-ID +aws_secret_access_key=STS-AWS-SECRET-ACCESS-KEY +aws_session_token=STS-AWS-SESSION-TOKEN +" +`; + +exports[`Configure AWS Credentials Profile Support only role arn and region provided to use GH OIDC Token 1`] = ` +"[profile test-profile] +region=fake-region-1 +role_arn=arn:aws:iam::111111111111:role/MY-ROLE +role_session_name=GitHubActions +" +`; + +exports[`Configure AWS Credentials Profile Support only role arn and region provided to use GH OIDC Token 2`] = ` +"[test-profile] +aws_access_key_id=STS-AWS-ACCESS-KEY-ID +aws_secret_access_key=STS-AWS-SECRET-ACCESS-KEY +aws_session_token=STS-AWS-SESSION-TOKEN +" +`; + +exports[`Configure AWS Credentials Profile Support use profile and save credentials file 1`] = ` +"[profile test-profile] +region=fake-region-1 +role_arn=arn:aws:iam::111111111111:role/MY-ROLE +role_session_name=GitHubActions +" +`; + +exports[`Configure AWS Credentials Profile Support use profile and save credentials file 2`] = ` +"[test-profile] +aws_access_key_id=STS-AWS-ACCESS-KEY-ID +aws_secret_access_key=STS-AWS-SECRET-ACCESS-KEY +aws_session_token=STS-AWS-SESSION-TOKEN +" +`; + +exports[`Configure AWS Credentials Profile Support web identity token file provided with relative path 1`] = ` +"[profile test-profile] +region=fake-region-1 +web_identity_token_file=fake/token/file +role_arn=arn:aws:iam::111111111111:role/MY-ROLE +role_session_name=GitHubActions +" +`; + +exports[`Configure AWS Credentials Profile Support web identity token file provided with relative path 2`] = ` +"[test-profile] +aws_access_key_id=STS-AWS-ACCESS-KEY-ID +aws_secret_access_key=STS-AWS-SECRET-ACCESS-KEY +aws_session_token=STS-AWS-SESSION-TOKEN +" +`; diff --git a/action.yml b/action.yml index b99f07f5e..cf70ee24a 100644 --- a/action.yml +++ b/action.yml @@ -1,12 +1,12 @@ name: '"Configure AWS Credentials" Action For GitHub Actions' -description: 'Configure AWS credential and region environment variables for use with the AWS CLI and AWS SDKs' +description: "Configure AWS credential and region environment variables for use with the AWS CLI and AWS SDKs" branding: - icon: 'cloud' - color: 'orange' + icon: "cloud" + color: "orange" inputs: audience: - default: 'sts.amazonaws.com' - description: 'The audience to use for the OIDC provider' + default: "sts.amazonaws.com" + description: "The audience to use for the OIDC provider" required: false aws-access-key-id: description: >- @@ -20,11 +20,14 @@ inputs: It is optional if running in a self-hosted environment that already has AWS credentials, for example on an EC2 instance. required: false + aws-profile: + description: "AWS Profile" + required: false aws-session-token: - description: 'AWS Session Token' + description: "AWS Session Token" required: false aws-region: - description: 'AWS Region, e.g. us-east-2' + description: "AWS Region, e.g. us-east-2" required: true mask-aws-account-id: description: >- @@ -47,20 +50,20 @@ inputs: description: "Role duration in seconds (default: 6 hours, 1 hour for OIDC/specified aws-session-token)" required: false role-session-name: - description: 'Role session name (default: GitHubActions)' + description: "Role session name (default: GitHubActions)" required: false role-external-id: - description: 'The external ID of the role to assume' + description: "The external ID of the role to assume" required: false role-skip-session-tagging: - description: 'Skip session tagging during role assumption' + description: "Skip session tagging during role assumption" required: false http-proxy: - description: 'Proxy to use for the AWS SDK agent' + description: "Proxy to use for the AWS SDK agent" required: false outputs: aws-account-id: - description: 'The AWS account ID for the provided credentials' + description: "The AWS account ID for the provided credentials" runs: using: 'node12' main: 'dist/index.js' diff --git a/cleanup.js b/cleanup.js index 0ea67f247..1aed4add0 100644 --- a/cleanup.js +++ b/cleanup.js @@ -1,4 +1,5 @@ -const core = require('@actions/core'); +const core = require("@actions/core"); +const fs = require("fs"); /** * When the GitHub Actions job is done, clean up any environment variables that @@ -17,13 +18,14 @@ async function cleanup() { // environment variables, so we overwrite the current value with an empty // string. The AWS CLI and AWS SDKs will behave correctly: they treat an // empty string value as if the environment variable does not exist. - core.exportVariable('AWS_ACCESS_KEY_ID', ''); - core.exportVariable('AWS_SECRET_ACCESS_KEY', ''); - core.exportVariable('AWS_SESSION_TOKEN', ''); - core.exportVariable('AWS_DEFAULT_REGION', ''); - core.exportVariable('AWS_REGION', ''); - } - catch (error) { + core.exportVariable("AWS_ACCESS_KEY_ID", ""); + core.exportVariable("AWS_SECRET_ACCESS_KEY", ""); + core.exportVariable("AWS_SESSION_TOKEN", ""); + core.exportVariable("AWS_DEFAULT_REGION", ""); + core.exportVariable("AWS_REGION", ""); + + fs.rmSync(`${process.env.HOME}/.aws`, { force: true, recursive: true }); + } catch (error) { core.setFailed(error.message); } } diff --git a/dist/cleanup/index.js b/dist/cleanup/index.js index 8bbd34659..3b5e2a7c3 100644 --- a/dist/cleanup/index.js +++ b/dist/cleanup/index.js @@ -5,6 +5,7 @@ /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const core = __nccwpck_require__(186); +const fs = __nccwpck_require__(147); /** * When the GitHub Actions job is done, clean up any environment variables that @@ -23,13 +24,14 @@ async function cleanup() { // environment variables, so we overwrite the current value with an empty // string. The AWS CLI and AWS SDKs will behave correctly: they treat an // empty string value as if the environment variable does not exist. - core.exportVariable('AWS_ACCESS_KEY_ID', ''); - core.exportVariable('AWS_SECRET_ACCESS_KEY', ''); - core.exportVariable('AWS_SESSION_TOKEN', ''); - core.exportVariable('AWS_DEFAULT_REGION', ''); - core.exportVariable('AWS_REGION', ''); - } - catch (error) { + core.exportVariable("AWS_ACCESS_KEY_ID", ""); + core.exportVariable("AWS_SECRET_ACCESS_KEY", ""); + core.exportVariable("AWS_SESSION_TOKEN", ""); + core.exportVariable("AWS_DEFAULT_REGION", ""); + core.exportVariable("AWS_REGION", ""); + + fs.rmSync(`${process.env.HOME}/.aws`, { force: true, recursive: true }); + } catch (error) { core.setFailed(error.message); } } diff --git a/dist/index.js b/dist/index.js index 23a35a938..1a1cdd74f 100644 --- a/dist/index.js +++ b/dist/index.js @@ -32659,6 +32659,243 @@ function parseProxyResponse(socket) { exports["default"] = parseProxyResponse; //# sourceMappingURL=parse-proxy-response.js.map +/***/ }), + +/***/ 80045: +/***/ ((module) => { + +const { hasOwnProperty } = Object.prototype + +/* istanbul ignore next */ +const eol = typeof process !== 'undefined' && + process.platform === 'win32' ? '\r\n' : '\n' + +const encode = (obj, opt) => { + const children = [] + let out = '' + + if (typeof opt === 'string') { + opt = { + section: opt, + whitespace: false, + } + } else { + opt = opt || Object.create(null) + opt.whitespace = opt.whitespace === true + } + + const separator = opt.whitespace ? ' = ' : '=' + + for (const k of Object.keys(obj)) { + const val = obj[k] + if (val && Array.isArray(val)) { + for (const item of val) { + out += safe(k + '[]') + separator + safe(item) + eol + } + } else if (val && typeof val === 'object') { + children.push(k) + } else { + out += safe(k) + separator + safe(val) + eol + } + } + + if (opt.section && out.length) { + out = '[' + safe(opt.section) + ']' + eol + out + } + + for (const k of children) { + const nk = dotSplit(k).join('\\.') + const section = (opt.section ? opt.section + '.' : '') + nk + const { whitespace } = opt + const child = encode(obj[k], { + section, + whitespace, + }) + if (out.length && child.length) { + out += eol + } + + out += child + } + + return out +} + +const dotSplit = str => + str.replace(/\1/g, '\u0002LITERAL\\1LITERAL\u0002') + .replace(/\\\./g, '\u0001') + .split(/\./) + .map(part => + part.replace(/\1/g, '\\.') + .replace(/\2LITERAL\\1LITERAL\2/g, '\u0001')) + +const decode = str => { + const out = Object.create(null) + let p = out + let section = null + // section |key = value + const re = /^\[([^\]]*)\]$|^([^=]+)(=(.*))?$/i + const lines = str.split(/[\r\n]+/g) + + for (const line of lines) { + if (!line || line.match(/^\s*[;#]/)) { + continue + } + const match = line.match(re) + if (!match) { + continue + } + if (match[1] !== undefined) { + section = unsafe(match[1]) + if (section === '__proto__') { + // not allowed + // keep parsing the section, but don't attach it. + p = Object.create(null) + continue + } + p = out[section] = out[section] || Object.create(null) + continue + } + const keyRaw = unsafe(match[2]) + const isArray = keyRaw.length > 2 && keyRaw.slice(-2) === '[]' + const key = isArray ? keyRaw.slice(0, -2) : keyRaw + if (key === '__proto__') { + continue + } + const valueRaw = match[3] ? unsafe(match[4]) : true + const value = valueRaw === 'true' || + valueRaw === 'false' || + valueRaw === 'null' ? JSON.parse(valueRaw) + : valueRaw + + // Convert keys with '[]' suffix to an array + if (isArray) { + if (!hasOwnProperty.call(p, key)) { + p[key] = [] + } else if (!Array.isArray(p[key])) { + p[key] = [p[key]] + } + } + + // safeguard against resetting a previously defined + // array by accidentally forgetting the brackets + if (Array.isArray(p[key])) { + p[key].push(value) + } else { + p[key] = value + } + } + + // {a:{y:1},"a.b":{x:2}} --> {a:{y:1,b:{x:2}}} + // use a filter to return the keys that have to be deleted. + const remove = [] + for (const k of Object.keys(out)) { + if (!hasOwnProperty.call(out, k) || + typeof out[k] !== 'object' || + Array.isArray(out[k])) { + continue + } + + // see if the parent section is also an object. + // if so, add it to that, and mark this one for deletion + const parts = dotSplit(k) + p = out + const l = parts.pop() + const nl = l.replace(/\\\./g, '.') + for (const part of parts) { + if (part === '__proto__') { + continue + } + if (!hasOwnProperty.call(p, part) || typeof p[part] !== 'object') { + p[part] = Object.create(null) + } + p = p[part] + } + if (p === out && nl === l) { + continue + } + + p[nl] = out[k] + remove.push(k) + } + for (const del of remove) { + delete out[del] + } + + return out +} + +const isQuoted = val => { + return (val.startsWith('"') && val.endsWith('"')) || + (val.startsWith("'") && val.endsWith("'")) +} + +const safe = val => { + if ( + typeof val !== 'string' || + val.match(/[=\r\n]/) || + val.match(/^\[/) || + (val.length > 1 && isQuoted(val)) || + val !== val.trim() + ) { + return JSON.stringify(val) + } + return val.split(';').join('\\;').split('#').join('\\#') +} + +const unsafe = (val, doUnesc) => { + val = (val || '').trim() + if (isQuoted(val)) { + // remove the single quotes before calling JSON.parse + if (val.charAt(0) === "'") { + val = val.slice(1, -1) + } + try { + val = JSON.parse(val) + } catch { + // ignore errors + } + } else { + // walk the val to find the first not-escaped ; character + let esc = false + let unesc = '' + for (let i = 0, l = val.length; i < l; i++) { + const c = val.charAt(i) + if (esc) { + if ('\\;#'.indexOf(c) !== -1) { + unesc += c + } else { + unesc += '\\' + c + } + + esc = false + } else if (';#'.indexOf(c) !== -1) { + break + } else if (c === '\\') { + esc = true + } else { + unesc += c + } + } + if (esc) { + unesc += '\\' + } + + return unesc.trim() + } + return val +} + +module.exports = { + parse: decode, + decode, + stringify: encode, + encode, + safe, + unsafe, +} + + /***/ }), /***/ 87783: @@ -46828,21 +47065,22 @@ const assert = __nccwpck_require__(39491); const fs = __nccwpck_require__(57147); const path = __nccwpck_require__(71017); const proxy = __nccwpck_require__(77219); +const ini = __nccwpck_require__(80045); // Use 1hr as role duration when using session token or OIDC // Otherwise, use the max duration of GitHub action (6hr) const MAX_ACTION_RUNTIME = 6 * 3600; const SESSION_ROLE_DURATION = 3600; const DEFAULT_ROLE_DURATION_FOR_OIDC_ROLES = 3600; -const USER_AGENT = 'configure-aws-credentials-for-github-actions'; +const USER_AGENT = "configure-aws-credentials-for-github-actions"; const MAX_TAG_VALUE_LENGTH = 256; -const SANITIZATION_CHARACTER = '_'; -const ROLE_SESSION_NAME = 'GitHubActions'; +const SANITIZATION_CHARACTER = "_"; +const ROLE_SESSION_NAME = "GitHubActions"; const REGION_REGEX = /^[a-z0-9-]+$/g; async function assumeRole(params) { // Assume a role to get short-lived credentials using longer-lived credentials. - const isDefined = i => !!i; + const isDefined = (i) => !!i; const { sourceAccountId, @@ -46853,57 +47091,57 @@ async function assumeRole(params) { region, roleSkipSessionTagging, webIdentityTokenFile, - webIdentityToken + webIdentityToken, } = params; assert( - [roleToAssume, roleDurationSeconds, roleSessionName, region].every(isDefined), - "Missing required input when assuming a Role." + [roleToAssume, roleDurationSeconds, roleSessionName, region].every(isDefined), + "Missing required input when assuming a Role.", ); - const {GITHUB_REPOSITORY, GITHUB_WORKFLOW, GITHUB_ACTION, GITHUB_ACTOR, GITHUB_SHA} = process.env; + const { GITHUB_REPOSITORY, GITHUB_WORKFLOW, GITHUB_ACTION, GITHUB_ACTOR, GITHUB_SHA } = process.env; assert( - [GITHUB_REPOSITORY, GITHUB_WORKFLOW, GITHUB_ACTION, GITHUB_ACTOR, GITHUB_SHA].every(isDefined), - 'Missing required environment value. Are you running in GitHub Actions?' + [GITHUB_REPOSITORY, GITHUB_WORKFLOW, GITHUB_ACTION, GITHUB_ACTOR, GITHUB_SHA].every(isDefined), + "Missing required environment value. Are you running in GitHub Actions?", ); const sts = getStsClient(region); let roleArn = roleToAssume; - if (!roleArn.startsWith('arn:aws')) { + if (!roleArn.startsWith("arn:aws")) { // Supports only 'aws' partition. Customers in other partitions ('aws-cn') will need to provide full ARN - assert( + assert( isDefined(sourceAccountId), - "Source Account ID is needed if the Role Name is provided and not the Role Arn." - ); + "Source Account ID is needed if the Role Name is provided and not the Role Arn.", + ); roleArn = `arn:aws:iam::${sourceAccountId}:role/${roleArn}`; } const tagArray = [ - {Key: 'GitHub', Value: 'Actions'}, - {Key: 'Repository', Value: GITHUB_REPOSITORY}, - {Key: 'Workflow', Value: sanitizeGithubWorkflowName(GITHUB_WORKFLOW)}, - {Key: 'Action', Value: GITHUB_ACTION}, - {Key: 'Actor', Value: sanitizeGithubActor(GITHUB_ACTOR)}, - {Key: 'Commit', Value: GITHUB_SHA}, + { Key: "GitHub", Value: "Actions" }, + { Key: "Repository", Value: GITHUB_REPOSITORY }, + { Key: "Workflow", Value: sanitizeGithubWorkflowName(GITHUB_WORKFLOW) }, + { Key: "Action", Value: GITHUB_ACTION }, + { Key: "Actor", Value: sanitizeGithubActor(GITHUB_ACTOR) }, + { Key: "Commit", Value: GITHUB_SHA }, ]; if (isDefined(process.env.GITHUB_REF)) { - tagArray.push({Key: 'Branch', Value: process.env.GITHUB_REF}); + tagArray.push({ Key: "Branch", Value: process.env.GITHUB_REF }); } const roleSessionTags = roleSkipSessionTagging ? undefined : tagArray; - if(roleSessionTags == undefined){ - core.debug("Role session tagging has been skipped.") + if (roleSessionTags == undefined) { + core.debug("Role session tagging has been skipped."); } else { - core.debug(roleSessionTags.length + " role session tags are being used.") + core.debug(roleSessionTags.length + " role session tags are being used."); } const assumeRoleRequest = { RoleArn: roleArn, RoleSessionName: roleSessionName, DurationSeconds: roleDurationSeconds, - Tags: roleSessionTags + Tags: roleSessionTags, }; if (roleExternalId) { @@ -46913,30 +47151,31 @@ async function assumeRole(params) { let assumeFunction = sts.assumeRole.bind(sts); // These are customizations needed for the GH OIDC Provider - if(isDefined(webIdentityToken)) { + if (isDefined(webIdentityToken)) { delete assumeRoleRequest.Tags; assumeRoleRequest.WebIdentityToken = webIdentityToken; assumeFunction = sts.assumeRoleWithWebIdentity.bind(sts); - } else if(isDefined(webIdentityTokenFile)) { - core.debug("webIdentityTokenFile provided. Will call sts:AssumeRoleWithWebIdentity and take session tags from token contents."); + } else if (isDefined(webIdentityTokenFile)) { + core.debug( + "webIdentityTokenFile provided. Will call sts:AssumeRoleWithWebIdentity and take session tags from token contents.", + ); delete assumeRoleRequest.Tags; - const webIdentityTokenFilePath = path.isAbsolute(webIdentityTokenFile) ? - webIdentityTokenFile : - path.join(process.env.GITHUB_WORKSPACE, webIdentityTokenFile); + const webIdentityTokenFilePath = path.isAbsolute(webIdentityTokenFile) + ? webIdentityTokenFile + : path.join(process.env.GITHUB_WORKSPACE, webIdentityTokenFile); if (!fs.existsSync(webIdentityTokenFilePath)) { throw new Error(`Web identity token file does not exist: ${webIdentityTokenFilePath}`); } try { - assumeRoleRequest.WebIdentityToken = await fs.promises.readFile(webIdentityTokenFilePath, 'utf8'); + assumeRoleRequest.WebIdentityToken = await fs.promises.readFile(webIdentityTokenFilePath, "utf8"); assumeFunction = sts.assumeRoleWithWebIdentity.bind(sts); - } catch(error) { + } catch (error) { throw new Error(`Web identity token file could not be read: ${error.message}`); } - } return assumeFunction(assumeRoleRequest) @@ -46953,7 +47192,7 @@ async function assumeRole(params) { function sanitizeGithubActor(actor) { // In some circumstances the actor may contain square brackets. For example, if they're a bot ('[bot]') // Square brackets are not allowed in AWS session tags - return actor.replace(/\[|\]/g, SANITIZATION_CHARACTER) + return actor.replace(/\[|\]/g, SANITIZATION_CHARACTER); } function sanitizeGithubWorkflowName(name) { @@ -46961,41 +47200,109 @@ function sanitizeGithubWorkflowName(name) { // This replaces anything not conforming to the tag restrictions by inverting the regular expression. // See the AWS documentation for constraint specifics https://docs.aws.amazon.com/STS/latest/APIReference/API_Tag.html. const nameWithoutSpecialCharacters = name.replace(/[^\p{L}\p{Z}\p{N}_:/=+.-@-]/gu, SANITIZATION_CHARACTER); - const nameTruncated = nameWithoutSpecialCharacters.slice(0, MAX_TAG_VALUE_LENGTH) - return nameTruncated + const nameTruncated = nameWithoutSpecialCharacters.slice(0, MAX_TAG_VALUE_LENGTH); + return nameTruncated; } -function exportCredentials(params){ +function exportCredentials(params) { // Configure the AWS CLI and AWS SDKs using environment variables and set them as secrets. // Setting the credentials as secrets masks them in Github Actions logs - const {accessKeyId, secretAccessKey, sessionToken} = params; + const { accessKeyId, secretAccessKey, sessionToken } = params; // AWS_ACCESS_KEY_ID: // Specifies an AWS access key associated with an IAM user or role core.setSecret(accessKeyId); - core.exportVariable('AWS_ACCESS_KEY_ID', accessKeyId); + core.exportVariable("AWS_ACCESS_KEY_ID", accessKeyId); // AWS_SECRET_ACCESS_KEY: // Specifies the secret key associated with the access key. This is essentially the "password" for the access key. core.setSecret(secretAccessKey); - core.exportVariable('AWS_SECRET_ACCESS_KEY', secretAccessKey); + core.exportVariable("AWS_SECRET_ACCESS_KEY", secretAccessKey); // AWS_SESSION_TOKEN: // Specifies the session token value that is required if you are using temporary security credentials. if (sessionToken) { core.setSecret(sessionToken); - core.exportVariable('AWS_SESSION_TOKEN', sessionToken); + core.exportVariable("AWS_SESSION_TOKEN", sessionToken); } else if (process.env.AWS_SESSION_TOKEN) { // clear session token from previous credentials action - core.exportVariable('AWS_SESSION_TOKEN', ''); + core.exportVariable("AWS_SESSION_TOKEN", ""); + } +} + +async function exportCredentialsToConfig(profile, params) { + const awsCredentialsFile = `${process.env.HOME}/.aws/credentials`; + const awsConfigFile = `${process.env.HOME}/.aws/config`; + let config = {}; + let credentials = {}; + + if (!fs.existsSync(`${process.env.HOME}/.aws/`)) { + fs.mkdirSync(`${process.env.HOME}/.aws/`, { recursive: true }); } + + if (fs.existsSync(awsConfigFile)) { + config = ini.parse(await fs.promises.readFile(awsConfigFile, "utf-8")); + } + + if (fs.existsSync(awsCredentialsFile)) { + credentials = ini.parse(await fs.promises.readFile(awsCredentialsFile, "utf-8")); + } + + // Configure the AWS CLI and AWS SDKs using environment variables and set them as secrets. + // Setting the credentials as secrets masks them in Github Actions logs + const { + webIdentityTokenFile, + roleArn, + accessKeyId, + secretAccessKey, + sessionToken, + region, + roleSessionName, + roleExternalId, + } = params; + + // Initialize the configuration objects + const profileName = profile; + const configProfileName = `profile ${profileName}`; + config[configProfileName] = {}; + config[configProfileName].region = region; + config[configProfileName].web_identity_token_file = webIdentityTokenFile; + config[configProfileName].role_arn = roleArn; + config[configProfileName].role_session_name = roleSessionName; + config[configProfileName].external_id = roleExternalId; + + credentials[profileName] = {}; + credentials[profileName].aws_access_key_id = accessKeyId; + credentials[profileName].aws_secret_access_key = secretAccessKey; + credentials[profileName].aws_session_token = sessionToken; + + // Clean up undefined values + Object.values(credentials).forEach((profile) => { + Object.keys(profile).forEach((key) => { + if (profile[key] === undefined || profile[key] === "") { + delete profile[key]; + } + }); + }); + + await fs.promises.writeFile(awsCredentialsFile, ini.stringify(credentials)); + await fs.promises.writeFile(awsConfigFile, ini.stringify(config)); + + // Set the AWS_PROFILE environment variable + core.exportVariable("AWS_PROFILE", profileName); + // Set the AWS_SHARED_CREDENTIALS_FILE environment variable + core.exportVariable("AWS_SHARED_CREDENTIALS_FILE", awsCredentialsFile); + // Set the AWS_CONFIG_FILE environment variable + core.exportVariable("AWS_CONFIG_FILE", awsConfigFile); + + // await validateCredentials(credentials[profileName].aws_access_key_id); } function exportRegion(region) { // AWS_DEFAULT_REGION and AWS_REGION: // Specifies the AWS Region to send requests to - core.exportVariable('AWS_DEFAULT_REGION', region); - core.exportVariable('AWS_REGION', region); + core.exportVariable("AWS_DEFAULT_REGION", region); + core.exportVariable("AWS_REGION", region); } async function exportAccountId(maskAccountId, region) { @@ -47003,10 +47310,10 @@ async function exportAccountId(maskAccountId, region) { const sts = getStsClient(region); const identity = await sts.getCallerIdentity().promise(); const accountId = identity.Account; - if (!maskAccountId || maskAccountId.toLowerCase() == 'true') { + if (!maskAccountId || maskAccountId.toLowerCase() == "true") { core.setSecret(accountId); } - core.setOutput('aws-account-id', accountId); + core.setOutput("aws-account-id", accountId); return accountId; } @@ -47031,7 +47338,7 @@ function loadCredentials() { reject(err); } resolve(aws.config.credentials); - }) + }); }); } @@ -47041,7 +47348,7 @@ async function validateCredentials(expectedAccessKeyId) { credentials = await loadCredentials(); if (!credentials.accessKeyId) { - throw new Error('Access key ID empty after loading credentials'); + throw new Error("Access key ID empty after loading credentials"); } } catch (error) { throw new Error(`Credentials could not be loaded, please check your action inputs: ${error.message}`); @@ -47050,15 +47357,17 @@ async function validateCredentials(expectedAccessKeyId) { const actualAccessKeyId = credentials.accessKeyId; if (expectedAccessKeyId && expectedAccessKeyId != actualAccessKeyId) { - throw new Error('Unexpected failure: Credentials loaded by the SDK do not match the access key ID configured by the action'); + throw new Error( + "Unexpected failure: Credentials loaded by the SDK do not match the access key ID configured by the action", + ); } } function getStsClient(region) { return new aws.STS({ region, - stsRegionalEndpoints: 'regional', - customUserAgent: USER_AGENT + stsRegionalEndpoints: "regional", + customUserAgent: USER_AGENT, }); } @@ -47076,14 +47385,14 @@ const retryAndBackoff = async (fn, isRetryable, retries = 0, maxRetries = 12, ba throw err; } // It's retryable, so sleep and retry. - await sleep(Math.random() * (Math.pow(2, retries) * base) ); + await sleep(Math.random() * (Math.pow(2, retries) * base)); retries += 1; if (retries === maxRetries) { throw err; } return await retryAndBackoff(fn, isRetryable, retries, maxRetries, base); } -} +}; function configureProxy(proxyServer) { const proxyFromEnv = process.env.HTTP_PROXY || process.env.http_proxy; @@ -47091,7 +47400,7 @@ function configureProxy(proxyServer) { if (proxyFromEnv || proxyServer) { let proxyToSet = null; - if (proxyServer){ + if (proxyServer) { console.log(`Setting proxy from actions input: ${proxyServer}`); proxyToSet = proxyServer; } else { @@ -47100,7 +47409,7 @@ function configureProxy(proxyServer) { } aws.config.update({ - httpOptions: { agent: proxy(proxyToSet) } + httpOptions: { agent: proxy(proxyToSet) }, }); } } @@ -47108,22 +47417,24 @@ function configureProxy(proxyServer) { async function run() { try { // Get inputs - const accessKeyId = core.getInput('aws-access-key-id', { required: false }); - const audience = core.getInput('audience', { required: false }); - const secretAccessKey = core.getInput('aws-secret-access-key', { required: false }); - const region = core.getInput('aws-region', { required: true }); - const sessionToken = core.getInput('aws-session-token', { required: false }); - const maskAccountId = core.getInput('mask-aws-account-id', { required: false }); - const roleToAssume = core.getInput('role-to-assume', {required: false}); - const roleExternalId = core.getInput('role-external-id', { required: false }); - let roleDurationSeconds = core.getInput('role-duration-seconds', {required: false}) - || (sessionToken && SESSION_ROLE_DURATION) - || MAX_ACTION_RUNTIME; - const roleSessionName = core.getInput('role-session-name', { required: false }) || ROLE_SESSION_NAME; - const roleSkipSessionTaggingInput = core.getInput('role-skip-session-tagging', { required: false })|| 'false'; - const roleSkipSessionTagging = roleSkipSessionTaggingInput.toLowerCase() === 'true'; - const webIdentityTokenFile = core.getInput('web-identity-token-file', { required: false }); - const proxyServer = core.getInput('http-proxy', { required: false }); + const accessKeyId = core.getInput("aws-access-key-id", { required: false }); + const audience = core.getInput("audience", { required: false }); + const secretAccessKey = core.getInput("aws-secret-access-key", { required: false }); + const profile = core.getInput("aws-profile", { required: false }); + const region = core.getInput("aws-region", { required: true }); + const sessionToken = core.getInput("aws-session-token", { required: false }); + const maskAccountId = core.getInput("mask-aws-account-id", { required: false }); + const roleToAssume = core.getInput("role-to-assume", { required: false }); + const roleExternalId = core.getInput("role-external-id", { required: false }); + let roleDurationSeconds = + core.getInput("role-duration-seconds", { required: false }) || + (sessionToken && SESSION_ROLE_DURATION) || + MAX_ACTION_RUNTIME; + const roleSessionName = core.getInput("role-session-name", { required: false }) || ROLE_SESSION_NAME; + const roleSkipSessionTaggingInput = core.getInput("role-skip-session-tagging", { required: false }) || "false"; + const roleSkipSessionTagging = roleSkipSessionTaggingInput.toLowerCase() === "true"; + const webIdentityTokenFile = core.getInput("web-identity-token-file", { required: false }); + const proxyServer = core.getInput("http-proxy", { required: false }); if (!region.match(REGION_REGEX)) { throw new Error(`Region is not valid: ${region}`); @@ -47134,12 +47445,12 @@ async function run() { // This wraps the logic for deciding if we should rely on the GH OIDC provider since we may need to reference // the decision in a few differennt places. Consolidating it here makes the logic clearer elsewhere. const useGitHubOIDCProvider = () => { - // The assumption here is that self-hosted runners won't be populating the `ACTIONS_ID_TOKEN_REQUEST_TOKEN` - // environment variable and they won't be providing a web idenity token file or access key either. - // V2 of the action might relax this a bit and create an explicit precedence for these so that customers - // can provide as much info as they want and we will follow the established credential loading precedence. - return roleToAssume && process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN && !accessKeyId && !webIdentityTokenFile - } + // The assumption here is that self-hosted runners won't be populating the `ACTIONS_ID_TOKEN_REQUEST_TOKEN` + // environment variable and they won't be providing a web idenity token file or access key either. + // V2 of the action might relax this a bit and create an explicit precedence for these so that customers + // can provide as much info as they want and we will follow the established credential loading precedence. + return roleToAssume && process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN && !accessKeyId && !webIdentityTokenFile; + }; // Always export the source credentials and account ID. // The STS client for calling AssumeRole pulls creds from the environment. @@ -47151,9 +47462,21 @@ async function run() { throw new Error("'aws-secret-access-key' must be provided if 'aws-access-key-id' is provided"); } - exportCredentials({accessKeyId, secretAccessKey, sessionToken}); + if (profile) { + await exportCredentialsToConfig(profile, { + accessKeyId, + secretAccessKey, + sessionToken, + webIdentityTokenFile, + region, + roleSessionName, + roleExternalId, + }); + } else { + exportCredentials({ accessKeyId, secretAccessKey, sessionToken }); + } } - + // Configures proxy configureProxy(proxyServer); @@ -47162,9 +47485,10 @@ async function run() { // The only way to assume the role is via GitHub's OIDC provider. let sourceAccountId; let webIdentityToken; - if(useGitHubOIDCProvider()) { + if (useGitHubOIDCProvider()) { webIdentityToken = await core.getIDToken(audience); - roleDurationSeconds = core.getInput('role-duration-seconds', {required: false}) || DEFAULT_ROLE_DURATION_FOR_OIDC_ROLES; + roleDurationSeconds = + core.getInput("role-duration-seconds", { required: false }) || DEFAULT_ROLE_DURATION_FOR_OIDC_ROLES; // We don't validate the credentials here because we don't have them yet when using OIDC. } else { // Regardless of whether any source credentials were provided as inputs, @@ -47179,19 +47503,31 @@ async function run() { // Get role credentials if configured to do so if (roleToAssume) { - const roleCredentials = await retryAndBackoff( - async () => { return await assumeRole({ - sourceAccountId, - region, - roleToAssume, - roleExternalId, - roleDurationSeconds, - roleSessionName, - roleSkipSessionTagging, - webIdentityTokenFile, - webIdentityToken - }) }, true); - exportCredentials(roleCredentials); + const roleCredentials = await retryAndBackoff(async () => { + return await assumeRole({ + sourceAccountId, + region, + roleToAssume, + roleExternalId, + roleDurationSeconds, + roleSessionName, + roleSkipSessionTagging, + webIdentityTokenFile, + webIdentityToken, + }); + }, true); + + if (profile) { + await exportCredentialsToConfig(profile, { + ...roleCredentials, + webIdentityTokenFile, + region, + roleSessionName, + roleExternalId, + }); + } else { + exportCredentials(roleCredentials); + } // We need to validate the credentials in 2 of our use-cases // First: self-hosted runners. If the GITHUB_ACTIONS environment variable // is set to `true` then we are NOT in a self-hosted runner. @@ -47199,18 +47535,19 @@ async function run() { if (!process.env.GITHUB_ACTIONS || accessKeyId) { await validateCredentials(roleCredentials.accessKeyId); } + await exportAccountId(maskAccountId, region); + + return; } - } - catch (error) { + } catch (error) { core.setFailed(error.message); const showStackTrace = process.env.SHOW_STACK_TRACE; - if (showStackTrace === 'true') { - throw(error) + if (showStackTrace === "true") { + throw error; } - } } @@ -47221,11 +47558,11 @@ exports.reset = function () { sleep = defaultSleep; }; -exports.run = run +exports.run = run; /* istanbul ignore next */ if (require.main === require.cache[eval('__filename')]) { - run(); + run(); } })(); diff --git a/index.js b/index.js index 06c546b16..33155297a 100644 --- a/index.js +++ b/index.js @@ -1,24 +1,25 @@ -const core = require('@actions/core'); -const aws = require('aws-sdk'); -const assert = require('assert'); -const fs = require('fs'); -const path = require('path'); -const proxy = require('https-proxy-agent'); +const core = require("@actions/core"); +const aws = require("aws-sdk"); +const assert = require("assert"); +const fs = require("fs"); +const path = require("path"); +const proxy = require("https-proxy-agent"); +const ini = require("ini"); // Use 1hr as role duration when using session token or OIDC // Otherwise, use the max duration of GitHub action (6hr) const MAX_ACTION_RUNTIME = 6 * 3600; const SESSION_ROLE_DURATION = 3600; const DEFAULT_ROLE_DURATION_FOR_OIDC_ROLES = 3600; -const USER_AGENT = 'configure-aws-credentials-for-github-actions'; +const USER_AGENT = "configure-aws-credentials-for-github-actions"; const MAX_TAG_VALUE_LENGTH = 256; -const SANITIZATION_CHARACTER = '_'; -const ROLE_SESSION_NAME = 'GitHubActions'; +const SANITIZATION_CHARACTER = "_"; +const ROLE_SESSION_NAME = "GitHubActions"; const REGION_REGEX = /^[a-z0-9-]+$/g; async function assumeRole(params) { // Assume a role to get short-lived credentials using longer-lived credentials. - const isDefined = i => !!i; + const isDefined = (i) => !!i; const { sourceAccountId, @@ -29,57 +30,57 @@ async function assumeRole(params) { region, roleSkipSessionTagging, webIdentityTokenFile, - webIdentityToken + webIdentityToken, } = params; assert( - [roleToAssume, roleDurationSeconds, roleSessionName, region].every(isDefined), - "Missing required input when assuming a Role." + [roleToAssume, roleDurationSeconds, roleSessionName, region].every(isDefined), + "Missing required input when assuming a Role.", ); - const {GITHUB_REPOSITORY, GITHUB_WORKFLOW, GITHUB_ACTION, GITHUB_ACTOR, GITHUB_SHA} = process.env; + const { GITHUB_REPOSITORY, GITHUB_WORKFLOW, GITHUB_ACTION, GITHUB_ACTOR, GITHUB_SHA } = process.env; assert( - [GITHUB_REPOSITORY, GITHUB_WORKFLOW, GITHUB_ACTION, GITHUB_ACTOR, GITHUB_SHA].every(isDefined), - 'Missing required environment value. Are you running in GitHub Actions?' + [GITHUB_REPOSITORY, GITHUB_WORKFLOW, GITHUB_ACTION, GITHUB_ACTOR, GITHUB_SHA].every(isDefined), + "Missing required environment value. Are you running in GitHub Actions?", ); const sts = getStsClient(region); let roleArn = roleToAssume; - if (!roleArn.startsWith('arn:aws')) { + if (!roleArn.startsWith("arn:aws")) { // Supports only 'aws' partition. Customers in other partitions ('aws-cn') will need to provide full ARN - assert( + assert( isDefined(sourceAccountId), - "Source Account ID is needed if the Role Name is provided and not the Role Arn." - ); + "Source Account ID is needed if the Role Name is provided and not the Role Arn.", + ); roleArn = `arn:aws:iam::${sourceAccountId}:role/${roleArn}`; } const tagArray = [ - {Key: 'GitHub', Value: 'Actions'}, - {Key: 'Repository', Value: GITHUB_REPOSITORY}, - {Key: 'Workflow', Value: sanitizeGithubWorkflowName(GITHUB_WORKFLOW)}, - {Key: 'Action', Value: GITHUB_ACTION}, - {Key: 'Actor', Value: sanitizeGithubActor(GITHUB_ACTOR)}, - {Key: 'Commit', Value: GITHUB_SHA}, + { Key: "GitHub", Value: "Actions" }, + { Key: "Repository", Value: GITHUB_REPOSITORY }, + { Key: "Workflow", Value: sanitizeGithubWorkflowName(GITHUB_WORKFLOW) }, + { Key: "Action", Value: GITHUB_ACTION }, + { Key: "Actor", Value: sanitizeGithubActor(GITHUB_ACTOR) }, + { Key: "Commit", Value: GITHUB_SHA }, ]; if (isDefined(process.env.GITHUB_REF)) { - tagArray.push({Key: 'Branch', Value: process.env.GITHUB_REF}); + tagArray.push({ Key: "Branch", Value: process.env.GITHUB_REF }); } const roleSessionTags = roleSkipSessionTagging ? undefined : tagArray; - if(roleSessionTags == undefined){ - core.debug("Role session tagging has been skipped.") + if (roleSessionTags == undefined) { + core.debug("Role session tagging has been skipped."); } else { - core.debug(roleSessionTags.length + " role session tags are being used.") + core.debug(roleSessionTags.length + " role session tags are being used."); } const assumeRoleRequest = { RoleArn: roleArn, RoleSessionName: roleSessionName, DurationSeconds: roleDurationSeconds, - Tags: roleSessionTags + Tags: roleSessionTags, }; if (roleExternalId) { @@ -89,30 +90,31 @@ async function assumeRole(params) { let assumeFunction = sts.assumeRole.bind(sts); // These are customizations needed for the GH OIDC Provider - if(isDefined(webIdentityToken)) { + if (isDefined(webIdentityToken)) { delete assumeRoleRequest.Tags; assumeRoleRequest.WebIdentityToken = webIdentityToken; assumeFunction = sts.assumeRoleWithWebIdentity.bind(sts); - } else if(isDefined(webIdentityTokenFile)) { - core.debug("webIdentityTokenFile provided. Will call sts:AssumeRoleWithWebIdentity and take session tags from token contents."); + } else if (isDefined(webIdentityTokenFile)) { + core.debug( + "webIdentityTokenFile provided. Will call sts:AssumeRoleWithWebIdentity and take session tags from token contents.", + ); delete assumeRoleRequest.Tags; - const webIdentityTokenFilePath = path.isAbsolute(webIdentityTokenFile) ? - webIdentityTokenFile : - path.join(process.env.GITHUB_WORKSPACE, webIdentityTokenFile); + const webIdentityTokenFilePath = path.isAbsolute(webIdentityTokenFile) + ? webIdentityTokenFile + : path.join(process.env.GITHUB_WORKSPACE, webIdentityTokenFile); if (!fs.existsSync(webIdentityTokenFilePath)) { throw new Error(`Web identity token file does not exist: ${webIdentityTokenFilePath}`); } try { - assumeRoleRequest.WebIdentityToken = await fs.promises.readFile(webIdentityTokenFilePath, 'utf8'); + assumeRoleRequest.WebIdentityToken = await fs.promises.readFile(webIdentityTokenFilePath, "utf8"); assumeFunction = sts.assumeRoleWithWebIdentity.bind(sts); - } catch(error) { + } catch (error) { throw new Error(`Web identity token file could not be read: ${error.message}`); } - } return assumeFunction(assumeRoleRequest) @@ -129,7 +131,7 @@ async function assumeRole(params) { function sanitizeGithubActor(actor) { // In some circumstances the actor may contain square brackets. For example, if they're a bot ('[bot]') // Square brackets are not allowed in AWS session tags - return actor.replace(/\[|\]/g, SANITIZATION_CHARACTER) + return actor.replace(/\[|\]/g, SANITIZATION_CHARACTER); } function sanitizeGithubWorkflowName(name) { @@ -137,41 +139,118 @@ function sanitizeGithubWorkflowName(name) { // This replaces anything not conforming to the tag restrictions by inverting the regular expression. // See the AWS documentation for constraint specifics https://docs.aws.amazon.com/STS/latest/APIReference/API_Tag.html. const nameWithoutSpecialCharacters = name.replace(/[^\p{L}\p{Z}\p{N}_:/=+.-@-]/gu, SANITIZATION_CHARACTER); - const nameTruncated = nameWithoutSpecialCharacters.slice(0, MAX_TAG_VALUE_LENGTH) - return nameTruncated + const nameTruncated = nameWithoutSpecialCharacters.slice(0, MAX_TAG_VALUE_LENGTH); + return nameTruncated; } -function exportCredentials(params){ +function exportCredentials(params) { // Configure the AWS CLI and AWS SDKs using environment variables and set them as secrets. // Setting the credentials as secrets masks them in Github Actions logs - const {accessKeyId, secretAccessKey, sessionToken} = params; + const { accessKeyId, secretAccessKey, sessionToken } = params; // AWS_ACCESS_KEY_ID: // Specifies an AWS access key associated with an IAM user or role core.setSecret(accessKeyId); - core.exportVariable('AWS_ACCESS_KEY_ID', accessKeyId); + core.exportVariable("AWS_ACCESS_KEY_ID", accessKeyId); // AWS_SECRET_ACCESS_KEY: // Specifies the secret key associated with the access key. This is essentially the "password" for the access key. core.setSecret(secretAccessKey); - core.exportVariable('AWS_SECRET_ACCESS_KEY', secretAccessKey); + core.exportVariable("AWS_SECRET_ACCESS_KEY", secretAccessKey); // AWS_SESSION_TOKEN: // Specifies the session token value that is required if you are using temporary security credentials. if (sessionToken) { core.setSecret(sessionToken); - core.exportVariable('AWS_SESSION_TOKEN', sessionToken); + core.exportVariable("AWS_SESSION_TOKEN", sessionToken); } else if (process.env.AWS_SESSION_TOKEN) { // clear session token from previous credentials action - core.exportVariable('AWS_SESSION_TOKEN', ''); + core.exportVariable("AWS_SESSION_TOKEN", ""); } } +async function exportCredentialsToConfig(profile, params) { + const awsConfigFolder = `${process.env.HOME}/.aws`; + const awsCredentialsFile = `${awsConfigFolder}/credentials`; + const awsConfigFile = `${awsConfigFolder}/config`; + let config = {}; + let credentials = {}; + + if (!fs.existsSync(awsConfigFolder)) { + fs.mkdirSync(awsConfigFolder, { recursive: true }); + } + + if (fs.existsSync(awsConfigFile)) { + config = ini.parse(await fs.promises.readFile(awsConfigFile, "utf-8")); + } + + if (fs.existsSync(awsCredentialsFile)) { + credentials = ini.parse(await fs.promises.readFile(awsCredentialsFile, "utf-8")); + } + + // Configure the AWS CLI and AWS SDKs using environment variables and set them as secrets. + // Setting the credentials as secrets masks them in Github Actions logs + const { + webIdentityTokenFile, + accessKeyId, + secretAccessKey, + sessionToken, + region, + roleToAssume, + roleSessionName, + roleExternalId, + } = params; + + // Initialize the configuration objects + const profileName = profile; + const configProfileName = `profile ${profileName}`; + config[configProfileName] = {}; + config[configProfileName].region = region; + config[configProfileName].web_identity_token_file = webIdentityTokenFile; + config[configProfileName].role_arn = roleToAssume; + config[configProfileName].role_session_name = roleSessionName; + config[configProfileName].external_id = roleExternalId; + + credentials[profileName] = {}; + credentials[profileName].aws_access_key_id = accessKeyId; + credentials[profileName].aws_secret_access_key = secretAccessKey; + credentials[profileName].aws_session_token = sessionToken; + + // Clean up empty values + Object.values(credentials).forEach((profile) => { + Object.keys(profile).forEach((key) => { + if (profile[key] === undefined || profile[key] === "") { + delete profile[key]; + } + }); + }); + // Clean up empty values + Object.values(config).forEach((profile) => { + Object.keys(profile).forEach((key) => { + if (profile[key] === undefined || profile[key] === "") { + delete profile[key]; + } + }); + }); + + await fs.promises.writeFile(awsConfigFile, ini.stringify(config)); + await fs.promises.writeFile(awsCredentialsFile, ini.stringify(credentials)); + + // Set the AWS_PROFILE environment variable + core.exportVariable("AWS_PROFILE", profileName); + // Set the AWS_SHARED_CREDENTIALS_FILE environment variable + core.exportVariable("AWS_SHARED_CREDENTIALS_FILE", awsCredentialsFile); + // Set the AWS_CONFIG_FILE environment variable + core.exportVariable("AWS_CONFIG_FILE", awsConfigFile); + + // await validateCredentials(credentials[profileName].aws_access_key_id); +} + function exportRegion(region) { // AWS_DEFAULT_REGION and AWS_REGION: // Specifies the AWS Region to send requests to - core.exportVariable('AWS_DEFAULT_REGION', region); - core.exportVariable('AWS_REGION', region); + core.exportVariable("AWS_DEFAULT_REGION", region); + core.exportVariable("AWS_REGION", region); } async function exportAccountId(maskAccountId, region) { @@ -179,10 +258,10 @@ async function exportAccountId(maskAccountId, region) { const sts = getStsClient(region); const identity = await sts.getCallerIdentity().promise(); const accountId = identity.Account; - if (!maskAccountId || maskAccountId.toLowerCase() == 'true') { + if (!maskAccountId || maskAccountId.toLowerCase() == "true") { core.setSecret(accountId); } - core.setOutput('aws-account-id', accountId); + core.setOutput("aws-account-id", accountId); return accountId; } @@ -207,7 +286,7 @@ function loadCredentials() { reject(err); } resolve(aws.config.credentials); - }) + }); }); } @@ -217,7 +296,7 @@ async function validateCredentials(expectedAccessKeyId) { credentials = await loadCredentials(); if (!credentials.accessKeyId) { - throw new Error('Access key ID empty after loading credentials'); + throw new Error("Access key ID empty after loading credentials"); } } catch (error) { throw new Error(`Credentials could not be loaded, please check your action inputs: ${error.message}`); @@ -226,15 +305,17 @@ async function validateCredentials(expectedAccessKeyId) { const actualAccessKeyId = credentials.accessKeyId; if (expectedAccessKeyId && expectedAccessKeyId != actualAccessKeyId) { - throw new Error('Unexpected failure: Credentials loaded by the SDK do not match the access key ID configured by the action'); + throw new Error( + "Unexpected failure: Credentials loaded by the SDK do not match the access key ID configured by the action", + ); } } function getStsClient(region) { return new aws.STS({ region, - stsRegionalEndpoints: 'regional', - customUserAgent: USER_AGENT + stsRegionalEndpoints: "regional", + customUserAgent: USER_AGENT, }); } @@ -252,14 +333,14 @@ const retryAndBackoff = async (fn, isRetryable, retries = 0, maxRetries = 12, ba throw err; } // It's retryable, so sleep and retry. - await sleep(Math.random() * (Math.pow(2, retries) * base) ); + await sleep(Math.random() * (Math.pow(2, retries) * base)); retries += 1; if (retries === maxRetries) { throw err; } return await retryAndBackoff(fn, isRetryable, retries, maxRetries, base); } -} +}; function configureProxy(proxyServer) { const proxyFromEnv = process.env.HTTP_PROXY || process.env.http_proxy; @@ -267,7 +348,7 @@ function configureProxy(proxyServer) { if (proxyFromEnv || proxyServer) { let proxyToSet = null; - if (proxyServer){ + if (proxyServer) { console.log(`Setting proxy from actions input: ${proxyServer}`); proxyToSet = proxyServer; } else { @@ -276,7 +357,7 @@ function configureProxy(proxyServer) { } aws.config.update({ - httpOptions: { agent: proxy(proxyToSet) } + httpOptions: { agent: proxy(proxyToSet) }, }); } } @@ -284,22 +365,24 @@ function configureProxy(proxyServer) { async function run() { try { // Get inputs - const accessKeyId = core.getInput('aws-access-key-id', { required: false }); - const audience = core.getInput('audience', { required: false }); - const secretAccessKey = core.getInput('aws-secret-access-key', { required: false }); - const region = core.getInput('aws-region', { required: true }); - const sessionToken = core.getInput('aws-session-token', { required: false }); - const maskAccountId = core.getInput('mask-aws-account-id', { required: false }); - const roleToAssume = core.getInput('role-to-assume', {required: false}); - const roleExternalId = core.getInput('role-external-id', { required: false }); - let roleDurationSeconds = core.getInput('role-duration-seconds', {required: false}) - || (sessionToken && SESSION_ROLE_DURATION) - || MAX_ACTION_RUNTIME; - const roleSessionName = core.getInput('role-session-name', { required: false }) || ROLE_SESSION_NAME; - const roleSkipSessionTaggingInput = core.getInput('role-skip-session-tagging', { required: false })|| 'false'; - const roleSkipSessionTagging = roleSkipSessionTaggingInput.toLowerCase() === 'true'; - const webIdentityTokenFile = core.getInput('web-identity-token-file', { required: false }); - const proxyServer = core.getInput('http-proxy', { required: false }); + const accessKeyId = core.getInput("aws-access-key-id", { required: false }); + const audience = core.getInput("audience", { required: false }); + const secretAccessKey = core.getInput("aws-secret-access-key", { required: false }); + const profile = core.getInput("aws-profile", { required: false }); + const region = core.getInput("aws-region", { required: true }); + const sessionToken = core.getInput("aws-session-token", { required: false }); + const maskAccountId = core.getInput("mask-aws-account-id", { required: false }); + const roleToAssume = core.getInput("role-to-assume", { required: false }); + const roleExternalId = core.getInput("role-external-id", { required: false }); + let roleDurationSeconds = + core.getInput("role-duration-seconds", { required: false }) || + (sessionToken && SESSION_ROLE_DURATION) || + MAX_ACTION_RUNTIME; + const roleSessionName = core.getInput("role-session-name", { required: false }) || ROLE_SESSION_NAME; + const roleSkipSessionTaggingInput = core.getInput("role-skip-session-tagging", { required: false }) || "false"; + const roleSkipSessionTagging = roleSkipSessionTaggingInput.toLowerCase() === "true"; + const webIdentityTokenFile = core.getInput("web-identity-token-file", { required: false }); + const proxyServer = core.getInput("http-proxy", { required: false }); if (!region.match(REGION_REGEX)) { throw new Error(`Region is not valid: ${region}`); @@ -310,12 +393,12 @@ async function run() { // This wraps the logic for deciding if we should rely on the GH OIDC provider since we may need to reference // the decision in a few differennt places. Consolidating it here makes the logic clearer elsewhere. const useGitHubOIDCProvider = () => { - // The assumption here is that self-hosted runners won't be populating the `ACTIONS_ID_TOKEN_REQUEST_TOKEN` - // environment variable and they won't be providing a web idenity token file or access key either. - // V2 of the action might relax this a bit and create an explicit precedence for these so that customers - // can provide as much info as they want and we will follow the established credential loading precedence. - return roleToAssume && process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN && !accessKeyId && !webIdentityTokenFile - } + // The assumption here is that self-hosted runners won't be populating the `ACTIONS_ID_TOKEN_REQUEST_TOKEN` + // environment variable and they won't be providing a web idenity token file or access key either. + // V2 of the action might relax this a bit and create an explicit precedence for these so that customers + // can provide as much info as they want and we will follow the established credential loading precedence. + return roleToAssume && process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN && !accessKeyId && !webIdentityTokenFile; + }; // Always export the source credentials and account ID. // The STS client for calling AssumeRole pulls creds from the environment. @@ -327,9 +410,22 @@ async function run() { throw new Error("'aws-secret-access-key' must be provided if 'aws-access-key-id' is provided"); } - exportCredentials({accessKeyId, secretAccessKey, sessionToken}); + if (profile) { + await exportCredentialsToConfig(profile, { + accessKeyId, + secretAccessKey, + sessionToken, + webIdentityTokenFile, + region, + roleToAssume, + roleSessionName, + roleExternalId, + }); + } else { + exportCredentials({ accessKeyId, secretAccessKey, sessionToken }); + } } - + // Configures proxy configureProxy(proxyServer); @@ -338,9 +434,10 @@ async function run() { // The only way to assume the role is via GitHub's OIDC provider. let sourceAccountId; let webIdentityToken; - if(useGitHubOIDCProvider()) { + if (useGitHubOIDCProvider()) { webIdentityToken = await core.getIDToken(audience); - roleDurationSeconds = core.getInput('role-duration-seconds', {required: false}) || DEFAULT_ROLE_DURATION_FOR_OIDC_ROLES; + roleDurationSeconds = + core.getInput("role-duration-seconds", { required: false }) || DEFAULT_ROLE_DURATION_FOR_OIDC_ROLES; // We don't validate the credentials here because we don't have them yet when using OIDC. } else { // Regardless of whether any source credentials were provided as inputs, @@ -355,19 +452,32 @@ async function run() { // Get role credentials if configured to do so if (roleToAssume) { - const roleCredentials = await retryAndBackoff( - async () => { return await assumeRole({ - sourceAccountId, - region, - roleToAssume, - roleExternalId, - roleDurationSeconds, - roleSessionName, - roleSkipSessionTagging, - webIdentityTokenFile, - webIdentityToken - }) }, true); - exportCredentials(roleCredentials); + const roleCredentials = await retryAndBackoff(async () => { + return await assumeRole({ + sourceAccountId, + region, + roleToAssume, + roleExternalId, + roleDurationSeconds, + roleSessionName, + roleSkipSessionTagging, + webIdentityTokenFile, + webIdentityToken, + }); + }, true); + + if (profile) { + await exportCredentialsToConfig(profile, { + ...roleCredentials, + roleToAssume, + webIdentityTokenFile, + region, + roleSessionName, + roleExternalId, + }); + } else { + exportCredentials(roleCredentials); + } // We need to validate the credentials in 2 of our use-cases // First: self-hosted runners. If the GITHUB_ACTIONS environment variable // is set to `true` then we are NOT in a self-hosted runner. @@ -375,18 +485,19 @@ async function run() { if (!process.env.GITHUB_ACTIONS || accessKeyId) { await validateCredentials(roleCredentials.accessKeyId); } + await exportAccountId(maskAccountId, region); + + return; } - } - catch (error) { + } catch (error) { core.setFailed(error.message); const showStackTrace = process.env.SHOW_STACK_TRACE; - if (showStackTrace === 'true') { - throw(error) + if (showStackTrace === "true") { + throw error; } - } } @@ -397,9 +508,9 @@ exports.reset = function () { sleep = defaultSleep; }; -exports.run = run +exports.run = run; /* istanbul ignore next */ if (require.main === module) { - run(); + run(); } diff --git a/index.test.js b/index.test.js index e6655adc7..1c3a24433 100644 --- a/index.test.js +++ b/index.test.js @@ -1,877 +1,1004 @@ -const core = require('@actions/core'); -const assert = require('assert'); -const aws = require('aws-sdk'); -const { run, withSleep, reset } = require('./index.js'); -const proxy = require('https-proxy-agent'); - -jest.mock('@actions/core'); - -const FAKE_ACCESS_KEY_ID = 'MY-AWS-ACCESS-KEY-ID'; -const FAKE_SECRET_ACCESS_KEY = 'MY-AWS-SECRET-ACCESS-KEY'; -const FAKE_SESSION_TOKEN = 'MY-AWS-SESSION-TOKEN'; -const FAKE_STS_ACCESS_KEY_ID = 'STS-AWS-ACCESS-KEY-ID'; -const FAKE_STS_SECRET_ACCESS_KEY = 'STS-AWS-SECRET-ACCESS-KEY'; -const FAKE_STS_SESSION_TOKEN = 'STS-AWS-SESSION-TOKEN'; -const FAKE_REGION = 'fake-region-1'; -const FAKE_ACCOUNT_ID = '123456789012'; -const FAKE_ROLE_ACCOUNT_ID = '111111111111'; -const ROLE_NAME = 'MY-ROLE'; -const ROLE_ARN = 'arn:aws:iam::111111111111:role/MY-ROLE'; +const core = require("@actions/core"); +const assert = require("assert"); +const aws = require("aws-sdk"); +const fs = require("fs"); +const { run, withSleep, reset } = require("./index.js"); +const proxy = require("https-proxy-agent"); + +jest.mock("@actions/core"); + +const FAKE_ACCESS_KEY_ID = "MY-AWS-ACCESS-KEY-ID"; +const FAKE_SECRET_ACCESS_KEY = "MY-AWS-SECRET-ACCESS-KEY"; +const FAKE_SESSION_TOKEN = "MY-AWS-SESSION-TOKEN"; +const FAKE_STS_ACCESS_KEY_ID = "STS-AWS-ACCESS-KEY-ID"; +const FAKE_STS_SECRET_ACCESS_KEY = "STS-AWS-SECRET-ACCESS-KEY"; +const FAKE_STS_SESSION_TOKEN = "STS-AWS-SESSION-TOKEN"; +const FAKE_REGION = "fake-region-1"; +const FAKE_ACCOUNT_ID = "123456789012"; +const FAKE_ROLE_ACCOUNT_ID = "111111111111"; +const ROLE_NAME = "MY-ROLE"; +const ROLE_ARN = "arn:aws:iam::111111111111:role/MY-ROLE"; const ENVIRONMENT_VARIABLE_OVERRIDES = { - SHOW_STACK_TRACE: 'true', - GITHUB_REPOSITORY: 'MY-REPOSITORY-NAME', - GITHUB_WORKFLOW: 'MY-WORKFLOW-ID', - GITHUB_ACTION: 'MY-ACTION-NAME', - GITHUB_ACTOR: 'MY-USERNAME[bot]', - GITHUB_SHA: 'MY-COMMIT-ID', - GITHUB_REF: 'MY-BRANCH', - GITHUB_WORKSPACE: '/home/github' + SHOW_STACK_TRACE: "true", + GITHUB_REPOSITORY: "MY-REPOSITORY-NAME", + GITHUB_WORKFLOW: "MY-WORKFLOW-ID", + GITHUB_ACTION: "MY-ACTION-NAME", + GITHUB_ACTOR: "MY-USERNAME[bot]", + GITHUB_SHA: "MY-COMMIT-ID", + GITHUB_REF: "MY-BRANCH", + GITHUB_WORKSPACE: "/home/github", + HOME: "/home", }; -const GITHUB_ACTOR_SANITIZED = 'MY-USERNAME_bot_' +const GITHUB_ACTOR_SANITIZED = "MY-USERNAME_bot_"; function mockGetInput(requestResponse) { - return function (name, options) { // eslint-disable-line no-unused-vars - return requestResponse[name] - } + // eslint-disable-next-line no-unused-vars + return function (name, options) { + // eslint-disable-line no-unused-vars + return requestResponse[name]; + }; } const CREDS_INPUTS = { - 'aws-access-key-id': FAKE_ACCESS_KEY_ID, - 'aws-secret-access-key': FAKE_SECRET_ACCESS_KEY + "aws-access-key-id": FAKE_ACCESS_KEY_ID, + "aws-secret-access-key": FAKE_SECRET_ACCESS_KEY, }; const DEFAULT_INPUTS = { - ...CREDS_INPUTS, - 'aws-session-token': FAKE_SESSION_TOKEN, - 'aws-region': FAKE_REGION, - 'mask-aws-account-id': 'TRUE' + ...CREDS_INPUTS, + "aws-session-token": FAKE_SESSION_TOKEN, + "aws-region": FAKE_REGION, + "mask-aws-account-id": "TRUE", }; -const ASSUME_ROLE_INPUTS = {...CREDS_INPUTS, 'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION}; +const ASSUME_ROLE_INPUTS = { ...CREDS_INPUTS, "role-to-assume": ROLE_ARN, "aws-region": FAKE_REGION }; + +const PROFILE_INPUTS = { "role-to-assume": ROLE_ARN, "aws-region": FAKE_REGION, "aws-profile": "test-profile" }; const mockStsCallerIdentity = jest.fn(); const mockStsAssumeRole = jest.fn(); const mockStsAssumeRoleWithWebIdentity = jest.fn(); -jest.mock('aws-sdk', () => { - return { - config: { - getCredentials: jest.fn(), - update: jest.fn(), - }, - STS: jest.fn(() => ({ - getCallerIdentity: mockStsCallerIdentity, - assumeRole: mockStsAssumeRole, - assumeRoleWithWebIdentity: mockStsAssumeRoleWithWebIdentity - })) - }; +jest.mock("aws-sdk", () => { + return { + config: { + getCredentials: jest.fn(), + update: jest.fn(), + }, + STS: jest.fn(() => ({ + getCallerIdentity: mockStsCallerIdentity, + assumeRole: mockStsAssumeRole, + assumeRoleWithWebIdentity: mockStsAssumeRoleWithWebIdentity, + })), + }; }); -jest.mock('fs', () => { - return { - promises: { - readFile: jest.fn(() => Promise.resolve('testpayload')), - }, - existsSync: jest.fn(() => true) - }; +jest.mock("fs", () => { + return { + promises: { + readFile: jest.fn(() => Promise.resolve()), + writeFile: jest.fn(() => Promise.resolve()), + }, + existsSync: jest.fn(() => true), + mkdirSync: jest.fn(() => true), + }; }); - -jest.mock('axios', () => ({ - get: jest.fn(() => Promise.resolve({ data: { value: "testtoken" }})), +jest.mock("axios", () => ({ + get: jest.fn(() => Promise.resolve({ data: { value: "testtoken" } })), })); -describe('Configure AWS Credentials', () => { - beforeEach(() => { - jest.resetModules(); - process.env = { ...ENVIRONMENT_VARIABLE_OVERRIDES }; - - jest.clearAllMocks(); - - core.getInput = jest - .fn() - .mockImplementation(mockGetInput(DEFAULT_INPUTS)); - - core.getIDToken = jest - .fn() - .mockImplementation(() => { - return "testtoken" - }); - - mockStsCallerIdentity.mockReset(); - mockStsCallerIdentity - .mockReturnValueOnce({ - promise() { - return Promise.resolve({ Account: FAKE_ACCOUNT_ID }); - } - }) - .mockReturnValueOnce({ - promise() { - return Promise.resolve({ Account: FAKE_ROLE_ACCOUNT_ID }); - } - }); - - aws.config.getCredentials.mockReset(); - aws.config.getCredentials - .mockImplementationOnce(callback => { - if (!aws.config.credentials) { - aws.config.credentials = { - accessKeyId: FAKE_ACCESS_KEY_ID, - secretAccessKey: FAKE_SECRET_ACCESS_KEY - } - } - callback(null); - }) - .mockImplementationOnce(callback => { - if (!aws.config.credentials) { - aws.config.credentials = { - accessKeyId: FAKE_STS_ACCESS_KEY_ID, - secretAccessKey: FAKE_STS_SECRET_ACCESS_KEY - } - } - callback(null); - }); - - aws.config.update.mockReset(); - aws.config.update.mockImplementationOnce(); - - mockStsAssumeRole.mockImplementation(() => { - return { - promise() { - return Promise.resolve({ - Credentials: { - AccessKeyId: FAKE_STS_ACCESS_KEY_ID, - SecretAccessKey: FAKE_STS_SECRET_ACCESS_KEY, - SessionToken: FAKE_STS_SESSION_TOKEN - } - }); - } - } - }); - - mockStsAssumeRoleWithWebIdentity.mockImplementation(() => { - return { - promise() { - return Promise.resolve({ - Credentials: { - AccessKeyId: FAKE_STS_ACCESS_KEY_ID, - SecretAccessKey: FAKE_STS_SECRET_ACCESS_KEY, - SessionToken: FAKE_STS_SESSION_TOKEN - } - }); - } - } - }); - - withSleep(() => { - return Promise.resolve(); - }); - }); - - afterEach(() => { - reset(); - }); - - test('exports env vars', async () => { - await run(); - expect(mockStsAssumeRole).toHaveBeenCalledTimes(0); - expect(core.exportVariable).toHaveBeenCalledTimes(5); - expect(core.setSecret).toHaveBeenCalledTimes(4); - expect(core.exportVariable).toHaveBeenCalledWith('AWS_ACCESS_KEY_ID', FAKE_ACCESS_KEY_ID); - expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCESS_KEY_ID); - expect(core.exportVariable).toHaveBeenCalledWith('AWS_SECRET_ACCESS_KEY', FAKE_SECRET_ACCESS_KEY); - expect(core.setSecret).toHaveBeenCalledWith(FAKE_SECRET_ACCESS_KEY); - expect(core.exportVariable).toHaveBeenCalledWith('AWS_SESSION_TOKEN', FAKE_SESSION_TOKEN); - expect(core.setSecret).toHaveBeenCalledWith(FAKE_SESSION_TOKEN); - expect(core.exportVariable).toHaveBeenCalledWith('AWS_DEFAULT_REGION', FAKE_REGION); - expect(core.exportVariable).toHaveBeenCalledWith('AWS_REGION', FAKE_REGION); - expect(core.setOutput).toHaveBeenCalledWith('aws-account-id', FAKE_ACCOUNT_ID); - expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCOUNT_ID); - }); - - test('action fails when github env vars are not set', async () => { - process.env.SHOW_STACK_TRACE = 'false'; - core.getInput = jest - .fn() - .mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS)); - delete process.env.GITHUB_SHA; - - await run(); - expect(core.setFailed).toHaveBeenCalledWith('Missing required environment value. Are you running in GitHub Actions?'); - }); - - test('action does not require GITHUB_REF env var', async () => { - core.getInput = jest - .fn() - .mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS)); - delete process.env.GITHUB_REF; - - await run(); - }); - - test('hosted runners can pull creds from a self-hosted environment', async () => { - const mockInputs = {'aws-region': FAKE_REGION}; - core.getInput = jest - .fn() - .mockImplementation(mockGetInput(mockInputs)); - - await run(); - expect(mockStsAssumeRole).toHaveBeenCalledTimes(0); - expect(core.exportVariable).toHaveBeenCalledTimes(2); - expect(core.setSecret).toHaveBeenCalledTimes(1); - expect(core.exportVariable).toHaveBeenCalledWith('AWS_DEFAULT_REGION', FAKE_REGION); - expect(core.exportVariable).toHaveBeenCalledWith('AWS_REGION', FAKE_REGION); - expect(core.setOutput).toHaveBeenCalledWith('aws-account-id', FAKE_ACCOUNT_ID); - expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCOUNT_ID); - }); - - test('action with no accessible credentials fails', async () => { - process.env.SHOW_STACK_TRACE = 'false'; - const mockInputs = {'aws-region': FAKE_REGION}; - core.getInput = jest - .fn() - .mockImplementation(mockGetInput(mockInputs)); - aws.config.getCredentials.mockReset(); - aws.config.getCredentials.mockImplementation(callback => { - callback(new Error('No credentials to load')); - }); - - await run(); - - expect(core.setFailed).toHaveBeenCalledWith("Credentials could not be loaded, please check your action inputs: No credentials to load"); - }); - - test('action with empty credentials fails', async () => { - process.env.SHOW_STACK_TRACE = 'false'; - const mockInputs = {'aws-region': FAKE_REGION}; - core.getInput = jest - .fn() - .mockImplementation(mockGetInput(mockInputs)); - aws.config.getCredentials.mockReset(); - aws.config.getCredentials.mockImplementation(callback => { - aws.config.credentials = { - accessKeyId: '' - } - callback(null); - }); - - await run(); - - expect(core.setFailed).toHaveBeenCalledWith("Credentials could not be loaded, please check your action inputs: Access key ID empty after loading credentials"); - }); - - test('action fails when credentials are not set in the SDK correctly', async () => { - process.env.SHOW_STACK_TRACE = 'false'; - core.getInput = jest - .fn() - .mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS)); - aws.config.getCredentials.mockReset(); - aws.config.getCredentials.mockImplementation(callback => { - aws.config.credentials = { - accessKeyId: FAKE_ACCESS_KEY_ID - } - callback(null); - }); - - await run(); - - expect(core.setFailed).toHaveBeenCalledWith("Unexpected failure: Credentials loaded by the SDK do not match the access key ID configured by the action"); - }); - - test('session token is optional', async () => { - const mockInputs = {...CREDS_INPUTS, 'aws-region': 'eu-west-1'}; - core.getInput = jest - .fn() - .mockImplementation(mockGetInput(mockInputs)); - - await run(); - expect(mockStsAssumeRole).toHaveBeenCalledTimes(0); - expect(core.exportVariable).toHaveBeenCalledTimes(4); - expect(core.setSecret).toHaveBeenCalledTimes(3); - expect(core.exportVariable).toHaveBeenCalledWith('AWS_ACCESS_KEY_ID', FAKE_ACCESS_KEY_ID); - expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCESS_KEY_ID); - expect(core.exportVariable).toHaveBeenCalledWith('AWS_SECRET_ACCESS_KEY', FAKE_SECRET_ACCESS_KEY); - expect(core.setSecret).toHaveBeenCalledWith(FAKE_SECRET_ACCESS_KEY); - expect(core.exportVariable).toHaveBeenCalledWith('AWS_DEFAULT_REGION', 'eu-west-1'); - expect(core.exportVariable).toHaveBeenCalledWith('AWS_REGION', 'eu-west-1'); - expect(core.setOutput).toHaveBeenCalledWith('aws-account-id', FAKE_ACCOUNT_ID); - expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCOUNT_ID); - }); - - test('existing env var creds are cleared', async () => { - const mockInputs = {...CREDS_INPUTS, 'aws-region': 'eu-west-1'}; - core.getInput = jest - .fn() - .mockImplementation(mockGetInput(mockInputs)); - process.env.AWS_ACCESS_KEY_ID = 'foo'; - process.env.AWS_SECRET_ACCESS_KEY = 'bar'; - process.env.AWS_SESSION_TOKEN = 'helloworld'; - aws.config.credentials = { - accessKeyId: 'foo', - secretAccessKey: 'bar', - sessionToken: 'helloworld' - }; - - await run(); - expect(mockStsAssumeRole).toHaveBeenCalledTimes(0); - expect(core.exportVariable).toHaveBeenCalledTimes(5); - expect(core.setSecret).toHaveBeenCalledTimes(3); - expect(core.exportVariable).toHaveBeenCalledWith('AWS_ACCESS_KEY_ID', FAKE_ACCESS_KEY_ID); - expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCESS_KEY_ID); - expect(core.exportVariable).toHaveBeenCalledWith('AWS_SECRET_ACCESS_KEY', FAKE_SECRET_ACCESS_KEY); - expect(core.setSecret).toHaveBeenCalledWith(FAKE_SECRET_ACCESS_KEY); - expect(core.exportVariable).toHaveBeenCalledWith('AWS_SESSION_TOKEN', ''); - expect(core.exportVariable).toHaveBeenCalledWith('AWS_DEFAULT_REGION', 'eu-west-1'); - expect(core.exportVariable).toHaveBeenCalledWith('AWS_REGION', 'eu-west-1'); - expect(core.setOutput).toHaveBeenCalledWith('aws-account-id', FAKE_ACCOUNT_ID); - expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCOUNT_ID); - expect(aws.config.credentials.accessKeyId).toBe(FAKE_ACCESS_KEY_ID); - expect(aws.config.credentials.secretAccessKey).toBe(FAKE_SECRET_ACCESS_KEY); - expect(aws.config.credentials.sessionToken).toBeUndefined(); - }); - - test('validates region name', async () => { - process.env.SHOW_STACK_TRACE = 'false'; - - const mockInputs = {...CREDS_INPUTS, 'aws-region': '$AWS_REGION'}; - core.getInput = jest - .fn() - .mockImplementation(mockGetInput(mockInputs)); - - await run(); - - expect(core.setFailed).toHaveBeenCalledWith('Region is not valid: $AWS_REGION'); - }); - - test('throws error if access key id exists but missing secret access key', async () => { - process.env.SHOW_STACK_TRACE = 'false'; - const inputsWIthoutSecretKey = {...ASSUME_ROLE_INPUTS} - inputsWIthoutSecretKey["aws-secret-access-key"] = undefined - core.getInput = jest - .fn() - .mockImplementation(mockGetInput(inputsWIthoutSecretKey)); - - await run(); - expect(core.setFailed).toHaveBeenCalledWith("'aws-secret-access-key' must be provided if 'aws-access-key-id' is provided"); - - }); - - test('can opt out of masking account ID', async () => { - const mockInputs = {...CREDS_INPUTS, 'aws-region': 'us-east-1', 'mask-aws-account-id': 'false'}; - core.getInput = jest - .fn() - .mockImplementation(mockGetInput(mockInputs)); - - await run(); - expect(mockStsAssumeRole).toHaveBeenCalledTimes(0); - expect(core.exportVariable).toHaveBeenCalledTimes(4); - expect(core.exportVariable).toHaveBeenCalledWith('AWS_ACCESS_KEY_ID', FAKE_ACCESS_KEY_ID); - expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCESS_KEY_ID); - expect(core.exportVariable).toHaveBeenCalledWith('AWS_SECRET_ACCESS_KEY', FAKE_SECRET_ACCESS_KEY); - expect(core.setSecret).toHaveBeenCalledWith(FAKE_SECRET_ACCESS_KEY); - expect(core.exportVariable).toHaveBeenCalledWith('AWS_DEFAULT_REGION', 'us-east-1'); - expect(core.exportVariable).toHaveBeenCalledWith('AWS_REGION', 'us-east-1'); - expect(core.setOutput).toHaveBeenCalledWith('aws-account-id', FAKE_ACCOUNT_ID); - expect(core.setSecret).toHaveBeenCalledTimes(2); - }); - - test('error is caught by core.setFailed and caught', async () => { - process.env.SHOW_STACK_TRACE = 'false'; - - mockStsCallerIdentity.mockReset(); - mockStsCallerIdentity.mockImplementation(() => { - throw new Error(); - }); - - await run(); - - expect(core.setFailed).toBeCalled(); - }); - - test('error is caught by core.setFailed and passed', async () => { - - mockStsCallerIdentity.mockReset(); - mockStsCallerIdentity.mockImplementation(() => { - throw new Error(); - }); - - await assert.rejects(() => run()); - - expect(core.setFailed).toBeCalled(); - }); - - test('basic role assumption exports', async () => { - core.getInput = jest - .fn() - .mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS)); - - await run(); - expect(mockStsAssumeRole).toHaveBeenCalledTimes(1); - expect(core.exportVariable).toHaveBeenCalledTimes(7); - expect(core.setSecret).toHaveBeenCalledTimes(7); - expect(core.setOutput).toHaveBeenCalledTimes(2); - - // first the source credentials are exported and masked - expect(core.setSecret).toHaveBeenNthCalledWith(1, FAKE_ACCESS_KEY_ID); - expect(core.setSecret).toHaveBeenNthCalledWith(2, FAKE_SECRET_ACCESS_KEY); - expect(core.setSecret).toHaveBeenNthCalledWith(3, FAKE_ACCOUNT_ID); - - expect(core.exportVariable).toHaveBeenNthCalledWith(1, 'AWS_DEFAULT_REGION', FAKE_REGION); - expect(core.exportVariable).toHaveBeenNthCalledWith(2, 'AWS_REGION', FAKE_REGION); - expect(core.exportVariable).toHaveBeenNthCalledWith(3, 'AWS_ACCESS_KEY_ID', FAKE_ACCESS_KEY_ID); - expect(core.exportVariable).toHaveBeenNthCalledWith(4, 'AWS_SECRET_ACCESS_KEY', FAKE_SECRET_ACCESS_KEY); - - expect(core.setOutput).toHaveBeenNthCalledWith(1, 'aws-account-id', FAKE_ACCOUNT_ID); - - // then the role credentials are exported and masked - expect(core.setSecret).toHaveBeenNthCalledWith(4, FAKE_STS_ACCESS_KEY_ID); - expect(core.setSecret).toHaveBeenNthCalledWith(5, FAKE_STS_SECRET_ACCESS_KEY); - expect(core.setSecret).toHaveBeenNthCalledWith(6, FAKE_STS_SESSION_TOKEN); - expect(core.setSecret).toHaveBeenNthCalledWith(7, FAKE_ROLE_ACCOUNT_ID); - - expect(core.exportVariable).toHaveBeenNthCalledWith(5, 'AWS_ACCESS_KEY_ID', FAKE_STS_ACCESS_KEY_ID); - expect(core.exportVariable).toHaveBeenNthCalledWith(6, 'AWS_SECRET_ACCESS_KEY', FAKE_STS_SECRET_ACCESS_KEY); - expect(core.exportVariable).toHaveBeenNthCalledWith(7, 'AWS_SESSION_TOKEN', FAKE_STS_SESSION_TOKEN); - - expect(core.setOutput).toHaveBeenNthCalledWith(2, 'aws-account-id', FAKE_ROLE_ACCOUNT_ID); - }); - - test('assume role can pull source credentials from self-hosted environment', async () => { - core.getInput = jest - .fn() - .mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION})); - - await run(); - expect(mockStsAssumeRole).toHaveBeenCalledTimes(1); - expect(core.exportVariable).toHaveBeenCalledTimes(5); - expect(core.setSecret).toHaveBeenCalledTimes(5); - expect(core.setOutput).toHaveBeenCalledTimes(2); - - // first the source account is exported and masked - expect(core.setSecret).toHaveBeenNthCalledWith(1, FAKE_ACCOUNT_ID); - expect(core.exportVariable).toHaveBeenNthCalledWith(1, 'AWS_DEFAULT_REGION', FAKE_REGION); - expect(core.exportVariable).toHaveBeenNthCalledWith(2, 'AWS_REGION', FAKE_REGION); - expect(core.setOutput).toHaveBeenNthCalledWith(1, 'aws-account-id', FAKE_ACCOUNT_ID); - - // then the role credentials are exported and masked - expect(core.setSecret).toHaveBeenNthCalledWith(2, FAKE_STS_ACCESS_KEY_ID); - expect(core.setSecret).toHaveBeenNthCalledWith(3, FAKE_STS_SECRET_ACCESS_KEY); - expect(core.setSecret).toHaveBeenNthCalledWith(4, FAKE_STS_SESSION_TOKEN); - expect(core.setSecret).toHaveBeenNthCalledWith(5, FAKE_ROLE_ACCOUNT_ID); - - expect(core.exportVariable).toHaveBeenNthCalledWith(3, 'AWS_ACCESS_KEY_ID', FAKE_STS_ACCESS_KEY_ID); - expect(core.exportVariable).toHaveBeenNthCalledWith(4, 'AWS_SECRET_ACCESS_KEY', FAKE_STS_SECRET_ACCESS_KEY); - expect(core.exportVariable).toHaveBeenNthCalledWith(5, 'AWS_SESSION_TOKEN', FAKE_STS_SESSION_TOKEN); - - expect(core.setOutput).toHaveBeenNthCalledWith(2, 'aws-account-id', FAKE_ROLE_ACCOUNT_ID); - }); - - test('role assumption tags', async () => { - core.getInput = jest - .fn() - .mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS)); - - await run(); - expect(mockStsAssumeRole).toHaveBeenCalledWith({ - RoleArn: ROLE_ARN, - RoleSessionName: 'GitHubActions', - DurationSeconds: 6 * 3600, - Tags: [ - {Key: 'GitHub', Value: 'Actions'}, - {Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY}, - {Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW}, - {Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION}, - {Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED}, - {Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA}, - {Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF}, - ] - }) - }); - - test('role assumption duration provided', async () => { - core.getInput = jest - .fn() - .mockImplementation(mockGetInput({...ASSUME_ROLE_INPUTS, 'role-duration-seconds': 5})); - - await run(); - expect(mockStsAssumeRole).toHaveBeenCalledWith({ - RoleArn: ROLE_ARN, - RoleSessionName: 'GitHubActions', - DurationSeconds: 5, - Tags: [ - {Key: 'GitHub', Value: 'Actions'}, - {Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY}, - {Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW}, - {Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION}, - {Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED}, - {Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA}, - {Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF}, - ] - }) - }); - - test('role assumption session name provided', async () => { - core.getInput = jest - .fn() - .mockImplementation(mockGetInput({...ASSUME_ROLE_INPUTS, 'role-session-name': 'MySessionName'})); - - await run(); - expect(mockStsAssumeRole).toHaveBeenCalledWith({ - RoleArn: ROLE_ARN, - RoleSessionName: 'MySessionName', - DurationSeconds: 6 * 3600, - Tags: [ - {Key: 'GitHub', Value: 'Actions'}, - {Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY}, - {Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW}, - {Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION}, - {Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED}, - {Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA}, - {Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF}, - ] - }) - }); - - test('sets durationSeconds to one hour when session token provided and no duration is provided', async () => { - core.getInput = jest - .fn() - .mockImplementation(mockGetInput({...ASSUME_ROLE_INPUTS, 'aws-session-token': FAKE_SESSION_TOKEN})); - - await run(); - expect(mockStsAssumeRole).toHaveBeenCalledWith({ - RoleArn: ROLE_ARN, - RoleSessionName: 'GitHubActions', - DurationSeconds: 3600, - Tags: [ - {Key: 'GitHub', Value: 'Actions'}, - {Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY}, - {Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW}, - {Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION}, - {Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED}, - {Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA}, - {Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF}, - ] - }) - }); - - test('sets durationSeconds to one 6 hours no session token or duration is provided', async () => { - core.getInput = jest - .fn() - .mockImplementation(mockGetInput({...ASSUME_ROLE_INPUTS})); - - await run(); - expect(mockStsAssumeRole).toHaveBeenCalledWith({ - RoleArn: ROLE_ARN, - RoleSessionName: 'GitHubActions', - DurationSeconds: 6 * 3600, - Tags: [ - {Key: 'GitHub', Value: 'Actions'}, - {Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY}, - {Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW}, - {Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION}, - {Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED}, - {Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA}, - {Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF}, - ] - }) - }); - - test('role name provided instead of ARN', async () => { - core.getInput = jest - .fn() - .mockImplementation(mockGetInput({...CREDS_INPUTS, 'role-to-assume': ROLE_NAME, 'aws-region': FAKE_REGION})); - - await run(); - expect(mockStsAssumeRole).toHaveBeenCalledWith({ - RoleArn: 'arn:aws:iam::123456789012:role/MY-ROLE', - RoleSessionName: 'GitHubActions', - DurationSeconds: 6 * 3600, - Tags: [ - {Key: 'GitHub', Value: 'Actions'}, - {Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY}, - {Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW}, - {Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION}, - {Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED}, - {Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA}, - {Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF}, - ] - }) - }); - - test('web identity token file provided with absolute path', async () => { - core.getInput = jest - .fn() - .mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION, 'web-identity-token-file': '/fake/token/file'})); +describe("Configure AWS Credentials", () => { + beforeEach(() => { + jest.resetModules(); + process.env = { ...ENVIRONMENT_VARIABLE_OVERRIDES }; - await run(); - expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledWith({ - RoleArn: 'arn:aws:iam::111111111111:role/MY-ROLE', - RoleSessionName: 'GitHubActions', - DurationSeconds: 6 * 3600, - WebIdentityToken: 'testpayload' - }) - }); + jest.clearAllMocks(); - test('web identity token file provided with relative path', async () => { - core.getInput = jest - .fn() - .mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION, 'web-identity-token-file': 'fake/token/file'})); + core.getInput = jest.fn().mockImplementation(mockGetInput(DEFAULT_INPUTS)); - await run(); - expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledWith({ - RoleArn: 'arn:aws:iam::111111111111:role/MY-ROLE', - RoleSessionName: 'GitHubActions', - DurationSeconds: 6 * 3600, - WebIdentityToken: 'testpayload' - }) + core.getIDToken = jest.fn().mockImplementation(() => { + return "testtoken"; }); - test('only role arn and region provided to use GH OIDC Token', async () => { - process.env.GITHUB_ACTIONS = 'true'; - process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token'; + mockStsCallerIdentity.mockReset(); + mockStsCallerIdentity + .mockReturnValueOnce({ + promise() { + return Promise.resolve({ Account: FAKE_ACCOUNT_ID }); + }, + }) + .mockReturnValueOnce({ + promise() { + return Promise.resolve({ Account: FAKE_ROLE_ACCOUNT_ID }); + }, + }); + + aws.config.getCredentials.mockReset(); + aws.config.getCredentials + .mockImplementationOnce((callback) => { + if (!aws.config.credentials) { + aws.config.credentials = { + accessKeyId: FAKE_ACCESS_KEY_ID, + secretAccessKey: FAKE_SECRET_ACCESS_KEY, + }; + } + callback(null); + }) + .mockImplementationOnce((callback) => { + if (!aws.config.credentials) { + aws.config.credentials = { + accessKeyId: FAKE_STS_ACCESS_KEY_ID, + secretAccessKey: FAKE_STS_SECRET_ACCESS_KEY, + }; + } + callback(null); + }); + + aws.config.update.mockReset(); + aws.config.update.mockImplementationOnce(); + + mockStsAssumeRole.mockImplementation(() => { + return { + promise() { + return Promise.resolve({ + Credentials: { + AccessKeyId: FAKE_STS_ACCESS_KEY_ID, + SecretAccessKey: FAKE_STS_SECRET_ACCESS_KEY, + SessionToken: FAKE_STS_SESSION_TOKEN, + }, + }); + }, + }; + }); + + mockStsAssumeRoleWithWebIdentity.mockImplementation(() => { + return { + promise() { + return Promise.resolve({ + Credentials: { + AccessKeyId: FAKE_STS_ACCESS_KEY_ID, + SecretAccessKey: FAKE_STS_SECRET_ACCESS_KEY, + SessionToken: FAKE_STS_SESSION_TOKEN, + }, + }); + }, + }; + }); + + withSleep(() => { + return Promise.resolve(); + }); + }); + + afterEach(() => { + reset(); + }); + + test("exports env vars", async () => { + await run(); + expect(mockStsAssumeRole).toHaveBeenCalledTimes(0); + expect(core.exportVariable).toHaveBeenCalledTimes(5); + expect(core.setSecret).toHaveBeenCalledTimes(4); + expect(core.exportVariable).toHaveBeenCalledWith("AWS_ACCESS_KEY_ID", FAKE_ACCESS_KEY_ID); + expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCESS_KEY_ID); + expect(core.exportVariable).toHaveBeenCalledWith("AWS_SECRET_ACCESS_KEY", FAKE_SECRET_ACCESS_KEY); + expect(core.setSecret).toHaveBeenCalledWith(FAKE_SECRET_ACCESS_KEY); + expect(core.exportVariable).toHaveBeenCalledWith("AWS_SESSION_TOKEN", FAKE_SESSION_TOKEN); + expect(core.setSecret).toHaveBeenCalledWith(FAKE_SESSION_TOKEN); + expect(core.exportVariable).toHaveBeenCalledWith("AWS_DEFAULT_REGION", FAKE_REGION); + expect(core.exportVariable).toHaveBeenCalledWith("AWS_REGION", FAKE_REGION); + expect(core.setOutput).toHaveBeenCalledWith("aws-account-id", FAKE_ACCOUNT_ID); + expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCOUNT_ID); + }); + + test("action fails when github env vars are not set", async () => { + process.env.SHOW_STACK_TRACE = "false"; + core.getInput = jest.fn().mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS)); + delete process.env.GITHUB_SHA; + + await run(); + expect(core.setFailed).toHaveBeenCalledWith( + "Missing required environment value. Are you running in GitHub Actions?", + ); + }); + + test("action does not require GITHUB_REF env var", async () => { + core.getInput = jest.fn().mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS)); + delete process.env.GITHUB_REF; + + await run(); + }); + + test("hosted runners can pull creds from a self-hosted environment", async () => { + const mockInputs = { "aws-region": FAKE_REGION }; + core.getInput = jest.fn().mockImplementation(mockGetInput(mockInputs)); + + await run(); + expect(mockStsAssumeRole).toHaveBeenCalledTimes(0); + expect(core.exportVariable).toHaveBeenCalledTimes(2); + expect(core.setSecret).toHaveBeenCalledTimes(1); + expect(core.exportVariable).toHaveBeenCalledWith("AWS_DEFAULT_REGION", FAKE_REGION); + expect(core.exportVariable).toHaveBeenCalledWith("AWS_REGION", FAKE_REGION); + expect(core.setOutput).toHaveBeenCalledWith("aws-account-id", FAKE_ACCOUNT_ID); + expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCOUNT_ID); + }); + + test("action with no accessible credentials fails", async () => { + process.env.SHOW_STACK_TRACE = "false"; + const mockInputs = { "aws-region": FAKE_REGION }; + core.getInput = jest.fn().mockImplementation(mockGetInput(mockInputs)); + aws.config.getCredentials.mockReset(); + aws.config.getCredentials.mockImplementation((callback) => { + callback(new Error("No credentials to load")); + }); + + await run(); + + expect(core.setFailed).toHaveBeenCalledWith( + "Credentials could not be loaded, please check your action inputs: No credentials to load", + ); + }); + + test("action with empty credentials fails", async () => { + process.env.SHOW_STACK_TRACE = "false"; + const mockInputs = { "aws-region": FAKE_REGION }; + core.getInput = jest.fn().mockImplementation(mockGetInput(mockInputs)); + aws.config.getCredentials.mockReset(); + aws.config.getCredentials.mockImplementation((callback) => { + aws.config.credentials = { + accessKeyId: "", + }; + callback(null); + }); + + await run(); + + expect(core.setFailed).toHaveBeenCalledWith( + "Credentials could not be loaded, please check your action inputs: Access key ID empty after loading credentials", + ); + }); + + test("action fails when credentials are not set in the SDK correctly", async () => { + process.env.SHOW_STACK_TRACE = "false"; + core.getInput = jest.fn().mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS)); + aws.config.getCredentials.mockReset(); + aws.config.getCredentials.mockImplementation((callback) => { + aws.config.credentials = { + accessKeyId: FAKE_ACCESS_KEY_ID, + }; + callback(null); + }); + + await run(); + + expect(core.setFailed).toHaveBeenCalledWith( + "Unexpected failure: Credentials loaded by the SDK do not match the access key ID configured by the action", + ); + }); + + test("session token is optional", async () => { + const mockInputs = { ...CREDS_INPUTS, "aws-region": "eu-west-1" }; + core.getInput = jest.fn().mockImplementation(mockGetInput(mockInputs)); + + await run(); + expect(mockStsAssumeRole).toHaveBeenCalledTimes(0); + expect(core.exportVariable).toHaveBeenCalledTimes(4); + expect(core.setSecret).toHaveBeenCalledTimes(3); + expect(core.exportVariable).toHaveBeenCalledWith("AWS_ACCESS_KEY_ID", FAKE_ACCESS_KEY_ID); + expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCESS_KEY_ID); + expect(core.exportVariable).toHaveBeenCalledWith("AWS_SECRET_ACCESS_KEY", FAKE_SECRET_ACCESS_KEY); + expect(core.setSecret).toHaveBeenCalledWith(FAKE_SECRET_ACCESS_KEY); + expect(core.exportVariable).toHaveBeenCalledWith("AWS_DEFAULT_REGION", "eu-west-1"); + expect(core.exportVariable).toHaveBeenCalledWith("AWS_REGION", "eu-west-1"); + expect(core.setOutput).toHaveBeenCalledWith("aws-account-id", FAKE_ACCOUNT_ID); + expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCOUNT_ID); + }); + + test("existing env var creds are cleared", async () => { + const mockInputs = { ...CREDS_INPUTS, "aws-region": "eu-west-1" }; + core.getInput = jest.fn().mockImplementation(mockGetInput(mockInputs)); + process.env.AWS_ACCESS_KEY_ID = "foo"; + process.env.AWS_SECRET_ACCESS_KEY = "bar"; + process.env.AWS_SESSION_TOKEN = "helloworld"; + aws.config.credentials = { + accessKeyId: "foo", + secretAccessKey: "bar", + sessionToken: "helloworld", + }; - core.getInput = jest - .fn() - .mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION})); + await run(); + expect(mockStsAssumeRole).toHaveBeenCalledTimes(0); + expect(core.exportVariable).toHaveBeenCalledTimes(5); + expect(core.setSecret).toHaveBeenCalledTimes(3); + expect(core.exportVariable).toHaveBeenCalledWith("AWS_ACCESS_KEY_ID", FAKE_ACCESS_KEY_ID); + expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCESS_KEY_ID); + expect(core.exportVariable).toHaveBeenCalledWith("AWS_SECRET_ACCESS_KEY", FAKE_SECRET_ACCESS_KEY); + expect(core.setSecret).toHaveBeenCalledWith(FAKE_SECRET_ACCESS_KEY); + expect(core.exportVariable).toHaveBeenCalledWith("AWS_SESSION_TOKEN", ""); + expect(core.exportVariable).toHaveBeenCalledWith("AWS_DEFAULT_REGION", "eu-west-1"); + expect(core.exportVariable).toHaveBeenCalledWith("AWS_REGION", "eu-west-1"); + expect(core.setOutput).toHaveBeenCalledWith("aws-account-id", FAKE_ACCOUNT_ID); + expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCOUNT_ID); + expect(aws.config.credentials.accessKeyId).toBe(FAKE_ACCESS_KEY_ID); + expect(aws.config.credentials.secretAccessKey).toBe(FAKE_SECRET_ACCESS_KEY); + expect(aws.config.credentials.sessionToken).toBeUndefined(); + }); + + test("validates region name", async () => { + process.env.SHOW_STACK_TRACE = "false"; + + const mockInputs = { ...CREDS_INPUTS, "aws-region": "$AWS_REGION" }; + core.getInput = jest.fn().mockImplementation(mockGetInput(mockInputs)); + + await run(); + + expect(core.setFailed).toHaveBeenCalledWith("Region is not valid: $AWS_REGION"); + }); + + test("throws error if access key id exists but missing secret access key", async () => { + process.env.SHOW_STACK_TRACE = "false"; + const inputsWIthoutSecretKey = { ...ASSUME_ROLE_INPUTS }; + inputsWIthoutSecretKey["aws-secret-access-key"] = undefined; + core.getInput = jest.fn().mockImplementation(mockGetInput(inputsWIthoutSecretKey)); + + await run(); + expect(core.setFailed).toHaveBeenCalledWith( + "'aws-secret-access-key' must be provided if 'aws-access-key-id' is provided", + ); + }); + + test("can opt out of masking account ID", async () => { + const mockInputs = { ...CREDS_INPUTS, "aws-region": "us-east-1", "mask-aws-account-id": "false" }; + core.getInput = jest.fn().mockImplementation(mockGetInput(mockInputs)); + + await run(); + expect(mockStsAssumeRole).toHaveBeenCalledTimes(0); + expect(core.exportVariable).toHaveBeenCalledTimes(4); + expect(core.exportVariable).toHaveBeenCalledWith("AWS_ACCESS_KEY_ID", FAKE_ACCESS_KEY_ID); + expect(core.setSecret).toHaveBeenCalledWith(FAKE_ACCESS_KEY_ID); + expect(core.exportVariable).toHaveBeenCalledWith("AWS_SECRET_ACCESS_KEY", FAKE_SECRET_ACCESS_KEY); + expect(core.setSecret).toHaveBeenCalledWith(FAKE_SECRET_ACCESS_KEY); + expect(core.exportVariable).toHaveBeenCalledWith("AWS_DEFAULT_REGION", "us-east-1"); + expect(core.exportVariable).toHaveBeenCalledWith("AWS_REGION", "us-east-1"); + expect(core.setOutput).toHaveBeenCalledWith("aws-account-id", FAKE_ACCOUNT_ID); + expect(core.setSecret).toHaveBeenCalledTimes(2); + }); + + test("error is caught by core.setFailed and caught", async () => { + process.env.SHOW_STACK_TRACE = "false"; + + mockStsCallerIdentity.mockReset(); + mockStsCallerIdentity.mockImplementation(() => { + throw new Error(); + }); + + await run(); + + expect(core.setFailed).toBeCalled(); + }); + + test("error is caught by core.setFailed and passed", async () => { + mockStsCallerIdentity.mockReset(); + mockStsCallerIdentity.mockImplementation(() => { + throw new Error(); + }); + + await assert.rejects(() => run()); + + expect(core.setFailed).toBeCalled(); + }); + + test("basic role assumption exports", async () => { + core.getInput = jest.fn().mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS)); + + await run(); + expect(mockStsAssumeRole).toHaveBeenCalledTimes(1); + expect(core.exportVariable).toHaveBeenCalledTimes(7); + expect(core.setSecret).toHaveBeenCalledTimes(7); + expect(core.setOutput).toHaveBeenCalledTimes(2); + + // first the source credentials are exported and masked + expect(core.setSecret).toHaveBeenNthCalledWith(1, FAKE_ACCESS_KEY_ID); + expect(core.setSecret).toHaveBeenNthCalledWith(2, FAKE_SECRET_ACCESS_KEY); + expect(core.setSecret).toHaveBeenNthCalledWith(3, FAKE_ACCOUNT_ID); + + expect(core.exportVariable).toHaveBeenNthCalledWith(1, "AWS_DEFAULT_REGION", FAKE_REGION); + expect(core.exportVariable).toHaveBeenNthCalledWith(2, "AWS_REGION", FAKE_REGION); + expect(core.exportVariable).toHaveBeenNthCalledWith(3, "AWS_ACCESS_KEY_ID", FAKE_ACCESS_KEY_ID); + expect(core.exportVariable).toHaveBeenNthCalledWith(4, "AWS_SECRET_ACCESS_KEY", FAKE_SECRET_ACCESS_KEY); + + expect(core.setOutput).toHaveBeenNthCalledWith(1, "aws-account-id", FAKE_ACCOUNT_ID); + + // then the role credentials are exported and masked + expect(core.setSecret).toHaveBeenNthCalledWith(4, FAKE_STS_ACCESS_KEY_ID); + expect(core.setSecret).toHaveBeenNthCalledWith(5, FAKE_STS_SECRET_ACCESS_KEY); + expect(core.setSecret).toHaveBeenNthCalledWith(6, FAKE_STS_SESSION_TOKEN); + expect(core.setSecret).toHaveBeenNthCalledWith(7, FAKE_ROLE_ACCOUNT_ID); + + expect(core.exportVariable).toHaveBeenNthCalledWith(5, "AWS_ACCESS_KEY_ID", FAKE_STS_ACCESS_KEY_ID); + expect(core.exportVariable).toHaveBeenNthCalledWith(6, "AWS_SECRET_ACCESS_KEY", FAKE_STS_SECRET_ACCESS_KEY); + expect(core.exportVariable).toHaveBeenNthCalledWith(7, "AWS_SESSION_TOKEN", FAKE_STS_SESSION_TOKEN); + + expect(core.setOutput).toHaveBeenNthCalledWith(2, "aws-account-id", FAKE_ROLE_ACCOUNT_ID); + }); + + test("assume role can pull source credentials from self-hosted environment", async () => { + core.getInput = jest + .fn() + .mockImplementation(mockGetInput({ "role-to-assume": ROLE_ARN, "aws-region": FAKE_REGION })); + + await run(); + expect(mockStsAssumeRole).toHaveBeenCalledTimes(1); + expect(core.exportVariable).toHaveBeenCalledTimes(5); + expect(core.setSecret).toHaveBeenCalledTimes(5); + expect(core.setOutput).toHaveBeenCalledTimes(2); + + // first the source account is exported and masked + expect(core.setSecret).toHaveBeenNthCalledWith(1, FAKE_ACCOUNT_ID); + expect(core.exportVariable).toHaveBeenNthCalledWith(1, "AWS_DEFAULT_REGION", FAKE_REGION); + expect(core.exportVariable).toHaveBeenNthCalledWith(2, "AWS_REGION", FAKE_REGION); + expect(core.setOutput).toHaveBeenNthCalledWith(1, "aws-account-id", FAKE_ACCOUNT_ID); + + // then the role credentials are exported and masked + expect(core.setSecret).toHaveBeenNthCalledWith(2, FAKE_STS_ACCESS_KEY_ID); + expect(core.setSecret).toHaveBeenNthCalledWith(3, FAKE_STS_SECRET_ACCESS_KEY); + expect(core.setSecret).toHaveBeenNthCalledWith(4, FAKE_STS_SESSION_TOKEN); + expect(core.setSecret).toHaveBeenNthCalledWith(5, FAKE_ROLE_ACCOUNT_ID); + + expect(core.exportVariable).toHaveBeenNthCalledWith(3, "AWS_ACCESS_KEY_ID", FAKE_STS_ACCESS_KEY_ID); + expect(core.exportVariable).toHaveBeenNthCalledWith(4, "AWS_SECRET_ACCESS_KEY", FAKE_STS_SECRET_ACCESS_KEY); + expect(core.exportVariable).toHaveBeenNthCalledWith(5, "AWS_SESSION_TOKEN", FAKE_STS_SESSION_TOKEN); + + expect(core.setOutput).toHaveBeenNthCalledWith(2, "aws-account-id", FAKE_ROLE_ACCOUNT_ID); + }); + + test("role assumption tags", async () => { + core.getInput = jest.fn().mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS)); + + await run(); + expect(mockStsAssumeRole).toHaveBeenCalledWith({ + RoleArn: ROLE_ARN, + RoleSessionName: "GitHubActions", + DurationSeconds: 6 * 3600, + Tags: [ + { Key: "GitHub", Value: "Actions" }, + { Key: "Repository", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY }, + { Key: "Workflow", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW }, + { Key: "Action", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION }, + { Key: "Actor", Value: GITHUB_ACTOR_SANITIZED }, + { Key: "Commit", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA }, + { Key: "Branch", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF }, + ], + }); + }); + + test("role assumption duration provided", async () => { + core.getInput = jest.fn().mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS, "role-duration-seconds": 5 })); + + await run(); + expect(mockStsAssumeRole).toHaveBeenCalledWith({ + RoleArn: ROLE_ARN, + RoleSessionName: "GitHubActions", + DurationSeconds: 5, + Tags: [ + { Key: "GitHub", Value: "Actions" }, + { Key: "Repository", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY }, + { Key: "Workflow", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW }, + { Key: "Action", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION }, + { Key: "Actor", Value: GITHUB_ACTOR_SANITIZED }, + { Key: "Commit", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA }, + { Key: "Branch", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF }, + ], + }); + }); + + test("role assumption session name provided", async () => { + core.getInput = jest + .fn() + .mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS, "role-session-name": "MySessionName" })); + + await run(); + expect(mockStsAssumeRole).toHaveBeenCalledWith({ + RoleArn: ROLE_ARN, + RoleSessionName: "MySessionName", + DurationSeconds: 6 * 3600, + Tags: [ + { Key: "GitHub", Value: "Actions" }, + { Key: "Repository", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY }, + { Key: "Workflow", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW }, + { Key: "Action", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION }, + { Key: "Actor", Value: GITHUB_ACTOR_SANITIZED }, + { Key: "Commit", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA }, + { Key: "Branch", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF }, + ], + }); + }); + + test("sets durationSeconds to one hour when session token provided and no duration is provided", async () => { + core.getInput = jest + .fn() + .mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS, "aws-session-token": FAKE_SESSION_TOKEN })); + + await run(); + expect(mockStsAssumeRole).toHaveBeenCalledWith({ + RoleArn: ROLE_ARN, + RoleSessionName: "GitHubActions", + DurationSeconds: 3600, + Tags: [ + { Key: "GitHub", Value: "Actions" }, + { Key: "Repository", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY }, + { Key: "Workflow", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW }, + { Key: "Action", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION }, + { Key: "Actor", Value: GITHUB_ACTOR_SANITIZED }, + { Key: "Commit", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA }, + { Key: "Branch", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF }, + ], + }); + }); + + test("sets durationSeconds to one 6 hours no session token or duration is provided", async () => { + core.getInput = jest.fn().mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS })); + + await run(); + expect(mockStsAssumeRole).toHaveBeenCalledWith({ + RoleArn: ROLE_ARN, + RoleSessionName: "GitHubActions", + DurationSeconds: 6 * 3600, + Tags: [ + { Key: "GitHub", Value: "Actions" }, + { Key: "Repository", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY }, + { Key: "Workflow", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW }, + { Key: "Action", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION }, + { Key: "Actor", Value: GITHUB_ACTOR_SANITIZED }, + { Key: "Commit", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA }, + { Key: "Branch", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF }, + ], + }); + }); + + test("role name provided instead of ARN", async () => { + core.getInput = jest + .fn() + .mockImplementation(mockGetInput({ ...CREDS_INPUTS, "role-to-assume": ROLE_NAME, "aws-region": FAKE_REGION })); + + await run(); + expect(mockStsAssumeRole).toHaveBeenCalledWith({ + RoleArn: "arn:aws:iam::123456789012:role/MY-ROLE", + RoleSessionName: "GitHubActions", + DurationSeconds: 6 * 3600, + Tags: [ + { Key: "GitHub", Value: "Actions" }, + { Key: "Repository", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY }, + { Key: "Workflow", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW }, + { Key: "Action", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION }, + { Key: "Actor", Value: GITHUB_ACTOR_SANITIZED }, + { Key: "Commit", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA }, + { Key: "Branch", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF }, + ], + }); + }); + + test("web identity token file provided with absolute path", async () => { + core.getInput = jest.fn().mockImplementation( + mockGetInput({ + "role-to-assume": ROLE_ARN, + "aws-region": FAKE_REGION, + "web-identity-token-file": "/fake/token/file", + }), + ); + fs.promises.readFile.mockResolvedValueOnce("testpayload"); + + await run(); + expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledWith({ + RoleArn: "arn:aws:iam::111111111111:role/MY-ROLE", + RoleSessionName: "GitHubActions", + DurationSeconds: 6 * 3600, + WebIdentityToken: "testpayload", + }); + }); + + test("web identity token file provided with relative path", async () => { + core.getInput = jest.fn().mockImplementation( + mockGetInput({ + "role-to-assume": ROLE_ARN, + "aws-region": FAKE_REGION, + "web-identity-token-file": "fake/token/file", + }), + ); + fs.promises.readFile.mockResolvedValueOnce("testpayload"); + + await run(); + expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledWith({ + RoleArn: "arn:aws:iam::111111111111:role/MY-ROLE", + RoleSessionName: "GitHubActions", + DurationSeconds: 6 * 3600, + WebIdentityToken: "testpayload", + }); + }); + + test("web identity token file does not exist", async () => { + process.env.SHOW_STACK_TRACE = "false"; + core.getInput = jest.fn().mockImplementation( + mockGetInput({ + "role-to-assume": ROLE_ARN, + "aws-region": FAKE_REGION, + "web-identity-token-file": "fake/token/file", + }), + ); + + fs.existsSync.mockImplementation(() => { + return false; + }); + + await run(); + expect(core.setFailed).toHaveBeenCalledWith("Web identity token file does not exist: /home/github/fake/token/file"); + }); + + test("only role arn and region provided to use GH OIDC Token", async () => { + process.env.GITHUB_ACTIONS = "true"; + process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = "test-token"; + + core.getInput = jest + .fn() + .mockImplementation(mockGetInput({ "role-to-assume": ROLE_ARN, "aws-region": FAKE_REGION })); + + await run(); + expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledWith({ + RoleArn: "arn:aws:iam::111111111111:role/MY-ROLE", + RoleSessionName: "GitHubActions", + DurationSeconds: 3600, + WebIdentityToken: "testtoken", + }); + + expect(core.exportVariable).toHaveBeenCalledTimes(5); + expect(core.setSecret).toHaveBeenCalledTimes(4); + expect(core.setOutput).toHaveBeenCalledTimes(1); + + expect(core.setSecret).toHaveBeenNthCalledWith(1, FAKE_STS_ACCESS_KEY_ID); + expect(core.setSecret).toHaveBeenNthCalledWith(2, FAKE_STS_SECRET_ACCESS_KEY); + expect(core.setSecret).toHaveBeenNthCalledWith(3, FAKE_STS_SESSION_TOKEN); + }); + + test("GH OIDC With custom role duration", async () => { + const CUSTOM_ROLE_DURATION = 1234; + process.env.GITHUB_ACTIONS = "true"; + process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = "test-token"; + core.getInput = jest.fn().mockImplementation( + mockGetInput({ + "role-to-assume": ROLE_ARN, + "aws-region": FAKE_REGION, + "role-duration-seconds": CUSTOM_ROLE_DURATION, + }), + ); + + await run(); + expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledWith({ + RoleArn: "arn:aws:iam::111111111111:role/MY-ROLE", + RoleSessionName: "GitHubActions", + DurationSeconds: CUSTOM_ROLE_DURATION, + WebIdentityToken: "testtoken", + }); + expect(core.setSecret).toHaveBeenNthCalledWith(1, FAKE_STS_ACCESS_KEY_ID); + expect(core.setSecret).toHaveBeenNthCalledWith(2, FAKE_STS_SECRET_ACCESS_KEY); + expect(core.setSecret).toHaveBeenNthCalledWith(3, FAKE_STS_SESSION_TOKEN); + }); + + test("role assumption fails after maximun trials using OIDC Provider", async () => { + process.env.GITHUB_ACTIONS = "true"; + process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = "test-token"; + + core.getInput = jest + .fn() + .mockImplementation(mockGetInput({ "role-to-assume": ROLE_ARN, "aws-region": FAKE_REGION })); + + mockStsAssumeRoleWithWebIdentity.mockReset(); + mockStsAssumeRoleWithWebIdentity.mockImplementation(() => { + throw new Error(); + }); + + await assert.rejects(() => run()); + expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledTimes(12); + }); + + test("role external ID provided", async () => { + core.getInput = jest.fn().mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS, "role-external-id": "abcdef" })); + + await run(); + expect(mockStsAssumeRole).toHaveBeenCalledWith({ + RoleArn: ROLE_ARN, + RoleSessionName: "GitHubActions", + DurationSeconds: 6 * 3600, + Tags: [ + { Key: "GitHub", Value: "Actions" }, + { Key: "Repository", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY }, + { Key: "Workflow", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW }, + { Key: "Action", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION }, + { Key: "Actor", Value: GITHUB_ACTOR_SANITIZED }, + { Key: "Commit", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA }, + { Key: "Branch", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF }, + ], + ExternalId: "abcdef", + }); + }); + + test("workflow name sanitized in role assumption tags", async () => { + core.getInput = jest.fn().mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS)); + + process.env = { + ...process.env, + GITHUB_WORKFLOW: + "Workflow!\"#$%&'()*+, -./:;<=>?@[]^_`{|}~🙂💥🍌1yFvMOeD3ZHYsHrGjCceOboMYzBPo0CRNFdcsVRG6UgR3A912a8KfcBtEVvkAS7kRBq80umGff8mux5IN1y55HQWPNBNyaruuVr4islFXte4FDQZexGJRUSMyHQpxJ8OmZnET84oDmbvmIjgxI6IBrdihX9PHMapT4gQvRYnLqNiKb18rEMWDNoZRy51UPX5sWK2GKPipgKSO9kqLckZai9D2AN2RlWCxtMqChNtxuxjqeqhoQZo0oaq39sjcRZgAAAAAAA", + }; - await run(); - expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledWith({ - RoleArn: 'arn:aws:iam::111111111111:role/MY-ROLE', - RoleSessionName: 'GitHubActions', - DurationSeconds: 3600, - WebIdentityToken: 'testtoken' - }); - expect(core.setSecret).toHaveBeenNthCalledWith(1, FAKE_STS_ACCESS_KEY_ID); - expect(core.setSecret).toHaveBeenNthCalledWith(2, FAKE_STS_SECRET_ACCESS_KEY); - expect(core.setSecret).toHaveBeenNthCalledWith(3, FAKE_STS_SESSION_TOKEN); - }); - - test('GH OIDC With custom role duration', async () => { - const CUSTOM_ROLE_DURATION = 1234; - process.env.GITHUB_ACTIONS = 'true'; - process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token'; - core.getInput = jest - .fn() - .mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION, 'role-duration-seconds': CUSTOM_ROLE_DURATION})); - - await run(); - expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledWith({ - RoleArn: 'arn:aws:iam::111111111111:role/MY-ROLE', - RoleSessionName: 'GitHubActions', - DurationSeconds: CUSTOM_ROLE_DURATION, - WebIdentityToken: 'testtoken' - }); - expect(core.setSecret).toHaveBeenNthCalledWith(1, FAKE_STS_ACCESS_KEY_ID); - expect(core.setSecret).toHaveBeenNthCalledWith(2, FAKE_STS_SECRET_ACCESS_KEY); - expect(core.setSecret).toHaveBeenNthCalledWith(3, FAKE_STS_SESSION_TOKEN); + const sanitizedWorkflowName = + "Workflow__________+_ -./:;<=>?@____________1yFvMOeD3ZHYsHrGjCceOboMYzBPo0CRNFdcsVRG6UgR3A912a8KfcBtEVvkAS7kRBq80umGff8mux5IN1y55HQWPNBNyaruuVr4islFXte4FDQZexGJRUSMyHQpxJ8OmZnET84oDmbvmIjgxI6IBrdihX9PHMapT4gQvRYnLqNiKb18rEMWDNoZRy51UPX5sWK2GKPipgKSO9kqLckZa"; + + await run(); + expect(mockStsAssumeRole).toHaveBeenCalledWith({ + RoleArn: ROLE_ARN, + RoleSessionName: "GitHubActions", + DurationSeconds: 6 * 3600, + Tags: [ + { Key: "GitHub", Value: "Actions" }, + { Key: "Repository", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY }, + { Key: "Workflow", Value: sanitizedWorkflowName }, + { Key: "Action", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION }, + { Key: "Actor", Value: GITHUB_ACTOR_SANITIZED }, + { Key: "Commit", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA }, + { Key: "Branch", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF }, + ], + }); + }); + + test("skip tagging provided as true", async () => { + core.getInput = jest + .fn() + .mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS, "role-skip-session-tagging": "true" })); + + await run(); + expect(mockStsAssumeRole).toHaveBeenCalledWith({ + RoleArn: ROLE_ARN, + RoleSessionName: "GitHubActions", + DurationSeconds: 21600, + Tags: undefined, + }); + }); + + test("skip tagging provided as false", async () => { + core.getInput = jest + .fn() + .mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS, "role-skip-session-tagging": "false" })); + + await run(); + expect(mockStsAssumeRole).toHaveBeenCalledWith({ + RoleArn: ROLE_ARN, + RoleSessionName: "GitHubActions", + DurationSeconds: 21600, + Tags: [ + { Key: "GitHub", Value: "Actions" }, + { Key: "Repository", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY }, + { Key: "Workflow", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW }, + { Key: "Action", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION }, + { Key: "Actor", Value: GITHUB_ACTOR_SANITIZED }, + { Key: "Commit", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA }, + { Key: "Branch", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF }, + ], + }); + }); + + test("skip tagging not provided", async () => { + core.getInput = jest.fn().mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS })); + + await run(); + expect(mockStsAssumeRole).toHaveBeenCalledWith({ + RoleArn: ROLE_ARN, + RoleSessionName: "GitHubActions", + DurationSeconds: 21600, + Tags: [ + { Key: "GitHub", Value: "Actions" }, + { Key: "Repository", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY }, + { Key: "Workflow", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW }, + { Key: "Action", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION }, + { Key: "Actor", Value: GITHUB_ACTOR_SANITIZED }, + { Key: "Commit", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA }, + { Key: "Branch", Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF }, + ], + }); + }); + + test("masks variables before exporting", async () => { + let maskedValues = []; + const publicFields = [ + "AWS_REGION", + "AWS_DEFAULT_REGION", + "AWS_PROFILE", + "AWS_SHARED_CREDENTIALS_FILE", + "AWS_CONFIG_FILE", + ]; + core.setSecret.mockReset(); + core.setSecret.mockImplementation((secret) => { + maskedValues.push(secret); + }); + + core.exportVariable.mockReset(); + core.exportVariable.mockImplementation((name, value) => { + if (!maskedValues.includes(value) && !publicFields.includes(name)) { + throw new Error(value + " for variable " + name + " is not masked yet!"); + } + }); + + core.getInput = jest.fn().mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS)); + + await run(); + }); + + describe("proxy settings", () => { + test("setting proxy with actions input", async () => { + const EXPECTED_PROXY = "http://test.me"; + core.getInput = jest.fn().mockImplementation(mockGetInput({ ...DEFAULT_INPUTS, "http-proxy": EXPECTED_PROXY })); + + await run(); + + expect(aws.config.update).toHaveBeenCalledTimes(1); + expect(aws.config.update).toHaveBeenCalledWith({ + httpOptions: { agent: proxy(EXPECTED_PROXY) }, + }); + }); + test("setting proxy from environment vars", async () => { + const EXPECTED_PROXY = "http://test.me"; + process.env.HTTP_PROXY = EXPECTED_PROXY; + core.getInput = jest.fn().mockImplementation(mockGetInput({ ...DEFAULT_INPUTS })); + + await run(); + + expect(aws.config.update).toHaveBeenCalledTimes(1); + expect(aws.config.update).toHaveBeenCalledWith({ + httpOptions: { agent: proxy(EXPECTED_PROXY) }, + }); + }); + + test("setting proxy - prefer action input", async () => { + const EXPECTED_PROXY = "http://test.me"; + const FALSE_PROXY = "http://env.me"; + process.env.HTTP_PROXY = FALSE_PROXY; + core.getInput = jest.fn().mockImplementation(mockGetInput({ ...DEFAULT_INPUTS, "http-proxy": EXPECTED_PROXY })); + + await run(); + + expect(aws.config.update).toHaveBeenCalledTimes(1); + expect(aws.config.update).toHaveBeenCalledWith({ + httpOptions: { agent: proxy(EXPECTED_PROXY) }, + }); + }); + + test("ignoring proxy - without anything set", async () => { + core.getInput = jest.fn().mockImplementation(mockGetInput({ ...DEFAULT_INPUTS })); + + await run(); + + expect(aws.config.update).toHaveBeenCalledTimes(0); + }); + }); + + describe("Profile Support", () => { + test("use profile and save credentials file", async () => { + process.env = { + ...ENVIRONMENT_VARIABLE_OVERRIDES, + AWS_ACCESS_KEY_ID: undefined, + AWS_SECRET_ACCESS_KEY: undefined, + }; + + core.getInput = jest.fn().mockImplementation(mockGetInput(PROFILE_INPUTS)); + await run(); + + // Don't export aws credentials + expect(core.exportVariable).toHaveBeenCalledTimes(5); + expect(core.exportVariable).toHaveBeenNthCalledWith(1, "AWS_DEFAULT_REGION", FAKE_REGION); + expect(core.exportVariable).toHaveBeenNthCalledWith(2, "AWS_REGION", FAKE_REGION); + expect(core.exportVariable).toHaveBeenNthCalledWith(3, "AWS_PROFILE", PROFILE_INPUTS["aws-profile"]); + expect(core.exportVariable).toHaveBeenNthCalledWith(4, "AWS_SHARED_CREDENTIALS_FILE", "/home/.aws/credentials"); + expect(core.exportVariable).toHaveBeenNthCalledWith(5, "AWS_CONFIG_FILE", "/home/.aws/config"); + + expect(fs.promises.writeFile).toHaveBeenCalledTimes(2); + expect(fs.promises.writeFile).toHaveBeenNthCalledWith(1, "/home/.aws/config", expect.toMatchSnapshot()); + expect(fs.promises.writeFile).toHaveBeenNthCalledWith(2, "/home/.aws/credentials", expect.toMatchSnapshot()); }); - test('role assumption fails after maximun trials using OIDC Provider', async () => { - process.env.GITHUB_ACTIONS = 'true'; - process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token'; - - core.getInput = jest - .fn() - .mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION})); + test("only role arn and region provided to use GH OIDC Token", async () => { + process.env.GITHUB_ACTIONS = "true"; + process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = "test-token"; - mockStsAssumeRoleWithWebIdentity.mockReset(); - mockStsAssumeRoleWithWebIdentity.mockImplementation(() => { - throw new Error(); - }); - - await assert.rejects(() => run()); - expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledTimes(12) - }); - - test('role external ID provided', async () => { - core.getInput = jest - .fn() - .mockImplementation(mockGetInput({...ASSUME_ROLE_INPUTS, 'role-external-id': 'abcdef'})); - - await run(); - expect(mockStsAssumeRole).toHaveBeenCalledWith({ - RoleArn: ROLE_ARN, - RoleSessionName: 'GitHubActions', - DurationSeconds: 6 * 3600, - Tags: [ - {Key: 'GitHub', Value: 'Actions'}, - {Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY}, - {Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW}, - {Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION}, - {Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED}, - {Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA}, - {Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF}, - ], - ExternalId: 'abcdef' - }) - }); - - test('workflow name sanitized in role assumption tags', async () => { - core.getInput = jest - .fn() - .mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS)); - - process.env = {...process.env, GITHUB_WORKFLOW: 'Workflow!"#$%&\'()*+, -./:;<=>?@[]^_`{|}~🙂💥🍌1yFvMOeD3ZHYsHrGjCceOboMYzBPo0CRNFdcsVRG6UgR3A912a8KfcBtEVvkAS7kRBq80umGff8mux5IN1y55HQWPNBNyaruuVr4islFXte4FDQZexGJRUSMyHQpxJ8OmZnET84oDmbvmIjgxI6IBrdihX9PHMapT4gQvRYnLqNiKb18rEMWDNoZRy51UPX5sWK2GKPipgKSO9kqLckZai9D2AN2RlWCxtMqChNtxuxjqeqhoQZo0oaq39sjcRZgAAAAAAA'}; - - const sanitizedWorkflowName = 'Workflow__________+_ -./:;<=>?@____________1yFvMOeD3ZHYsHrGjCceOboMYzBPo0CRNFdcsVRG6UgR3A912a8KfcBtEVvkAS7kRBq80umGff8mux5IN1y55HQWPNBNyaruuVr4islFXte4FDQZexGJRUSMyHQpxJ8OmZnET84oDmbvmIjgxI6IBrdihX9PHMapT4gQvRYnLqNiKb18rEMWDNoZRy51UPX5sWK2GKPipgKSO9kqLckZa' - - await run(); - expect(mockStsAssumeRole).toHaveBeenCalledWith({ - RoleArn: ROLE_ARN, - RoleSessionName: 'GitHubActions', - DurationSeconds: 6 * 3600, - Tags: [ - {Key: 'GitHub', Value: 'Actions'}, - {Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY}, - {Key: 'Workflow', Value: sanitizedWorkflowName}, - {Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION}, - {Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED}, - {Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA}, - {Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF}, - ] - }) - }); + core.getInput = jest.fn().mockImplementation(mockGetInput(PROFILE_INPUTS)); + await run(); - test('skip tagging provided as true', async () => { - core.getInput = jest - .fn() - .mockImplementation(mockGetInput({...ASSUME_ROLE_INPUTS, 'role-skip-session-tagging': 'true'})); + // Don't export aws credentials + expect(core.exportVariable).toHaveBeenCalledTimes(5); + expect(core.exportVariable).toHaveBeenNthCalledWith(1, "AWS_DEFAULT_REGION", FAKE_REGION); + expect(core.exportVariable).toHaveBeenNthCalledWith(2, "AWS_REGION", FAKE_REGION); + expect(core.exportVariable).toHaveBeenNthCalledWith(3, "AWS_PROFILE", PROFILE_INPUTS["aws-profile"]); + expect(core.exportVariable).toHaveBeenNthCalledWith(4, "AWS_SHARED_CREDENTIALS_FILE", "/home/.aws/credentials"); + expect(core.exportVariable).toHaveBeenNthCalledWith(5, "AWS_CONFIG_FILE", "/home/.aws/config"); - await run(); - expect(mockStsAssumeRole).toHaveBeenCalledWith({ - RoleArn: ROLE_ARN, - RoleSessionName: 'GitHubActions', - DurationSeconds: 21600, - Tags: undefined - }) + expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledWith({ + RoleArn: "arn:aws:iam::111111111111:role/MY-ROLE", + RoleSessionName: "GitHubActions", + DurationSeconds: 3600, + WebIdentityToken: "testtoken", + }); + expect(fs.promises.writeFile).toHaveBeenCalledTimes(2); + expect(fs.promises.writeFile).toHaveBeenNthCalledWith(1, "/home/.aws/config", expect.toMatchSnapshot()); + expect(fs.promises.writeFile).toHaveBeenNthCalledWith(2, "/home/.aws/credentials", expect.toMatchSnapshot()); }); - test('skip tagging provided as false', async () => { - core.getInput = jest - .fn() - .mockImplementation(mockGetInput({...ASSUME_ROLE_INPUTS, 'role-skip-session-tagging': 'false'})); - - await run(); - expect(mockStsAssumeRole).toHaveBeenCalledWith({ - RoleArn: ROLE_ARN, - RoleSessionName: 'GitHubActions', - DurationSeconds: 21600, - Tags: [ - {Key: 'GitHub', Value: 'Actions'}, - {Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY}, - {Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW}, - {Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION}, - {Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED}, - {Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA}, - {Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF}, - ] + test("add new profile if credentials file already exists", async () => { + fs.existsSync + .mockImplementationOnce(() => { + return true; }) - }); - - test('skip tagging not provided', async () => { - core.getInput = jest - .fn() - .mockImplementation(mockGetInput({...ASSUME_ROLE_INPUTS})); - - await run(); - expect(mockStsAssumeRole).toHaveBeenCalledWith({ - RoleArn: ROLE_ARN, - RoleSessionName: 'GitHubActions', - DurationSeconds: 21600, - Tags: [ - {Key: 'GitHub', Value: 'Actions'}, - {Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY}, - {Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW}, - {Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION}, - {Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED}, - {Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA}, - {Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF}, - ] + .mockImplementationOnce(() => { + return true; }) - }); - - test('masks variables before exporting', async () => { - let maskedValues = []; - const publicFields = ['AWS_REGION', 'AWS_DEFAULT_REGION']; - core.setSecret.mockReset(); - core.setSecret.mockImplementation((secret) => { - maskedValues.push(secret); + .mockImplementationOnce(() => { + return true; }); - core.exportVariable.mockReset(); - core.exportVariable.mockImplementation((name, value) => { - if (!maskedValues.includes(value) && !publicFields.includes(name)) { - throw new Error(value + " for variable " + name + " is not masked yet!"); - } - }); - - core.getInput = jest - .fn() - .mockImplementation(mockGetInput(ASSUME_ROLE_INPUTS)); - - await run(); - }); - - describe('proxy settings', () => { - - test('setting proxy with actions input', async () => { - const EXPECTED_PROXY = 'http://test.me' - core.getInput = jest - .fn() - .mockImplementation( - mockGetInput({ ...DEFAULT_INPUTS, 'http-proxy': EXPECTED_PROXY }) - ); - - await run(); - - expect(aws.config.update).toHaveBeenCalledTimes(1); - expect(aws.config.update).toHaveBeenCalledWith({ - httpOptions: { agent: proxy(EXPECTED_PROXY) } - }); - }); - test('setting proxy from environment vars', async () => { - const EXPECTED_PROXY = 'http://test.me' - process.env.HTTP_PROXY = EXPECTED_PROXY; - core.getInput = jest - .fn() - .mockImplementation( - mockGetInput({ ...DEFAULT_INPUTS }) - ); - - await run(); - - expect(aws.config.update).toHaveBeenCalledTimes(1); - expect(aws.config.update).toHaveBeenCalledWith({ - httpOptions: { agent: proxy(EXPECTED_PROXY) } - }); - }); - - test('setting proxy - prefer action input', async () => { - const EXPECTED_PROXY = 'http://test.me' - const FALSE_PROXY = 'http://env.me' - process.env.HTTP_PROXY = FALSE_PROXY; - core.getInput = jest - .fn() - .mockImplementation( - mockGetInput({ ...DEFAULT_INPUTS, 'http-proxy': EXPECTED_PROXY }) - ); - - await run(); - - expect(aws.config.update).toHaveBeenCalledTimes(1); - expect(aws.config.update).toHaveBeenCalledWith({ - httpOptions: { agent: proxy(EXPECTED_PROXY) } - }); - }); - - test('ignoring proxy - without anything set', async () => { - core.getInput = jest - .fn() - .mockImplementation( - mockGetInput({ ...DEFAULT_INPUTS}) - ); - - await run(); - - expect(aws.config.update).toHaveBeenCalledTimes(0); - }); - }); + fs.promises.readFile.mockResolvedValueOnce(`[profile default] + region=fake-region-1`).mockResolvedValueOnce(`[default] + aws_access_key=STS-AWS-ACCESS-KEY-ID + aws_secret_access_key=STS-AWS-SECRET-ACCESS-KEY + aws_session_token=STS-AWS-SESSION-TOKEN`); + + core.getInput = jest.fn().mockImplementation(mockGetInput(PROFILE_INPUTS)); + await run(); + + // Don't export aws credentials + expect(core.exportVariable).toHaveBeenCalledTimes(5); + expect(core.exportVariable).toHaveBeenNthCalledWith(1, "AWS_DEFAULT_REGION", FAKE_REGION); + expect(core.exportVariable).toHaveBeenNthCalledWith(2, "AWS_REGION", FAKE_REGION); + expect(core.exportVariable).toHaveBeenNthCalledWith(3, "AWS_PROFILE", PROFILE_INPUTS["aws-profile"]); + expect(core.exportVariable).toHaveBeenNthCalledWith(4, "AWS_SHARED_CREDENTIALS_FILE", "/home/.aws/credentials"); + expect(core.exportVariable).toHaveBeenNthCalledWith(5, "AWS_CONFIG_FILE", "/home/.aws/config"); + + expect(fs.promises.writeFile).toHaveBeenNthCalledWith(1, "/home/.aws/config", expect.toMatchSnapshot()); + expect(fs.promises.writeFile).toHaveBeenNthCalledWith(2, "/home/.aws/credentials", expect.toMatchSnapshot()); + }); + + test("web identity token file provided with relative path", async () => { + core.getInput = jest.fn().mockImplementation( + mockGetInput({ + "role-to-assume": ROLE_ARN, + "aws-region": FAKE_REGION, + "web-identity-token-file": "fake/token/file", + "aws-profile": "test-profile", + }), + ); + + fs.existsSync.mockImplementation(() => { + return true; + }); + // Identity token file is read from the workspace root + fs.promises.readFile.mockImplementationOnce(() => Promise.resolve("testpayload")); + + fs.promises.readFile.mockResolvedValueOnce("").mockResolvedValueOnce(""); + + await run(); + + // Don't export aws credentials + expect(core.exportVariable).toHaveBeenCalledTimes(5); + expect(core.exportVariable).toHaveBeenNthCalledWith(1, "AWS_DEFAULT_REGION", FAKE_REGION); + expect(core.exportVariable).toHaveBeenNthCalledWith(2, "AWS_REGION", FAKE_REGION); + expect(core.exportVariable).toHaveBeenNthCalledWith(3, "AWS_PROFILE", PROFILE_INPUTS["aws-profile"]); + expect(core.exportVariable).toHaveBeenNthCalledWith(4, "AWS_SHARED_CREDENTIALS_FILE", "/home/.aws/credentials"); + expect(core.exportVariable).toHaveBeenNthCalledWith(5, "AWS_CONFIG_FILE", "/home/.aws/config"); + + expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledWith({ + RoleArn: "arn:aws:iam::111111111111:role/MY-ROLE", + RoleSessionName: "GitHubActions", + DurationSeconds: 6 * 3600, + WebIdentityToken: "testpayload", + }); + expect(fs.promises.writeFile).toHaveBeenCalledTimes(2); + expect(fs.promises.writeFile).toHaveBeenNthCalledWith(1, "/home/.aws/config", expect.toMatchSnapshot()); + expect(fs.promises.writeFile).toHaveBeenNthCalledWith(2, "/home/.aws/credentials", expect.toMatchSnapshot()); + }); + }); }); diff --git a/package-lock.json b/package-lock.json index 5d505b7ff..278f311b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,8 +1,4689 @@ { "name": "aws-actions-configure-aws-credentials", "version": "1.7.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "aws-actions-configure-aws-credentials", + "version": "1.7.0", + "license": "MIT", + "dependencies": { + "@actions/core": "^1.10.0", + "aws-sdk": "^2.1300.0", + "axios": "^1.2.3", + "https-proxy-agent": "^5.0.1", + "ini": "^3.0.1" + }, + "devDependencies": { + "@vercel/ncc": "^0.36.0", + "eslint": "^8.31.0", + "jest": "^29.3.1" + } + }, + "node_modules/@actions/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", + "integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", + "dependencies": { + "@actions/http-client": "^2.0.1", + "uuid": "^8.3.2" + } + }, + "node_modules/@actions/http-client": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz", + "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==", + "dependencies": { + "tunnel": "^0.0.6" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", + "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz", + "integrity": "sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.2", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-module-transforms": "^7.20.2", + "@babel/helpers": "^7.20.1", + "@babel/parser": "^7.20.2", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.2", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/@babel/generator": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.4.tgz", + "integrity": "sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.2", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", + "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.20.0", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz", + "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", + "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz", + "integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", + "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", + "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.1", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.1", + "@babel/types": "^7.20.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.2.tgz", + "integrity": "sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@eslint/eslintrc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.3.1.tgz", + "integrity": "sha512-IRE6GD47KwcqA09RIWrabKdHPiKDGgtAL31xDxbi/RjQMsr+lY+ppxmHwY0dUEV3qvvxZzoe5Hl0RXZJOjQNUg==", + "dev": true, + "dependencies": { + "@jest/types": "^29.3.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.3.1", + "jest-util": "^29.3.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.3.1.tgz", + "integrity": "sha512-0ohVjjRex985w5MmO5L3u5GR1O30DexhBSpuwx2P+9ftyqHdJXnk7IUWiP80oHMvt7ubHCJHxV0a0vlKVuZirw==", + "dev": true, + "dependencies": { + "@jest/console": "^29.3.1", + "@jest/reporters": "^29.3.1", + "@jest/test-result": "^29.3.1", + "@jest/transform": "^29.3.1", + "@jest/types": "^29.3.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.2.0", + "jest-config": "^29.3.1", + "jest-haste-map": "^29.3.1", + "jest-message-util": "^29.3.1", + "jest-regex-util": "^29.2.0", + "jest-resolve": "^29.3.1", + "jest-resolve-dependencies": "^29.3.1", + "jest-runner": "^29.3.1", + "jest-runtime": "^29.3.1", + "jest-snapshot": "^29.3.1", + "jest-util": "^29.3.1", + "jest-validate": "^29.3.1", + "jest-watcher": "^29.3.1", + "micromatch": "^4.0.4", + "pretty-format": "^29.3.1", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.3.1.tgz", + "integrity": "sha512-pMmvfOPmoa1c1QpfFW0nXYtNLpofqo4BrCIk6f2kW4JFeNlHV2t3vd+3iDLf31e2ot2Mec0uqZfmI+U0K2CFag==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^29.3.1", + "@jest/types": "^29.3.1", + "@types/node": "*", + "jest-mock": "^29.3.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.3.1.tgz", + "integrity": "sha512-QivM7GlSHSsIAWzgfyP8dgeExPRZ9BIe2LsdPyEhCGkZkoyA+kGsoIzbKAfZCvvRzfZioKwPtCZIt5SaoxYCvg==", + "dev": true, + "dependencies": { + "expect": "^29.3.1", + "jest-snapshot": "^29.3.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.3.1.tgz", + "integrity": "sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.2.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.3.1.tgz", + "integrity": "sha512-iHTL/XpnDlFki9Tq0Q1GGuVeQ8BHZGIYsvCO5eN/O/oJaRzofG9Xndd9HuSDBI/0ZS79pg0iwn07OMTQ7ngF2A==", + "dev": true, + "dependencies": { + "@jest/types": "^29.3.1", + "@sinonjs/fake-timers": "^9.1.2", + "@types/node": "*", + "jest-message-util": "^29.3.1", + "jest-mock": "^29.3.1", + "jest-util": "^29.3.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.3.1.tgz", + "integrity": "sha512-cTicd134vOcwO59OPaB6AmdHQMCtWOe+/DitpTZVxWgMJ+YvXL1HNAmPyiGbSHmF/mXVBkvlm8YYtQhyHPnV6Q==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.3.1", + "@jest/expect": "^29.3.1", + "@jest/types": "^29.3.1", + "jest-mock": "^29.3.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.3.1.tgz", + "integrity": "sha512-GhBu3YFuDrcAYW/UESz1JphEAbvUjaY2vShRZRoRY1mxpCMB3yGSJ4j9n0GxVlEOdCf7qjvUfBCrTUUqhVfbRA==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.3.1", + "@jest/test-result": "^29.3.1", + "@jest/transform": "^29.3.1", + "@jest/types": "^29.3.1", + "@jridgewell/trace-mapping": "^0.3.15", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.3.1", + "jest-util": "^29.3.1", + "jest-worker": "^29.3.1", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", + "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.2.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.2.0.tgz", + "integrity": "sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.15", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.3.1.tgz", + "integrity": "sha512-qeLa6qc0ddB0kuOZyZIhfN5q0e2htngokyTWsGriedsDhItisW7SDYZ7ceOe57Ii03sL988/03wAcBh3TChMGw==", + "dev": true, + "dependencies": { + "@jest/console": "^29.3.1", + "@jest/types": "^29.3.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.3.1.tgz", + "integrity": "sha512-IqYvLbieTv20ArgKoAMyhLHNrVHJfzO6ARZAbQRlY4UGWfdDnLlZEF0BvKOMd77uIiIjSZRwq3Jb3Fa3I8+2UA==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.3.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.3.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.3.1.tgz", + "integrity": "sha512-8wmCFBTVGYqFNLWfcOWoVuMuKYPUBTnTMDkdvFtAYELwDOl9RGwOsvQWGPFxDJ8AWY9xM/8xCXdqmPK3+Q5Lug==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.3.1", + "@jridgewell/trace-mapping": "^0.3.15", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.3.1", + "jest-regex-util": "^29.2.0", + "jest-util": "^29.3.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz", + "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.5.tgz", + "integrity": "sha512-rTpCA0wG1wUxglBSFdMMY0oTrKYvgf4fNgv/sXbfCVAdf+FnPBdKJR/7XbpTCwbCrvCbdPYnlWaUUYz4V2fPDA==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.1.20", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", + "integrity": "sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.2.tgz", + "integrity": "sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/node": { + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", + "dev": true + }, + "node_modules/@types/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", + "dev": true + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", + "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "node_modules/@vercel/ncc": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.36.0.tgz", + "integrity": "sha512-/ZTUJ/ZkRt694k7KJNimgmHjtQcRuVwsST2Z6XfYveQIuBbHR+EqkTc1jfgPkQmMyk/vtpxo3nVxe8CNuau86A==", + "dev": true, + "bin": { + "ncc": "dist/ncc/cli.js" + } + }, + "node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sdk": { + "version": "2.1302.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1302.0.tgz", + "integrity": "sha512-OeP31meLGCcBJel2Re1yRsrjqDT3FvLFMQwPVtKHkXnws6QpgVg1FPiEjz4emEREUi6NfbqGNVExOGLsKiz0YA==", + "dependencies": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.4.19" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aws-sdk/node_modules/uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/axios": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.4.tgz", + "integrity": "sha512-lIQuCfBJvZB/Bv7+RWUqEJqNShGOVpk9v7P0ZWx5Ip0qY6u7JBAU6dzQPMLasU9vHL2uD8av/1FDJXj7n6c39w==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-jest": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.3.1.tgz", + "integrity": "sha512-aard+xnMoxgjwV70t0L6wkW/3HQQtV+O0PEimxKgzNqCJnbYmroPojdP2tqKSOAt8QAKV/uSZU8851M7B5+fcA==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.3.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.2.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.2.0.tgz", + "integrity": "sha512-TnspP2WNiR3GLfCsUNHqeXw0RoQ2f9U5hQ5L3XFpwuO8htQmSrhh8qsB6vi5Yi8+kuynN1yjDjQsPfkebmB6ZA==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.2.0.tgz", + "integrity": "sha512-z9JmMJppMxNv8N7fNRHvhMg9cvIkMxQBXgFkane3yKVEvEOP+kB50lk8DFRvF9PGqbyXxlmebKWhuDORO8RgdA==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.2.0", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001431", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz", + "integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.6.1.tgz", + "integrity": "sha512-up5ggbaDqOqJ4UqLKZ2naVkyqSJQgJi5lwD6b6mM748ysrghDBX0bx/qJTUHzw7zu6Mq4gycviSF5hJnwceD8w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz", + "integrity": "sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.32.0.tgz", + "integrity": "sha512-nETVXpnthqKPFyuY2FNjz/bEd6nbosRgKbkgS/y1C7LJop96gYHWpiguLecMHQ2XCPxn77DS0P+68WzG6vkZSQ==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.3.1.tgz", + "integrity": "sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.3.1", + "jest-get-type": "^29.2.0", + "jest-matcher-utils": "^29.3.1", + "jest-message-util": "^29.3.1", + "jest-util": "^29.3.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", + "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.3.1.tgz", + "integrity": "sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==", + "dev": true, + "dependencies": { + "@jest/core": "^29.3.1", + "@jest/types": "^29.3.1", + "import-local": "^3.0.2", + "jest-cli": "^29.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.2.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.2.0.tgz", + "integrity": "sha512-qPVmLLyBmvF5HJrY7krDisx6Voi8DmlV3GZYX0aFNbaQsZeoz1hfxcCMbqDGuQCxU1dJy9eYc2xscE8QrCCYaA==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.3.1.tgz", + "integrity": "sha512-wpr26sEvwb3qQQbdlmei+gzp6yoSSoSL6GsLPxnuayZSMrSd5Ka7IjAvatpIernBvT2+Ic6RLTg+jSebScmasg==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.3.1", + "@jest/expect": "^29.3.1", + "@jest/test-result": "^29.3.1", + "@jest/types": "^29.3.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.3.1", + "jest-matcher-utils": "^29.3.1", + "jest-message-util": "^29.3.1", + "jest-runtime": "^29.3.1", + "jest-snapshot": "^29.3.1", + "jest-util": "^29.3.1", + "p-limit": "^3.1.0", + "pretty-format": "^29.3.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-config": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.3.1.tgz", + "integrity": "sha512-y0tFHdj2WnTEhxmGUK1T7fgLen7YK4RtfvpLFBXfQkh2eMJAQq24Vx9472lvn5wg0MAO6B+iPfJfzdR9hJYalg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.3.1", + "@jest/types": "^29.3.1", + "babel-jest": "^29.3.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.3.1", + "jest-environment-node": "^29.3.1", + "jest-get-type": "^29.2.0", + "jest-regex-util": "^29.2.0", + "jest-resolve": "^29.3.1", + "jest-runner": "^29.3.1", + "jest-util": "^29.3.1", + "jest-validate": "^29.3.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.3.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz", + "integrity": "sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.3.1", + "jest-get-type": "^29.2.0", + "pretty-format": "^29.3.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.2.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.2.0.tgz", + "integrity": "sha512-bkxUsxTgWQGbXV5IENmfiIuqZhJcyvF7tU4zJ/7ioTutdz4ToB5Yx6JOFBpgI+TphRY4lhOyCWGNH/QFQh5T6A==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.3.1.tgz", + "integrity": "sha512-qrZH7PmFB9rEzCSl00BWjZYuS1BSOH8lLuC0azQE9lQrAx3PWGKHTDudQiOSwIy5dGAJh7KA0ScYlCP7JxvFYA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.3.1", + "chalk": "^4.0.0", + "jest-get-type": "^29.2.0", + "jest-util": "^29.3.1", + "pretty-format": "^29.3.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.3.1.tgz", + "integrity": "sha512-xm2THL18Xf5sIHoU7OThBPtuH6Lerd+Y1NLYiZJlkE3hbE+7N7r8uvHIl/FkZ5ymKXJe/11SQuf3fv4v6rUMag==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.3.1", + "@jest/fake-timers": "^29.3.1", + "@jest/types": "^29.3.1", + "@types/node": "*", + "jest-mock": "^29.3.1", + "jest-util": "^29.3.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.2.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz", + "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.3.1.tgz", + "integrity": "sha512-/FFtvoG1xjbbPXQLFef+WSU4yrc0fc0Dds6aRPBojUid7qlPqZvxdUBA03HW0fnVHXVCnCdkuoghYItKNzc/0A==", + "dev": true, + "dependencies": { + "@jest/types": "^29.3.1", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.2.0", + "jest-util": "^29.3.1", + "jest-worker": "^29.3.1", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.3.1.tgz", + "integrity": "sha512-3DA/VVXj4zFOPagGkuqHnSQf1GZBmmlagpguxEERO6Pla2g84Q1MaVIB3YMxgUaFIaYag8ZnTyQgiZ35YEqAQA==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.2.0", + "pretty-format": "^29.3.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz", + "integrity": "sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.3.1", + "jest-get-type": "^29.2.0", + "pretty-format": "^29.3.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz", + "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.3.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.3.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.3.1.tgz", + "integrity": "sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.3.1", + "@types/node": "*", + "jest-util": "^29.3.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.2.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.2.0.tgz", + "integrity": "sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.3.1.tgz", + "integrity": "sha512-amXJgH/Ng712w3Uz5gqzFBBjxV8WFLSmNjoreBGMqxgCz5cH7swmBZzgBaCIOsvb0NbpJ0vgaSFdJqMdT+rADw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.3.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.3.1", + "jest-validate": "^29.3.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.3.1.tgz", + "integrity": "sha512-Vk0cYq0byRw2WluNmNWGqPeRnZ3p3hHmjJMp2dyyZeYIfiBskwq4rpiuGFR6QGAdbj58WC7HN4hQHjf2mpvrLA==", + "dev": true, + "dependencies": { + "jest-regex-util": "^29.2.0", + "jest-snapshot": "^29.3.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.3.1.tgz", + "integrity": "sha512-oFvcwRNrKMtE6u9+AQPMATxFcTySyKfLhvso7Sdk/rNpbhg4g2GAGCopiInk1OP4q6gz3n6MajW4+fnHWlU3bA==", + "dev": true, + "dependencies": { + "@jest/console": "^29.3.1", + "@jest/environment": "^29.3.1", + "@jest/test-result": "^29.3.1", + "@jest/transform": "^29.3.1", + "@jest/types": "^29.3.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.2.0", + "jest-environment-node": "^29.3.1", + "jest-haste-map": "^29.3.1", + "jest-leak-detector": "^29.3.1", + "jest-message-util": "^29.3.1", + "jest-resolve": "^29.3.1", + "jest-runtime": "^29.3.1", + "jest-util": "^29.3.1", + "jest-watcher": "^29.3.1", + "jest-worker": "^29.3.1", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.3.1.tgz", + "integrity": "sha512-jLzkIxIqXwBEOZx7wx9OO9sxoZmgT2NhmQKzHQm1xwR1kNW/dn0OjxR424VwHHf1SPN6Qwlb5pp1oGCeFTQ62A==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.3.1", + "@jest/fake-timers": "^29.3.1", + "@jest/globals": "^29.3.1", + "@jest/source-map": "^29.2.0", + "@jest/test-result": "^29.3.1", + "@jest/transform": "^29.3.1", + "@jest/types": "^29.3.1", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.3.1", + "jest-message-util": "^29.3.1", + "jest-mock": "^29.3.1", + "jest-regex-util": "^29.2.0", + "jest-resolve": "^29.3.1", + "jest-snapshot": "^29.3.1", + "jest-util": "^29.3.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.3.1.tgz", + "integrity": "sha512-+3JOc+s28upYLI2OJM4PWRGK9AgpsMs/ekNryUV0yMBClT9B1DF2u2qay8YxcQd338PPYSFNb0lsar1B49sLDA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.3.1", + "@jest/transform": "^29.3.1", + "@jest/types": "^29.3.1", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.3.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.3.1", + "jest-get-type": "^29.2.0", + "jest-haste-map": "^29.3.1", + "jest-matcher-utils": "^29.3.1", + "jest-message-util": "^29.3.1", + "jest-util": "^29.3.1", + "natural-compare": "^1.4.0", + "pretty-format": "^29.3.1", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz", + "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.3.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.3.1.tgz", + "integrity": "sha512-N9Lr3oYR2Mpzuelp1F8negJR3YE+L1ebk1rYA5qYo9TTY3f9OWdptLoNSPP9itOCBIRBqjt/S5XHlzYglLN67g==", + "dev": true, + "dependencies": { + "@jest/types": "^29.3.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.2.0", + "leven": "^3.1.0", + "pretty-format": "^29.3.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.3.1.tgz", + "integrity": "sha512-RspXG2BQFDsZSRKGCT/NiNa8RkQ1iKAjrO0//soTMWx/QUt+OcxMqMSBxz23PYGqUuWm2+m2mNNsmj0eIoOaFg==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.3.1", + "@jest/types": "^29.3.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.3.1", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.3.1.tgz", + "integrity": "sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.3.1", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest/node_modules/jest-cli": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.3.1.tgz", + "integrity": "sha512-TO/ewvwyvPOiBBuWZ0gm04z3WWP8TIK8acgPzE4IxgsLKQgb377NYGrQLc3Wl/7ndWzIH2CDNNsUjGxwLL43VQ==", + "dev": true, + "dependencies": { + "@jest/core": "^29.3.1", + "@jest/test-result": "^29.3.1", + "@jest/types": "^29.3.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^29.3.1", + "jest-util": "^29.3.1", + "jest-validate": "^29.3.1", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/js-sdsl": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", + "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-format": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", + "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve.exports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", + "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + } + }, + "node_modules/xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, "dependencies": { "@actions/core": { "version": "1.10.0", @@ -1025,7 +5706,8 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true + "dev": true, + "requires": {} }, "agent-base": { "version": "6.0.2", @@ -1106,9 +5788,9 @@ "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" }, "aws-sdk": { - "version": "2.1273.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1273.0.tgz", - "integrity": "sha512-QF37fm1DfUxjw+IJtDMTDBckVwAOf8EHQjs4NxJp5TtRkeqtWkxNzq/ViI8kAS+0n8JZaom8Oenmy8ufGfLMAQ==", + "version": "2.1302.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1302.0.tgz", + "integrity": "sha512-OeP31meLGCcBJel2Re1yRsrjqDT3FvLFMQwPVtKHkXnws6QpgVg1FPiEjz4emEREUi6NfbqGNVExOGLsKiz0YA==", "requires": { "buffer": "4.9.2", "events": "1.1.1", @@ -1130,9 +5812,9 @@ } }, "axios": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.2.tgz", - "integrity": "sha512-bz/J4gS2S3I7mpN/YZfGFTqhXTYzRho8Ay38w2otuuDR322KzFIWm/4W2K6gIwvWaws5n+mnb7D1lN9uD+QH6Q==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.4.tgz", + "integrity": "sha512-lIQuCfBJvZB/Bv7+RWUqEJqNShGOVpk9v7P0ZWx5Ip0qY6u7JBAU6dzQPMLasU9vHL2uD8av/1FDJXj7n6c39w==", "requires": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -1492,9 +6174,9 @@ "dev": true }, "eslint": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", - "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", + "version": "8.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.32.0.tgz", + "integrity": "sha512-nETVXpnthqKPFyuY2FNjz/bEd6nbosRgKbkgS/y1C7LJop96gYHWpiguLecMHQ2XCPxn77DS0P+68WzG6vkZSQ==", "dev": true, "requires": { "@eslint/eslintrc": "^1.4.1", @@ -1966,6 +6648,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "ini": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", + "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==" + }, "is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -2351,7 +7038,8 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true + "dev": true, + "requires": {} }, "jest-regex-util": { "version": "29.2.0", diff --git a/package.json b/package.json index c63ba612a..03d18157a 100644 --- a/package.json +++ b/package.json @@ -26,9 +26,10 @@ "homepage": "https://github.com/aws-actions/configure-aws-credentials#readme", "dependencies": { "@actions/core": "^1.10.0", - "aws-sdk": "^2.1273.0", - "axios": "^1.2.2", - "https-proxy-agent": "^5.0.1" + "aws-sdk": "^2.1300.0", + "axios": "^1.2.3", + "https-proxy-agent": "^5.0.1", + "ini": "^3.0.1" }, "devDependencies": { "@vercel/ncc": "^0.36.0",