├── .bumpversion.cfg ├── .eslintignore ├── .eslintrc.json ├── .gitattributes ├── .github ├── CODEOWNERS ├── CONTRIBUTING.md ├── dependabot.yml ├── pull_request_template.md └── workflows │ ├── hawkscan-integration.yml │ ├── test.yml │ └── update-main-version.yml ├── .gitignore ├── .nvmrc ├── LICENSE ├── README.md ├── __tests__ ├── index.js ├── integration-tests │ └── configs │ │ └── javaspringvulny │ │ ├── openapi.yaml │ │ └── stackhawk-jsv-json-token.yml ├── stackhawk.yml └── stackhawk_spider.yml ├── action.yml ├── dist ├── index.js ├── index.js.map ├── licenses.txt └── sourcemap-register.js ├── package-lock.json ├── package.json ├── scripts ├── action-tester.sh ├── actionTester.js ├── release-pr.sh └── version-check.sh └── src ├── cli_utils.js ├── hawk_process.js ├── index.js ├── sarif.js ├── setup.js ├── signal_handler.js └── utilities.js /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 2.2.0 3 | commit = True 4 | tag = False 5 | 6 | [bumpversion:file:package.json] 7 | search = "version": "{current_version}" 8 | replace = "version": "{new_version}" 9 | 10 | [bumpversion:file:README.md] 11 | search = stackhawk/hawkscan-action@v{current_version} 12 | replace = stackhawk/hawkscan-action@v{new_version} 13 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "commonjs": true, 4 | "es6": true, 5 | "jest": true, 6 | "node": true 7 | }, 8 | "extends": "eslint:recommended", 9 | "globals": { 10 | "Atomics": "readonly", 11 | "SharedArrayBuffer": "readonly" 12 | }, 13 | "parserOptions": { 14 | "ecmaVersion": 2018 15 | }, 16 | "rules": { 17 | "no-control-regex": 0, 18 | "guard-for-in": "warn", 19 | "object-shorthand": "warn", 20 | "@typescript-eslint/no-var-requires": "off" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | dist/** -diff linguist-generated=true -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @stackhawk/engineering 2 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Develop 2 | 3 | To install and update dependencies: 4 | 5 | ```bash 6 | npm install 7 | ``` 8 | 9 | To run tests: 10 | 11 | ```bash 12 | npm test 13 | ``` 14 | 15 | To lint the code: 16 | 17 | ```bash 18 | npm run lint 19 | ``` 20 | 21 | ## Package for Distribution 22 | 23 | To prepare this action for distribution, you must package it into the `dist` directory: 24 | 25 | ```bash 26 | npm run prepare 27 | ``` 28 | 29 | Better yet, you can test, lint, and package it all in one step: 30 | 31 | ```bash 32 | npm run all 33 | ``` 34 | 35 | Packaging creates a single consolidated action file in the `dist` folder. That directory contains all code, dependencies, and licenses, enabling fast and reliable execution and preventing the need to check in the `node_modules` directory. 36 | 37 | ## Releasing and Publishing to the GitHub Marketplace 38 | 39 | To release a new version of this action to the marketplace, you must do the following: 40 | 1. Lint, package, and test the code in your feature branch 41 | 2. Bump the version number in `package.json` and `README.md` and `.bumpversion.cfg`. run npm install again to ensure version attaches in package-lock.json. 42 | 3. Create a PR to `main` with your changes 43 | 4. Once the PR is merged, tag and release it 44 | 5. Publish the release to the GitHub Marketplace 45 | 46 | The `release-pr.sh` script handles steps 1 through 3, up to and including the creation of a PR. 47 | 48 | > `release-pr.sh` requires [bump2version](https://pypi.org/project/bump2version/) and [gh](https://cli.github.com/manual/installation). 49 | 50 | Run `release-pr.sh` with your desired bump level - **major**, **minor**, or **patch**: 51 | 52 | ```shell 53 | ./scripts/release-pr.sh -b patch 54 | ``` 55 | 56 | Once the PR is merged, the `.github/workflows/test.yml` workflow handles step 4, tagging and releasing, automatically. 57 | 58 | The next *manual* step is to [edit the release](https://github.com/stackhawk/hawkscan-action/releases) and publish it to the GitHub Marketplace. 59 | 60 | Lastly, you must *manually* run the hawkscan-action job to update the main version. You must provide the same release tag as what was just released. This will update the major version tag (e.g. `v2`) to this specific version. 61 | 62 | > ✅ *Publish this Action to the GitHub Marketplace* 63 | 64 | ## Check the Marketplace 65 | 66 | To make sure the action has been released correctly, [view it on the Marketplace](https://github.com/marketplace/actions/stackhawk-hawkscan-action), and check the latest available version there. 67 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Enable version updates for npm 4 | - package-ecosystem: "npm" 5 | # Look for `package.json` and `lock` files in the `root` directory 6 | directory: "/" 7 | # Check the npm registry for updates every day (weekdays) 8 | schedule: 9 | interval: "daily" 10 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Description of the change 2 | 3 | > Description here 4 | 5 | 6 | ![replace me](giphy-url.gif) 7 | 8 | ## Type of change 9 | - [ ] Bug fix (non-breaking change that fixes an issue) 10 | - [ ] New feature (non-breaking change that adds functionality) 11 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 12 | 13 | ## Related issues 14 | 15 | > [ISSUE-ID](https://.atlassian.net/browse/ISSUE-ID) 16 | 17 | ## Checklists 18 | 19 | ### Development 20 | 21 | - [ ] Lint rules pass locally 22 | - [ ] The code changed/added as part of this pull request has been covered with tests 23 | - [ ] All tests related to the changed code pass in development 24 | 25 | ### Code review 26 | 27 | - [ ] This pull request has a descriptive title and information useful to a reviewer. There may be a screenshot or screencast attached 28 | - [ ] "Ready for review" label attached to the PR and reviewers mentioned in a comment 29 | - [ ] Changes have been reviewed by at least one other engineer 30 | - [ ] Issue from task tracker has a link to this pull request 31 | -------------------------------------------------------------------------------- /.github/workflows/hawkscan-integration.yml: -------------------------------------------------------------------------------- 1 | name: HawkScan Integration Tests 2 | on: 3 | repository_dispatch: 4 | types: [integration-test] 5 | jobs: 6 | hawkscan: 7 | name: HawkScan Action Integration Test 8 | runs-on: ubuntu-20.04 9 | steps: 10 | - uses: actions/checkout@v3 11 | with: 12 | ref: ${{ github.event.client_payload.ref }} 13 | - name: Checkout javaspringvulny repository 14 | uses: actions/checkout@v3 15 | with: 16 | repository: ${{ github.event.client_payload.repoOrg }}/${{ github.event.client_payload.repoName }} 17 | path: ./__tests__/integration-tests/apps/${{ github.event.client_payload.repoName }} 18 | - name: Run ${{ github.event.client_payload.repoName }} 19 | run: | 20 | cd __tests__/integration-tests/apps/${{ github.event.client_payload.repoName }} 21 | docker-compose up -d 22 | - name: Run HawkScan 23 | id: run-hawkscan 24 | uses: stackhawk/hawkscan-action@main 25 | with: 26 | apiKey: ${{ secrets.HAWK_API_KEY }} 27 | workspace: ${{ github.workspace }}/__tests__/integration-tests/configs/${{ github.event.client_payload.repoName }}/ 28 | configurationFiles: ${{ github.event.client_payload.configFiles }} 29 | sourceURL: ${{ github.event.client_payload.hawkscanSourceUrl }} 30 | version: ${{ github.event.client_payload.hawkscanVersion }} 31 | verbose: ${{ github.event.client_payload.verbose }} 32 | debug: ${{ github.event.client_payload.debug }} 33 | env: 34 | APPLICATION_ID: ${{ github.event.client_payload.appId }} -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: "action-tests" 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | # Run JS unit tests 10 | unit-tests: 11 | strategy: 12 | matrix: 13 | runner: [ 'ubuntu-latest', 'windows-latest' ] 14 | name: Unit Tests 15 | runs-on: ${{ matrix.runner }} 16 | env: 17 | SHAWK_API_KEY: ${{ secrets.HAWK_API_KEY }} 18 | steps: 19 | - uses: actions/checkout@v3 20 | - run: npm install --only=dev 21 | - run: npm run lint 22 | - run: npm clean-install 23 | - run: npm test 24 | 25 | # Run a HawkScan with this Action 26 | live-test: 27 | strategy: 28 | matrix: 29 | runner: [ 'ubuntu-latest', 'windows-latest' ] 30 | name: Live Test 31 | runs-on: ${{ matrix.runner }} 32 | steps: 33 | - name: Check it out 34 | uses: actions/checkout@v3 35 | - name: Setup java 36 | uses: actions/setup-java@v4 37 | with: 38 | distribution: 'temurin' 39 | java-version: '17' 40 | - name: Run Scan 41 | id: run-scan 42 | uses: ./ 43 | with: 44 | apiKey: ${{ secrets.HAWK_API_KEY }} 45 | githubToken: ${{ github.token }} 46 | configurationFiles: __tests__/stackhawk.yml 47 | codeScanningAlerts: true 48 | # Use the output from the `hello` step 49 | - name: Check Scan Id 50 | run: echo "The last scan id was ${{ steps.run-scan.outputs.scanId }}" 51 | 52 | # Run a HawkScan with verbose and debug logging 53 | verbose-debug-test: 54 | name: Verbose and Debug Logging Test 55 | strategy: 56 | matrix: 57 | runner: [ 'ubuntu-latest', 'windows-latest' ] 58 | runs-on: ${{ matrix.runner }} 59 | steps: 60 | - name: Check it out 61 | uses: actions/checkout@v3 62 | - name: Setup java 63 | uses: actions/setup-java@v4 64 | with: 65 | distribution: 'temurin' 66 | java-version: '17' 67 | - name: Run Scan 68 | uses: ./ 69 | with: 70 | apiKey: ${{ secrets.HAWK_API_KEY }} 71 | githubToken: ${{ github.token }} 72 | configurationFiles: __tests__/stackhawk.yml 73 | codeScanningAlerts: true 74 | verbose: true 75 | debug: true 76 | 77 | # Run a HawkScan with this Action 78 | command-line-test: 79 | name: Command Line Test 80 | runs-on: ubuntu-20.04 81 | steps: 82 | - uses: actions/checkout@v3 83 | - name: Setup java 84 | uses: actions/setup-java@v4 85 | with: 86 | distribution: 'temurin' 87 | java-version: '17' 88 | - name: Install CLI 89 | uses: ./ 90 | with: 91 | installCLIOnly: true 92 | - name: Run the scan 93 | run: hawk --api-key=${{ secrets.HAWK_API_KEY }} scan __tests__/stackhawk.yml 94 | 95 | # Run a HawkScan with this Action 96 | ajax-test: 97 | name: Ajax Test 98 | runs-on: ubuntu-20.04 99 | steps: 100 | - name: Check it out 101 | uses: actions/checkout@v3 102 | - name: Setup java 103 | uses: actions/setup-java@v4 104 | with: 105 | distribution: 'temurin' 106 | java-version: '17' 107 | - name: Run Scan 108 | uses: ./ 109 | with: 110 | apiKey: ${{ secrets.HAWK_API_KEY }} 111 | githubToken: ${{ github.token }} 112 | configurationFiles: __tests__/stackhawk.yml 113 | codeScanningAlerts: true 114 | 115 | javaspringvulny-test: 116 | name: Java Spring Vulny Test 117 | runs-on: ubuntu-20.04 118 | steps: 119 | - uses: actions/checkout@v3 120 | - name: Setup java 121 | uses: actions/setup-java@v4 122 | with: 123 | distribution: 'temurin' 124 | java-version: '17' 125 | - name: Checkout javaspringvulny repository 126 | uses: actions/checkout@v3 127 | with: 128 | repository: kaakaww/javaspringvulny 129 | path: ./__tests__/integration-tests/apps/javaspringvulny 130 | - name: Run javaspringvulny 131 | run: | 132 | cd __tests__/integration-tests/apps/javaspringvulny 133 | docker-compose up -d 134 | - name: Run HawkScan 135 | id: run-hawkscan 136 | uses: ./ 137 | with: 138 | apiKey: ${{ secrets.HAWK_API_KEY }} 139 | workspace: ${{ github.workspace }}/__tests__/integration-tests/configs/javaspringvulny/ 140 | configurationFiles: stackhawk-jsv-json-token.yml 141 | # verbose: true 142 | debug: true 143 | env: 144 | APPLICATION_ID: 4030d674-88b7-4e07-8065-7761f9c63788 145 | - name: Run ReScan 146 | uses: ./ 147 | with: 148 | apiKey: ${{ secrets.HAWK_API_KEY }} 149 | workspace: ${{ github.workspace }}/__tests__/integration-tests/configs/javaspringvulny/ 150 | configurationFiles: stackhawk-jsv-json-token.yml 151 | command: rescan 152 | args: | 153 | --scan-id ${{ steps.run-hawkscan.outputs.scanId }} 154 | env: 155 | APPLICATION_ID: 4030d674-88b7-4e07-8065-7761f9c63788 156 | 157 | # If there is a new version according to the .bumpversion.cfg file in the main branch, tag and release 158 | release-new-version: 159 | name: Release New Version 160 | runs-on: ubuntu-20.04 161 | if: github.ref == 'refs/heads/main' && github.event_name == 'push' 162 | needs: 163 | - unit-tests 164 | - live-test 165 | - ajax-test 166 | - verbose-debug-test 167 | - command-line-test 168 | - javaspringvulny-test 169 | steps: 170 | - uses: actions/checkout@v3 171 | with: 172 | fetch-depth: 0 173 | - name: Check Release Version 174 | run: | 175 | echo "RELEASE_VERSION=$(./scripts/version-check.sh)" >> $GITHUB_ENV 176 | - name: Create Release 177 | id: create_release 178 | if: env.RELEASE_VERSION != '' 179 | uses: actions/create-release@v1 180 | env: 181 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 182 | with: 183 | tag_name: v${{ env.RELEASE_VERSION }} 184 | release_name: HawkScan Action ${{ env.RELEASE_VERSION }} 185 | -------------------------------------------------------------------------------- /.github/workflows/update-main-version.yml: -------------------------------------------------------------------------------- 1 | name: Update Main Version 2 | run-name: Move ${{ github.event.inputs.main_version }} to ${{ github.event.inputs.target }} 3 | 4 | on: 5 | workflow_dispatch: 6 | inputs: 7 | target: 8 | description: The tag or reference to use 9 | required: true 10 | main_version: 11 | type: choice 12 | description: The main version to update 13 | options: 14 | - v2 15 | 16 | jobs: 17 | tag: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v3 21 | with: 22 | fetch-depth: 0 23 | - name: Git config 24 | run: | 25 | git config user.name hawkdeploy 26 | git config user.email hawkdeploy@stackhawk.com 27 | - name: Tag new target 28 | run: git tag -f ${{ github.event.inputs.main_version }} ${{ github.event.inputs.target }} 29 | - name: Push new tag 30 | run: git push origin ${{ github.event.inputs.main_version }} --force 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | scratch 3 | 4 | # Editors 5 | .vscode/ 6 | .idea/ 7 | *.iml 8 | 9 | # Logs 10 | logs 11 | *.log 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | 16 | # Runtime data 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | lib-cov 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage 27 | 28 | # nyc test coverage 29 | .nyc_output 30 | 31 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 32 | .grunt 33 | 34 | # Bower dependency directory (https://bower.io/) 35 | bower_components 36 | 37 | # node-waf configuration 38 | .lock-wscript 39 | 40 | # Compiled binary addons (https://nodejs.org/api/addons.html) 41 | build/Release 42 | 43 | # Other Dependency directories 44 | jspm_packages/ 45 | 46 | # TypeScript v1 declaration files 47 | typings/ 48 | 49 | # Optional npm cache directory 50 | .npm 51 | 52 | # Optional eslint cache 53 | .eslintcache 54 | 55 | # Optional REPL history 56 | .node_repl_history 57 | 58 | # Output of 'npm pack' 59 | *.tgz 60 | 61 | # Yarn Integrity file 62 | .yarn-integrity 63 | 64 | # dotenv environment variables file 65 | .env 66 | 67 | # next.js build output 68 | .next 69 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v20.11.0 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 GitHub Actions 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![StackHawk](https://www.stackhawk.com/stackhawk-light-long@2x.png)](https://stackhawk.com) 2 | 3 | # StackHawk HawkScan Action 4 | 5 | The [StackHawk](https://www.stackhawk.com/) [HawkScan](https://hub.docker.com/r/stackhawk/hawkscan) GitHub Action makes it easy to integrate application security testing into your CI pipeline. 6 | 7 | ## About StackHawk 8 | Here's the rundown: 9 | 10 | * 🧪 Modern Application Security Testing: StackHawk is a dynamic application security testing (DAST) tool, helping you catch security bugs before they hit production. 11 | * 💻 Built for Developers: The engineers building software are the best equipped to fix bugs, including security bugs. StackHawk does security, but is built for engineers like you. 12 | * 🤖 Simple to Automate in CI: Application security tests belong in CI, running tests on every PR. Adding StackHawk tests to a DevOps pipeline is easy. 13 | 14 | ## Getting Started 15 | * Get your application set up in StackHawk with our [quickstart guide](https://docs.stackhawk.com/hawkscan/#quickstart) 16 | * Add your HawkScan Action to your GitHub repository. [Continuous Integration with HawkScan GitHub Action](https://docs.stackhawk.com/continuous-integration/github-actions.html) 17 | 18 | ## Inputs 19 | 20 | ### `apiKey` 21 | 22 | **Required** Your StackHawk API key. 23 | 24 | For example: 25 | ```yaml 26 | jobs: 27 | stackhawk-hawkscan: 28 | runs-on: ubuntu-latest 29 | steps: 30 | - uses: actions/checkout@v2 31 | - uses: stackhawk/hawkscan-action@v2.2.0 32 | with: 33 | apiKey: ${{ secrets.HAWK_API_KEY }} 34 | ``` 35 | 36 | ### `args` 37 | 38 | **Optional** If you wish to supply additional arguments as a multi line input use the `args` option. 39 | 40 | For example: 41 | ```yaml 42 | jobs: 43 | stackhawk-hawkscan: 44 | runs-on: ubuntu-latest 45 | steps: 46 | - uses: actions/checkout@v2 47 | - uses: stackhawk/hawkscan-action@v2.2.0 48 | with: 49 | args: | 50 | --hawk-mem 1g 51 | ``` 52 | 53 | ### `command` 54 | 55 | **Optional** If you want to run a command other than `scan`, it can be supplied in the command option. 56 | 57 | For example: 58 | ```yaml 59 | jobs: 60 | stackhawk-hawkscan: 61 | runs-on: ubuntu-latest 62 | steps: 63 | - uses: actions/checkout@v2 64 | - uses: stackhawk/hawkscan-action@v2.2.0 65 | with: 66 | command: rescan 67 | ``` 68 | 69 | ### `dryRun` 70 | 71 | **Optional** If set to `true`, shows HawkScan commands, but don't run them. 72 | 73 | For example: 74 | ```yaml 75 | jobs: 76 | stackhawk-hawkscan: 77 | runs-on: ubuntu-latest 78 | steps: 79 | - uses: actions/checkout@v2 80 | - uses: stackhawk/hawkscan-action@v2.2.0 81 | with: 82 | apiKey: ${{ secrets.HAWK_API_KEY }} 83 | dryRun: true 84 | ``` 85 | 86 | ### `configurationFiles` 87 | 88 | **Optional** A list of HawkScan configuration files to use. Defaults to `stackhawk.yml`. File names can be separated with spaces, commas, or newlines. 89 | 90 | For example: 91 | ```yaml 92 | jobs: 93 | stackhawk-hawkscan: 94 | runs-on: ubuntu-latest 95 | steps: 96 | - uses: actions/checkout@v2 97 | - uses: stackhawk/hawkscan-action@v2.2.0 98 | with: 99 | apiKey: ${{ secrets.HAWK_API_KEY }} 100 | configurationFiles: stackhawk.yml stackhawk-extra.yml 101 | ``` 102 | 103 | ### `installCLIOnly` 104 | 105 | **Optional** Flag to signal to only install the CLI and not run a scan if set to true. Then you can optionally run hawk CLI from the job 106 | 107 | For example: 108 | ```yaml 109 | jobs: 110 | stackhawk-hawkscan: 111 | runs-on: ubuntu-latest 112 | steps: 113 | - uses: actions/checkout@v2 114 | - uses: stackhawk/hawkscan-action@v2.2.0 115 | with: 116 | installCLIOnly: true 117 | - name: Run CLI Scan 118 | run: hawk --api-key=${{ secrets.HAWK_API_KEY }} scan 119 | ``` 120 | 121 | ### `codeScanningAlerts` 122 | 123 | **Optional** *(requires [`githubToken`](#githubtoken))* If set to `true`, uploads SARIF scan data to GitHub so that scan results are available from [Code Scanning](https://docs.github.com/en/code-security/secure-coding/automatically-scanning-your-code-for-vulnerabilities-and-errors/about-code-scanning). 124 | 125 | The `codeScanningAlerts` feature works in conjunction with the HawkScan's [`hawk.failureThreshold`](https://docs.stackhawk.com/hawkscan/configuration/#hawk) configuration option. If your scan produces alerts that meet or exceed your `hawk.failureThreshold` alert level, it will fail the scan with exit code 42, and trigger a Code Scanning alert in GitHub with a link to your scan results. 126 | 127 | For example: 128 | ```yaml 129 | jobs: 130 | stackhawk-hawkscan: 131 | runs-on: ubuntu-latest 132 | steps: 133 | - uses: actions/checkout@v2 134 | - uses: stackhawk/hawkscan-action@v2.2.0 135 | with: 136 | apiKey: ${{ secrets.HAWK_API_KEY }} 137 | codeScanningAlerts: true 138 | githubToken: ${{ github.token }} 139 | ``` 140 | 141 | > NOTE: GitHub Code Scanning features are free for public repositories. For private repositories, a [GitHub Advanced Security](https://docs.github.com/en/get-started/learning-about-github/about-github-advanced-security) license is required. 142 | 143 | ### `githubToken` 144 | 145 | **Optional** If set to `${{ github.token }}`, gives HawkScan Action a temporary GitHub API token to enable uploading SARIF data. This input is required if `codeScanningAlerts` is set to `true`. 146 | 147 | ### `debug` 148 | 149 | **Optional** If you need additional information on your scans enable the debug and verbose environment variables to see detailed logs in the workflow output 150 | 151 | ```yaml 152 | jobs: 153 | stackhawk-hawkscan: 154 | runs-on: ubuntu-latest 155 | steps: 156 | - uses: actions/checkout@v2 157 | - uses: stackhawk/hawkscan-action@v2.2.0 158 | with: 159 | apiKey: ${{ secrets.HAWK_API_KEY }} 160 | verbose: true 161 | debug: true 162 | ``` 163 | 164 | ### `workspace` 165 | 166 | **Optional** If you need to configure your scan to run in folder outside your .github folder you can set a workspace path relative to your directory 167 | 168 | ```yaml 169 | jobs: 170 | stackhawk-hawkscan: 171 | runs-on: ubuntu-latest 172 | steps: 173 | - uses: actions/checkout@v2 174 | - uses: stackhawk/hawkscan-action@v2.2.0 175 | with: 176 | workspace: ./app/config/ 177 | ``` 178 | 179 | ### `version` 180 | 181 | **Optional** If you need to configure your scan to run with a specific version of HawkScan you can set the version 182 | 183 | ```yaml 184 | jobs: 185 | stackhawk-hawkscan: 186 | runs-on: ubuntu-latest 187 | steps: 188 | - uses: actions/checkout@v2 189 | - uses: stackhawk/hawkscan-action@v2.2.0 190 | with: 191 | version: 2.7.0 192 | ``` 193 | 194 | ## Examples 195 | 196 | The following example shows how to run HawkScan with a StackHawk platform API key stored as a GitHub Actions secret environment variable, `HAWK_API_KEY`. In this workflow, GitHub Actions will checkout your repository, build your Python app, and run it. It then uses the HawkScan Action to run HawkScan with the given API key. HawkScan automatically finds the `stackhawk.yml` configuration file at the root of your repository and runs a scan based on that configuration. 197 | 198 | ```yaml 199 | jobs: 200 | stackhawk-hawkscan: 201 | runs-on: ubuntu-latest 202 | name: Run my app and scan it 203 | steps: 204 | - name: Check out repo 205 | uses: actions/checkout@v2 206 | - name: Build and run my app 207 | run: | 208 | pip3 install -r requirements.txt 209 | nohup python3 app.py & 210 | - name: Scan my app 211 | uses: stackhawk/hawkscan-action@v2.2.0 212 | with: 213 | apiKey: ${{ secrets.HAWK_API_KEY }} 214 | ``` 215 | 216 | The next example shows a similar job with more options enabled, described below. 217 | 218 | ```yaml 219 | jobs: 220 | stackhawk-hawkscan: 221 | runs-on: ubuntu-latest 222 | name: Run my app and scan it 223 | steps: 224 | - name: Check out repo 225 | uses: actions/checkout@v2 226 | - name: Build and run my app 227 | run: | 228 | pip3 install -r requirements.txt 229 | nohup python3 app.py & 230 | - name: Scan my app 231 | env: 232 | APP_HOST: 'http://localhost:5000' 233 | APP_ID: AE624DB7-11FC-4561-B8F2-2C8ECF77C2C7 234 | APP_ENV: Development 235 | uses: stackhawk/hawkscan-action@v2.2.0 236 | with: 237 | apiKey: ${{ secrets.HAWK_API_KEY }} 238 | dryRun: true 239 | configurationFiles: | 240 | stackhawk.yml 241 | stackhawk-extras.yml 242 | ``` 243 | 244 | The configuration above will perform a dry run, meaning it will only print out the Docker command that it would run if `dryRun` were set to `false`, which is the default. Finally, it tells HawkScan to use the `stackhawk.yml` configuration file and overlay the `stackhawk-extra.yml` configuration file on top of it. 245 | 246 | ## Java Requirements for HawkScan 247 | HawkScan 4 and above requires Java 17 through 21. If you are defaulting to latest version of HawkScan, please ensure your Java is set to the correct version on your Github runners. 248 | 249 | To address this, Java on Hosted Runners can be easily setup in a prior workflow step to instead use the correct Java version: 250 | ```yaml 251 | - uses: actions/setup-java@v4 252 | with: 253 | distribution: 'temurin' 254 | java-version: '17' 255 | ``` 256 | 257 | ## Need Help? 258 | 259 | If you have questions or need some help, please email us at support@stackhawk.com. 260 | -------------------------------------------------------------------------------- /__tests__/index.js: -------------------------------------------------------------------------------- 1 | const utilities = require('../src/utilities'); 2 | const process = require('process'); 3 | const { getDownloadObject } = require('../src/cli_utils'); 4 | 5 | // Our workspace should be GITHUB_WORSPACE if it exists, or the current working directory otherwise 6 | const workspace = process.env.GITHUB_WORKSPACE || process.cwd(); 7 | 8 | // Take an object of key/value pairs and convert it to input environment variables 9 | function buildInput(inputs) { 10 | let key = ""; 11 | for(key in inputs) { 12 | process.env[`INPUT_${key.replace(/ /g, '_').toUpperCase()}`] = inputs[key]; 13 | } 14 | } 15 | 16 | // Reset modules and remove input environment variables before each run 17 | beforeEach(() => { 18 | jest.resetModules(); 19 | delete process.env.INPUT_DRYRUN; 20 | delete process.env.INPUT_APIKEY; 21 | delete process.env.INPUT_WORKSPACE; 22 | delete process.env.INPUT_CONFIGURATIONFILES; 23 | delete process.env.INPUT_VERSION; 24 | delete process.env.INPUT_CODESCANNINGALERTS; 25 | delete process.env.INPUT_GITHUBTOKEN; 26 | delete process.env.INPUT_INSTALLCLIONLY; 27 | delete process.env.INPUT_SOURCEURL; 28 | delete process.env.INPUT_VERBOSE; 29 | delete process.env.INPUT_DEBUG; 30 | delete process.env.INPUT_COMMAND; 31 | delete process.env.INPUT_ARGS; 32 | }); 33 | 34 | test('gather minimal inputs', () => { 35 | expect(utilities.gatherInputs()).toEqual({ 36 | apiKey: '', 37 | args: [], 38 | command: 'scan', 39 | githubToken: "", 40 | configurationFiles: ['stackhawk.yml'], 41 | version: 'latest', 42 | dryRun: 'false', 43 | installCLIOnly : 'false', 44 | codeScanningAlerts: 'false', 45 | workspace : workspace, 46 | sourceURL : 'https://download.stackhawk.com/hawk/cli', 47 | verbose: 'false', 48 | debug: 'false', 49 | }); 50 | }); 51 | 52 | test('gather max inputs', () => { 53 | buildInput({ 54 | apiKey: 'testkey', 55 | args: '--scan-id XXxxXXXX-xXXX-xxXX-XXxX-xXXxxXXXXxXX', 56 | command: 'rescan', 57 | githubToken: "gh.xXx.XxX", 58 | configurationFiles: "one.yml two.yml, three.yml\nfour.yml five.yaml,,six.yml,\n\n seven.yml, ", 59 | version: 'latest', 60 | dryRun: 'true', 61 | codeScanningAlerts: 'true', 62 | installCLIOnly : 'true', 63 | sourceURL : 'https://download.stackhawk.com/hawk/cli', 64 | verbose: 'false', 65 | debug: 'false' 66 | }); 67 | 68 | expect(utilities.gatherInputs()).toEqual({ 69 | workspace: workspace, 70 | apiKey: 'testkey', 71 | args: ['--scan-id XXxxXXXX-xXXX-xxXX-XXxX-xXXxxXXXXxXX'], 72 | command: 'rescan', 73 | githubToken: "gh.xXx.XxX", 74 | configurationFiles: ['one.yml', 'two.yml', 'three.yml', 'four.yml', 'five.yaml', 'six.yml', 'seven.yml'], 75 | version: 'latest', 76 | dryRun: 'true', 77 | codeScanningAlerts: 'true', 78 | installCLIOnly : 'true', 79 | sourceURL : 'https://download.stackhawk.com/hawk/cli', 80 | verbose: 'false', 81 | debug: 'false' 82 | }); 83 | }); 84 | 85 | test('cli dry-run', () => { 86 | buildInput({ 87 | dryRun: 'true', 88 | apiKey: 'hawk.xxxxXXXXxxXXxxxXXxXX.xxxXXxxxXXxxXXxxxXXX', 89 | version: '2.1.0', 90 | }); 91 | const inputs = utilities.gatherInputs(); 92 | const cliCommand = utilities.buildCLICommand(inputs); 93 | const hawk = utilities.hawkExecutable(); 94 | expect(cliCommand) 95 | .toEqual(`${hawk} --api-key=hawk.xxxxXXXXxxXXxxxXXxXX.xxxXXxxxXXxxXXxxxXXX scan --repo-dir ${workspace} --cicd-platform github-action stackhawk.yml`); 96 | }); 97 | 98 | test('cli dry-run args', () => { 99 | buildInput({ 100 | dryRun: 'true', 101 | apiKey: 'hawk.xxxxXXXXxxXXxxxXXxXX.xxxXXxxxXXxxXXxxxXXX', 102 | version: '2.1.0', 103 | command: 'rescan', 104 | args: '--scan-id XXxxXXXX-xXXX-xxXX-XXxX-xXXxxXXXXxXX\n--debug true' 105 | }); 106 | const inputs = utilities.gatherInputs(); 107 | const cliCommand = utilities.buildCLICommand(inputs); 108 | const hawk = utilities.hawkExecutable(); 109 | expect(cliCommand) 110 | .toEqual(`${hawk} --api-key=hawk.xxxxXXXXxxXXxxxXXxXX.xxxXXxxxXXxxXXxxxXXX rescan --repo-dir ${workspace} --cicd-platform github-action --scan-id XXxxXXXX-xXXX-xxXX-XXxX-xXXxxXXXXxXX --debug true stackhawk.yml`); 111 | }); 112 | 113 | test('get download object', () => { 114 | const downloadObject = getDownloadObject('2.1.0', 'https://download.stackhawk.com/hawk/cli'); 115 | expect(downloadObject.url).toEqual('https://download.stackhawk.com/hawk/cli/hawk-2.1.0.zip'); 116 | expect(downloadObject.binPath).toEqual('/hawk-2.1.0'); 117 | }); 118 | 119 | test('get custom url download object', () => { 120 | const downloadObject = getDownloadObject('2.1.0', 'https://download.stackhawk.com/hawk/cli'); 121 | expect(downloadObject.url).toEqual('https://download.stackhawk.com/hawk/cli/hawk-2.1.0.zip'); 122 | expect(downloadObject.binPath).toEqual('/hawk-2.1.0'); 123 | }) 124 | -------------------------------------------------------------------------------- /__tests__/integration-tests/configs/javaspringvulny/openapi.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.1 2 | info: 3 | title: OpenAPI definition 4 | version: v0 5 | servers: 6 | - url: https://localhost:9000 7 | description: Generated server url 8 | paths: 9 | /api/jwt/items/search/: 10 | get: 11 | tags: 12 | - jwt-item-controller 13 | operationId: searchAll 14 | responses: 15 | 200: 16 | description: default response 17 | content: 18 | '*/*': 19 | schema: 20 | type: string 21 | /api/jwt/items/search/{text}: 22 | get: 23 | tags: 24 | - jwt-item-controller 25 | operationId: search 26 | parameters: 27 | - name: text 28 | in: path 29 | required: true 30 | schema: 31 | type: string 32 | responses: 33 | 200: 34 | description: default response 35 | content: 36 | '*/*': 37 | schema: 38 | type: string 39 | /api/jwt/auth/signin: 40 | post: 41 | tags: 42 | - jwt-auth-controller 43 | operationId: signin 44 | requestBody: 45 | content: 46 | application/json: 47 | schema: 48 | $ref: '#/components/schemas/AuthenticationRequest' 49 | responses: 50 | 200: 51 | description: default response 52 | content: 53 | '*/*': 54 | schema: 55 | type: string 56 | /api/token/items/search/: 57 | get: 58 | tags: 59 | - token-item-controller 60 | operationId: search_1 61 | responses: 62 | 200: 63 | description: default response 64 | content: 65 | '*/*': 66 | schema: 67 | type: string 68 | /api/token/items/search/{text}: 69 | get: 70 | tags: 71 | - token-item-controller 72 | operationId: search_2 73 | parameters: 74 | - name: text 75 | in: path 76 | required: true 77 | schema: 78 | type: string 79 | responses: 80 | 200: 81 | description: default response 82 | content: 83 | '*/*': 84 | schema: 85 | type: string 86 | /api/basic/items/search/: 87 | get: 88 | tags: 89 | - basic-auth-item-controller 90 | operationId: search_3 91 | responses: 92 | 200: 93 | description: default response 94 | content: 95 | '*/*': 96 | schema: 97 | type: string 98 | /api/basic/items/search/{text}: 99 | get: 100 | tags: 101 | - basic-auth-item-controller 102 | operationId: search_4 103 | parameters: 104 | - name: text 105 | in: path 106 | required: true 107 | schema: 108 | type: string 109 | responses: 110 | 200: 111 | description: default response 112 | content: 113 | '*/*': 114 | schema: 115 | type: string 116 | /api/jwt/log4j: 117 | get: 118 | tags: 119 | - jwt-auth-controller 120 | operationId: log4j, 121 | requestBody: 122 | content: 123 | '*/*': 124 | schema: 125 | type: string 126 | responses: 127 | 200: 128 | description: default response, 129 | content: 130 | '*/*': 131 | schema: 132 | type: string 133 | components: 134 | schemas: 135 | AuthenticationRequest: 136 | type: object 137 | properties: 138 | username: 139 | type: string 140 | password: 141 | type: string 142 | -------------------------------------------------------------------------------- /__tests__/integration-tests/configs/javaspringvulny/stackhawk-jsv-json-token.yml: -------------------------------------------------------------------------------- 1 | hawk: 2 | spider: 3 | maxDurationMinutes: 2 4 | app: 5 | applicationId: ${APPLICATION_ID:test-app-id} 6 | env: ${ENV:Action Test} 7 | host: ${APP_HOST:https://localhost:9000} 8 | openApiConf: 9 | filePath: openapi.yaml 10 | authentication: 11 | loggedInIndicator: "\\QSign Out\\E" 12 | loggedOutIndicator: ".*Location:.*/login.*" 13 | usernamePassword: 14 | type: JSON 15 | loginPath: /api/jwt/auth/signin 16 | usernameField: username 17 | passwordField: password 18 | scanUsername: "user" 19 | scanPassword: "password" 20 | tokenAuthorization: 21 | type: HEADER 22 | value: Authorization 23 | tokenType: Bearer 24 | tokenExtraction: 25 | type: TOKEN_PATH 26 | value: "token" 27 | testPath: 28 | path: /api/jwt/items/search/i 29 | success: ".*200.*" 30 | autoPolicy: true 31 | autoInputVectors: true -------------------------------------------------------------------------------- /__tests__/stackhawk.yml: -------------------------------------------------------------------------------- 1 | app: 2 | applicationId: f5ee2290-3383-415c-96c7-ee0a398d90b9 3 | env: Action Tests 4 | host: ${HOST:http://example.com} 5 | 6 | hawk: 7 | spider: 8 | base: false 9 | failureThreshold: high 10 | -------------------------------------------------------------------------------- /__tests__/stackhawk_spider.yml: -------------------------------------------------------------------------------- 1 | app: 2 | applicationId: f5ee2290-3383-415c-96c7-ee0a398d90b9 3 | env: Action Tests 4 | host: ${HOST:http://example.com} 5 | 6 | hawk: 7 | spider: 8 | ajax: true 9 | base: false 10 | failureThreshold: high -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'StackHawk HawkScan Action' 2 | description: 'Find security bugs in your application with HawkScan DAST' 3 | author: 'Zachary Conger' 4 | 5 | inputs: 6 | apiKey: 7 | description: StackHawk API key 8 | required: true 9 | args: 10 | description: Arguments to be passed to the scan as a multi line option 11 | required: false 12 | command: 13 | description: Command to be passed to HawkScan 14 | default: scan 15 | required: false 16 | dryRun: 17 | description: If set to `true`, show HawkScan commands, but don't run them 18 | required: false 19 | default: false 20 | workspace: 21 | description: Working directory accessed by HawkScan including configuration files 22 | required: false 23 | default: ${{ github.workspace }} 24 | configurationFiles: 25 | description: Space-separated list of HawkScan configuration files to use 26 | required: false 27 | default: stackhawk.yml 28 | codeScanningAlerts: 29 | description: If `true`, Register a Code Scanning Alert in GitHub if scan alerts exceed `hawk.failureThreshold` 30 | required: false 31 | default: false 32 | githubToken: 33 | description: GitHub Token for uploading Code Scanning Alert info - required if `codeScanningAlerts` is enabled 34 | required: false 35 | default: ${{ github.token }} 36 | installCLIOnly: 37 | description: If `true` the action will only install the CLI and not run a scan 38 | required: false 39 | default: false 40 | sourceURL: 41 | description: Source for ZIP file 42 | required: false 43 | default: https://download.stackhawk.com/hawk/cli 44 | version: 45 | description: HawkScan CLI version to use 46 | required: false 47 | default: latest 48 | verbose: 49 | description: HawkScan CLI verbose log output flag 50 | required: false 51 | default: false 52 | debug: 53 | description: HawkScan CLI debug log output flag 54 | required: false 55 | default: false 56 | 57 | runs: 58 | using: node20 59 | main: dist/index.js 60 | 61 | branding: 62 | icon: 'octagon' 63 | color: 'green' 64 | -------------------------------------------------------------------------------- /dist/licenses.txt: -------------------------------------------------------------------------------- 1 | @actions/core 2 | MIT 3 | The MIT License (MIT) 4 | 5 | Copyright 2019 GitHub 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 12 | 13 | @actions/exec 14 | MIT 15 | The MIT License (MIT) 16 | 17 | Copyright 2019 GitHub 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | @actions/http-client 26 | MIT 27 | Actions Http Client for Node.js 28 | 29 | Copyright (c) GitHub, Inc. 30 | 31 | All rights reserved. 32 | 33 | MIT License 34 | 35 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 36 | associated documentation files (the "Software"), to deal in the Software without restriction, 37 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 38 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 39 | subject to the following conditions: 40 | 41 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 42 | 43 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 44 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 45 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 46 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 47 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 48 | 49 | 50 | @actions/io 51 | MIT 52 | The MIT License (MIT) 53 | 54 | Copyright 2019 GitHub 55 | 56 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 57 | 58 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 59 | 60 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 61 | 62 | @actions/tool-cache 63 | MIT 64 | The MIT License (MIT) 65 | 66 | Copyright 2019 GitHub 67 | 68 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 69 | 70 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 71 | 72 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 73 | 74 | @kwsites/file-exists 75 | MIT 76 | The MIT License (MIT) 77 | 78 | Copyright (c) 2015 Steve King 79 | 80 | Permission is hereby granted, free of charge, to any person obtaining a copy of 81 | this software and associated documentation files (the "Software"), to deal in 82 | the Software without restriction, including without limitation the rights to 83 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 84 | the Software, and to permit persons to whom the Software is furnished to do so, 85 | subject to the following conditions: 86 | 87 | The above copyright notice and this permission notice shall be included in all 88 | copies or substantial portions of the Software. 89 | 90 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 91 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 92 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 93 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 94 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 95 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 96 | 97 | 98 | @kwsites/promise-deferred 99 | MIT 100 | MIT License 101 | 102 | Copyright (c) 2018 kwsites 103 | 104 | Permission is hereby granted, free of charge, to any person obtaining a copy 105 | of this software and associated documentation files (the "Software"), to deal 106 | in the Software without restriction, including without limitation the rights 107 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 108 | copies of the Software, and to permit persons to whom the Software is 109 | furnished to do so, subject to the following conditions: 110 | 111 | The above copyright notice and this permission notice shall be included in all 112 | copies or substantial portions of the Software. 113 | 114 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 115 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 116 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 117 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 118 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 119 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 120 | SOFTWARE. 121 | 122 | 123 | @octokit/auth-token 124 | MIT 125 | The MIT License 126 | 127 | Copyright (c) 2019 Octokit contributors 128 | 129 | Permission is hereby granted, free of charge, to any person obtaining a copy 130 | of this software and associated documentation files (the "Software"), to deal 131 | in the Software without restriction, including without limitation the rights 132 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 133 | copies of the Software, and to permit persons to whom the Software is 134 | furnished to do so, subject to the following conditions: 135 | 136 | The above copyright notice and this permission notice shall be included in 137 | all copies or substantial portions of the Software. 138 | 139 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 140 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 141 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 142 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 143 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 144 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 145 | THE SOFTWARE. 146 | 147 | 148 | @octokit/core 149 | MIT 150 | The MIT License 151 | 152 | Copyright (c) 2019 Octokit contributors 153 | 154 | Permission is hereby granted, free of charge, to any person obtaining a copy 155 | of this software and associated documentation files (the "Software"), to deal 156 | in the Software without restriction, including without limitation the rights 157 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 158 | copies of the Software, and to permit persons to whom the Software is 159 | furnished to do so, subject to the following conditions: 160 | 161 | The above copyright notice and this permission notice shall be included in 162 | all copies or substantial portions of the Software. 163 | 164 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 165 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 166 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 167 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 168 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 169 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 170 | THE SOFTWARE. 171 | 172 | 173 | @octokit/endpoint 174 | MIT 175 | The MIT License 176 | 177 | Copyright (c) 2018 Octokit contributors 178 | 179 | Permission is hereby granted, free of charge, to any person obtaining a copy 180 | of this software and associated documentation files (the "Software"), to deal 181 | in the Software without restriction, including without limitation the rights 182 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 183 | copies of the Software, and to permit persons to whom the Software is 184 | furnished to do so, subject to the following conditions: 185 | 186 | The above copyright notice and this permission notice shall be included in 187 | all copies or substantial portions of the Software. 188 | 189 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 190 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 191 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 192 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 193 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 194 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 195 | THE SOFTWARE. 196 | 197 | 198 | @octokit/graphql 199 | MIT 200 | The MIT License 201 | 202 | Copyright (c) 2018 Octokit contributors 203 | 204 | Permission is hereby granted, free of charge, to any person obtaining a copy 205 | of this software and associated documentation files (the "Software"), to deal 206 | in the Software without restriction, including without limitation the rights 207 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 208 | copies of the Software, and to permit persons to whom the Software is 209 | furnished to do so, subject to the following conditions: 210 | 211 | The above copyright notice and this permission notice shall be included in 212 | all copies or substantial portions of the Software. 213 | 214 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 215 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 216 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 217 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 218 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 219 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 220 | THE SOFTWARE. 221 | 222 | 223 | @octokit/request 224 | MIT 225 | The MIT License 226 | 227 | Copyright (c) 2018 Octokit contributors 228 | 229 | Permission is hereby granted, free of charge, to any person obtaining a copy 230 | of this software and associated documentation files (the "Software"), to deal 231 | in the Software without restriction, including without limitation the rights 232 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 233 | copies of the Software, and to permit persons to whom the Software is 234 | furnished to do so, subject to the following conditions: 235 | 236 | The above copyright notice and this permission notice shall be included in 237 | all copies or substantial portions of the Software. 238 | 239 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 240 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 241 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 242 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 243 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 244 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 245 | THE SOFTWARE. 246 | 247 | 248 | @octokit/request-error 249 | MIT 250 | The MIT License 251 | 252 | Copyright (c) 2019 Octokit contributors 253 | 254 | Permission is hereby granted, free of charge, to any person obtaining a copy 255 | of this software and associated documentation files (the "Software"), to deal 256 | in the Software without restriction, including without limitation the rights 257 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 258 | copies of the Software, and to permit persons to whom the Software is 259 | furnished to do so, subject to the following conditions: 260 | 261 | The above copyright notice and this permission notice shall be included in 262 | all copies or substantial portions of the Software. 263 | 264 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 265 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 266 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 267 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 268 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 269 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 270 | THE SOFTWARE. 271 | 272 | 273 | @vercel/ncc 274 | MIT 275 | Copyright 2018 ZEIT, Inc. 276 | 277 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 278 | 279 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 280 | 281 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 282 | 283 | before-after-hook 284 | Apache-2.0 285 | Apache License 286 | Version 2.0, January 2004 287 | http://www.apache.org/licenses/ 288 | 289 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 290 | 291 | 1. Definitions. 292 | 293 | "License" shall mean the terms and conditions for use, reproduction, 294 | and distribution as defined by Sections 1 through 9 of this document. 295 | 296 | "Licensor" shall mean the copyright owner or entity authorized by 297 | the copyright owner that is granting the License. 298 | 299 | "Legal Entity" shall mean the union of the acting entity and all 300 | other entities that control, are controlled by, or are under common 301 | control with that entity. For the purposes of this definition, 302 | "control" means (i) the power, direct or indirect, to cause the 303 | direction or management of such entity, whether by contract or 304 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 305 | outstanding shares, or (iii) beneficial ownership of such entity. 306 | 307 | "You" (or "Your") shall mean an individual or Legal Entity 308 | exercising permissions granted by this License. 309 | 310 | "Source" form shall mean the preferred form for making modifications, 311 | including but not limited to software source code, documentation 312 | source, and configuration files. 313 | 314 | "Object" form shall mean any form resulting from mechanical 315 | transformation or translation of a Source form, including but 316 | not limited to compiled object code, generated documentation, 317 | and conversions to other media types. 318 | 319 | "Work" shall mean the work of authorship, whether in Source or 320 | Object form, made available under the License, as indicated by a 321 | copyright notice that is included in or attached to the work 322 | (an example is provided in the Appendix below). 323 | 324 | "Derivative Works" shall mean any work, whether in Source or Object 325 | form, that is based on (or derived from) the Work and for which the 326 | editorial revisions, annotations, elaborations, or other modifications 327 | represent, as a whole, an original work of authorship. For the purposes 328 | of this License, Derivative Works shall not include works that remain 329 | separable from, or merely link (or bind by name) to the interfaces of, 330 | the Work and Derivative Works thereof. 331 | 332 | "Contribution" shall mean any work of authorship, including 333 | the original version of the Work and any modifications or additions 334 | to that Work or Derivative Works thereof, that is intentionally 335 | submitted to Licensor for inclusion in the Work by the copyright owner 336 | or by an individual or Legal Entity authorized to submit on behalf of 337 | the copyright owner. For the purposes of this definition, "submitted" 338 | means any form of electronic, verbal, or written communication sent 339 | to the Licensor or its representatives, including but not limited to 340 | communication on electronic mailing lists, source code control systems, 341 | and issue tracking systems that are managed by, or on behalf of, the 342 | Licensor for the purpose of discussing and improving the Work, but 343 | excluding communication that is conspicuously marked or otherwise 344 | designated in writing by the copyright owner as "Not a Contribution." 345 | 346 | "Contributor" shall mean Licensor and any individual or Legal Entity 347 | on behalf of whom a Contribution has been received by Licensor and 348 | subsequently incorporated within the Work. 349 | 350 | 2. Grant of Copyright License. Subject to the terms and conditions of 351 | this License, each Contributor hereby grants to You a perpetual, 352 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 353 | copyright license to reproduce, prepare Derivative Works of, 354 | publicly display, publicly perform, sublicense, and distribute the 355 | Work and such Derivative Works in Source or Object form. 356 | 357 | 3. Grant of Patent License. Subject to the terms and conditions of 358 | this License, each Contributor hereby grants to You a perpetual, 359 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 360 | (except as stated in this section) patent license to make, have made, 361 | use, offer to sell, sell, import, and otherwise transfer the Work, 362 | where such license applies only to those patent claims licensable 363 | by such Contributor that are necessarily infringed by their 364 | Contribution(s) alone or by combination of their Contribution(s) 365 | with the Work to which such Contribution(s) was submitted. If You 366 | institute patent litigation against any entity (including a 367 | cross-claim or counterclaim in a lawsuit) alleging that the Work 368 | or a Contribution incorporated within the Work constitutes direct 369 | or contributory patent infringement, then any patent licenses 370 | granted to You under this License for that Work shall terminate 371 | as of the date such litigation is filed. 372 | 373 | 4. Redistribution. You may reproduce and distribute copies of the 374 | Work or Derivative Works thereof in any medium, with or without 375 | modifications, and in Source or Object form, provided that You 376 | meet the following conditions: 377 | 378 | (a) You must give any other recipients of the Work or 379 | Derivative Works a copy of this License; and 380 | 381 | (b) You must cause any modified files to carry prominent notices 382 | stating that You changed the files; and 383 | 384 | (c) You must retain, in the Source form of any Derivative Works 385 | that You distribute, all copyright, patent, trademark, and 386 | attribution notices from the Source form of the Work, 387 | excluding those notices that do not pertain to any part of 388 | the Derivative Works; and 389 | 390 | (d) If the Work includes a "NOTICE" text file as part of its 391 | distribution, then any Derivative Works that You distribute must 392 | include a readable copy of the attribution notices contained 393 | within such NOTICE file, excluding those notices that do not 394 | pertain to any part of the Derivative Works, in at least one 395 | of the following places: within a NOTICE text file distributed 396 | as part of the Derivative Works; within the Source form or 397 | documentation, if provided along with the Derivative Works; or, 398 | within a display generated by the Derivative Works, if and 399 | wherever such third-party notices normally appear. The contents 400 | of the NOTICE file are for informational purposes only and 401 | do not modify the License. You may add Your own attribution 402 | notices within Derivative Works that You distribute, alongside 403 | or as an addendum to the NOTICE text from the Work, provided 404 | that such additional attribution notices cannot be construed 405 | as modifying the License. 406 | 407 | You may add Your own copyright statement to Your modifications and 408 | may provide additional or different license terms and conditions 409 | for use, reproduction, or distribution of Your modifications, or 410 | for any such Derivative Works as a whole, provided Your use, 411 | reproduction, and distribution of the Work otherwise complies with 412 | the conditions stated in this License. 413 | 414 | 5. Submission of Contributions. Unless You explicitly state otherwise, 415 | any Contribution intentionally submitted for inclusion in the Work 416 | by You to the Licensor shall be under the terms and conditions of 417 | this License, without any additional terms or conditions. 418 | Notwithstanding the above, nothing herein shall supersede or modify 419 | the terms of any separate license agreement you may have executed 420 | with Licensor regarding such Contributions. 421 | 422 | 6. Trademarks. This License does not grant permission to use the trade 423 | names, trademarks, service marks, or product names of the Licensor, 424 | except as required for reasonable and customary use in describing the 425 | origin of the Work and reproducing the content of the NOTICE file. 426 | 427 | 7. Disclaimer of Warranty. Unless required by applicable law or 428 | agreed to in writing, Licensor provides the Work (and each 429 | Contributor provides its Contributions) on an "AS IS" BASIS, 430 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 431 | implied, including, without limitation, any warranties or conditions 432 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 433 | PARTICULAR PURPOSE. You are solely responsible for determining the 434 | appropriateness of using or redistributing the Work and assume any 435 | risks associated with Your exercise of permissions under this License. 436 | 437 | 8. Limitation of Liability. In no event and under no legal theory, 438 | whether in tort (including negligence), contract, or otherwise, 439 | unless required by applicable law (such as deliberate and grossly 440 | negligent acts) or agreed to in writing, shall any Contributor be 441 | liable to You for damages, including any direct, indirect, special, 442 | incidental, or consequential damages of any character arising as a 443 | result of this License or out of the use or inability to use the 444 | Work (including but not limited to damages for loss of goodwill, 445 | work stoppage, computer failure or malfunction, or any and all 446 | other commercial damages or losses), even if such Contributor 447 | has been advised of the possibility of such damages. 448 | 449 | 9. Accepting Warranty or Additional Liability. While redistributing 450 | the Work or Derivative Works thereof, You may choose to offer, 451 | and charge a fee for, acceptance of support, warranty, indemnity, 452 | or other liability obligations and/or rights consistent with this 453 | License. However, in accepting such obligations, You may act only 454 | on Your own behalf and on Your sole responsibility, not on behalf 455 | of any other Contributor, and only if You agree to indemnify, 456 | defend, and hold each Contributor harmless for any liability 457 | incurred by, or claims asserted against, such Contributor by reason 458 | of your accepting any such warranty or additional liability. 459 | 460 | END OF TERMS AND CONDITIONS 461 | 462 | APPENDIX: How to apply the Apache License to your work. 463 | 464 | To apply the Apache License to your work, attach the following 465 | boilerplate notice, with the fields enclosed by brackets "{}" 466 | replaced with your own identifying information. (Don't include 467 | the brackets!) The text should be enclosed in the appropriate 468 | comment syntax for the file format. We also recommend that a 469 | file or class name and description of purpose be included on the 470 | same "printed page" as the copyright notice for easier 471 | identification within third-party archives. 472 | 473 | Copyright 2018 Gregor Martynus and other contributors. 474 | 475 | Licensed under the Apache License, Version 2.0 (the "License"); 476 | you may not use this file except in compliance with the License. 477 | You may obtain a copy of the License at 478 | 479 | http://www.apache.org/licenses/LICENSE-2.0 480 | 481 | Unless required by applicable law or agreed to in writing, software 482 | distributed under the License is distributed on an "AS IS" BASIS, 483 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 484 | See the License for the specific language governing permissions and 485 | limitations under the License. 486 | 487 | 488 | debug 489 | MIT 490 | (The MIT License) 491 | 492 | Copyright (c) 2014-2017 TJ Holowaychuk 493 | Copyright (c) 2018-2021 Josh Junon 494 | 495 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software 496 | and associated documentation files (the 'Software'), to deal in the Software without restriction, 497 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 498 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 499 | subject to the following conditions: 500 | 501 | The above copyright notice and this permission notice shall be included in all copies or substantial 502 | portions of the Software. 503 | 504 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 505 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 506 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 507 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 508 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 509 | 510 | 511 | 512 | deprecation 513 | ISC 514 | The ISC License 515 | 516 | Copyright (c) Gregor Martynus and contributors 517 | 518 | Permission to use, copy, modify, and/or distribute this software for any 519 | purpose with or without fee is hereby granted, provided that the above 520 | copyright notice and this permission notice appear in all copies. 521 | 522 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 523 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 524 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 525 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 526 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 527 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 528 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 529 | 530 | 531 | has-flag 532 | MIT 533 | MIT License 534 | 535 | Copyright (c) Sindre Sorhus (sindresorhus.com) 536 | 537 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 538 | 539 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 540 | 541 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 542 | 543 | 544 | is-plain-object 545 | MIT 546 | The MIT License (MIT) 547 | 548 | Copyright (c) 2014-2017, Jon Schlinkert. 549 | 550 | Permission is hereby granted, free of charge, to any person obtaining a copy 551 | of this software and associated documentation files (the "Software"), to deal 552 | in the Software without restriction, including without limitation the rights 553 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 554 | copies of the Software, and to permit persons to whom the Software is 555 | furnished to do so, subject to the following conditions: 556 | 557 | The above copyright notice and this permission notice shall be included in 558 | all copies or substantial portions of the Software. 559 | 560 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 561 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 562 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 563 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 564 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 565 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 566 | THE SOFTWARE. 567 | 568 | 569 | ms 570 | MIT 571 | The MIT License (MIT) 572 | 573 | Copyright (c) 2016 Zeit, Inc. 574 | 575 | Permission is hereby granted, free of charge, to any person obtaining a copy 576 | of this software and associated documentation files (the "Software"), to deal 577 | in the Software without restriction, including without limitation the rights 578 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 579 | copies of the Software, and to permit persons to whom the Software is 580 | furnished to do so, subject to the following conditions: 581 | 582 | The above copyright notice and this permission notice shall be included in all 583 | copies or substantial portions of the Software. 584 | 585 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 586 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 587 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 588 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 589 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 590 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 591 | SOFTWARE. 592 | 593 | 594 | node-fetch 595 | MIT 596 | The MIT License (MIT) 597 | 598 | Copyright (c) 2016 David Frank 599 | 600 | Permission is hereby granted, free of charge, to any person obtaining a copy 601 | of this software and associated documentation files (the "Software"), to deal 602 | in the Software without restriction, including without limitation the rights 603 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 604 | copies of the Software, and to permit persons to whom the Software is 605 | furnished to do so, subject to the following conditions: 606 | 607 | The above copyright notice and this permission notice shall be included in all 608 | copies or substantial portions of the Software. 609 | 610 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 611 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 612 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 613 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 614 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 615 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 616 | SOFTWARE. 617 | 618 | 619 | 620 | once 621 | ISC 622 | The ISC License 623 | 624 | Copyright (c) Isaac Z. Schlueter and Contributors 625 | 626 | Permission to use, copy, modify, and/or distribute this software for any 627 | purpose with or without fee is hereby granted, provided that the above 628 | copyright notice and this permission notice appear in all copies. 629 | 630 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 631 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 632 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 633 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 634 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 635 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 636 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 637 | 638 | 639 | semver 640 | ISC 641 | The ISC License 642 | 643 | Copyright (c) Isaac Z. Schlueter and Contributors 644 | 645 | Permission to use, copy, modify, and/or distribute this software for any 646 | purpose with or without fee is hereby granted, provided that the above 647 | copyright notice and this permission notice appear in all copies. 648 | 649 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 650 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 651 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 652 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 653 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 654 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 655 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 656 | 657 | 658 | simple-git 659 | MIT 660 | 661 | supports-color 662 | MIT 663 | MIT License 664 | 665 | Copyright (c) Sindre Sorhus (sindresorhus.com) 666 | 667 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 668 | 669 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 670 | 671 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 672 | 673 | 674 | tr46 675 | MIT 676 | 677 | tunnel 678 | MIT 679 | The MIT License (MIT) 680 | 681 | Copyright (c) 2012 Koichi Kobayashi 682 | 683 | Permission is hereby granted, free of charge, to any person obtaining a copy 684 | of this software and associated documentation files (the "Software"), to deal 685 | in the Software without restriction, including without limitation the rights 686 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 687 | copies of the Software, and to permit persons to whom the Software is 688 | furnished to do so, subject to the following conditions: 689 | 690 | The above copyright notice and this permission notice shall be included in 691 | all copies or substantial portions of the Software. 692 | 693 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 694 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 695 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 696 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 697 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 698 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 699 | THE SOFTWARE. 700 | 701 | 702 | universal-user-agent 703 | ISC 704 | # [ISC License](https://spdx.org/licenses/ISC) 705 | 706 | Copyright (c) 2018, Gregor Martynus (https://github.com/gr2m) 707 | 708 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. 709 | 710 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 711 | 712 | 713 | uuid 714 | MIT 715 | The MIT License (MIT) 716 | 717 | Copyright (c) 2010-2020 Robert Kieffer and other contributors 718 | 719 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 720 | 721 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 722 | 723 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 724 | 725 | 726 | webidl-conversions 727 | BSD-2-Clause 728 | # The BSD 2-Clause License 729 | 730 | Copyright (c) 2014, Domenic Denicola 731 | All rights reserved. 732 | 733 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 734 | 735 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 736 | 737 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 738 | 739 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 740 | 741 | 742 | whatwg-url 743 | MIT 744 | The MIT License (MIT) 745 | 746 | Copyright (c) 2015–2016 Sebastian Mayr 747 | 748 | Permission is hereby granted, free of charge, to any person obtaining a copy 749 | of this software and associated documentation files (the "Software"), to deal 750 | in the Software without restriction, including without limitation the rights 751 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 752 | copies of the Software, and to permit persons to whom the Software is 753 | furnished to do so, subject to the following conditions: 754 | 755 | The above copyright notice and this permission notice shall be included in 756 | all copies or substantial portions of the Software. 757 | 758 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 759 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 760 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 761 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 762 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 763 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 764 | THE SOFTWARE. 765 | 766 | 767 | wrappy 768 | ISC 769 | The ISC License 770 | 771 | Copyright (c) Isaac Z. Schlueter and Contributors 772 | 773 | Permission to use, copy, modify, and/or distribute this software for any 774 | purpose with or without fee is hereby granted, provided that the above 775 | copyright notice and this permission notice appear in all copies. 776 | 777 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 778 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 779 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 780 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 781 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 782 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 783 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 784 | -------------------------------------------------------------------------------- /dist/sourcemap-register.js: -------------------------------------------------------------------------------- 1 | (()=>{var e={650:e=>{var r=Object.prototype.toString;var n=typeof Buffer.alloc==="function"&&typeof Buffer.allocUnsafe==="function"&&typeof Buffer.from==="function";function isArrayBuffer(e){return r.call(e).slice(8,-1)==="ArrayBuffer"}function fromArrayBuffer(e,r,t){r>>>=0;var o=e.byteLength-r;if(o<0){throw new RangeError("'offset' is out of bounds")}if(t===undefined){t=o}else{t>>>=0;if(t>o){throw new RangeError("'length' is out of bounds")}}return n?Buffer.from(e.slice(r,r+t)):new Buffer(new Uint8Array(e.slice(r,r+t)))}function fromString(e,r){if(typeof r!=="string"||r===""){r="utf8"}if(!Buffer.isEncoding(r)){throw new TypeError('"encoding" must be a valid string encoding')}return n?Buffer.from(e,r):new Buffer(e,r)}function bufferFrom(e,r,t){if(typeof e==="number"){throw new TypeError('"value" argument must not be a number')}if(isArrayBuffer(e)){return fromArrayBuffer(e,r,t)}if(typeof e==="string"){return fromString(e,r)}return n?Buffer.from(e):new Buffer(e)}e.exports=bufferFrom},284:(e,r,n)=>{e=n.nmd(e);var t=n(596).SourceMapConsumer;var o=n(17);var i;try{i=n(147);if(!i.existsSync||!i.readFileSync){i=null}}catch(e){}var a=n(650);function dynamicRequire(e,r){return e.require(r)}var u=false;var s=false;var l=false;var c="auto";var p={};var f={};var g=/^data:application\/json[^,]+base64,/;var h=[];var d=[];function isInBrowser(){if(c==="browser")return true;if(c==="node")return false;return typeof window!=="undefined"&&typeof XMLHttpRequest==="function"&&!(window.require&&window.module&&window.process&&window.process.type==="renderer")}function hasGlobalProcessEventEmitter(){return typeof process==="object"&&process!==null&&typeof process.on==="function"}function globalProcessVersion(){if(typeof process==="object"&&process!==null){return process.version}else{return""}}function globalProcessStderr(){if(typeof process==="object"&&process!==null){return process.stderr}}function globalProcessExit(e){if(typeof process==="object"&&process!==null&&typeof process.exit==="function"){return process.exit(e)}}function handlerExec(e){return function(r){for(var n=0;n"}var n=this.getLineNumber();if(n!=null){r+=":"+n;var t=this.getColumnNumber();if(t){r+=":"+t}}}var o="";var i=this.getFunctionName();var a=true;var u=this.isConstructor();var s=!(this.isToplevel()||u);if(s){var l=this.getTypeName();if(l==="[object Object]"){l="null"}var c=this.getMethodName();if(i){if(l&&i.indexOf(l)!=0){o+=l+"."}o+=i;if(c&&i.indexOf("."+c)!=i.length-c.length-1){o+=" [as "+c+"]"}}else{o+=l+"."+(c||"")}}else if(u){o+="new "+(i||"")}else if(i){o+=i}else{o+=r;a=false}if(a){o+=" ("+r+")"}return o}function cloneCallSite(e){var r={};Object.getOwnPropertyNames(Object.getPrototypeOf(e)).forEach((function(n){r[n]=/^(?:is|get)/.test(n)?function(){return e[n].call(e)}:e[n]}));r.toString=CallSiteToString;return r}function wrapCallSite(e,r){if(r===undefined){r={nextPosition:null,curPosition:null}}if(e.isNative()){r.curPosition=null;return e}var n=e.getFileName()||e.getScriptNameOrSourceURL();if(n){var t=e.getLineNumber();var o=e.getColumnNumber()-1;var i=/^v(10\.1[6-9]|10\.[2-9][0-9]|10\.[0-9]{3,}|1[2-9]\d*|[2-9]\d|\d{3,}|11\.11)/;var a=i.test(globalProcessVersion())?0:62;if(t===1&&o>a&&!isInBrowser()&&!e.isEval()){o-=a}var u=mapSourcePosition({source:n,line:t,column:o});r.curPosition=u;e=cloneCallSite(e);var s=e.getFunctionName;e.getFunctionName=function(){if(r.nextPosition==null){return s()}return r.nextPosition.name||s()};e.getFileName=function(){return u.source};e.getLineNumber=function(){return u.line};e.getColumnNumber=function(){return u.column+1};e.getScriptNameOrSourceURL=function(){return u.source};return e}var l=e.isEval()&&e.getEvalOrigin();if(l){l=mapEvalOrigin(l);e=cloneCallSite(e);e.getEvalOrigin=function(){return l};return e}return e}function prepareStackTrace(e,r){if(l){p={};f={}}var n=e.name||"Error";var t=e.message||"";var o=n+": "+t;var i={nextPosition:null,curPosition:null};var a=[];for(var u=r.length-1;u>=0;u--){a.push("\n at "+wrapCallSite(r[u],i));i.nextPosition=i.curPosition}i.curPosition=i.nextPosition=null;return o+a.reverse().join("")}function getErrorSource(e){var r=/\n at [^(]+ \((.*):(\d+):(\d+)\)/.exec(e.stack);if(r){var n=r[1];var t=+r[2];var o=+r[3];var a=p[n];if(!a&&i&&i.existsSync(n)){try{a=i.readFileSync(n,"utf8")}catch(e){a=""}}if(a){var u=a.split(/(?:\r\n|\r|\n)/)[t-1];if(u){return n+":"+t+"\n"+u+"\n"+new Array(o).join(" ")+"^"}}}return null}function printErrorAndExit(e){var r=getErrorSource(e);var n=globalProcessStderr();if(n&&n._handle&&n._handle.setBlocking){n._handle.setBlocking(true)}if(r){console.error();console.error(r)}console.error(e.stack);globalProcessExit(1)}function shimEmitUncaughtException(){var e=process.emit;process.emit=function(r){if(r==="uncaughtException"){var n=arguments[1]&&arguments[1].stack;var t=this.listeners(r).length>0;if(n&&!t){return printErrorAndExit(arguments[1])}}return e.apply(this,arguments)}}var S=h.slice(0);var _=d.slice(0);r.wrapCallSite=wrapCallSite;r.getErrorSource=getErrorSource;r.mapSourcePosition=mapSourcePosition;r.retrieveSourceMap=v;r.install=function(r){r=r||{};if(r.environment){c=r.environment;if(["node","browser","auto"].indexOf(c)===-1){throw new Error("environment "+c+" was unknown. Available options are {auto, browser, node}")}}if(r.retrieveFile){if(r.overrideRetrieveFile){h.length=0}h.unshift(r.retrieveFile)}if(r.retrieveSourceMap){if(r.overrideRetrieveSourceMap){d.length=0}d.unshift(r.retrieveSourceMap)}if(r.hookRequire&&!isInBrowser()){var n=dynamicRequire(e,"module");var t=n.prototype._compile;if(!t.__sourceMapSupport){n.prototype._compile=function(e,r){p[r]=e;f[r]=undefined;return t.call(this,e,r)};n.prototype._compile.__sourceMapSupport=true}}if(!l){l="emptyCacheBetweenOperations"in r?r.emptyCacheBetweenOperations:false}if(!u){u=true;Error.prepareStackTrace=prepareStackTrace}if(!s){var o="handleUncaughtExceptions"in r?r.handleUncaughtExceptions:true;try{var i=dynamicRequire(e,"worker_threads");if(i.isMainThread===false){o=false}}catch(e){}if(o&&hasGlobalProcessEventEmitter()){s=true;shimEmitUncaughtException()}}};r.resetRetrieveHandlers=function(){h.length=0;d.length=0;h=S.slice(0);d=_.slice(0);v=handlerExec(d);m=handlerExec(h)}},837:(e,r,n)=>{var t=n(983);var o=Object.prototype.hasOwnProperty;var i=typeof Map!=="undefined";function ArraySet(){this._array=[];this._set=i?new Map:Object.create(null)}ArraySet.fromArray=function ArraySet_fromArray(e,r){var n=new ArraySet;for(var t=0,o=e.length;t=0){return r}}else{var n=t.toSetString(e);if(o.call(this._set,n)){return this._set[n]}}throw new Error('"'+e+'" is not in the set.')};ArraySet.prototype.at=function ArraySet_at(e){if(e>=0&&e{var t=n(537);var o=5;var i=1<>1;return r?-n:n}r.encode=function base64VLQ_encode(e){var r="";var n;var i=toVLQSigned(e);do{n=i&a;i>>>=o;if(i>0){n|=u}r+=t.encode(n)}while(i>0);return r};r.decode=function base64VLQ_decode(e,r,n){var i=e.length;var s=0;var l=0;var c,p;do{if(r>=i){throw new Error("Expected more digits in base 64 VLQ value.")}p=t.decode(e.charCodeAt(r++));if(p===-1){throw new Error("Invalid base64 digit: "+e.charAt(r-1))}c=!!(p&u);p&=a;s=s+(p<{var n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");r.encode=function(e){if(0<=e&&e{r.GREATEST_LOWER_BOUND=1;r.LEAST_UPPER_BOUND=2;function recursiveSearch(e,n,t,o,i,a){var u=Math.floor((n-e)/2)+e;var s=i(t,o[u],true);if(s===0){return u}else if(s>0){if(n-u>1){return recursiveSearch(u,n,t,o,i,a)}if(a==r.LEAST_UPPER_BOUND){return n1){return recursiveSearch(e,u,t,o,i,a)}if(a==r.LEAST_UPPER_BOUND){return u}else{return e<0?-1:e}}}r.search=function search(e,n,t,o){if(n.length===0){return-1}var i=recursiveSearch(-1,n.length,e,n,t,o||r.GREATEST_LOWER_BOUND);if(i<0){return-1}while(i-1>=0){if(t(n[i],n[i-1],true)!==0){break}--i}return i}},740:(e,r,n)=>{var t=n(983);function generatedPositionAfter(e,r){var n=e.generatedLine;var o=r.generatedLine;var i=e.generatedColumn;var a=r.generatedColumn;return o>n||o==n&&a>=i||t.compareByGeneratedPositionsInflated(e,r)<=0}function MappingList(){this._array=[];this._sorted=true;this._last={generatedLine:-1,generatedColumn:0}}MappingList.prototype.unsortedForEach=function MappingList_forEach(e,r){this._array.forEach(e,r)};MappingList.prototype.add=function MappingList_add(e){if(generatedPositionAfter(this._last,e)){this._last=e;this._array.push(e)}else{this._sorted=false;this._array.push(e)}};MappingList.prototype.toArray=function MappingList_toArray(){if(!this._sorted){this._array.sort(t.compareByGeneratedPositionsInflated);this._sorted=true}return this._array};r.H=MappingList},226:(e,r)=>{function swap(e,r,n){var t=e[r];e[r]=e[n];e[n]=t}function randomIntInRange(e,r){return Math.round(e+Math.random()*(r-e))}function doQuickSort(e,r,n,t){if(n{var t;var o=n(983);var i=n(164);var a=n(837).I;var u=n(215);var s=n(226).U;function SourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}return n.sections!=null?new IndexedSourceMapConsumer(n,r):new BasicSourceMapConsumer(n,r)}SourceMapConsumer.fromSourceMap=function(e,r){return BasicSourceMapConsumer.fromSourceMap(e,r)};SourceMapConsumer.prototype._version=3;SourceMapConsumer.prototype.__generatedMappings=null;Object.defineProperty(SourceMapConsumer.prototype,"_generatedMappings",{configurable:true,enumerable:true,get:function(){if(!this.__generatedMappings){this._parseMappings(this._mappings,this.sourceRoot)}return this.__generatedMappings}});SourceMapConsumer.prototype.__originalMappings=null;Object.defineProperty(SourceMapConsumer.prototype,"_originalMappings",{configurable:true,enumerable:true,get:function(){if(!this.__originalMappings){this._parseMappings(this._mappings,this.sourceRoot)}return this.__originalMappings}});SourceMapConsumer.prototype._charIsMappingSeparator=function SourceMapConsumer_charIsMappingSeparator(e,r){var n=e.charAt(r);return n===";"||n===","};SourceMapConsumer.prototype._parseMappings=function SourceMapConsumer_parseMappings(e,r){throw new Error("Subclasses must implement _parseMappings")};SourceMapConsumer.GENERATED_ORDER=1;SourceMapConsumer.ORIGINAL_ORDER=2;SourceMapConsumer.GREATEST_LOWER_BOUND=1;SourceMapConsumer.LEAST_UPPER_BOUND=2;SourceMapConsumer.prototype.eachMapping=function SourceMapConsumer_eachMapping(e,r,n){var t=r||null;var i=n||SourceMapConsumer.GENERATED_ORDER;var a;switch(i){case SourceMapConsumer.GENERATED_ORDER:a=this._generatedMappings;break;case SourceMapConsumer.ORIGINAL_ORDER:a=this._originalMappings;break;default:throw new Error("Unknown order of iteration.")}var u=this.sourceRoot;a.map((function(e){var r=e.source===null?null:this._sources.at(e.source);r=o.computeSourceURL(u,r,this._sourceMapURL);return{source:r,generatedLine:e.generatedLine,generatedColumn:e.generatedColumn,originalLine:e.originalLine,originalColumn:e.originalColumn,name:e.name===null?null:this._names.at(e.name)}}),this).forEach(e,t)};SourceMapConsumer.prototype.allGeneratedPositionsFor=function SourceMapConsumer_allGeneratedPositionsFor(e){var r=o.getArg(e,"line");var n={source:o.getArg(e,"source"),originalLine:r,originalColumn:o.getArg(e,"column",0)};n.source=this._findSourceIndex(n.source);if(n.source<0){return[]}var t=[];var a=this._findMapping(n,this._originalMappings,"originalLine","originalColumn",o.compareByOriginalPositions,i.LEAST_UPPER_BOUND);if(a>=0){var u=this._originalMappings[a];if(e.column===undefined){var s=u.originalLine;while(u&&u.originalLine===s){t.push({line:o.getArg(u,"generatedLine",null),column:o.getArg(u,"generatedColumn",null),lastColumn:o.getArg(u,"lastGeneratedColumn",null)});u=this._originalMappings[++a]}}else{var l=u.originalColumn;while(u&&u.originalLine===r&&u.originalColumn==l){t.push({line:o.getArg(u,"generatedLine",null),column:o.getArg(u,"generatedColumn",null),lastColumn:o.getArg(u,"lastGeneratedColumn",null)});u=this._originalMappings[++a]}}}return t};r.SourceMapConsumer=SourceMapConsumer;function BasicSourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}var t=o.getArg(n,"version");var i=o.getArg(n,"sources");var u=o.getArg(n,"names",[]);var s=o.getArg(n,"sourceRoot",null);var l=o.getArg(n,"sourcesContent",null);var c=o.getArg(n,"mappings");var p=o.getArg(n,"file",null);if(t!=this._version){throw new Error("Unsupported version: "+t)}if(s){s=o.normalize(s)}i=i.map(String).map(o.normalize).map((function(e){return s&&o.isAbsolute(s)&&o.isAbsolute(e)?o.relative(s,e):e}));this._names=a.fromArray(u.map(String),true);this._sources=a.fromArray(i,true);this._absoluteSources=this._sources.toArray().map((function(e){return o.computeSourceURL(s,e,r)}));this.sourceRoot=s;this.sourcesContent=l;this._mappings=c;this._sourceMapURL=r;this.file=p}BasicSourceMapConsumer.prototype=Object.create(SourceMapConsumer.prototype);BasicSourceMapConsumer.prototype.consumer=SourceMapConsumer;BasicSourceMapConsumer.prototype._findSourceIndex=function(e){var r=e;if(this.sourceRoot!=null){r=o.relative(this.sourceRoot,r)}if(this._sources.has(r)){return this._sources.indexOf(r)}var n;for(n=0;n1){v.source=l+_[1];l+=_[1];v.originalLine=i+_[2];i=v.originalLine;v.originalLine+=1;v.originalColumn=a+_[3];a=v.originalColumn;if(_.length>4){v.name=c+_[4];c+=_[4]}}m.push(v);if(typeof v.originalLine==="number"){d.push(v)}}}s(m,o.compareByGeneratedPositionsDeflated);this.__generatedMappings=m;s(d,o.compareByOriginalPositions);this.__originalMappings=d};BasicSourceMapConsumer.prototype._findMapping=function SourceMapConsumer_findMapping(e,r,n,t,o,a){if(e[n]<=0){throw new TypeError("Line must be greater than or equal to 1, got "+e[n])}if(e[t]<0){throw new TypeError("Column must be greater than or equal to 0, got "+e[t])}return i.search(e,r,o,a)};BasicSourceMapConsumer.prototype.computeColumnSpans=function SourceMapConsumer_computeColumnSpans(){for(var e=0;e=0){var t=this._generatedMappings[n];if(t.generatedLine===r.generatedLine){var i=o.getArg(t,"source",null);if(i!==null){i=this._sources.at(i);i=o.computeSourceURL(this.sourceRoot,i,this._sourceMapURL)}var a=o.getArg(t,"name",null);if(a!==null){a=this._names.at(a)}return{source:i,line:o.getArg(t,"originalLine",null),column:o.getArg(t,"originalColumn",null),name:a}}}return{source:null,line:null,column:null,name:null}};BasicSourceMapConsumer.prototype.hasContentsOfAllSources=function BasicSourceMapConsumer_hasContentsOfAllSources(){if(!this.sourcesContent){return false}return this.sourcesContent.length>=this._sources.size()&&!this.sourcesContent.some((function(e){return e==null}))};BasicSourceMapConsumer.prototype.sourceContentFor=function SourceMapConsumer_sourceContentFor(e,r){if(!this.sourcesContent){return null}var n=this._findSourceIndex(e);if(n>=0){return this.sourcesContent[n]}var t=e;if(this.sourceRoot!=null){t=o.relative(this.sourceRoot,t)}var i;if(this.sourceRoot!=null&&(i=o.urlParse(this.sourceRoot))){var a=t.replace(/^file:\/\//,"");if(i.scheme=="file"&&this._sources.has(a)){return this.sourcesContent[this._sources.indexOf(a)]}if((!i.path||i.path=="/")&&this._sources.has("/"+t)){return this.sourcesContent[this._sources.indexOf("/"+t)]}}if(r){return null}else{throw new Error('"'+t+'" is not in the SourceMap.')}};BasicSourceMapConsumer.prototype.generatedPositionFor=function SourceMapConsumer_generatedPositionFor(e){var r=o.getArg(e,"source");r=this._findSourceIndex(r);if(r<0){return{line:null,column:null,lastColumn:null}}var n={source:r,originalLine:o.getArg(e,"line"),originalColumn:o.getArg(e,"column")};var t=this._findMapping(n,this._originalMappings,"originalLine","originalColumn",o.compareByOriginalPositions,o.getArg(e,"bias",SourceMapConsumer.GREATEST_LOWER_BOUND));if(t>=0){var i=this._originalMappings[t];if(i.source===n.source){return{line:o.getArg(i,"generatedLine",null),column:o.getArg(i,"generatedColumn",null),lastColumn:o.getArg(i,"lastGeneratedColumn",null)}}}return{line:null,column:null,lastColumn:null}};t=BasicSourceMapConsumer;function IndexedSourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}var t=o.getArg(n,"version");var i=o.getArg(n,"sections");if(t!=this._version){throw new Error("Unsupported version: "+t)}this._sources=new a;this._names=new a;var u={line:-1,column:0};this._sections=i.map((function(e){if(e.url){throw new Error("Support for url field in sections not implemented.")}var n=o.getArg(e,"offset");var t=o.getArg(n,"line");var i=o.getArg(n,"column");if(t{var t=n(215);var o=n(983);var i=n(837).I;var a=n(740).H;function SourceMapGenerator(e){if(!e){e={}}this._file=o.getArg(e,"file",null);this._sourceRoot=o.getArg(e,"sourceRoot",null);this._skipValidation=o.getArg(e,"skipValidation",false);this._sources=new i;this._names=new i;this._mappings=new a;this._sourcesContents=null}SourceMapGenerator.prototype._version=3;SourceMapGenerator.fromSourceMap=function SourceMapGenerator_fromSourceMap(e){var r=e.sourceRoot;var n=new SourceMapGenerator({file:e.file,sourceRoot:r});e.eachMapping((function(e){var t={generated:{line:e.generatedLine,column:e.generatedColumn}};if(e.source!=null){t.source=e.source;if(r!=null){t.source=o.relative(r,t.source)}t.original={line:e.originalLine,column:e.originalColumn};if(e.name!=null){t.name=e.name}}n.addMapping(t)}));e.sources.forEach((function(t){var i=t;if(r!==null){i=o.relative(r,t)}if(!n._sources.has(i)){n._sources.add(i)}var a=e.sourceContentFor(t);if(a!=null){n.setSourceContent(t,a)}}));return n};SourceMapGenerator.prototype.addMapping=function SourceMapGenerator_addMapping(e){var r=o.getArg(e,"generated");var n=o.getArg(e,"original",null);var t=o.getArg(e,"source",null);var i=o.getArg(e,"name",null);if(!this._skipValidation){this._validateMapping(r,n,t,i)}if(t!=null){t=String(t);if(!this._sources.has(t)){this._sources.add(t)}}if(i!=null){i=String(i);if(!this._names.has(i)){this._names.add(i)}}this._mappings.add({generatedLine:r.line,generatedColumn:r.column,originalLine:n!=null&&n.line,originalColumn:n!=null&&n.column,source:t,name:i})};SourceMapGenerator.prototype.setSourceContent=function SourceMapGenerator_setSourceContent(e,r){var n=e;if(this._sourceRoot!=null){n=o.relative(this._sourceRoot,n)}if(r!=null){if(!this._sourcesContents){this._sourcesContents=Object.create(null)}this._sourcesContents[o.toSetString(n)]=r}else if(this._sourcesContents){delete this._sourcesContents[o.toSetString(n)];if(Object.keys(this._sourcesContents).length===0){this._sourcesContents=null}}};SourceMapGenerator.prototype.applySourceMap=function SourceMapGenerator_applySourceMap(e,r,n){var t=r;if(r==null){if(e.file==null){throw new Error("SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, "+'or the source map\'s "file" property. Both were omitted.')}t=e.file}var a=this._sourceRoot;if(a!=null){t=o.relative(a,t)}var u=new i;var s=new i;this._mappings.unsortedForEach((function(r){if(r.source===t&&r.originalLine!=null){var i=e.originalPositionFor({line:r.originalLine,column:r.originalColumn});if(i.source!=null){r.source=i.source;if(n!=null){r.source=o.join(n,r.source)}if(a!=null){r.source=o.relative(a,r.source)}r.originalLine=i.line;r.originalColumn=i.column;if(i.name!=null){r.name=i.name}}}var l=r.source;if(l!=null&&!u.has(l)){u.add(l)}var c=r.name;if(c!=null&&!s.has(c)){s.add(c)}}),this);this._sources=u;this._names=s;e.sources.forEach((function(r){var t=e.sourceContentFor(r);if(t!=null){if(n!=null){r=o.join(n,r)}if(a!=null){r=o.relative(a,r)}this.setSourceContent(r,t)}}),this)};SourceMapGenerator.prototype._validateMapping=function SourceMapGenerator_validateMapping(e,r,n,t){if(r&&typeof r.line!=="number"&&typeof r.column!=="number"){throw new Error("original.line and original.column are not numbers -- you probably meant to omit "+"the original mapping entirely and only map the generated position. If so, pass "+"null for the original mapping instead of an object with empty or null values.")}if(e&&"line"in e&&"column"in e&&e.line>0&&e.column>=0&&!r&&!n&&!t){return}else if(e&&"line"in e&&"column"in e&&r&&"line"in r&&"column"in r&&e.line>0&&e.column>=0&&r.line>0&&r.column>=0&&n){return}else{throw new Error("Invalid mapping: "+JSON.stringify({generated:e,source:n,original:r,name:t}))}};SourceMapGenerator.prototype._serializeMappings=function SourceMapGenerator_serializeMappings(){var e=0;var r=1;var n=0;var i=0;var a=0;var u=0;var s="";var l;var c;var p;var f;var g=this._mappings.toArray();for(var h=0,d=g.length;h0){if(!o.compareByGeneratedPositionsInflated(c,g[h-1])){continue}l+=","}}l+=t.encode(c.generatedColumn-e);e=c.generatedColumn;if(c.source!=null){f=this._sources.indexOf(c.source);l+=t.encode(f-u);u=f;l+=t.encode(c.originalLine-1-i);i=c.originalLine-1;l+=t.encode(c.originalColumn-n);n=c.originalColumn;if(c.name!=null){p=this._names.indexOf(c.name);l+=t.encode(p-a);a=p}}s+=l}return s};SourceMapGenerator.prototype._generateSourcesContent=function SourceMapGenerator_generateSourcesContent(e,r){return e.map((function(e){if(!this._sourcesContents){return null}if(r!=null){e=o.relative(r,e)}var n=o.toSetString(e);return Object.prototype.hasOwnProperty.call(this._sourcesContents,n)?this._sourcesContents[n]:null}),this)};SourceMapGenerator.prototype.toJSON=function SourceMapGenerator_toJSON(){var e={version:this._version,sources:this._sources.toArray(),names:this._names.toArray(),mappings:this._serializeMappings()};if(this._file!=null){e.file=this._file}if(this._sourceRoot!=null){e.sourceRoot=this._sourceRoot}if(this._sourcesContents){e.sourcesContent=this._generateSourcesContent(e.sources,e.sourceRoot)}return e};SourceMapGenerator.prototype.toString=function SourceMapGenerator_toString(){return JSON.stringify(this.toJSON())};r.h=SourceMapGenerator},990:(e,r,n)=>{var t;var o=n(341).h;var i=n(983);var a=/(\r?\n)/;var u=10;var s="$$$isSourceNode$$$";function SourceNode(e,r,n,t,o){this.children=[];this.sourceContents={};this.line=e==null?null:e;this.column=r==null?null:r;this.source=n==null?null:n;this.name=o==null?null:o;this[s]=true;if(t!=null)this.add(t)}SourceNode.fromStringWithSourceMap=function SourceNode_fromStringWithSourceMap(e,r,n){var t=new SourceNode;var o=e.split(a);var u=0;var shiftNextLine=function(){var e=getNextLine();var r=getNextLine()||"";return e+r;function getNextLine(){return u=0;r--){this.prepend(e[r])}}else if(e[s]||typeof e==="string"){this.children.unshift(e)}else{throw new TypeError("Expected a SourceNode, string, or an array of SourceNodes and strings. Got "+e)}return this};SourceNode.prototype.walk=function SourceNode_walk(e){var r;for(var n=0,t=this.children.length;n0){r=[];for(n=0;n{function getArg(e,r,n){if(r in e){return e[r]}else if(arguments.length===3){return n}else{throw new Error('"'+r+'" is a required argument.')}}r.getArg=getArg;var n=/^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.-]*)(?::(\d+))?(.*)$/;var t=/^data:.+\,.+$/;function urlParse(e){var r=e.match(n);if(!r){return null}return{scheme:r[1],auth:r[2],host:r[3],port:r[4],path:r[5]}}r.urlParse=urlParse;function urlGenerate(e){var r="";if(e.scheme){r+=e.scheme+":"}r+="//";if(e.auth){r+=e.auth+"@"}if(e.host){r+=e.host}if(e.port){r+=":"+e.port}if(e.path){r+=e.path}return r}r.urlGenerate=urlGenerate;function normalize(e){var n=e;var t=urlParse(e);if(t){if(!t.path){return e}n=t.path}var o=r.isAbsolute(n);var i=n.split(/\/+/);for(var a,u=0,s=i.length-1;s>=0;s--){a=i[s];if(a==="."){i.splice(s,1)}else if(a===".."){u++}else if(u>0){if(a===""){i.splice(s+1,u);u=0}else{i.splice(s,2);u--}}}n=i.join("/");if(n===""){n=o?"/":"."}if(t){t.path=n;return urlGenerate(t)}return n}r.normalize=normalize;function join(e,r){if(e===""){e="."}if(r===""){r="."}var n=urlParse(r);var o=urlParse(e);if(o){e=o.path||"/"}if(n&&!n.scheme){if(o){n.scheme=o.scheme}return urlGenerate(n)}if(n||r.match(t)){return r}if(o&&!o.host&&!o.path){o.host=r;return urlGenerate(o)}var i=r.charAt(0)==="/"?r:normalize(e.replace(/\/+$/,"")+"/"+r);if(o){o.path=i;return urlGenerate(o)}return i}r.join=join;r.isAbsolute=function(e){return e.charAt(0)==="/"||n.test(e)};function relative(e,r){if(e===""){e="."}e=e.replace(/\/$/,"");var n=0;while(r.indexOf(e+"/")!==0){var t=e.lastIndexOf("/");if(t<0){return r}e=e.slice(0,t);if(e.match(/^([^\/]+:\/)?\/*$/)){return r}++n}return Array(n+1).join("../")+r.substr(e.length+1)}r.relative=relative;var o=function(){var e=Object.create(null);return!("__proto__"in e)}();function identity(e){return e}function toSetString(e){if(isProtoString(e)){return"$"+e}return e}r.toSetString=o?identity:toSetString;function fromSetString(e){if(isProtoString(e)){return e.slice(1)}return e}r.fromSetString=o?identity:fromSetString;function isProtoString(e){if(!e){return false}var r=e.length;if(r<9){return false}if(e.charCodeAt(r-1)!==95||e.charCodeAt(r-2)!==95||e.charCodeAt(r-3)!==111||e.charCodeAt(r-4)!==116||e.charCodeAt(r-5)!==111||e.charCodeAt(r-6)!==114||e.charCodeAt(r-7)!==112||e.charCodeAt(r-8)!==95||e.charCodeAt(r-9)!==95){return false}for(var n=r-10;n>=0;n--){if(e.charCodeAt(n)!==36){return false}}return true}function compareByOriginalPositions(e,r,n){var t=strcmp(e.source,r.source);if(t!==0){return t}t=e.originalLine-r.originalLine;if(t!==0){return t}t=e.originalColumn-r.originalColumn;if(t!==0||n){return t}t=e.generatedColumn-r.generatedColumn;if(t!==0){return t}t=e.generatedLine-r.generatedLine;if(t!==0){return t}return strcmp(e.name,r.name)}r.compareByOriginalPositions=compareByOriginalPositions;function compareByGeneratedPositionsDeflated(e,r,n){var t=e.generatedLine-r.generatedLine;if(t!==0){return t}t=e.generatedColumn-r.generatedColumn;if(t!==0||n){return t}t=strcmp(e.source,r.source);if(t!==0){return t}t=e.originalLine-r.originalLine;if(t!==0){return t}t=e.originalColumn-r.originalColumn;if(t!==0){return t}return strcmp(e.name,r.name)}r.compareByGeneratedPositionsDeflated=compareByGeneratedPositionsDeflated;function strcmp(e,r){if(e===r){return 0}if(e===null){return 1}if(r===null){return-1}if(e>r){return 1}return-1}function compareByGeneratedPositionsInflated(e,r){var n=e.generatedLine-r.generatedLine;if(n!==0){return n}n=e.generatedColumn-r.generatedColumn;if(n!==0){return n}n=strcmp(e.source,r.source);if(n!==0){return n}n=e.originalLine-r.originalLine;if(n!==0){return n}n=e.originalColumn-r.originalColumn;if(n!==0){return n}return strcmp(e.name,r.name)}r.compareByGeneratedPositionsInflated=compareByGeneratedPositionsInflated;function parseSourceMapInput(e){return JSON.parse(e.replace(/^\)]}'[^\n]*\n/,""))}r.parseSourceMapInput=parseSourceMapInput;function computeSourceURL(e,r,n){r=r||"";if(e){if(e[e.length-1]!=="/"&&r[0]!=="/"){e+="/"}r=e+r}if(n){var t=urlParse(n);if(!t){throw new Error("sourceMapURL could not be parsed")}if(t.path){var o=t.path.lastIndexOf("/");if(o>=0){t.path=t.path.substring(0,o+1)}}r=join(urlGenerate(t),r)}return normalize(r)}r.computeSourceURL=computeSourceURL},596:(e,r,n)=>{n(341).h;r.SourceMapConsumer=n(327).SourceMapConsumer;n(990)},147:e=>{"use strict";e.exports=require("fs")},17:e=>{"use strict";e.exports=require("path")}};var r={};function __webpack_require__(n){var t=r[n];if(t!==undefined){return t.exports}var o=r[n]={id:n,loaded:false,exports:{}};var i=true;try{e[n](o,o.exports,__webpack_require__);i=false}finally{if(i)delete r[n]}o.loaded=true;return o.exports}(()=>{__webpack_require__.nmd=e=>{e.paths=[];if(!e.children)e.children=[];return e}})();if(typeof __webpack_require__!=="undefined")__webpack_require__.ab=__dirname+"/";var n={};(()=>{__webpack_require__(284).install()})();module.exports=n})(); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hawkscan-action", 3 | "version": "2.2.0", 4 | "description": "StackHawk HawkScan Action", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "lint": "eslint .", 8 | "prepare": "ncc build src/index.js -o dist --source-map --license licenses.txt", 9 | "test": "jest", 10 | "all": "npm run lint && npm run prepare && npm run test" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/actions/javascript-action.git" 15 | }, 16 | "keywords": [ 17 | "GitHub", 18 | "Actions", 19 | "JavaScript" 20 | ], 21 | "author": "", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/actions/javascript-action/issues" 25 | }, 26 | "homepage": "https://github.com/actions/javascript-action#readme", 27 | "dependencies": { 28 | "@actions/core": "^1.10.1", 29 | "@actions/exec": "^1.1.1", 30 | "@actions/tool-cache": "^2.0.1", 31 | "@octokit/core": "^5.1.0", 32 | "process": "^0.11.10" 33 | }, 34 | "devDependencies": { 35 | "@vercel/ncc": "^0.38.1", 36 | "eslint": "^8.56.0", 37 | "jest": "^29.7.0", 38 | "simple-git": "^3.22.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /scripts/action-tester.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export INPUT_DRYRUN='false' 4 | export INPUT_APIKEY='hawk.xxxxXXXXxxXXxxxXXxXX.xxxXXxxxXXxxXXxxxXXX' 5 | export INPUT_CONFIGURATIONFILES="__tests__/stackhawk.yml" 6 | export INPUT_VERSION='latest' 7 | export INPUT_CODESCANNINGALERTS='true' 8 | export INPUT_GITHUBTOKEN="${GITHUB_PAT}" 9 | export HOST='http://localhost:8080' 10 | export APP_ENV='unit_tests' 11 | 12 | node --trace-warnings ./src/index.js 13 | -------------------------------------------------------------------------------- /scripts/actionTester.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* eslint-disable no-console */ 3 | const utilities = require('../src/utilities'); 4 | const process = require('process'); 5 | const { spawn } = require('child_process'); 6 | 7 | // Take an object of key/value pairs and convert it to input environment variables 8 | function buildInput(inputs) { 9 | let key = ""; 10 | for(key in inputs) { 11 | process.env[`INPUT_${key.replace(/ /g, '_').toUpperCase()}`] = inputs[key]; 12 | } 13 | } 14 | 15 | function run() { 16 | buildInput({ 17 | dryRun: 'true', 18 | apiKey: 'hawk.xxxxXXXXxxXXxxxXXxXX.xxxXXxxxXXxxXXxxxXXX', 19 | configurationFiles: "__tests__/stackhawk.yml", 20 | version: 'latest', 21 | codeScanningAlerts: 'true', 22 | }); 23 | process.env['HOST'] = 'http://example.com'; 24 | process.env['APP_ENV'] = 'unit_tests'; 25 | const inputs = utilities.gatherInputs(); 26 | const cliCommand = utilities.buildCLICommand(inputs); 27 | const scanCommandList = cliCommand.split(" "); 28 | const scanCommand = scanCommandList[0]; 29 | const scanArgs = scanCommandList.slice(1); 30 | const scanner = spawn(scanCommand, scanArgs); 31 | 32 | scanner.stdout.on("data", data => { 33 | console.log(data.toString()); 34 | }); 35 | scanner.stderr.on("data", data => { 36 | console.error(`stderr: ${data}`); 37 | }); 38 | scanner.on("error", (error) => { 39 | console.error(`ERROR: ${error}`); 40 | }); 41 | scanner.on("close", code => { 42 | console.log(`Scanner process exited with code ${code}`); 43 | }); 44 | } 45 | 46 | run() 47 | -------------------------------------------------------------------------------- /scripts/release-pr.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Declare variables 4 | BASE=main 5 | REPO_URL="https://github.com/stackhawk/hawkscan-action" 6 | 7 | function help() { 8 | local error=$1 9 | if [[ -n "${error}" ]]; then 10 | echo >&2 "ERROR: ${error}" 11 | fi 12 | cat <&2 "ERROR: This shouldn't happen" 81 | exit 1 82 | fi 83 | 84 | # Here's the plan: 85 | bump_version "${mode}" 86 | package_prep "${mode}" 87 | git_commit "${mode}" 88 | git_push "${mode}" 89 | gh_pr "${mode}" 90 | 91 | if [[ ${mode} == "plan" ]]; then 92 | echo "Check the plan above. Hit return to continue, or -c to bail." 93 | read -r 94 | fi 95 | } 96 | 97 | function check_deps() { 98 | echo -n "Checking dependencies... " 99 | for prereq in gh bump2version jq; do 100 | if ! command -v "${prereq}" >/dev/null; then 101 | echo "Not OK!" 102 | echo >&2 "ERROR: Prerequisite '${prereq}' not found." 103 | exit 1 104 | fi 105 | done 106 | echo "OK" 107 | } 108 | 109 | function check_repo() { 110 | echo -n "Checking if repo is clean... " 111 | local branch=$(git branch --show-current) 112 | if [[ ${branch} =~ ^(master|main|develop)$ ]]; then 113 | echo "OH NO!" 114 | echo " You can't push to the master, main, or develop branches. Try this from a feature branch." 115 | exit 1 116 | fi 117 | if output=$(git status --untracked-files=no --porcelain) && [ -z "$output" ]; then 118 | # Working directory clean 119 | echo "OK!" 120 | else 121 | # Uncommitted changes 122 | echo "OH NO!" 123 | echo " There are uncommitted changes in this repo." 124 | echo " Please commit any staged changes before running this again:" 125 | echo "${output}" 126 | exit 1 127 | fi 128 | } 129 | 130 | function check_version() { 131 | echo "Checking version info" 132 | bump_list=$(bump_version run --dry-run --list) 133 | CURRENT_VERSION=$(echo "${bump_list}" | grep current_version | cut -d'=' -f2) 134 | NEW_VERSION=$(echo "${bump_list}" | grep new_version | cut -d'=' -f2) 135 | echo " Current version: ${CURRENT_VERSION}" 136 | echo " Proposed version: ${NEW_VERSION}" 137 | if [[ $(git tag -l "v${NEW_VERSION}") == "v${NEW_VERSION}" ]]; then 138 | >&2 echo "ERROR: There is already a release for version ${NEW_VERSION}!" 139 | exit 1 140 | fi 141 | } 142 | 143 | function git_pull() { 144 | echo "Pulling any remote commits..." 145 | run "git pull" run 146 | } 147 | 148 | function package_prep() { 149 | local mode=${1} 150 | run "npm run all" "${mode}" 151 | run "git add dist" "${mode}" 152 | } 153 | 154 | function bump_version() { 155 | local mode=${1} 156 | shift 157 | cmd="bump2version ${*} ${PART}" 158 | run "${cmd}" "${mode}" 159 | } 160 | 161 | function git_commit() { 162 | local mode=${1} 163 | local cmd="git commit -m \"${MSG}\" --allow-empty" 164 | run "${cmd}" "${mode}" 165 | } 166 | 167 | function git_push() { 168 | local mode=${1} 169 | run "git push" "${mode}" 170 | } 171 | 172 | # add --no-pr 173 | function gh_pr() { 174 | local mode=${1} 175 | if [[ -z $TITLE ]]; then 176 | TITLE="Bump version: ${CURRENT_VERSION} → ${NEW_VERSION}" 177 | fi 178 | local cmd="gh pr create --web --base ${BASE} --title \"${TITLE}\"" 179 | run "${cmd}" "${mode}" 180 | } 181 | 182 | function release_information() { 183 | echo 184 | echo "Yay! Once this PR has been approved and built, it will automatically be released as v${NEW_VERSION}." 185 | echo "You may need to edit this release to publish it to the GitHub Marketplace. Check it out at:" 186 | echo " ${REPO_URL}/releases/tag/v${NEW_VERSION}" 187 | } 188 | 189 | function run() { 190 | local cmd=${1} 191 | local mode=${2} 192 | echo "Run: '${cmd}'" 193 | if [[ ${mode} == "run" ]]; then 194 | if ! eval "${cmd}"; then 195 | echo >&2 "ERROR: '${cmd}' failed." 196 | exit 1 197 | fi 198 | fi 199 | } 200 | 201 | # The things 202 | function main() { 203 | parse_args "$@" 204 | check_deps 205 | check_repo 206 | git_pull 207 | check_version 208 | planner plan 209 | planner run 210 | release_information 211 | } 212 | 213 | # Do the things 214 | main "$@" 215 | -------------------------------------------------------------------------------- /scripts/version-check.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This script checks the version in .bumpversion.cfg against tags in Git. If there's no tag for this version, 4 | # it returns the .bumpversion current version number. Otherwise it prints an error message to std-err and returns 5 | # nothing to std-out. 6 | 7 | RELEASE_VERSION=$(grep "^current_version" ./.bumpversion.cfg | egrep -o '[0-9]+\.[0-9]+\.[0-9]+') 8 | 9 | if [[ -z "${RELEASE_VERSION}" ]]; then 10 | >&2 echo "No valid version number found." 11 | elif [[ $(git tag -l "v${RELEASE_VERSION}") == "v${RELEASE_VERSION}" ]]; then 12 | >&2 echo "Version ${RELEASE_VERSION} has already been released." 13 | else 14 | echo "${RELEASE_VERSION}" 15 | fi 16 | -------------------------------------------------------------------------------- /src/cli_utils.js: -------------------------------------------------------------------------------- 1 | const https = require('https'); 2 | 3 | function getDownloadObject(version, urlPath) { 4 | const binPath = `/hawk-${version}`; 5 | const url = `${urlPath}/hawk-${version}.zip`; 6 | return { 7 | url, 8 | binPath, 9 | }; 10 | } 11 | 12 | async function getLatestVersion() { 13 | return new Promise(function (resolve, reject) { 14 | https 15 | .get('https://api.stackhawk.com/hawkscan/version', (res) => { 16 | if (res.statusCode !== 200) { 17 | reject(res); 18 | } 19 | let data = ''; 20 | res.on('data', function (chunk) { 21 | data += chunk; 22 | }); 23 | res.on('end', function () { 24 | resolve(data); 25 | }); 26 | }) 27 | .on('error', (e) => { 28 | // eslint-disable-next-line no-console 29 | console.error(e); 30 | reject(e); 31 | }); 32 | }); 33 | } 34 | module.exports = { getDownloadObject, getLatestVersion }; 35 | -------------------------------------------------------------------------------- /src/hawk_process.js: -------------------------------------------------------------------------------- 1 | const {spawn} = require("child_process"); 2 | 3 | module.exports.spawnHawk = function spawnHawk(command, args) { 4 | const child = spawn(command, args) 5 | let stdout = ''; 6 | let stderr = ''; 7 | const response = {}; 8 | 9 | if (child.stdout) { 10 | child.stdout.on('data', data => { 11 | stdout += data.toString(); 12 | process.stdout.write(data); 13 | }) 14 | } 15 | 16 | if (child.stderr) { 17 | child.stderr.on('data', data => { 18 | stderr += data.toString(); 19 | process.stderr.write(data); 20 | }) 21 | } 22 | 23 | const promise = new Promise((resolve, reject) => { 24 | child.on('error',(err) => { 25 | reject(err); 26 | }); 27 | 28 | child.on('close', code => { 29 | if (code === 0) { 30 | response.stdout = stdout; 31 | response.code = code; 32 | resolve(response); 33 | } else { 34 | const err = new Error(`child exited with code ${code}`); 35 | err.code = code; 36 | err.stderr = stderr; 37 | err.stdout = stdout; 38 | reject(err); 39 | } 40 | }) 41 | }) 42 | 43 | promise.child = child 44 | 45 | return promise 46 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const core = require('@actions/core'); 2 | const utilities = require('./utilities'); 3 | const sarif = require('./sarif'); 4 | const { setup } = require('./setup'); 5 | const {addSignalHandler} = require("./signal_handler"); 6 | 7 | async function run() { 8 | core.info('Starting HawkScan Action'); 9 | const inputs = utilities.gatherInputs(); 10 | const cliCommand = utilities.buildCLICommand(inputs); 11 | let exitCode = 0; 12 | let scanData; 13 | 14 | // Run the scanner 15 | if (inputs.dryRun !== 'true') { 16 | // Install the CLI and set up signal handling 17 | addSignalHandler(); 18 | const hawkPath = await setup(); 19 | // Run hawk command if installCLIOnly is false 20 | if (inputs.installCLIOnly !== 'true') { 21 | scanData = await utilities.runCommand(hawkPath, cliCommand); 22 | exitCode = scanData.exitCode; 23 | core.debug(`Scanner exit code: ${scanData.exitCode} (${typeof scanData.exitCode})`); 24 | core.debug(`Link to scan results: ${scanData.resultsLink} (${typeof scanData.resultsLink})`); 25 | core.debug(`This is the scan id: ${scanData.scanId} (${typeof scanData.scanId})`); 26 | core.setOutput("scanId", scanData.scanId); 27 | if (exitCode !== 0) { 28 | core.setFailed(scanData.errorMessage) 29 | } 30 | } 31 | 32 | } 33 | 34 | // Upload SARIF data 35 | if (scanData && inputs.codeScanningAlerts === 'true' ) { 36 | if (exitCode === 0 || exitCode === 42) { 37 | await sarif.uploadSarif(scanData, inputs.githubToken); 38 | } else { 39 | core.error(`Skipping SARIF upload due to scan error.`) 40 | } 41 | } 42 | 43 | process.exit(exitCode); 44 | } 45 | 46 | run(); 47 | -------------------------------------------------------------------------------- /src/sarif.js: -------------------------------------------------------------------------------- 1 | const core = require('@actions/core'); 2 | const { Octokit } = require('@octokit/core'); 3 | const simpleGit = require('simple-git'); 4 | const zlib = require('zlib'); 5 | const url = require("url"); 6 | const git = simpleGit(); 7 | 8 | // https://docs.github.com/en/rest/reference/code-scanning#upload-an-analysis-as-sarif-data--code-samples 9 | module.exports.uploadSarif = async function uploadSarif(scanData, githubToken) { 10 | const octokit = new Octokit({ auth: githubToken }); 11 | 12 | const githubRepository = process.env['GITHUB_REPOSITORY']; 13 | if (githubRepository === undefined || ''){ 14 | throw new Error(`GITHUB_REPOSITORY environment variable must be set`); 15 | } 16 | const [owner, repo] = githubRepository.split('/'); 17 | const ref = await getRef(); 18 | const commitShaLocal = await git.revparse('HEAD') 19 | const commitSha = process.env['GITHUB_SHA'] || commitShaLocal; 20 | 21 | let exitCode = 0; 22 | 23 | const sarifContent = sarifBuilder(scanData); 24 | core.debug(`Running SARIF upload with results link: ${scanData.resultsLink}`); 25 | core.debug(`Running SARIF upload with HawkScan version: ${scanData.hawkscanVersion}`); 26 | core.debug(`Running SARIF upload with failure threshold: ${scanData.failureThreshold}`); 27 | core.debug(`SARIF file contents:\n${JSON.stringify(sarifContent)}`); 28 | 29 | const sarifZip = zlib.gzipSync(JSON.stringify(sarifContent)).toString('base64'); 30 | 31 | core.info('Uploading SARIF results to GitHub.'); 32 | try { 33 | const response = await octokit.request(`POST /repos/${owner}/${repo}/code-scanning/sarifs`, { 34 | commit_sha: commitSha, 35 | ref: ref, 36 | sarif: sarifZip, 37 | tool_name: 'StackHawk HawkScan Dynamic Application Security Test Scanner', 38 | checkout_uri: url.pathToFileURL(process.cwd()).toString(), 39 | }); 40 | core.info('SARIF upload complete.'); 41 | core.debug(response.data); 42 | } catch (e) { 43 | exitCode = 1; 44 | core.error('Error uploading the SARIF results.') 45 | core.error(e); 46 | } 47 | return exitCode; 48 | } 49 | 50 | async function getRef() { 51 | const gitRefLocal = await git.revparse(['--symbolic-full-name', 'HEAD']); 52 | const gitRef = process.env['GITHUB_REF'] || gitRefLocal; 53 | const pullRefRegex = /refs\/pull\/(\d+)\/merge/; 54 | if (pullRefRegex.test(gitRef)) { 55 | return gitRef.replace(pullRefRegex, 'refs/pull/$1/head'); 56 | } else { 57 | return gitRef; 58 | } 59 | } 60 | 61 | function sarifBuilder(scanData) { 62 | core.info('Preparing SARIF scan results file for GitHub Code Scanning Alerts.'); 63 | const sarif = { 64 | "version": "2.1.0", 65 | "$schema": "http://json.schemastore.org/sarif-2.1.0", 66 | "runs": [ 67 | { 68 | "tool": { 69 | "driver": { 70 | "name": "HawkScan", 71 | "version": scanData.hawkscanVersion, 72 | "semanticVersion": scanData.hawkscanVersion, 73 | "informationUri": "https://docs.stackhawk.com/hawkscan/", 74 | "rules": [ 75 | { 76 | "id": "alert/threshold-met", 77 | "name": "alert/threshold-met", 78 | "helpUri": "https://docs.stackhawk.com/web-app/scans.html#scan-details-page", 79 | "help": { 80 | "text": "StackHawk found results that meet or exceed your failure threshold (`hawk.failureThreshold`)." 81 | }, 82 | "shortDescription": { 83 | "text": "StackHawk found results that meet or exceed your failure threshold" 84 | }, 85 | "properties": { 86 | "tags": [ 87 | "🦅" 88 | ] 89 | } 90 | } 91 | ] 92 | } 93 | }, 94 | "results": [] 95 | } 96 | ] 97 | }; 98 | if (scanData.exitCode === 42) { 99 | sarif.runs[0].results[0] = { 100 | "level": "note", 101 | "locations": [ 102 | { 103 | "id": 1, 104 | "physicalLocation": { 105 | "region": { 106 | "startLine": 1 107 | }, 108 | "artifactLocation": { 109 | "uri": "./nofile" 110 | } 111 | } 112 | } 113 | ], 114 | "message": { 115 | "text": `StackHawk found issues that meet or exceed your failure threshold (\`hawk.failureThreshold=${scanData.failureThreshold}\`).\nSee [Scan Results](${scanData.resultsLink}) for more details.` 116 | }, 117 | "ruleId": "alert/threshold-met" 118 | } 119 | } 120 | return sarif; 121 | } 122 | -------------------------------------------------------------------------------- /src/setup.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const core = require('@actions/core'); 3 | const tc = require('@actions/tool-cache'); 4 | const fs = require('fs'); 5 | const os = require('os') 6 | const { getDownloadObject, getLatestVersion } = require('./cli_utils'); 7 | const {gatherInputs} = require('./utilities') 8 | 9 | /* 10 | Returns the path of the hawkscan executable to run for the respective OS 11 | */ 12 | async function setup() { 13 | try { 14 | const inputs = gatherInputs(); 15 | // Get version of tool to be installed 16 | const version = inputs.version; 17 | const sourceUrl = inputs.sourceURL; 18 | 19 | // Download the specific version of the tool, e.g. as a tarball/zipball 20 | const cliVersion = 21 | version === "latest" ? await getLatestVersion() : version; 22 | const download = getDownloadObject(cliVersion, sourceUrl); 23 | const pathToTarball = await tc.downloadTool(download.url); 24 | 25 | // Extract the zip onto host runner 26 | const extract = download.url.endsWith(".zip") 27 | ? tc.extractZip 28 | : tc.extractTar; 29 | const pathToCLI = await extract(pathToTarball); 30 | const hawkScanPath = path.join(pathToCLI, download.binPath) 31 | 32 | // Ensure expected HawkScan executables are present 33 | const hawkShPath = path.join(hawkScanPath, "hawk") 34 | const hawkPwshPath = path.join(hawkScanPath, "hawk.ps1") 35 | if (!fs.existsSync(hawkShPath)) { 36 | core.setFailed(`could not find ${hawkShPath}`) 37 | } 38 | if (!fs.existsSync(hawkPwshPath)) { 39 | core.setFailed(`could not find ${hawkPwshPath}`) 40 | } 41 | 42 | // Expose the tool by adding it to the PATH 43 | core.addPath(hawkScanPath); 44 | core.info(`added ${hawkScanPath} to the ${os.platform()} PATH`); 45 | 46 | return os.platform() === 'win32' ? hawkPwshPath : hawkShPath; 47 | } catch (e) { 48 | core.info(e); 49 | core.setFailed(e); 50 | } 51 | } 52 | 53 | module.exports = { setup }; 54 | -------------------------------------------------------------------------------- /src/signal_handler.js: -------------------------------------------------------------------------------- 1 | const core = require("@actions/core"); 2 | const {exec} = require("child_process"); 3 | 4 | function killHawkProcess() { 5 | interruptProcess('hawk'); 6 | interruptProcess('java'); 7 | } 8 | 9 | function interruptProcess(name){ 10 | core.debug(`Killing process ${name}`) 11 | exec(`pgrep ${name}`, function(err, stdout) { 12 | const result = stdout.toString().split('\n'); 13 | result.forEach(element => { 14 | const pid = parseInt(element, 10); 15 | if (!isNaN(pid) && pid > -1) { 16 | core.debug(`Killing process id ${element}`); 17 | try { 18 | process.kill(pid, 'SIGINT'); 19 | } catch (e) { 20 | core.error(e.message); 21 | } 22 | } 23 | }); 24 | }); 25 | } 26 | 27 | module.exports.addSignalHandler = function addSignalHandler(){ 28 | process.on('SIGINT', () => { 29 | core.debug(`SIGINT received for ${process.pid}`); 30 | killHawkProcess(); 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /src/utilities.js: -------------------------------------------------------------------------------- 1 | const core = require('@actions/core'); 2 | const os = require('os') 3 | const { spawnHawk } = require('./hawk_process') 4 | 5 | // A filter that returns 'true' if an element contains anything other than null or an empty string 6 | function checkNotEmpty(element) { 7 | return (element !== null && element !== ""); 8 | } 9 | 10 | // Convert a string to a list of strings. Separator can be any mix of commas, spaces, or newlines 11 | function stringToList(list) { 12 | return list 13 | .split(/[, \n]/) 14 | .filter(checkNotEmpty); 15 | } 16 | 17 | // Produce a list of arguments from a list, like ['API_KEY', 'APP_ENV', 'HOST'], and a prefix, like '--env' 18 | function stringifyArguments(list, prefix = '') { 19 | return list.reduce((accumulator, currentValue) => { 20 | if (currentValue === '') { 21 | return `${accumulator}`; 22 | } else { 23 | return `${accumulator} ${prefix} ${currentValue}`.trim(); 24 | } 25 | }, '') 26 | } 27 | 28 | function stripAnsi(inputString) { 29 | const ansiRegex = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g 30 | return inputString.replace(ansiRegex, ''); 31 | } 32 | 33 | function scanParser(input, regex, captureGroup) { 34 | const matchResults = input.match(regex); 35 | let capturedString = null; 36 | if (matchResults && matchResults.groups && matchResults.groups[captureGroup]) { 37 | capturedString = matchResults.groups[captureGroup]; 38 | core.debug(`Found captured string: ${capturedString}`); 39 | } else { 40 | core.debug(`Scan results regex parser expected to capture a string, but found only ${matchResults}`); 41 | } 42 | if (capturedString !== null) { 43 | return stripAnsi(capturedString) 44 | } else { 45 | return null 46 | } 47 | } 48 | 49 | // Gather all conditioned inputs 50 | module.exports.gatherInputs = function gatherInputs() { 51 | return { 52 | workspace: core.getInput('workspace') || process.cwd(), 53 | apiKey: core.getInput('apiKey') || '', 54 | configurationFiles: stringToList(core.getInput('configurationFiles') || 'stackhawk.yml'), 55 | version: core.getInput('version') || 'latest', 56 | dryRun: core.getInput('dryRun').toLowerCase() || 'false', 57 | codeScanningAlerts: core.getInput('codeScanningAlerts').toLowerCase() || 'false', 58 | githubToken: core.getInput('githubToken') || process.env['GITHUB_TOKEN'] || '', 59 | installCLIOnly : core.getInput('installCLIOnly') || 'false', 60 | sourceURL : core.getInput('sourceURL') || 'https://download.stackhawk.com/hawk/cli', 61 | verbose: core.getInput('verbose').toLowerCase() || 'false', 62 | debug: core.getInput('debug').toLowerCase() || 'false', 63 | command: core.getInput('command').toLowerCase() || 'scan', 64 | args: core.getMultilineInput('args', { required: false }), 65 | } 66 | } 67 | 68 | module.exports.hawkExecutable = function() { 69 | return os.platform() === 'win32' ? 'hawk.ps1' : 'hawk' 70 | } 71 | 72 | module.exports.buildCLICommand = function buildCLICommand(inputs) { 73 | const configurationFiles = stringifyArguments(inputs.configurationFiles); 74 | const hawk = this.hawkExecutable() 75 | const cliCommand = (`${hawk} ` + 76 | `--api-key=${inputs.apiKey} ` + 77 | `${inputs.command} ` + 78 | `${(inputs.verbose === 'true') ? "--verbose " : ""}` + 79 | `${(inputs.debug === 'true') ? "--debug " : ""}` + 80 | `--repo-dir ${inputs.workspace} ` + 81 | `--cicd-platform github-action ` + 82 | `${inputs.args.join(' ')} ` + 83 | `${configurationFiles}`); 84 | const cleanCliClean = cliCommand.replace(/ +/g, ' ') 85 | if (inputs.dryRun === 'true') { 86 | core.info(`DRY-RUN MODE - The following command will not be run:`); 87 | } 88 | core.info(`CLI Command: ${cleanCliClean}`); 89 | return cleanCliClean 90 | } 91 | 92 | module.exports.spawnFileArgs = function spawnFileArgs(hawkPath, command) { 93 | const hawkArgs = command.split(" ").slice(1); 94 | return (os.platform() === 'win32') ? { 95 | file: 'powershell', 96 | args: [hawkPath, ...hawkArgs] 97 | } : { 98 | file: hawkPath, 99 | args: hawkArgs 100 | } 101 | } 102 | 103 | module.exports.runCommand = async function runCommand(hawkPath, command) { 104 | const scanData = {}; 105 | const { file, args } = this.spawnFileArgs(hawkPath, command) 106 | core.info(`${file} ${args}`) 107 | await spawnHawk(file, args) 108 | .then(data => { 109 | scanData.exitCode = data.code; 110 | scanData.resultsLink = scanParser(data.stdout, 111 | /(?<=View on StackHawk platform: )(?.*)/m, 'group') || 'https://app.stackhawk.com'; 112 | scanData.failureThreshold = scanParser(data.stdout, 113 | /(?<=Error: [0-9]+ findings with severity greater than or equal to )(?.*)/m, 'group') || ''; 114 | scanData.hawkscanVersion = scanParser(data.stdout, 115 | /(?<=StackHawk 🦅 HAWKSCAN - )(?.*)/m, 'group') || 'v0'; 116 | scanData.scanId = scanParser(data.stdout, 117 | /(?<=View on StackHawk platform: https:\/\/app.stackhawk.com\/scans\/)(?.*)/m, 'group') || 'No scan id found'; 118 | }) 119 | .catch(error => { 120 | scanData.exitCode = error.code; 121 | scanData.errorMessage = error.message; 122 | core.error(error.message); 123 | }); 124 | 125 | return scanData; 126 | } 127 | --------------------------------------------------------------------------------