├── .eslintignore ├── .eslintrc.js ├── .gitattributes ├── .github ├── CODEOWNERS ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ ├── feedback.md │ └── submit_a_request.md ├── PULL_REQUEST_TEMPLATE.md ├── codeql-config.yml └── workflows │ ├── codeql.yml │ ├── development.yml │ ├── distribution.yml │ ├── release.yml │ ├── test.yaml │ └── validation.yml ├── .gitignore ├── .prettierignore ├── .prettierrc.js ├── AUTHORS ├── LICENSE ├── README.md ├── __tests__ ├── .gitignore ├── flags.test.ts ├── install.test._ts ├── testdata │ ├── .lstn.yaml │ ├── from_root.yaml │ ├── monorepo │ │ ├── package-lock.json │ │ ├── poetry.lock │ │ └── sub │ │ │ └── poetry.lock │ └── nolockfiles │ │ └── .gitignore └── utils.test.ts ├── action.yml ├── devbox.json ├── devbox.lock ├── dist ├── index.js ├── index.js.map ├── licenses.txt └── sourcemap-register.js ├── docs └── listendev_pro_jwt_api_key.png ├── jest.config.js ├── package-lock.json ├── package.json ├── reviewpad.yml ├── src ├── constants.ts ├── eavesdrop.ts ├── flags.ts ├── install.ts ├── lstn.ts ├── main.ts ├── state.ts ├── systemctl.ts └── utils.ts └── tsconfig.json /.eslintignore: -------------------------------------------------------------------------------- 1 | # Ignore list 2 | /* 3 | 4 | # Do not ignore these folders: 5 | !__tests__/ 6 | !src/ -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // This is a reusable configuration file copied from https://github.com/actions/reusable-workflows/tree/main/reusable-configurations. Please don't make changes to this file as it's the subject of an automatic update. 2 | module.exports = { 3 | extends: [ 4 | 'eslint:recommended', 5 | 'plugin:@typescript-eslint/recommended', 6 | 'plugin:eslint-plugin-jest/recommended', 7 | 'eslint-config-prettier' 8 | ], 9 | parser: '@typescript-eslint/parser', 10 | plugins: ['@typescript-eslint', 'eslint-plugin-node', 'eslint-plugin-jest'], 11 | rules: { 12 | '@typescript-eslint/no-require-imports': 'error', 13 | '@typescript-eslint/no-non-null-assertion': 'off', 14 | '@typescript-eslint/no-explicit-any': 'off', 15 | '@typescript-eslint/no-empty-function': 'off', 16 | '@typescript-eslint/ban-ts-comment': [ 17 | 'error', 18 | { 19 | 'ts-ignore': 'allow-with-description' 20 | } 21 | ], 22 | 'no-console': 'error', 23 | 'yoda': 'error', 24 | 'prefer-const': [ 25 | 'error', 26 | { 27 | destructuring: 'all' 28 | } 29 | ], 30 | 'no-control-regex': 'off', 31 | 'no-constant-condition': ['error', {checkLoops: false}], 32 | 'node/no-extraneous-import': 'error' 33 | }, 34 | overrides: [ 35 | { 36 | files: ['**/*{test,spec}.ts'], 37 | rules: { 38 | '@typescript-eslint/no-unused-vars': 'off', 39 | 'jest/no-standalone-expect': 'off', 40 | 'jest/no-conditional-expect': 'off', 41 | 'no-console': 'off', 42 | 43 | } 44 | } 45 | ], 46 | env: { 47 | node: true, 48 | es6: true, 49 | 'jest/globals': true 50 | } 51 | }; -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | dist/** -diff linguist-generated=true -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @guerinoni -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | Hello! 4 | 5 | Thank you for your interest in contributing to this repository! 6 | 7 | We accept pull requests for bug fixes and features where we've discussed the approach in an issue and given the go-ahead for a community member to work on it. We'd also love to hear about ideas for new features as issues. 8 | 9 | Please **do**: 10 | 11 | - Check existing issues to verify that the [`bug`][bug issues] or [`feature request`][feature request issues] has not already been submitted. 12 | - Open an issue if things aren't working as expected. 13 | - Open an issue to propose a significant change. 14 | - Open a pull request to fix a bug. 15 | - Open a pull request to fix documentation about a command. 16 | - Open a pull request for any issue labelled [`help wanted`][hw] or [`good first issue`][gfi]. 17 | 18 | Please **avoid**: 19 | 20 | - Opening pull requests for issues marked [`needs-design`][needs design], [`needs-investigation`][needs investigation], or [`blocked`][blocked]. 21 | - Opening pull requests for any issue marked [`core`][core]. 22 | - These issues require additional context from the core CLI team and any external pull requests will not be accepted. 23 | 24 | ## Building the listendev/action 25 | 26 | Prerequisites: 27 | 28 | - Node.js 16.x 29 | 30 | Build with: 31 | 32 | ```bash 33 | npm i 34 | npm run make 35 | ``` 36 | 37 | ## Testing the listendev/action 38 | 39 | Run tests with: `npm run test` 40 | 41 | ## Commit convention 42 | 43 | We enforce the commits to follow the [Conventional Commits v1.0 spec](https://www.conventionalcommits.org/en/v1.0.0/) with the following (the default one) set of prefixes: 44 | 45 |
46 |
build
47 |
you're changing something in the build system
48 |
ci
49 |
you're taking care of our CI and automation
50 |
chore
51 |
little changes like typos; generally nothing very significant
52 |
docs
53 |
you are helping us with documentation
54 |
feat
55 |
your changes implement a new feature or update an existing one
56 |
fix
57 |
we'll always be grateful to you for your bug fixes
58 |
perf
59 |
you wrote a beautiful Go benchmark
60 |
refactor
61 |
when you are moving pieces around, changing file names, etc.
62 |
revert
63 |
you're reverting some changes: it may happen
64 |
test
65 |
your changes introduce, extend, or update some tests
66 |
67 | 68 | Let us now provide you some examples of commit messages we accept: 69 | 70 | ``` 71 | chore: make linter happy 72 | chore: fix a little typo 73 | test: check edge case X doesn't happen 74 | fix: ensure edge case X doesn't verify anymore 75 | test: ensure lstn installation works correctly on windows runners 76 | docs: improve the commit convention examples 77 | build: make everything 78 | feat!: change the parameter X 79 | ``` 80 | 81 | Notice that by using `!` after the prefix and before the colon you are communicating **breaking changes**. 82 | 83 | Enforcing the commits to follow this convention helps us: 84 | 85 | - keep the commit history readable 86 | - have an easily understandable commit history 87 | - manually label the pull requests accordingly 88 | 89 | Thank you for sticking to using it! 90 | 91 | Notice that we check the commit messages and lint them on every pull request. Should you find some bugs with the commit linting process, you can notify the author of the underlying parser at [leodido/go-conventionalcommits](https://github.com/leodido/go-conventionalcommits). 92 | 93 | Notice also that the enforcement of the Conventional Commit v1.0 spec is from v0.1.0 onwards, previous git history may not follow it perfectly. 94 | 95 | ## Submitting a pull request 96 | 97 | We also enforce the **pull requests titles** to follow the [Conventional Commits v1.0 spec](https://www.conventionalcommits.org/en/v1.0.0/). 98 | 99 | This because we have machinery in place that automatically labels the pull requests depending on the: 100 | 101 | - the path and file changes 102 | - the title of the pull request 103 | - the branch name of the pull request 104 | 105 | You can see the rules we use [here](../reviewpad.yml). 106 | 107 | It helps us automatically generate a wonderful changelog! 108 | 109 | Let's say that you spot a bug and you wanna fix it... 110 | You can open a pull request with title `fix: some subtle bug` and it will be automatically labeled with the `bug` label. 111 | 112 | 1. Create a new branch: `git checkout -b fix/some-subtle-bug` 113 | 1. Make your change, add tests, and ensure tests pass 114 | 1. Submit a pull request: `gh pr create --web` 115 | 116 | Please write **small pull requests** to ease our review and maintenance burdens. 117 | 118 | Contributions to this project are [released][legal] to the public under the [project's open source license][license]. 119 | 120 | Please note that this project adheres to a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms. 121 | 122 | ## Releases 123 | 124 | Just create a tag. 125 | 126 | ``` 127 | git tag -a vX.Y.Z -m "Release vX.Y.Z" 128 | git push origin vX.Y.Z 129 | ``` 130 | 131 | Once the release CI workflow completed, **manually** edit the release to: 132 | 133 | 1. generate GitHub release notes by clicking the top-right button 134 | 2. publish the new release on the GitHub Actions Marketplace by ensuring its checkbox is selected 135 | 136 | ## Resources 137 | 138 | - [How to Contribute to Open Source][] 139 | - [Using Pull Requests][] 140 | - [GitHub Help][] 141 | 142 | [bug issues]: https://github.com/listendev/action/issues?q=is%3Aopen+is%3Aissue+label%3Abug 143 | [feature request issues]: https://github.com/listendev/action/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement 144 | [hw]: https://github.com/listendev/action/issues?q=is%3Aopen+is%3Aissue+label%3A"help+wanted" 145 | [blocked]: https://github.com/listendev/action/issues?q=is%3Aopen+is%3Aissue+label%3Ablocked 146 | [needs design]: https://github.com/listendev/action/issues?q=is%3Aopen+is%3Aissue+label%3A"needs+design" 147 | [needs investigation]: https://github.com/listendev/action/issues?q=is%3Aopen+is%3Aissue+label%3A"needs+investigation" 148 | [gfi]: https://github.com/listendev/action/issues?q=is%3Aopen+is%3Aissue+label%3A"good+first+issue" 149 | [core]: https://github.com/listendev/action/issues?q=is%3Aopen+is%3Aissue+label%3Acore 150 | [legal]: https://docs.github.com/en/free-pro-team@latest/github/site-policy/github-terms-of-service#6-contributions-under-repository-license 151 | [license]: ../LICENSE 152 | [code-of-conduct]: https://github.com/listendev/.github/blob/main/CODE_OF_CONDUCT.md 153 | [how to contribute to open source]: https://opensource.guide/how-to-contribute/ 154 | [using pull requests]: https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/about-pull-requests 155 | [github help]: https://docs.github.com/ 156 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B Bug report" 3 | about: Report a bug or unexpected behavior while using this GitHub action 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Describe the bug 11 | 12 | A clear and concise description of what the bug is. 13 | 14 | Please include a reference to the GitHub action workflow where you are using it. 15 | 16 | ### Expected vs actual behavior 17 | 18 | A clear and concise description of what you expected to happen and what actually happened. 19 | 20 | ### Logs 21 | 22 | Paste the activity from your command line. **REDACT IF NEEDED**. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Ask a question on how to use listendev/action 4 | about: For general-purpose questions and answers, see the discussions section. 5 | url: https://github.com/listendev/action/discussions 6 | - name: Ask a question about listen.dev 7 | about: Please check out our Discord for discussions about listen.dev and our approach to supply chain security. 8 | url: https://discord.gg/JB6tvTs5Fc 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feedback.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F4E3 Feedback" 3 | about: Give us general feedback about this GitHub action 4 | title: "" 5 | labels: feedback 6 | assignees: "" 7 | --- 8 | 9 | # Feedback 10 | 11 | You can use this template to give us structured feedback or just wipe it and leave us a note. Thank you! 12 | 13 | ## What have you loved? 14 | 15 | _eg., "the nice colors"_ 16 | 17 | ## What was confusing or gave you pause? 18 | 19 | _eg., "it did something unexpected"_ 20 | 21 | ## Are there features you'd like to see added? 22 | 23 | _eg., "erborist needs more unicorns"_ 24 | 25 | ## Anything else? 26 | 27 | _eg., "have a nice day"_ 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/submit_a_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "⭐ Submit a request" 3 | about: Surface a feature or problem that you think we should solve 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Describe the feature or problem you’d like to solve 11 | 12 | A clear and concise description of what the feature or problem is. 13 | 14 | ### Proposed solution 15 | 16 | How will it benefit the project and its users? 17 | 18 | ### Additional context 19 | 20 | Add any other context like screenshots or mockups are helpful, if applicable. -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 9 | 10 | - [ ] I have read the [contributing guidelines](https://github.com/listendev/action/blob/main/.github/CONTRIBUTING.md) 11 | - [ ] I have written unit tests 12 | - [ ] I have made sure that the pull request is of reasonable size and can be easily reviewed 13 | -------------------------------------------------------------------------------- /.github/codeql-config.yml: -------------------------------------------------------------------------------- 1 | paths-ignore: 2 | - 'dist/**' 3 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: codeql 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | schedule: 9 | - cron: '0 8 * * 1' # every Monday at 8am 10 | 11 | jobs: 12 | call-codeql-analysis: 13 | name: analysis 14 | uses: actions/reusable-workflows/.github/workflows/codeql-analysis.yml@main 15 | with: 16 | codeql-cfg-path: './.github/codeql-config.yml' 17 | -------------------------------------------------------------------------------- /.github/workflows/development.yml: -------------------------------------------------------------------------------- 1 | name: listendev 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths-ignore: 8 | - '**.md' 9 | pull_request: 10 | paths-ignore: 11 | - '**.md' 12 | 13 | jobs: 14 | development: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | 20 | # Self inspect ourselves 21 | - uses: ./ 22 | with: 23 | runtime: only 24 | jwt: ${{ secrets.LISTENDEV_TOKEN }} 25 | 26 | - name: Self inspect with nightly (private) CLI 27 | uses: ./ 28 | with: 29 | runtime: only 30 | jwt: ${{ secrets.LISTENDEV_TOKEN }} 31 | lstn: dev 32 | env: 33 | pat_pvt_repo: ${{ secrets.PAT_PVT_REPO }} 34 | 35 | - name: Debug 36 | run: | 37 | sudo cat /var/run/jibril/default 38 | 39 | - name: Setup Node.JS 40 | uses: actions/setup-node@v4 41 | with: 42 | node-version: 20 43 | 44 | - name: Install dependencies 45 | run: npm ci 46 | 47 | - name: Run prettier 48 | run: npm run format-check 49 | 50 | - name: Run linter 51 | run: npm run lint 52 | 53 | - name: Build 54 | run: npm run build 55 | 56 | - name: Test 57 | run: npm test 58 | -------------------------------------------------------------------------------- /.github/workflows/distribution.yml: -------------------------------------------------------------------------------- 1 | name: distribution 2 | 3 | # This workflow ensures that the generated contents of the dist directory match what they are expected to be. 4 | # For actions that follow our TypeScript or JavaScript templates, dist contains the packaged script that is executed by the runner. 5 | # Whenever you update the source code, the dist files must be regenerated for the changes to take effect. 6 | 7 | on: 8 | push: 9 | branches: 10 | - main 11 | paths-ignore: 12 | - '**.md' 13 | pull_request: 14 | paths-ignore: 15 | - '**.md' 16 | workflow_dispatch: 17 | 18 | jobs: 19 | distribution: 20 | uses: actions/reusable-workflows/.github/workflows/check-dist.yml@main 21 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | tags: 8 | - 'v*.*.*' 9 | pull_request: 10 | types: 11 | - labeled 12 | 13 | jobs: 14 | release: 15 | if: "${{ github.event.action != 'labeled' }}" 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v4 19 | 20 | # Bump the version on merging pull requests with specific labels (bump:major, bump:minor, bump:patch) 21 | - id: bumpr 22 | if: "${{ !startsWith(github.ref, 'refs/tags/') }}" 23 | uses: haya14busa/action-bumpr@v1 24 | 25 | # Update corresponding major and minor tags 26 | # e.g. update v1 and v1.2 when releasing v1.2.3 27 | - uses: haya14busa/action-update-semver@v1 28 | if: '${{ !steps.bumpr.outputs.skip }}' 29 | with: 30 | tag: ${{ steps.bumpr.outputs.next_version }} 31 | 32 | # Get the tag name 33 | - id: tag 34 | uses: haya14busa/action-cond@v1 35 | with: 36 | cond: "${{ startsWith(github.ref, 'refs/tags/') }}" 37 | if_true: ${{ github.ref }} 38 | if_false: ${{ steps.bumpr.outputs.next_version }} 39 | 40 | # Release 41 | - uses: actions/create-release@v1 42 | if: "${{ steps.tag.outputs.value != '' }}" 43 | env: 44 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 45 | with: 46 | tag_name: ${{ steps.tag.outputs.value }} 47 | release_name: Release ${{ steps.tag.outputs.value }} 48 | body: ${{ steps.bumpr.outputs.message }} 49 | draft: false 50 | prerelease: false 51 | 52 | release-check: 53 | name: 'release / check' 54 | if: ${{ github.event.action == 'labeled' }} 55 | runs-on: ubuntu-latest 56 | steps: 57 | - uses: actions/checkout@v4 58 | - name: Post bumpr status comment 59 | uses: haya14busa/action-bumpr@v1 60 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: testing 2 | 3 | on: 4 | pull_request: 5 | branches: ['main'] 6 | push: 7 | branches: ['main'] 8 | 9 | jobs: 10 | unit: 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | platform: [ubuntu-latest, macos-latest] 15 | runs-on: ${{ matrix.platform }} 16 | steps: 17 | - name: Check out 18 | uses: actions/checkout@v4 19 | 20 | - name: Install the dependencies 21 | run: npm ci 22 | 23 | - name: Run tests 24 | run: npm run test 25 | 26 | # TODO: check all the outputs 27 | integration: 28 | needs: unit 29 | strategy: 30 | fail-fast: false 31 | matrix: 32 | platform: [ubuntu-latest, macos-latest] 33 | runs-on: ${{ matrix.platform }} 34 | steps: 35 | - name: Check out 36 | uses: actions/checkout@v4 37 | 38 | - name: Debug options 39 | uses: ./ 40 | with: 41 | lstn: v0.13.0 42 | lstn_flags: '--debug-options' 43 | 44 | - name: Debug jwt input 45 | uses: ./ 46 | with: 47 | jwt: 'xxx.yyy.zzz' # NOTE: do not do this, use a secret 48 | lstn_flags: '--debug-options' 49 | 50 | - name: Debug jwt input with additional reporter 51 | uses: ./ 52 | with: 53 | jwt: 'xxx.yyy.zzz' # NOTE: do not do this, use a secret 54 | lstn_flags: '-r gh-pull-comment --debug-options' 55 | 56 | - name: Debug invoking lstn from root with custom config file containing multiple lockfiles 57 | uses: ./ 58 | with: 59 | jwt: 'xxx.123.987' # NOTE: do not do this, use a secret 60 | workdir: '.' 61 | lstn_flags: '--config __tests__/testdata/from_root.yaml --debug-options' 62 | # Expects "lockfiles": ["__tests__/testdata/monorepo/package-lock.json","__tests__/testdata/monorepo/poetry.lock","__tests__/testdata/monorepo/sub/poetry.lock"] 63 | 64 | - name: Debug invoking lstn from root with custom config file containing multiple lockfiles using action input 65 | uses: ./ 66 | with: 67 | jwt: 'xxx.123.987' # NOTE: do not do this, use a secret 68 | workdir: '.' 69 | config: '__tests__/testdata/from_root.yaml' 70 | lstn_flags: '--debug-options' 71 | # Expects "lockfiles": ["__tests__/testdata/monorepo/package-lock.json","__tests__/testdata/monorepo/poetry.lock","__tests__/testdata/monorepo/sub/poetry.lock"] 72 | 73 | - name: Debug invoking lstn from root with custom config directory containing .lstn.yaml using action input 74 | uses: ./ 75 | with: 76 | jwt: 'xxx.123.456' # NOTE: do not do this, use a secret 77 | workdir: '.' 78 | config: '__tests__/testdata' 79 | lstn_flags: '--debug-options' 80 | # Expects "lockfiles": ["monorepo/package-lock.json","monorepo/poetry.lock","monorepo/sub/poetry.lock"] 81 | 82 | - name: Debug invoking lstn from root with custom workdir + explicit lockfiles flag 83 | uses: ./ 84 | with: 85 | jwt: 'xxx.123.789' # NOTE: do not do this, use a secret 86 | workdir: '__tests__/testdata' 87 | lstn_flags: '--lockfiles monorepo/package-lock.json,monorepo/sub/poetry.lock --debug-options' 88 | # Expects "lockfiles": ["monorepo/package-lock.json","monorepo/sub/poetry.lock"] 89 | 90 | - name: Debug invoking lstn from root with custom workdir containing .lstn.yaml (lockfiles relative to workdir) 91 | uses: ./ 92 | with: 93 | jwt: 'xxx.123.789' # NOTE: do not do this, use a secret 94 | workdir: '__tests__/testdata' 95 | lstn_flags: '--debug-options' 96 | # Expects "lockfiles": ["monorepo/package-lock.json","monorepo/poetry.lock","monorepo/sub/poetry.lock"] 97 | 98 | - name: Debug invoking lstn from root with custom workdir containing default lockfiles 99 | uses: ./ 100 | with: 101 | jwt: 'xxx.123.yyy' # NOTE: do not do this, use a secret 102 | workdir: '__tests__/testdata/monorepo' 103 | lstn_flags: '--debug-options' 104 | # Expects "lockfiles": ["package-lock.json","poetry.lock"] 105 | 106 | - name: Debug invoking CI eavesdrop tool 107 | if: runner.os == 'Linux' 108 | uses: ./ 109 | with: 110 | jwt: 'xxx.yyy.zzz' # NOTE: do not do this, use a secret 111 | runtime: true 112 | lstn_flags: '--debug-options' 113 | 114 | # We wanna point the action to a directory that DOES NOT contain any lock file 115 | - name: Debug invoking CI eavesdrop tool only 116 | if: runner.os == 'Linux' 117 | uses: ./ 118 | with: 119 | jwt: 'xxx.yyy.zzz' # NOTE: do not do this, use a secret 120 | workdir: '__tests__/testdata/nolockfiles' 121 | runtime: only 122 | lstn_flags: '--debug-options' 123 | 124 | - name: Self run (custom reporter) 125 | uses: ./ 126 | with: 127 | reporter: gh-pull-review 128 | lstn_flags: '--debug-options' 129 | 130 | - name: Self run with lstn_flags 131 | uses: ./ 132 | with: 133 | reporter: gh-pull-check 134 | lstn_flags: "--json --jq '.[] | select(.verdicts == [])' --debug-options" 135 | -------------------------------------------------------------------------------- /.github/workflows/validation.yml: -------------------------------------------------------------------------------- 1 | name: validation 2 | 3 | # This workflow compiles and tests the code in the repo. It also checks that it passes linting and formatting rules. 4 | # Optionally, it can run npm audit on the packages in the repo. 5 | 6 | on: 7 | push: 8 | branches: 9 | - main 10 | paths-ignore: 11 | - '**.md' 12 | pull_request: 13 | paths-ignore: 14 | - '**.md' 15 | 16 | jobs: 17 | basic: 18 | uses: actions/reusable-workflows/.github/workflows/basic-validation.yml@main 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib/ 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | lerna-debug.log* 10 | 11 | # Diagnostic reports (https://nodejs.org/api/report.html) 12 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | *.pid.lock 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | *.lcov 26 | 27 | # nyc test coverage 28 | .nyc_output 29 | 30 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 31 | .grunt 32 | 33 | # Bower dependency directory (https://bower.io/) 34 | bower_components 35 | 36 | # node-waf configuration 37 | .lock-wscript 38 | 39 | # Compiled binary addons (https://nodejs.org/api/addons.html) 40 | build/Release 41 | 42 | # Dependency directories 43 | node_modules/ 44 | jspm_packages/ 45 | 46 | # TypeScript v1 declaration files 47 | typings/ 48 | 49 | # TypeScript cache 50 | *.tsbuildinfo 51 | 52 | # Optional npm cache directory 53 | .npm 54 | 55 | # Optional eslint cache 56 | .eslintcache 57 | 58 | # Microbundle cache 59 | .rpt2_cache/ 60 | .rts2_cache_cjs/ 61 | .rts2_cache_es/ 62 | .rts2_cache_umd/ 63 | 64 | # Optional REPL history 65 | .node_repl_history 66 | 67 | # Output of 'npm pack' 68 | *.tgz 69 | 70 | # Yarn Integrity file 71 | .yarn-integrity 72 | 73 | # dotenv environment variables file 74 | .env 75 | .env.test 76 | 77 | # parcel-bundler cache (https://parceljs.org/) 78 | .cache 79 | 80 | # Next.js build output 81 | .next 82 | 83 | # Nuxt.js build / generate output 84 | .nuxt 85 | 86 | # Gatsby files 87 | .cache/ 88 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 89 | # https://nextjs.org/blog/next-9-1#public-directory-support 90 | # public 91 | 92 | # vuepress build output 93 | .vuepress/dist 94 | 95 | # Serverless directories 96 | .serverless/ 97 | 98 | # FuseBox cache 99 | .fusebox/ 100 | 101 | # DynamoDB Local files 102 | .dynamodb/ 103 | 104 | # TernJS port file 105 | .tern-port 106 | 107 | lstn 108 | .envrc 109 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore list 2 | /* 3 | 4 | # Do not ignore these folders: 5 | !__tests__/ 6 | !.github/ 7 | !src/ -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | // This is a reusable configuration file copied from https://github.com/actions/reusable-workflows/tree/main/reusable-configurations. Please don't make changes to this file as it's the subject of an automatic update. 2 | module.exports = { 3 | printWidth: 80, 4 | tabWidth: 2, 5 | useTabs: false, 6 | semi: true, 7 | singleQuote: true, 8 | trailingComma: 'none', 9 | bracketSpacing: false, 10 | arrowParens: 'avoid' 11 | }; 12 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Farrukh Jadoon (https://github.com/jadoonf) 2 | Federico Guerinoni (https://github.com/guerinoni) 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # listendev/action 2 | 3 | > Proactive Security Monitoring Inside GitHub Actions 🐬 4 | 5 | _Observe network, file, and process behaviors during every workflow run and flags anomalous and malicious activities — such as connections to unknown IPs or unauthorized source code changes – in your GitHub actions workflows._ 6 | 7 | ## Usage 8 | 9 | See [action.yml](action.yml). 10 | 11 | ### Basic 12 | 13 | ```yaml 14 | steps: 15 | - uses: listendev/action@v0.19.0 16 | with: 17 | runtime: only 18 | jwt: ${{ secrets.LSTN_API_KEY }} 19 | ``` 20 | 21 | ### Full 22 | 23 | ```yaml 24 | steps: 25 | - uses: listendev/action@v0.19.0 26 | with: 27 | # The Github API token. 28 | # Defaults to ${{ github.token }} 29 | token: "..." 30 | # The listen.dev JWT token. 31 | # Defaults to empty string. 32 | jwt: ${{ secrets.MY_JWT_TOKEN }} 33 | # Whether to enable the eavesdrop tool or not to inspect the runtime threats in your CI. 34 | # Works only on linux runners. Requires a valid `jwt` option. 35 | # Defaults to false. 36 | runtime: "true|false|only" 37 | # The lstn version. 38 | # Defaults to the latest lstn release tag (recommended). 39 | lstn: "vX.Y.Z" 40 | # The working directory relative to the root one. 41 | # Defaults to the root directory. 42 | workdir: "." 43 | # The path to the YAML configuration file. 44 | # Or the path of the directory containing a .lstn.yaml file. 45 | # Defaults to empty. 46 | config: "..." 47 | # One or more reporting mechanisms (gh-pull-comment,gh-pull-review,gh-pull-check,pro) 48 | # Defaults to "gh-pull-comment" when there is no JWT input, to "pro" otherwise. 49 | reporter: "gh-pull-comment" 50 | # Addition lstn flags for power users 51 | lstn_flags: "" 52 | ``` 53 | 54 | ### Connect to listen.dev 55 | 56 | Just [create a secret](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions) and pass it to the `jwt` input... 57 | 58 | ```yaml 59 | steps: 60 | - uses: listendev/action@v0.19.0 61 | with: 62 | runtime: true 63 | jwt: ${{ secrets.LSTN_API_KEY }} 64 | ``` 65 | 66 | When the action notices that the [listen.dev](https://listen.dev) JWT secret exists, it will automatically override the reporter to the `pro` one. 67 | 68 | Because of the `runtime` option set to `true`, it will also start the CI eavesdrop tool under the hoods. 69 | 70 | Notice it only works on linux runners. 71 | 72 | **Where to get your JWT token?** 73 | 74 | [How to get your API key from the project settings](https://docs.listen.dev/workflows/generate-api-token). 75 | 76 | It's _recommended_ to regenerate the JWT token for every release, until we will release stable versions. 77 | 78 |
79 | Do you also want to also use another reporter together with the pro one? 80 | 81 | ```yaml 82 | steps: 83 | - uses: listendev/action@v0.19.0 84 | with: 85 | jwt: ${{ secrets.LSTN_API_KEY }} 86 | lstn_flags: "--reporter gh-pull-comment" 87 | ``` 88 |
89 | 90 | ### Examples 91 | 92 | Let's say you don't want verdicts and events about the dependencies into your lockfiles. 93 | Or maybe your repository doesn't contain lockfiles (package-lock.json, poetry.lock, etc.) at all... 94 | 95 | So, you only want it to eavesdrop for runtime threats... 96 | 97 | ```yaml 98 | steps: 99 | - uses: listendev/action@v0.19.0 100 | with: 101 | runtime: only 102 | jwt: ${{ secrets.LSTN_API_KEY }} 103 | ``` 104 | 105 | Let's say you want the verdicts in JSON format... 106 | 107 | ```yaml 108 | steps: 109 | - uses: listendev/action@v0.19.0 110 | with: 111 | lstn_flags: "--json" 112 | ``` 113 | 114 | Let's say you only care for high severity verdicts... 115 | 116 | ```yaml 117 | steps: 118 | - uses: listendev/action@v0.19.0 119 | with: 120 | lstn: "v0.20.0" 121 | lstn_flags: "--select '@.severity == \"high\"'" 122 | ``` 123 | 124 | You can select the verdicts also with the `select` input. 125 | 126 | Let's say we only care for dynamic instrumentation verdicts regarding processes... 127 | 128 | ```yaml 129 | steps: 130 | - uses: listendev/action@v0.19.0 131 | with: 132 | select: "(@.file =~ \"^dynamic\" && \"process\" in @.categories)" 133 | ``` 134 | 135 | ## Development 136 | 137 | To develop this GitHub action you first need to install its dependencies: 138 | 139 | ```bash 140 | npm install 141 | ``` 142 | 143 | You can then use `npm run build` to compile it. Also, remember that we check on every pull request that you've run this command, as to avoid the `dist/` directory to be out of sync. 144 | 145 | You can also run unit tests locally with the `npm run test` command. 146 | 147 | The CI makes extensive use of the official [GitHub reusable workflows](https://github.com/actions/reusable-workflows) for developing actions following best practices (see the [.github](./.github) directory). 148 | 149 | ## License 150 | 151 | The scripts and documentation in this project are released under the [Apache 2.0](LICENSE) license. 152 | 153 | ## Contributions 154 | 155 | Contributions are always welcome! 156 | 157 | See [contributor's guide](.github/CONTRIBUTING.md). 158 | 159 | ### Code of Conduct 160 | 161 | Practice kindness. ✨ 162 | 163 | See [our code of conduct](https://github.com/listendev/.github/blob/main/CODE_OF_CONDUCT.md). 164 | -------------------------------------------------------------------------------- /__tests__/.gitignore: -------------------------------------------------------------------------------- 1 | _temp -------------------------------------------------------------------------------- /__tests__/flags.test.ts: -------------------------------------------------------------------------------- 1 | import * as flags from '../src/flags'; 2 | 3 | describe('flags', () => { 4 | it('empty', () => { 5 | const input = ''; 6 | expect(flags.parse(input)).toEqual([]); 7 | }); 8 | 9 | it('parses singe bool flag', () => { 10 | const input = '--debug-options'; 11 | expect(flags.parse(input)).toEqual(['--debug-options']); 12 | }); 13 | 14 | it('parses multiple flags', () => { 15 | const input = 16 | '--debug-options -r gh-pull-check,gh-pull-comment --gh-pull-id 123'; 17 | expect(flags.parse(input)).toEqual([ 18 | '--debug-options', 19 | '-r', 20 | 'gh-pull-check,gh-pull-comment', 21 | '--gh-pull-id', 22 | '123' 23 | ]); 24 | }); 25 | 26 | it('parses multiple flags with double quotes', () => { 27 | const input = 28 | '--debug-options -r "gh-pull-check, gh-pull-comment" --gh-pull-id 123'; 29 | expect(flags.parse(input)).toEqual([ 30 | '--debug-options', 31 | '-r', 32 | 'gh-pull-check, gh-pull-comment', 33 | '--gh-pull-id', 34 | '123' 35 | ]); 36 | }); 37 | 38 | it('parses multiple flags with single quotes', () => { 39 | const input = "--debug-options --npm-registry 'https://registry.npmjs.org'"; 40 | expect(flags.parse(input)).toEqual([ 41 | '--debug-options', 42 | '--npm-registry', 43 | 'https://registry.npmjs.org' 44 | ]); 45 | }); 46 | 47 | it('parses flag with nested quotes', () => { 48 | const input = '--select \'(@.severity == "high")\''; 49 | expect(flags.parse(input)).toEqual(['--select', '(@.severity == "high")']); 50 | }); 51 | 52 | it('parses short flag (value with quotes)', () => { 53 | const input = '-s \'(@.severity == "high")\''; 54 | expect(flags.parse(input)).toEqual(['-s', '(@.severity == "high")']); 55 | }); 56 | 57 | it('parses short flag with equal', () => { 58 | const input = `-s='@.severity == "high"'`; 59 | expect(flags.parse(input)).toEqual(['-s', `@.severity == "high"`]); 60 | }); 61 | 62 | it('parses short flag', () => { 63 | const input = '-r=gh-pull-check,gh-pull-comment'; 64 | expect(flags.parse(input)).toEqual(['-r', 'gh-pull-check,gh-pull-comment']); 65 | }); 66 | 67 | it('parses flag with equal and nested quotes', () => { 68 | const input = `--select='"network" in @.categories' --json`; 69 | expect(flags.parse(input)).toEqual([ 70 | '--select', 71 | `"network" in @.categories`, 72 | '--json' 73 | ]); 74 | }); 75 | 76 | it('complex', () => { 77 | const input = 78 | '--select \'(@.file =~ "^dynamic" && "process" in @.categories)\' --json -r=gh-pull-check,gh-pull-comment --gh-pull-id 123'; 79 | expect(flags.parse(input)).toEqual([ 80 | '--select', 81 | '(@.file =~ "^dynamic" && "process" in @.categories)', 82 | '--json', 83 | '-r', 84 | 'gh-pull-check,gh-pull-comment', 85 | '--gh-pull-id', 86 | '123' 87 | ]); 88 | }); 89 | }); 90 | -------------------------------------------------------------------------------- /__tests__/install.test._ts: -------------------------------------------------------------------------------- 1 | import {promises as fs} from 'fs'; 2 | import * as path from 'path'; 3 | 4 | const tmpdir = path.join(__dirname, '_temp'); 5 | process.env['RUNNER_TEMP'] = tmpdir; 6 | 7 | import * as io from '@actions/io'; 8 | import * as exec from '@actions/exec'; 9 | import * as core from '@actions/core'; 10 | import * as eavesdrop from '../src/eavesdrop'; 11 | import * as lstn from '../src/lstn'; 12 | 13 | jest.mock('../src/constants', () => ({ 14 | EavesdropMustRun: true 15 | })); 16 | 17 | describe('installer', () => { 18 | beforeAll(async () => { 19 | await io.mkdirP(tmpdir); 20 | }); 21 | 22 | afterAll(async () => { 23 | await io.rmRF(tmpdir); 24 | }); 25 | 26 | it.skipWindows( 27 | 'installs specific lstn version', 28 | async () => { 29 | const getInputSpy = jest 30 | .spyOn(core, 'getInput') 31 | .mockImplementation((name: string) => { 32 | const data: {[key: string]: string} = { 33 | lstn: 'v0.3.1', 34 | workdir: '.', 35 | reporter: 'gh-pull-comment', 36 | lstn_flags: '', 37 | jwt: '12345' 38 | }; 39 | 40 | return data[name]; 41 | }); 42 | 43 | const tool = new lstn.Tool(); 44 | 45 | expect(getInputSpy).toHaveBeenCalledWith('lstn'); 46 | expect(getInputSpy).toHaveBeenCalledWith('jwt', {required: true}); 47 | expect(getInputSpy).toHaveBeenCalledWith('reporter'); 48 | expect(getInputSpy).toHaveBeenCalledWith('select'); 49 | expect(getInputSpy).toHaveBeenCalledWith('workdir'); 50 | expect(getInputSpy).toHaveBeenCalledWith('lstn_flags'); 51 | 52 | expect(tool.getVersion()).toEqual('v0.3.1'); 53 | 54 | const dir = await fs.mkdtemp(path.join(tmpdir, 'lstn-')); 55 | 56 | const res = await tool.install(dir); 57 | 58 | expect(res.startsWith(dir)).toBe(true); 59 | expect(tool.isInstalled()).toBe(true); 60 | 61 | const out = await exec.getExecOutput(res, ['version']); 62 | expect(out.exitCode).toBe(0); 63 | expect(out.stderr.trim()).toEqual('lstn v0.3.1'); 64 | }, 65 | 5 * 60 * 1000 66 | ); 67 | 68 | it.skipWindows( 69 | 'installs the latest version of lstn', 70 | async () => { 71 | const getInputSpy = jest 72 | .spyOn(core, 'getInput') 73 | .mockImplementation((name: string) => { 74 | const data: {[key: string]: string} = { 75 | lstn: 'latest', 76 | workdir: '.', 77 | reporter: 'gh-pull-comment', 78 | lstn_flags: '', 79 | jwt: '12345' 80 | }; 81 | 82 | return data[name]; 83 | }); 84 | 85 | const tool = new lstn.Tool(); 86 | 87 | expect(getInputSpy).toHaveBeenCalledWith('lstn'); 88 | expect(getInputSpy).toHaveBeenCalledWith('jwt', {required: true}); 89 | expect(getInputSpy).toHaveBeenCalledWith('reporter'); 90 | expect(getInputSpy).toHaveBeenCalledWith('select'); 91 | expect(getInputSpy).toHaveBeenCalledWith('workdir'); 92 | expect(getInputSpy).toHaveBeenCalledWith('lstn_flags'); 93 | 94 | expect(tool.getVersion()).toEqual(Object.keys(eavesdrop.Tool.tagMap)[0]); 95 | 96 | const dir = await fs.mkdtemp(path.join(tmpdir, 'lstn-')); 97 | 98 | const res = await tool.install(dir); 99 | 100 | expect(res.startsWith(dir)).toBe(true); 101 | expect(tool.isInstalled()).toBe(true); 102 | 103 | const code = await exec.exec(res, ['version']); 104 | expect(code).toBe(0); 105 | }, 106 | 5 * 60 * 1000 107 | ); 108 | 109 | it.onLinux( 110 | 'installs eavesdrop tool for the lstn v0.13.0', 111 | async () => { 112 | const getInputSpy = jest 113 | .spyOn(core, 'getInput') 114 | .mockImplementation((name: string) => { 115 | const data: {[key: string]: string} = { 116 | lstn: 'v0.13.0' 117 | }; 118 | 119 | return data[name]; 120 | }); 121 | 122 | const tool = new eavesdrop.Tool(); 123 | 124 | expect(getInputSpy).toHaveBeenCalledWith('lstn'); 125 | expect(getInputSpy).toHaveBeenCalledWith('eavesdrop_version'); 126 | 127 | expect(tool.getName()).toEqual('argus'); 128 | expect(tool.getVersion()).toEqual('v0.1'); 129 | expect(tool.getCliEnablingCommand()).toEqual(['ci']); 130 | 131 | const fileDir = await fs.mkdtemp(path.join(tmpdir, 'lstn-')); 132 | const destDir = await fs.mkdtemp(path.join(tmpdir, 'eavesdrop-')); 133 | const toolPath = await tool.install(fileDir, destDir); 134 | 135 | expect(tool.isInstalled()).toBe(true); 136 | 137 | const code = await exec.exec(toolPath, ['-v']); 138 | expect(code).toBe(0); 139 | }, 140 | 5 * 60 * 1000 141 | ); 142 | 143 | it.onLinux( 144 | 'installs eavesdrop tool for the latest lstn', 145 | async () => { 146 | const getInputSpy = jest 147 | .spyOn(core, 'getInput') 148 | .mockImplementation((name: string) => { 149 | const data: {[key: string]: string} = { 150 | lstn: 'latest' 151 | }; 152 | 153 | return data[name]; 154 | }); 155 | 156 | const tool = new eavesdrop.Tool(); 157 | 158 | expect(getInputSpy).toHaveBeenCalledWith('lstn'); 159 | expect(getInputSpy).toHaveBeenCalledWith('eavesdrop_version'); 160 | 161 | expect(tool.getVersion()).toEqual('v1.0'); 162 | expect(tool.getCliEnablingCommand()).toEqual(['ci', 'enable']); 163 | expect(tool.getName()).toEqual('jibril'); 164 | 165 | const fileDir = await fs.mkdtemp(path.join(tmpdir, 'lstn-')); 166 | const destDir = await fs.mkdtemp(path.join(tmpdir, 'eavesdrop-')); 167 | const toolPath = await tool.install(fileDir, destDir); 168 | 169 | expect(tool.isInstalled()).toBe(true); 170 | 171 | const code = await exec.exec(toolPath, ['--version']); 172 | expect(code).toBe(0); 173 | }, 174 | 5 * 60 * 1000 175 | ); 176 | 177 | it.onLinux( 178 | 'installs custom eavesdrop tool version lt v0.8', 179 | async () => { 180 | const getInputSpy = jest 181 | .spyOn(core, 'getInput') 182 | .mockImplementation((name: string) => { 183 | const data: {[key: string]: string} = { 184 | lstn: 'v0.15.0', 185 | eavesdrop_version: 'v0.3' 186 | }; 187 | 188 | return data[name]; 189 | }); 190 | 191 | const tool = new eavesdrop.Tool(); 192 | 193 | expect(getInputSpy).toHaveBeenCalledWith('lstn'); 194 | expect(getInputSpy).toHaveBeenCalledWith('eavesdrop_version'); 195 | 196 | expect(tool.getVersion()).toEqual('v0.3.0'); 197 | expect(tool.getCliEnablingCommand()).toEqual(['ci']); 198 | expect(tool.getName()).toEqual('argus'); 199 | 200 | const fileDir = await fs.mkdtemp(path.join(tmpdir, 'lstn-')); 201 | const destDir = await fs.mkdtemp(path.join(tmpdir, 'eavesdrop-')); 202 | const toolPath = await tool.install(fileDir, destDir); 203 | 204 | expect(tool.isInstalled()).toBe(true); 205 | 206 | const code = await exec.exec(toolPath, ['--version']); 207 | expect(code).toBe(0); 208 | }, 209 | 5 * 60 * 1000 210 | ); 211 | 212 | it.onLinux( 213 | 'installs nightly eavesdrop tool version with lstn gte v0.16.0', 214 | async () => { 215 | const getInputSpy = jest 216 | .spyOn(core, 'getInput') 217 | .mockImplementation((name: string) => { 218 | const data: {[key: string]: string} = { 219 | lstn: 'v0.16.0', 220 | eavesdrop_version: '0.0' 221 | }; 222 | 223 | return data[name]; 224 | }); 225 | 226 | const tool = new eavesdrop.Tool(); 227 | 228 | expect(getInputSpy).toHaveBeenCalledWith('lstn'); 229 | expect(getInputSpy).toHaveBeenCalledWith('eavesdrop_version'); 230 | 231 | expect(tool.getVersion()).toEqual('v0.0.0'); 232 | expect(tool.getCliEnablingCommand()).toEqual(['ci', 'enable']); 233 | expect(tool.getName()).toEqual('jibril'); 234 | 235 | const fileDir = await fs.mkdtemp(path.join(tmpdir, 'lstn-')); 236 | const destDir = await fs.mkdtemp(path.join(tmpdir, 'eavesdrop-')); 237 | const toolPath = await tool.install(fileDir, destDir); 238 | 239 | expect(tool.isInstalled()).toBe(true); 240 | 241 | const code = await exec.exec(toolPath, ['--version']); 242 | expect(code).toBe(0); 243 | }, 244 | 5 * 60 * 1000 245 | ); 246 | 247 | it.skipWindows( 248 | 'installs custom eavesdrop tool version lt v0.8 with lstn gte v0.16.0 should error', 249 | async () => { 250 | const getInputSpy = jest 251 | .spyOn(core, 'getInput') 252 | .mockImplementation((name: string) => { 253 | const data: {[key: string]: string} = { 254 | lstn: 'v0.16.0', 255 | eavesdrop_version: 'v0.3' 256 | }; 257 | 258 | return data[name]; 259 | }); 260 | 261 | expect(() => new eavesdrop.Tool()).toThrow( 262 | 'custom eavesdrop tool version (v0.3) cannot work with lstn versions >= v0.16.0' 263 | ); 264 | }, 265 | 5 * 60 * 1000 266 | ); 267 | 268 | it.skipWindows( 269 | 'installs custom eavesdrop tool version gte v0.8 with lstn lt v0.16.0 should error', 270 | async () => { 271 | const getInputSpy = jest 272 | .spyOn(core, 'getInput') 273 | .mockImplementation((name: string) => { 274 | const data: {[key: string]: string} = { 275 | lstn: 'v0.15.0', 276 | eavesdrop_version: 'v1.0' 277 | }; 278 | 279 | return data[name]; 280 | }); 281 | 282 | expect(() => new eavesdrop.Tool()).toThrow( 283 | 'custom eavesdrop tool version (v1.0) cannot work with lstn versions < v0.16.0' 284 | ); 285 | }, 286 | 5 * 60 * 1000 287 | ); 288 | 289 | it.skipWindows( 290 | 'installs nightly eavesdrop tool version with lstn lt v0.16.0 should error', 291 | async () => { 292 | const getInputSpy = jest 293 | .spyOn(core, 'getInput') 294 | .mockImplementation((name: string) => { 295 | const data: {[key: string]: string} = { 296 | lstn: 'v0.15.0', 297 | eavesdrop_version: 'v0.0' 298 | }; 299 | 300 | return data[name]; 301 | }); 302 | 303 | expect(() => new eavesdrop.Tool()).toThrow( 304 | 'nightly eavesdrop tool version (v0.0) cannot work with lstn versions < v0.16.0' 305 | ); 306 | }, 307 | 5 * 60 * 1000 308 | ); 309 | 310 | it.skipWindows( 311 | 'installs unsupported eavesdrop tool version throws', 312 | async () => { 313 | const getInputSpy = jest 314 | .spyOn(core, 'getInput') 315 | .mockImplementation((name: string) => { 316 | const data: {[key: string]: string} = { 317 | lstn: 'latest', 318 | eavesdrop_version: 'v0.2' 319 | }; 320 | 321 | return data[name]; 322 | }); 323 | 324 | expect(() => new eavesdrop.Tool()).toThrow( 325 | `unsupported custom eavesdrop tool version (v0.2)` 326 | ); 327 | }, 328 | 5 * 60 * 1000 329 | ); 330 | }); 331 | -------------------------------------------------------------------------------- /__tests__/testdata/.lstn.yaml: -------------------------------------------------------------------------------- 1 | timeout: 3000 2 | lockfiles: 3 | - monorepo/package-lock.json 4 | - monorepo/poetry.lock 5 | - monorepo/sub/poetry.lock 6 | -------------------------------------------------------------------------------- /__tests__/testdata/from_root.yaml: -------------------------------------------------------------------------------- 1 | timeout: 5000 2 | lockfiles: 3 | - __tests__/testdata/monorepo/package-lock.json 4 | - __tests__/testdata/monorepo/poetry.lock 5 | - __tests__/testdata/monorepo/sub/poetry.lock 6 | -------------------------------------------------------------------------------- /__tests__/testdata/monorepo/package-lock.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/listendev/action/49b8e3dcdec362c3603fb4e79a366e7e30b8451d/__tests__/testdata/monorepo/package-lock.json -------------------------------------------------------------------------------- /__tests__/testdata/monorepo/poetry.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/listendev/action/49b8e3dcdec362c3603fb4e79a366e7e30b8451d/__tests__/testdata/monorepo/poetry.lock -------------------------------------------------------------------------------- /__tests__/testdata/monorepo/sub/poetry.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/listendev/action/49b8e3dcdec362c3603fb4e79a366e7e30b8451d/__tests__/testdata/monorepo/sub/poetry.lock -------------------------------------------------------------------------------- /__tests__/testdata/nolockfiles/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | -------------------------------------------------------------------------------- /__tests__/utils.test.ts: -------------------------------------------------------------------------------- 1 | import * as utils from '../src/utils'; 2 | import * as path from 'path'; 3 | 4 | describe('checkPath', () => { 5 | const cwd = path.basename(__dirname); 6 | 7 | it('empty', async () => { 8 | const res = await utils.checkPath(''); 9 | expect(res).toEqual({exists: false}); 10 | }); 11 | 12 | it('existing folder', async () => { 13 | const res = await utils.checkPath(path.join(cwd, 'testdata')); 14 | 15 | expect(res).toEqual({exists: true, isFile: false}); 16 | }); 17 | 18 | it('existing file', async () => { 19 | const res = await utils.checkPath( 20 | path.join(cwd, 'testdata', 'from_root.yaml') 21 | ); 22 | 23 | expect(res).toEqual({exists: true, isFile: true}); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: "listen.dev" 2 | description: "Proactive Security Monitoring Inside GitHub Actions." 3 | author: "The listen.dev team " 4 | inputs: 5 | token: 6 | description: "The GitHub API token." 7 | required: true 8 | default: ${{ github.token }} 9 | jwt: 10 | description: "The listen.dev JWT token." 11 | required: false 12 | default: "" 13 | lstn: 14 | description: "The lstn CLI version." 15 | required: false 16 | default: "latest" 17 | runtime: 18 | description: "Whether to only or also use our eavesdrop tool to inspect the runtime threats in your CI. A listen.dev JWT token is mandatory." 19 | required: false 20 | default: "false" 21 | workdir: 22 | description: "Working directory relative to the root directory." 23 | required: false 24 | default: "." 25 | config: 26 | description: "The path of the configuration file." 27 | required: false 28 | default: "" 29 | reporter: 30 | description: "Preferred reporting mechanisms (gh-pull-comment,gh-pull-review,gh-pull-check,pro)" 31 | required: false 32 | default: "gh-pull-comment" 33 | select: 34 | description: "JSONPath script expression to filter the output verdicts" 35 | required: false 36 | default: "" 37 | lstn_flags: 38 | description: "Additional lstn CLI flags" 39 | required: false 40 | default: "" 41 | eavesdrop_version: 42 | description: "Use a custom version of our CI eavesdrop tool" 43 | required: false 44 | default: "" 45 | 46 | runs: 47 | using: "node20" 48 | main: "dist/index.js" 49 | post: "dist/index.js" 50 | 51 | # https://actions-cool.github.io/github-action-branding/ 52 | branding: 53 | icon: 'shield' 54 | color: 'green' 55 | -------------------------------------------------------------------------------- /devbox.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.13.6/.schema/devbox.schema.json", 3 | "packages": ["nodejs@20"], 4 | "shell": { 5 | "init_hook": [ 6 | "echo 'Welcome to devbox!' > /dev/null" 7 | ], 8 | "scripts": { 9 | "test": [ 10 | "echo \"Error: no test specified\" && exit 1" 11 | ] 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /devbox.lock: -------------------------------------------------------------------------------- 1 | { 2 | "lockfile_version": "1", 3 | "packages": { 4 | "github:NixOS/nixpkgs/nixpkgs-unstable": { 5 | "last_modified": "2025-05-04T04:25:16Z", 6 | "resolved": "github:NixOS/nixpkgs/6b1c028bce9c89e9824cde040d6986d428296055?lastModified=1746332716&narHash=sha256-VBmKSkmw9PYBCEGhBKzORjx%2BnwNZkPZyHcUHE21A%2Fws%3D" 7 | }, 8 | "nodejs@20": { 9 | "last_modified": "2025-03-16T23:54:35Z", 10 | "plugin_version": "0.0.2", 11 | "resolved": "github:NixOS/nixpkgs/5d9b5431f967007b3952c057fc92af49a4c5f3b2#nodejs_20", 12 | "source": "devbox-search", 13 | "version": "20.19.0", 14 | "systems": { 15 | "aarch64-darwin": { 16 | "outputs": [ 17 | { 18 | "name": "out", 19 | "path": "/nix/store/4i96rnl7hdzm3k3w36gx7d2p1af3b64q-nodejs-20.19.0", 20 | "default": true 21 | }, 22 | { 23 | "name": "libv8", 24 | "path": "/nix/store/dvr6jyyhygpci5yj5mdl3p0xi2qcm02g-nodejs-20.19.0-libv8" 25 | } 26 | ], 27 | "store_path": "/nix/store/4i96rnl7hdzm3k3w36gx7d2p1af3b64q-nodejs-20.19.0" 28 | }, 29 | "aarch64-linux": { 30 | "outputs": [ 31 | { 32 | "name": "out", 33 | "path": "/nix/store/qz522zmsx441py29xy69sf5671bkhpj2-nodejs-20.19.0", 34 | "default": true 35 | }, 36 | { 37 | "name": "libv8", 38 | "path": "/nix/store/7i02830b2pxlapzav6yyggymqmp6rk02-nodejs-20.19.0-libv8" 39 | } 40 | ], 41 | "store_path": "/nix/store/qz522zmsx441py29xy69sf5671bkhpj2-nodejs-20.19.0" 42 | }, 43 | "x86_64-darwin": { 44 | "outputs": [ 45 | { 46 | "name": "out", 47 | "path": "/nix/store/4k73p2z9h5rnfv9gal8n6m4srx5sggs8-nodejs-20.19.0", 48 | "default": true 49 | }, 50 | { 51 | "name": "libv8", 52 | "path": "/nix/store/px89hqr3wcfk0w6146hf4171bvj4chgp-nodejs-20.19.0-libv8" 53 | } 54 | ], 55 | "store_path": "/nix/store/4k73p2z9h5rnfv9gal8n6m4srx5sggs8-nodejs-20.19.0" 56 | }, 57 | "x86_64-linux": { 58 | "outputs": [ 59 | { 60 | "name": "out", 61 | "path": "/nix/store/088a1y8kvrmvi7vm5ff67hg7c4hcnqg7-nodejs-20.19.0", 62 | "default": true 63 | }, 64 | { 65 | "name": "libv8", 66 | "path": "/nix/store/njqqwr5311xmnm05ms3n7b8piwnyq7x1-nodejs-20.19.0-libv8" 67 | } 68 | ], 69 | "store_path": "/nix/store/088a1y8kvrmvi7vm5ff67hg7c4hcnqg7-nodejs-20.19.0" 70 | } 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /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 | @fastify/busboy 75 | MIT 76 | Copyright Brian White. All rights reserved. 77 | 78 | Permission is hereby granted, free of charge, to any person obtaining a copy 79 | of this software and associated documentation files (the "Software"), to 80 | deal in the Software without restriction, including without limitation the 81 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 82 | sell copies of the Software, and to permit persons to whom the Software is 83 | furnished to do so, subject to the following conditions: 84 | 85 | The above copyright notice and this permission notice shall be included in 86 | all copies or substantial portions of the Software. 87 | 88 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 89 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 90 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 91 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 92 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 93 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 94 | IN THE SOFTWARE. 95 | 96 | @octokit/auth-token 97 | MIT 98 | The MIT License 99 | 100 | Copyright (c) 2019 Octokit contributors 101 | 102 | Permission is hereby granted, free of charge, to any person obtaining a copy 103 | of this software and associated documentation files (the "Software"), to deal 104 | in the Software without restriction, including without limitation the rights 105 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 106 | copies of the Software, and to permit persons to whom the Software is 107 | furnished to do so, subject to the following conditions: 108 | 109 | The above copyright notice and this permission notice shall be included in 110 | all copies or substantial portions of the Software. 111 | 112 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 113 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 114 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 115 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 116 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 117 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 118 | THE SOFTWARE. 119 | 120 | 121 | @octokit/core 122 | MIT 123 | The MIT License 124 | 125 | Copyright (c) 2019 Octokit contributors 126 | 127 | Permission is hereby granted, free of charge, to any person obtaining a copy 128 | of this software and associated documentation files (the "Software"), to deal 129 | in the Software without restriction, including without limitation the rights 130 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 131 | copies of the Software, and to permit persons to whom the Software is 132 | furnished to do so, subject to the following conditions: 133 | 134 | The above copyright notice and this permission notice shall be included in 135 | all copies or substantial portions of the Software. 136 | 137 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 138 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 139 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 140 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 141 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 142 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 143 | THE SOFTWARE. 144 | 145 | 146 | @octokit/endpoint 147 | MIT 148 | The MIT License 149 | 150 | Copyright (c) 2018 Octokit contributors 151 | 152 | Permission is hereby granted, free of charge, to any person obtaining a copy 153 | of this software and associated documentation files (the "Software"), to deal 154 | in the Software without restriction, including without limitation the rights 155 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 156 | copies of the Software, and to permit persons to whom the Software is 157 | furnished to do so, subject to the following conditions: 158 | 159 | The above copyright notice and this permission notice shall be included in 160 | all copies or substantial portions of the Software. 161 | 162 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 163 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 164 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 165 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 166 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 167 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 168 | THE SOFTWARE. 169 | 170 | 171 | @octokit/graphql 172 | MIT 173 | The MIT License 174 | 175 | Copyright (c) 2018 Octokit contributors 176 | 177 | Permission is hereby granted, free of charge, to any person obtaining a copy 178 | of this software and associated documentation files (the "Software"), to deal 179 | in the Software without restriction, including without limitation the rights 180 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 181 | copies of the Software, and to permit persons to whom the Software is 182 | furnished to do so, subject to the following conditions: 183 | 184 | The above copyright notice and this permission notice shall be included in 185 | all copies or substantial portions of the Software. 186 | 187 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 188 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 189 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 190 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 191 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 192 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 193 | THE SOFTWARE. 194 | 195 | 196 | @octokit/plugin-paginate-rest 197 | MIT 198 | MIT License Copyright (c) 2019 Octokit contributors 199 | 200 | 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: 201 | 202 | The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. 203 | 204 | 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. 205 | 206 | 207 | @octokit/plugin-request-log 208 | MIT 209 | MIT License Copyright (c) 2020 Octokit contributors 210 | 211 | 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: 212 | 213 | The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. 214 | 215 | 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. 216 | 217 | 218 | @octokit/plugin-rest-endpoint-methods 219 | MIT 220 | MIT License Copyright (c) 2019 Octokit contributors 221 | 222 | 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: 223 | 224 | The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. 225 | 226 | 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. 227 | 228 | 229 | @octokit/request 230 | MIT 231 | The MIT License 232 | 233 | Copyright (c) 2018 Octokit contributors 234 | 235 | Permission is hereby granted, free of charge, to any person obtaining a copy 236 | of this software and associated documentation files (the "Software"), to deal 237 | in the Software without restriction, including without limitation the rights 238 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 239 | copies of the Software, and to permit persons to whom the Software is 240 | furnished to do so, subject to the following conditions: 241 | 242 | The above copyright notice and this permission notice shall be included in 243 | all copies or substantial portions of the Software. 244 | 245 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 246 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 247 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 248 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 249 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 250 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 251 | THE SOFTWARE. 252 | 253 | 254 | @octokit/request-error 255 | MIT 256 | The MIT License 257 | 258 | Copyright (c) 2019 Octokit contributors 259 | 260 | Permission is hereby granted, free of charge, to any person obtaining a copy 261 | of this software and associated documentation files (the "Software"), to deal 262 | in the Software without restriction, including without limitation the rights 263 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 264 | copies of the Software, and to permit persons to whom the Software is 265 | furnished to do so, subject to the following conditions: 266 | 267 | The above copyright notice and this permission notice shall be included in 268 | all copies or substantial portions of the Software. 269 | 270 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 271 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 272 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 273 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 274 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 275 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 276 | THE SOFTWARE. 277 | 278 | 279 | @octokit/rest 280 | MIT 281 | The MIT License 282 | 283 | Copyright (c) 2012 Cloud9 IDE, Inc. (Mike de Boer) 284 | Copyright (c) 2017-2018 Octokit contributors 285 | 286 | Permission is hereby granted, free of charge, to any person obtaining a copy 287 | of this software and associated documentation files (the "Software"), to deal 288 | in the Software without restriction, including without limitation the rights 289 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 290 | copies of the Software, and to permit persons to whom the Software is 291 | furnished to do so, subject to the following conditions: 292 | 293 | The above copyright notice and this permission notice shall be included in 294 | all copies or substantial portions of the Software. 295 | 296 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 297 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 298 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 299 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 300 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 301 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 302 | THE SOFTWARE. 303 | 304 | 305 | asynckit 306 | MIT 307 | The MIT License (MIT) 308 | 309 | Copyright (c) 2016 Alex Indigo 310 | 311 | Permission is hereby granted, free of charge, to any person obtaining a copy 312 | of this software and associated documentation files (the "Software"), to deal 313 | in the Software without restriction, including without limitation the rights 314 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 315 | copies of the Software, and to permit persons to whom the Software is 316 | furnished to do so, subject to the following conditions: 317 | 318 | The above copyright notice and this permission notice shall be included in all 319 | copies or substantial portions of the Software. 320 | 321 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 322 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 323 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 324 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 325 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 326 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 327 | SOFTWARE. 328 | 329 | 330 | axios 331 | MIT 332 | # Copyright (c) 2014-present Matt Zabriskie & Collaborators 333 | 334 | 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: 335 | 336 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 337 | 338 | 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. 339 | 340 | 341 | before-after-hook 342 | Apache-2.0 343 | Apache License 344 | Version 2.0, January 2004 345 | http://www.apache.org/licenses/ 346 | 347 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 348 | 349 | 1. Definitions. 350 | 351 | "License" shall mean the terms and conditions for use, reproduction, 352 | and distribution as defined by Sections 1 through 9 of this document. 353 | 354 | "Licensor" shall mean the copyright owner or entity authorized by 355 | the copyright owner that is granting the License. 356 | 357 | "Legal Entity" shall mean the union of the acting entity and all 358 | other entities that control, are controlled by, or are under common 359 | control with that entity. For the purposes of this definition, 360 | "control" means (i) the power, direct or indirect, to cause the 361 | direction or management of such entity, whether by contract or 362 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 363 | outstanding shares, or (iii) beneficial ownership of such entity. 364 | 365 | "You" (or "Your") shall mean an individual or Legal Entity 366 | exercising permissions granted by this License. 367 | 368 | "Source" form shall mean the preferred form for making modifications, 369 | including but not limited to software source code, documentation 370 | source, and configuration files. 371 | 372 | "Object" form shall mean any form resulting from mechanical 373 | transformation or translation of a Source form, including but 374 | not limited to compiled object code, generated documentation, 375 | and conversions to other media types. 376 | 377 | "Work" shall mean the work of authorship, whether in Source or 378 | Object form, made available under the License, as indicated by a 379 | copyright notice that is included in or attached to the work 380 | (an example is provided in the Appendix below). 381 | 382 | "Derivative Works" shall mean any work, whether in Source or Object 383 | form, that is based on (or derived from) the Work and for which the 384 | editorial revisions, annotations, elaborations, or other modifications 385 | represent, as a whole, an original work of authorship. For the purposes 386 | of this License, Derivative Works shall not include works that remain 387 | separable from, or merely link (or bind by name) to the interfaces of, 388 | the Work and Derivative Works thereof. 389 | 390 | "Contribution" shall mean any work of authorship, including 391 | the original version of the Work and any modifications or additions 392 | to that Work or Derivative Works thereof, that is intentionally 393 | submitted to Licensor for inclusion in the Work by the copyright owner 394 | or by an individual or Legal Entity authorized to submit on behalf of 395 | the copyright owner. For the purposes of this definition, "submitted" 396 | means any form of electronic, verbal, or written communication sent 397 | to the Licensor or its representatives, including but not limited to 398 | communication on electronic mailing lists, source code control systems, 399 | and issue tracking systems that are managed by, or on behalf of, the 400 | Licensor for the purpose of discussing and improving the Work, but 401 | excluding communication that is conspicuously marked or otherwise 402 | designated in writing by the copyright owner as "Not a Contribution." 403 | 404 | "Contributor" shall mean Licensor and any individual or Legal Entity 405 | on behalf of whom a Contribution has been received by Licensor and 406 | subsequently incorporated within the Work. 407 | 408 | 2. Grant of Copyright License. Subject to the terms and conditions of 409 | this License, each Contributor hereby grants to You a perpetual, 410 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 411 | copyright license to reproduce, prepare Derivative Works of, 412 | publicly display, publicly perform, sublicense, and distribute the 413 | Work and such Derivative Works in Source or Object form. 414 | 415 | 3. Grant of Patent License. Subject to the terms and conditions of 416 | this License, each Contributor hereby grants to You a perpetual, 417 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 418 | (except as stated in this section) patent license to make, have made, 419 | use, offer to sell, sell, import, and otherwise transfer the Work, 420 | where such license applies only to those patent claims licensable 421 | by such Contributor that are necessarily infringed by their 422 | Contribution(s) alone or by combination of their Contribution(s) 423 | with the Work to which such Contribution(s) was submitted. If You 424 | institute patent litigation against any entity (including a 425 | cross-claim or counterclaim in a lawsuit) alleging that the Work 426 | or a Contribution incorporated within the Work constitutes direct 427 | or contributory patent infringement, then any patent licenses 428 | granted to You under this License for that Work shall terminate 429 | as of the date such litigation is filed. 430 | 431 | 4. Redistribution. You may reproduce and distribute copies of the 432 | Work or Derivative Works thereof in any medium, with or without 433 | modifications, and in Source or Object form, provided that You 434 | meet the following conditions: 435 | 436 | (a) You must give any other recipients of the Work or 437 | Derivative Works a copy of this License; and 438 | 439 | (b) You must cause any modified files to carry prominent notices 440 | stating that You changed the files; and 441 | 442 | (c) You must retain, in the Source form of any Derivative Works 443 | that You distribute, all copyright, patent, trademark, and 444 | attribution notices from the Source form of the Work, 445 | excluding those notices that do not pertain to any part of 446 | the Derivative Works; and 447 | 448 | (d) If the Work includes a "NOTICE" text file as part of its 449 | distribution, then any Derivative Works that You distribute must 450 | include a readable copy of the attribution notices contained 451 | within such NOTICE file, excluding those notices that do not 452 | pertain to any part of the Derivative Works, in at least one 453 | of the following places: within a NOTICE text file distributed 454 | as part of the Derivative Works; within the Source form or 455 | documentation, if provided along with the Derivative Works; or, 456 | within a display generated by the Derivative Works, if and 457 | wherever such third-party notices normally appear. The contents 458 | of the NOTICE file are for informational purposes only and 459 | do not modify the License. You may add Your own attribution 460 | notices within Derivative Works that You distribute, alongside 461 | or as an addendum to the NOTICE text from the Work, provided 462 | that such additional attribution notices cannot be construed 463 | as modifying the License. 464 | 465 | You may add Your own copyright statement to Your modifications and 466 | may provide additional or different license terms and conditions 467 | for use, reproduction, or distribution of Your modifications, or 468 | for any such Derivative Works as a whole, provided Your use, 469 | reproduction, and distribution of the Work otherwise complies with 470 | the conditions stated in this License. 471 | 472 | 5. Submission of Contributions. Unless You explicitly state otherwise, 473 | any Contribution intentionally submitted for inclusion in the Work 474 | by You to the Licensor shall be under the terms and conditions of 475 | this License, without any additional terms or conditions. 476 | Notwithstanding the above, nothing herein shall supersede or modify 477 | the terms of any separate license agreement you may have executed 478 | with Licensor regarding such Contributions. 479 | 480 | 6. Trademarks. This License does not grant permission to use the trade 481 | names, trademarks, service marks, or product names of the Licensor, 482 | except as required for reasonable and customary use in describing the 483 | origin of the Work and reproducing the content of the NOTICE file. 484 | 485 | 7. Disclaimer of Warranty. Unless required by applicable law or 486 | agreed to in writing, Licensor provides the Work (and each 487 | Contributor provides its Contributions) on an "AS IS" BASIS, 488 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 489 | implied, including, without limitation, any warranties or conditions 490 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 491 | PARTICULAR PURPOSE. You are solely responsible for determining the 492 | appropriateness of using or redistributing the Work and assume any 493 | risks associated with Your exercise of permissions under this License. 494 | 495 | 8. Limitation of Liability. In no event and under no legal theory, 496 | whether in tort (including negligence), contract, or otherwise, 497 | unless required by applicable law (such as deliberate and grossly 498 | negligent acts) or agreed to in writing, shall any Contributor be 499 | liable to You for damages, including any direct, indirect, special, 500 | incidental, or consequential damages of any character arising as a 501 | result of this License or out of the use or inability to use the 502 | Work (including but not limited to damages for loss of goodwill, 503 | work stoppage, computer failure or malfunction, or any and all 504 | other commercial damages or losses), even if such Contributor 505 | has been advised of the possibility of such damages. 506 | 507 | 9. Accepting Warranty or Additional Liability. While redistributing 508 | the Work or Derivative Works thereof, You may choose to offer, 509 | and charge a fee for, acceptance of support, warranty, indemnity, 510 | or other liability obligations and/or rights consistent with this 511 | License. However, in accepting such obligations, You may act only 512 | on Your own behalf and on Your sole responsibility, not on behalf 513 | of any other Contributor, and only if You agree to indemnify, 514 | defend, and hold each Contributor harmless for any liability 515 | incurred by, or claims asserted against, such Contributor by reason 516 | of your accepting any such warranty or additional liability. 517 | 518 | END OF TERMS AND CONDITIONS 519 | 520 | APPENDIX: How to apply the Apache License to your work. 521 | 522 | To apply the Apache License to your work, attach the following 523 | boilerplate notice, with the fields enclosed by brackets "{}" 524 | replaced with your own identifying information. (Don't include 525 | the brackets!) The text should be enclosed in the appropriate 526 | comment syntax for the file format. We also recommend that a 527 | file or class name and description of purpose be included on the 528 | same "printed page" as the copyright notice for easier 529 | identification within third-party archives. 530 | 531 | Copyright 2018 Gregor Martynus and other contributors. 532 | 533 | Licensed under the Apache License, Version 2.0 (the "License"); 534 | you may not use this file except in compliance with the License. 535 | You may obtain a copy of the License at 536 | 537 | http://www.apache.org/licenses/LICENSE-2.0 538 | 539 | Unless required by applicable law or agreed to in writing, software 540 | distributed under the License is distributed on an "AS IS" BASIS, 541 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 542 | See the License for the specific language governing permissions and 543 | limitations under the License. 544 | 545 | 546 | call-bind-apply-helpers 547 | MIT 548 | MIT License 549 | 550 | Copyright (c) 2024 Jordan Harband 551 | 552 | Permission is hereby granted, free of charge, to any person obtaining a copy 553 | of this software and associated documentation files (the "Software"), to deal 554 | in the Software without restriction, including without limitation the rights 555 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 556 | copies of the Software, and to permit persons to whom the Software is 557 | furnished to do so, subject to the following conditions: 558 | 559 | The above copyright notice and this permission notice shall be included in all 560 | copies or substantial portions of the Software. 561 | 562 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 563 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 564 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 565 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 566 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 567 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 568 | SOFTWARE. 569 | 570 | 571 | combined-stream 572 | MIT 573 | Copyright (c) 2011 Debuggable Limited 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 583 | all 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 591 | THE SOFTWARE. 592 | 593 | 594 | debug 595 | MIT 596 | (The MIT License) 597 | 598 | Copyright (c) 2014-2017 TJ Holowaychuk 599 | Copyright (c) 2018-2021 Josh Junon 600 | 601 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software 602 | and associated documentation files (the 'Software'), to deal in the Software without restriction, 603 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 604 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 605 | subject to the following conditions: 606 | 607 | The above copyright notice and this permission notice shall be included in all copies or substantial 608 | portions of the Software. 609 | 610 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 611 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 612 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 613 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 614 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 615 | 616 | 617 | 618 | delayed-stream 619 | MIT 620 | Copyright (c) 2011 Debuggable Limited 621 | 622 | Permission is hereby granted, free of charge, to any person obtaining a copy 623 | of this software and associated documentation files (the "Software"), to deal 624 | in the Software without restriction, including without limitation the rights 625 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 626 | copies of the Software, and to permit persons to whom the Software is 627 | furnished to do so, subject to the following conditions: 628 | 629 | The above copyright notice and this permission notice shall be included in 630 | all copies or substantial portions of the Software. 631 | 632 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 633 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 634 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 635 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 636 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 637 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 638 | THE SOFTWARE. 639 | 640 | 641 | dunder-proto 642 | MIT 643 | MIT License 644 | 645 | Copyright (c) 2024 ECMAScript Shims 646 | 647 | Permission is hereby granted, free of charge, to any person obtaining a copy 648 | of this software and associated documentation files (the "Software"), to deal 649 | in the Software without restriction, including without limitation the rights 650 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 651 | copies of the Software, and to permit persons to whom the Software is 652 | furnished to do so, subject to the following conditions: 653 | 654 | The above copyright notice and this permission notice shall be included in all 655 | copies or substantial portions of the Software. 656 | 657 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 658 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 659 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 660 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 661 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 662 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 663 | SOFTWARE. 664 | 665 | 666 | es-define-property 667 | MIT 668 | MIT License 669 | 670 | Copyright (c) 2024 Jordan Harband 671 | 672 | Permission is hereby granted, free of charge, to any person obtaining a copy 673 | of this software and associated documentation files (the "Software"), to deal 674 | in the Software without restriction, including without limitation the rights 675 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 676 | copies of the Software, and to permit persons to whom the Software is 677 | furnished to do so, subject to the following conditions: 678 | 679 | The above copyright notice and this permission notice shall be included in all 680 | copies or substantial portions of the Software. 681 | 682 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 683 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 684 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 685 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 686 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 687 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 688 | SOFTWARE. 689 | 690 | 691 | es-errors 692 | MIT 693 | MIT License 694 | 695 | Copyright (c) 2024 Jordan Harband 696 | 697 | Permission is hereby granted, free of charge, to any person obtaining a copy 698 | of this software and associated documentation files (the "Software"), to deal 699 | in the Software without restriction, including without limitation the rights 700 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 701 | copies of the Software, and to permit persons to whom the Software is 702 | furnished to do so, subject to the following conditions: 703 | 704 | The above copyright notice and this permission notice shall be included in all 705 | copies or substantial portions of the Software. 706 | 707 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 708 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 709 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 710 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 711 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 712 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 713 | SOFTWARE. 714 | 715 | 716 | es-object-atoms 717 | MIT 718 | MIT License 719 | 720 | Copyright (c) 2024 Jordan Harband 721 | 722 | Permission is hereby granted, free of charge, to any person obtaining a copy 723 | of this software and associated documentation files (the "Software"), to deal 724 | in the Software without restriction, including without limitation the rights 725 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 726 | copies of the Software, and to permit persons to whom the Software is 727 | furnished to do so, subject to the following conditions: 728 | 729 | The above copyright notice and this permission notice shall be included in all 730 | copies or substantial portions of the Software. 731 | 732 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 733 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 734 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 735 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 736 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 737 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 738 | SOFTWARE. 739 | 740 | 741 | es-set-tostringtag 742 | MIT 743 | MIT License 744 | 745 | Copyright (c) 2022 ECMAScript Shims 746 | 747 | Permission is hereby granted, free of charge, to any person obtaining a copy 748 | of this software and associated documentation files (the "Software"), to deal 749 | in the Software without restriction, including without limitation the rights 750 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 751 | copies of the Software, and to permit persons to whom the Software is 752 | furnished to do so, subject to the following conditions: 753 | 754 | The above copyright notice and this permission notice shall be included in all 755 | copies or substantial portions of the Software. 756 | 757 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 758 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 759 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 760 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 761 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 762 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 763 | SOFTWARE. 764 | 765 | 766 | fast-content-type-parse 767 | MIT 768 | MIT License 769 | 770 | Copyright (c) 2023 The Fastify Team 771 | 772 | The Fastify team members are listed at https://github.com/fastify/fastify#team 773 | and in the README file. 774 | 775 | Permission is hereby granted, free of charge, to any person obtaining a copy 776 | of this software and associated documentation files (the "Software"), to deal 777 | in the Software without restriction, including without limitation the rights 778 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 779 | copies of the Software, and to permit persons to whom the Software is 780 | furnished to do so, subject to the following conditions: 781 | 782 | The above copyright notice and this permission notice shall be included in all 783 | copies or substantial portions of the Software. 784 | 785 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 786 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 787 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 788 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 789 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 790 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 791 | SOFTWARE. 792 | 793 | follow-redirects 794 | MIT 795 | Copyright 2014–present Olivier Lalonde , James Talmage , Ruben Verborgh 796 | 797 | Permission is hereby granted, free of charge, to any person obtaining a copy of 798 | this software and associated documentation files (the "Software"), to deal in 799 | the Software without restriction, including without limitation the rights to 800 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 801 | of the Software, and to permit persons to whom the Software is furnished to do 802 | so, subject to the following conditions: 803 | 804 | The above copyright notice and this permission notice shall be included in all 805 | copies or substantial portions of the Software. 806 | 807 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 808 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 809 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 810 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 811 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 812 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 813 | 814 | 815 | form-data 816 | MIT 817 | Copyright (c) 2012 Felix Geisendörfer (felix@debuggable.com) and contributors 818 | 819 | Permission is hereby granted, free of charge, to any person obtaining a copy 820 | of this software and associated documentation files (the "Software"), to deal 821 | in the Software without restriction, including without limitation the rights 822 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 823 | copies of the Software, and to permit persons to whom the Software is 824 | furnished to do so, subject to the following conditions: 825 | 826 | The above copyright notice and this permission notice shall be included in 827 | all copies or substantial portions of the Software. 828 | 829 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 830 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 831 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 832 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 833 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 834 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 835 | THE SOFTWARE. 836 | 837 | 838 | function-bind 839 | MIT 840 | Copyright (c) 2013 Raynos. 841 | 842 | Permission is hereby granted, free of charge, to any person obtaining a copy 843 | of this software and associated documentation files (the "Software"), to deal 844 | in the Software without restriction, including without limitation the rights 845 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 846 | copies of the Software, and to permit persons to whom the Software is 847 | furnished to do so, subject to the following conditions: 848 | 849 | The above copyright notice and this permission notice shall be included in 850 | all copies or substantial portions of the Software. 851 | 852 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 853 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 854 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 855 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 856 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 857 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 858 | THE SOFTWARE. 859 | 860 | 861 | 862 | get-intrinsic 863 | MIT 864 | MIT License 865 | 866 | Copyright (c) 2020 Jordan Harband 867 | 868 | Permission is hereby granted, free of charge, to any person obtaining a copy 869 | of this software and associated documentation files (the "Software"), to deal 870 | in the Software without restriction, including without limitation the rights 871 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 872 | copies of the Software, and to permit persons to whom the Software is 873 | furnished to do so, subject to the following conditions: 874 | 875 | The above copyright notice and this permission notice shall be included in all 876 | copies or substantial portions of the Software. 877 | 878 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 879 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 880 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 881 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 882 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 883 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 884 | SOFTWARE. 885 | 886 | 887 | get-proto 888 | MIT 889 | MIT License 890 | 891 | Copyright (c) 2025 Jordan Harband 892 | 893 | Permission is hereby granted, free of charge, to any person obtaining a copy 894 | of this software and associated documentation files (the "Software"), to deal 895 | in the Software without restriction, including without limitation the rights 896 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 897 | copies of the Software, and to permit persons to whom the Software is 898 | furnished to do so, subject to the following conditions: 899 | 900 | The above copyright notice and this permission notice shall be included in all 901 | copies or substantial portions of the Software. 902 | 903 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 904 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 905 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 906 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 907 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 908 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 909 | SOFTWARE. 910 | 911 | 912 | gopd 913 | MIT 914 | MIT License 915 | 916 | Copyright (c) 2022 Jordan Harband 917 | 918 | Permission is hereby granted, free of charge, to any person obtaining a copy 919 | of this software and associated documentation files (the "Software"), to deal 920 | in the Software without restriction, including without limitation the rights 921 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 922 | copies of the Software, and to permit persons to whom the Software is 923 | furnished to do so, subject to the following conditions: 924 | 925 | The above copyright notice and this permission notice shall be included in all 926 | copies or substantial portions of the Software. 927 | 928 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 929 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 930 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 931 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 932 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 933 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 934 | SOFTWARE. 935 | 936 | 937 | has-flag 938 | MIT 939 | MIT License 940 | 941 | Copyright (c) Sindre Sorhus (sindresorhus.com) 942 | 943 | 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: 944 | 945 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 946 | 947 | 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. 948 | 949 | 950 | has-symbols 951 | MIT 952 | MIT License 953 | 954 | Copyright (c) 2016 Jordan Harband 955 | 956 | Permission is hereby granted, free of charge, to any person obtaining a copy 957 | of this software and associated documentation files (the "Software"), to deal 958 | in the Software without restriction, including without limitation the rights 959 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 960 | copies of the Software, and to permit persons to whom the Software is 961 | furnished to do so, subject to the following conditions: 962 | 963 | The above copyright notice and this permission notice shall be included in all 964 | copies or substantial portions of the Software. 965 | 966 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 967 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 968 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 969 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 970 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 971 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 972 | SOFTWARE. 973 | 974 | 975 | has-tostringtag 976 | MIT 977 | MIT License 978 | 979 | Copyright (c) 2021 Inspect JS 980 | 981 | Permission is hereby granted, free of charge, to any person obtaining a copy 982 | of this software and associated documentation files (the "Software"), to deal 983 | in the Software without restriction, including without limitation the rights 984 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 985 | copies of the Software, and to permit persons to whom the Software is 986 | furnished to do so, subject to the following conditions: 987 | 988 | The above copyright notice and this permission notice shall be included in all 989 | copies or substantial portions of the Software. 990 | 991 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 992 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 993 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 994 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 995 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 996 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 997 | SOFTWARE. 998 | 999 | 1000 | hasown 1001 | MIT 1002 | MIT License 1003 | 1004 | Copyright (c) Jordan Harband and contributors 1005 | 1006 | Permission is hereby granted, free of charge, to any person obtaining a copy 1007 | of this software and associated documentation files (the "Software"), to deal 1008 | in the Software without restriction, including without limitation the rights 1009 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1010 | copies of the Software, and to permit persons to whom the Software is 1011 | furnished to do so, subject to the following conditions: 1012 | 1013 | The above copyright notice and this permission notice shall be included in all 1014 | copies or substantial portions of the Software. 1015 | 1016 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1017 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1018 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1019 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1020 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1021 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 1022 | SOFTWARE. 1023 | 1024 | 1025 | math-intrinsics 1026 | MIT 1027 | MIT License 1028 | 1029 | Copyright (c) 2024 ECMAScript Shims 1030 | 1031 | Permission is hereby granted, free of charge, to any person obtaining a copy 1032 | of this software and associated documentation files (the "Software"), to deal 1033 | in the Software without restriction, including without limitation the rights 1034 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1035 | copies of the Software, and to permit persons to whom the Software is 1036 | furnished to do so, subject to the following conditions: 1037 | 1038 | The above copyright notice and this permission notice shall be included in all 1039 | copies or substantial portions of the Software. 1040 | 1041 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1042 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1043 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1044 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1045 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1046 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 1047 | SOFTWARE. 1048 | 1049 | 1050 | mime-db 1051 | MIT 1052 | (The MIT License) 1053 | 1054 | Copyright (c) 2014 Jonathan Ong 1055 | Copyright (c) 2015-2022 Douglas Christopher Wilson 1056 | 1057 | Permission is hereby granted, free of charge, to any person obtaining 1058 | a copy of this software and associated documentation files (the 1059 | 'Software'), to deal in the Software without restriction, including 1060 | without limitation the rights to use, copy, modify, merge, publish, 1061 | distribute, sublicense, and/or sell copies of the Software, and to 1062 | permit persons to whom the Software is furnished to do so, subject to 1063 | the following conditions: 1064 | 1065 | The above copyright notice and this permission notice shall be 1066 | included in all copies or substantial portions of the Software. 1067 | 1068 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 1069 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1070 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 1071 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 1072 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 1073 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 1074 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 1075 | 1076 | 1077 | mime-types 1078 | MIT 1079 | (The MIT License) 1080 | 1081 | Copyright (c) 2014 Jonathan Ong 1082 | Copyright (c) 2015 Douglas Christopher Wilson 1083 | 1084 | Permission is hereby granted, free of charge, to any person obtaining 1085 | a copy of this software and associated documentation files (the 1086 | 'Software'), to deal in the Software without restriction, including 1087 | without limitation the rights to use, copy, modify, merge, publish, 1088 | distribute, sublicense, and/or sell copies of the Software, and to 1089 | permit persons to whom the Software is furnished to do so, subject to 1090 | the following conditions: 1091 | 1092 | The above copyright notice and this permission notice shall be 1093 | included in all copies or substantial portions of the Software. 1094 | 1095 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 1096 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1097 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 1098 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 1099 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 1100 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 1101 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 1102 | 1103 | 1104 | ms 1105 | MIT 1106 | The MIT License (MIT) 1107 | 1108 | Copyright (c) 2020 Vercel, Inc. 1109 | 1110 | Permission is hereby granted, free of charge, to any person obtaining a copy 1111 | of this software and associated documentation files (the "Software"), to deal 1112 | in the Software without restriction, including without limitation the rights 1113 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1114 | copies of the Software, and to permit persons to whom the Software is 1115 | furnished to do so, subject to the following conditions: 1116 | 1117 | The above copyright notice and this permission notice shall be included in all 1118 | copies or substantial portions of the Software. 1119 | 1120 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1121 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1122 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1123 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1124 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1125 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 1126 | SOFTWARE. 1127 | 1128 | 1129 | proxy-from-env 1130 | MIT 1131 | The MIT License 1132 | 1133 | Copyright (C) 2016-2018 Rob Wu 1134 | 1135 | Permission is hereby granted, free of charge, to any person obtaining a copy of 1136 | this software and associated documentation files (the "Software"), to deal in 1137 | the Software without restriction, including without limitation the rights to 1138 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 1139 | of the Software, and to permit persons to whom the Software is furnished to do 1140 | so, subject to the following conditions: 1141 | 1142 | The above copyright notice and this permission notice shall be included in all 1143 | copies or substantial portions of the Software. 1144 | 1145 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1146 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 1147 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 1148 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 1149 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 1150 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 1151 | 1152 | 1153 | semver 1154 | ISC 1155 | The ISC License 1156 | 1157 | Copyright (c) Isaac Z. Schlueter and Contributors 1158 | 1159 | Permission to use, copy, modify, and/or distribute this software for any 1160 | purpose with or without fee is hereby granted, provided that the above 1161 | copyright notice and this permission notice appear in all copies. 1162 | 1163 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1164 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1165 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1166 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1167 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1168 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 1169 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1170 | 1171 | 1172 | superserial 1173 | MIT 1174 | 1175 | supports-color 1176 | MIT 1177 | MIT License 1178 | 1179 | Copyright (c) Sindre Sorhus (sindresorhus.com) 1180 | 1181 | 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: 1182 | 1183 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 1184 | 1185 | 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. 1186 | 1187 | 1188 | tunnel 1189 | MIT 1190 | The MIT License (MIT) 1191 | 1192 | Copyright (c) 2012 Koichi Kobayashi 1193 | 1194 | Permission is hereby granted, free of charge, to any person obtaining a copy 1195 | of this software and associated documentation files (the "Software"), to deal 1196 | in the Software without restriction, including without limitation the rights 1197 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1198 | copies of the Software, and to permit persons to whom the Software is 1199 | furnished to do so, subject to the following conditions: 1200 | 1201 | The above copyright notice and this permission notice shall be included in 1202 | all copies or substantial portions of the Software. 1203 | 1204 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1205 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1206 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1207 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1208 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1209 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 1210 | THE SOFTWARE. 1211 | 1212 | 1213 | undici 1214 | MIT 1215 | MIT License 1216 | 1217 | Copyright (c) Matteo Collina and Undici contributors 1218 | 1219 | Permission is hereby granted, free of charge, to any person obtaining a copy 1220 | of this software and associated documentation files (the "Software"), to deal 1221 | in the Software without restriction, including without limitation the rights 1222 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1223 | copies of the Software, and to permit persons to whom the Software is 1224 | furnished to do so, subject to the following conditions: 1225 | 1226 | The above copyright notice and this permission notice shall be included in all 1227 | copies or substantial portions of the Software. 1228 | 1229 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1230 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1231 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1232 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1233 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1234 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 1235 | SOFTWARE. 1236 | 1237 | 1238 | universal-user-agent 1239 | ISC 1240 | # [ISC License](https://spdx.org/licenses/ISC) 1241 | 1242 | Copyright (c) 2018-2021, Gregor Martynus (https://github.com/gr2m) 1243 | 1244 | 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. 1245 | 1246 | 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. 1247 | -------------------------------------------------------------------------------- /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},274:(e,r,n)=>{var t=n(339);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(190);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}},680:(e,r,n)=>{var t=n(339);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},758:(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(339);var i=n(345);var a=n(274).I;var u=n(449);var s=n(758).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(449);var o=n(339);var i=n(274).I;var a=n(680).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},351:(e,r,n)=>{var t;var o=n(591).h;var i=n(339);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},997:(e,r,n)=>{n(591).h;r.SourceMapConsumer=n(952).SourceMapConsumer;n(351)},284:(e,r,n)=>{e=n.nmd(e);var t=n(997).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)}},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})(); -------------------------------------------------------------------------------- /docs/listendev_pro_jwt_api_key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/listendev/action/49b8e3dcdec362c3603fb4e79a366e7e30b8451d/docs/listendev_pro_jwt_api_key.png -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | clearMocks: true, 3 | moduleFileExtensions: ["js", "ts"], 4 | testEnvironment: "node", 5 | testMatch: ["**/*.test.ts"], 6 | transform: { 7 | "^.+\\.ts$": "ts-jest", 8 | }, 9 | verbose: true, 10 | setupFilesAfterEnv: ["jest-os-detection"], 11 | }; 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@listendev/action", 3 | "version": "0.19.0", 4 | "description": "Get real-time dependency insights in your pull requests", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "test": "jest", 8 | "format": "prettier --no-error-on-unmatched-pattern --config ./.prettierrc.js --write **/*.{ts,yml,yaml}", 9 | "format-check": "prettier --no-error-on-unmatched-pattern --config ./.prettierrc.js --check **/*.{ts,yml,yaml}", 10 | "lint": "eslint --config ./.eslintrc.js **/*.ts", 11 | "lint:fix": "eslint --config ./.eslintrc.js **/*.ts --fix", 12 | "build": "tsc && ncc build --source-map --license licenses.txt -o dist/ src/main.ts" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/listendev/action.git" 17 | }, 18 | "keywords": [ 19 | "actions", 20 | "github", 21 | "lstn", 22 | "listendev", 23 | "o11y", 24 | "security", 25 | "pullrequests", 26 | "annotations", 27 | "suggestions", 28 | "deps", 29 | "dependencies", 30 | "supply", 31 | "chain", 32 | "security" 33 | ], 34 | "private": true, 35 | "author": "The listen.dev team ", 36 | "license": "Apache-2.0", 37 | "bugs": { 38 | "url": "https://github.com/listendev/action/issues" 39 | }, 40 | "homepage": "https://github.com/listendev/action#readme", 41 | "dependencies": { 42 | "@actions/core": "^1.10.0", 43 | "@actions/exec": "^1.1.1", 44 | "@actions/http-client": "^2.1.0", 45 | "@actions/io": "^1.1.3", 46 | "@actions/tool-cache": "^2.0.1", 47 | "@octokit/rest": "^21.0.2", 48 | "axios": "^1.7.9", 49 | "semver": "^7.6.3", 50 | "superserial": "^0.3.5" 51 | }, 52 | "devDependencies": { 53 | "@types/jest": "^29.4.4", 54 | "@types/node": "^18.15.3", 55 | "@types/semver": "^7.3.13", 56 | "@typescript-eslint/eslint-plugin": "^5.55.0", 57 | "@typescript-eslint/parser": "^5.55.0", 58 | "@vercel/ncc": "^0.36.1", 59 | "eslint": "^8.36.0", 60 | "eslint-config-prettier": "^8.7.0", 61 | "eslint-plugin-jest": "^27.2.1", 62 | "eslint-plugin-node": "^11.1.0", 63 | "jest": "^29.5.0", 64 | "jest-os-detection": "^1.3.1", 65 | "prettier": "^2.8.5", 66 | "ts-jest": "^29.0.5", 67 | "typescript": "^4.9.5" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /reviewpad.yml: -------------------------------------------------------------------------------- 1 | extends: 2 | - https://github.com/listendev/.github/blob/main/reviewpad/common.yml 3 | 4 | # For more details see https://docs.reviewpad.com/guides/syntax#label. 5 | labels: 6 | "bump:major": 7 | description: Marks a pull request as introducing a breaking change 8 | color: "#fc0324" 9 | "bump:minor": 10 | description: Marks a pull request as introducing a minor change 11 | color: "#ae40b8" 12 | "bump:patch": 13 | description: Marks a pull request as introducing a patch 14 | color: "#ad8fb0" 15 | 16 | 17 | rules: 18 | - name: docs-changes 19 | spec: $hasFileExtensions([".md", ".txt"]) || $matchString("^docs(\([A-Za-z0-9_\/]+\))??:.+$", $title()) 20 | - name: ci-changes 21 | spec: $hasFilePattern(".github/**") || $hasFileName("reviewpad.yml") || $matchString("^ci(\([A-Za-z0-9_\/]+\))??:.+$", $title()) 22 | - name: deps-changes 23 | spec: $hasFileName("package.json") || $hasFileName("package-lock.json") || $matchString("^build\(deps\)\/.+", $title()) 24 | - name: feat-changes 25 | spec: $matchString("^feat(\([A-Za-z0-9_\/]+\))??:.+$", $title()) 26 | - name: fix-changes 27 | spec: $matchString("^fix(\([A-Za-z0-9_\/]+\))??:.+$", $title()) 28 | - name: breaking-changes 29 | spec: $matchString("^([A-Za-z0-9_]+)??(\([A-Za-z0-9_\/]+\))??!:.+$", $title()) 30 | - name: exclude-changes 31 | spec: $matchString("^(chore|refactor|revert|perf|test)(\([A-Za-z0-9_\/]+\))??:.+$", $title()) 32 | - name: by-bot 33 | spec: $matchString("^(dependabot|github-actions).*$", $author()) 34 | - name: build-changes 35 | spec: $hasFilePattern("make/**") || $matchString("^build(\([A-Za-z0-9_\/]+\))??:.+$", $title()) || $matchString("^build\/.+", $head()) 36 | - name: test-changes 37 | spec: $hasFilePattern("__tests__/**") || $hasFileName(".github/workflows/test.yaml") 38 | 39 | 40 | groups: 41 | - name: ignore-patterns 42 | spec: '["package-lock.json", "dist/**"]' 43 | 44 | # For more details see https://docs.reviewpad.com/guides/syntax#workflow. 45 | workflows: 46 | # This workflow labels pull requests based on the pull request change type. 47 | # This helps pick pull requests based on their change type. 48 | - name: pulls-labelling 49 | description: Label pull requests 50 | always-run: true 51 | if: 52 | - rule: feat-changes 53 | extra-actions: 54 | - $addLabel("enhancement") 55 | - $addLabel("bump:minor") 56 | - $removeLabel("bump:patch") 57 | - rule: docs-changes 58 | extra-actions: 59 | - $addLabel("documentation") 60 | - $addLabel("bump:patch") 61 | - rule: ci-changes 62 | extra-actions: 63 | - $addLabel("ci") 64 | - $addLabel("bump:patch") 65 | - rule: deps-changes 66 | extra-actions: 67 | - $addLabel("dependencies") 68 | - $addLabel("bump:patch") 69 | - rule: test-changes 70 | extra-actions: 71 | - $addLabel("test") 72 | - $addLabel("bump:patch") 73 | - rule: build-changes 74 | extra-actions: 75 | - $addLabel("build") 76 | - $addLabel("bump:patch") 77 | - rule: fix-changes 78 | extra-actions: 79 | - $addLabel("bug") 80 | - $addLabel("bump:patch") 81 | - rule: breaking-changes 82 | extra-actions: 83 | - $addLabel("breaking-change") 84 | - $addLabel("bump:major") 85 | - $removeLabels("bump:minor", "bump:patch") 86 | - rule: exclude-changes 87 | extra-actions: 88 | - $addLabel("no-releasenotes") 89 | - $removeLabels("bump:major", "bump:minor", "bump:patch") 90 | - rule: by-bot 91 | extra-actions: 92 | - $addLabel("no-releasenotes") 93 | - $removeLabels("bump:major", "bump:minor", "bump:patch") 94 | - rule: $isWaitingForReview() 95 | extra-actions: 96 | - $addLabel("needs-review") 97 | - rule: $isWaitingForReview() == false 98 | extra-actions: 99 | - $removeLabel("needs-review") 100 | -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core'; 2 | 3 | /** 4 | * EavesdropMustRunAlone is true when the eavesdrop tool is the only one that must run. 5 | */ 6 | export const EavesdropMustRunAlone: boolean = 7 | core.getInput('runtime') == 'only'; 8 | 9 | /** 10 | * EavesdropMustRun is true when the eavesdrop tool will run, either alone or together with other tools. 11 | */ 12 | export const EavesdropMustRun: boolean = 13 | core.getInput('runtime') == 'true' || EavesdropMustRunAlone; 14 | -------------------------------------------------------------------------------- /src/eavesdrop.ts: -------------------------------------------------------------------------------- 1 | import * as semver from 'semver'; 2 | import * as core from '@actions/core'; 3 | import * as exec from '@actions/exec'; 4 | import {daemonsReload} from './systemctl'; 5 | import {checkPath} from './utils'; 6 | import {Writable} from 'stream'; 7 | import {getArch, getPlat, tagToVersion} from './install'; 8 | import * as tc from '@actions/tool-cache'; 9 | import * as path from 'path'; 10 | import * as io from '@actions/io'; 11 | import * as fs from 'fs'; 12 | import * as state from './state'; 13 | import {Serializer, toSerialize, toDeserialize} from 'superserial'; 14 | import {EavesdropMustRun} from './constants'; 15 | 16 | const STATE_ID = 'eavesdrop_instance'; 17 | 18 | export class Tool { 19 | private lstn: string; 20 | private version: string; 21 | private name: string; 22 | private cliEnablingCommand: string[]; 23 | private installed = false; 24 | 25 | // tagMap maps the lstn tags to the eavesdrop tool versions. 26 | public static tagMap: Record = { 27 | 'v0.20.0': 'v1.9', 28 | 'v0.19.0': 'v1.5', 29 | 'v0.18.0': 'v1.2', 30 | 'v0.17.0': 'v1.1', 31 | 'v0.16.0': 'v1.0', 32 | 'v0.15.0': 'v0.6', 33 | 'v0.14.0': 'v0.4', 34 | 'v0.13.2': 'v0.3', 35 | 'v0.13.1': 'v0.1', 36 | 'v0.13.0': 'v0.1' 37 | } as const; 38 | 39 | serialize() { 40 | return s.serialize(this); 41 | } 42 | 43 | [toSerialize]() { 44 | return { 45 | lstn: this.lstn, 46 | version: this.version, 47 | name: this.name, 48 | cliEnablingCommand: this.cliEnablingCommand, 49 | installed: this.installed 50 | }; 51 | } 52 | 53 | [toDeserialize](value: { 54 | lstn: string; 55 | version: string; 56 | name: string; 57 | cliEnablingCommand: string[]; 58 | installed: boolean; 59 | }) { 60 | this.lstn = value.lstn; 61 | this.version = value.version; 62 | this.name = value.name; 63 | this.cliEnablingCommand = value.cliEnablingCommand; 64 | this.installed = value.installed; 65 | } 66 | 67 | private initCliVersion(): string { 68 | const versions = Object.keys(Tool.tagMap); 69 | const v = core.getInput('lstn'); 70 | if (v === 'dev') { 71 | return 'dev'; 72 | } 73 | 74 | const tag = v == 'latest' ? versions[0] : core.getInput('lstn'); 75 | const version = semver.coerce(tag); 76 | if (!version || !semver.valid(version)) { 77 | throw new Error(`invalid lstn version (${tag})`); 78 | } 79 | 80 | if (!versions.includes(tag.startsWith('v') ? tag : `v${tag}`)) { 81 | throw new Error(`unsupported lstn version (${tag})`); 82 | } 83 | 84 | return version.format(); 85 | } 86 | 87 | private initVersion(): string { 88 | if (!EavesdropMustRun) return ''; 89 | 90 | const explicit = core.getInput('eavesdrop_version'); 91 | if (!explicit) { 92 | if (this.lstn === 'dev') { 93 | // if we are using dev CLI we can use the nightly version of the eavesdrop tool 94 | return 'v0.0.0'; 95 | } 96 | 97 | return Tool.tagMap[ 98 | this.lstn.startsWith('v') ? this.lstn : `v${this.lstn}` 99 | ]; 100 | } 101 | const v = explicit.startsWith('v') ? explicit : `v${explicit}`; 102 | 103 | const custom = semver.coerce(v); 104 | if (!custom || !semver.valid(custom)) { 105 | throw new Error(`invalid custom eavesdrop tool version (${custom})`); 106 | } 107 | 108 | if ( 109 | !semver.eq(custom, 'v0.0.0') && 110 | !Object.values(Tool.tagMap).includes(v) 111 | ) { 112 | throw new Error(`unsupported custom eavesdrop tool version (${v})`); 113 | } 114 | 115 | if (this.lstn === 'dev') { 116 | // skip check with dev lstn CLI 117 | return custom.format(); 118 | } 119 | 120 | const lstnv = semver.coerce(this.lstn); 121 | if (!lstnv || !semver.valid(lstnv)) { 122 | throw new Error(`invalid lstn version (${this.lstn})`); 123 | } 124 | 125 | // Check that the explicit version is compatible with the current lstn version 126 | if (!semver.eq(custom, 'v0.0.0')) { 127 | if (semver.gte(lstnv, 'v0.16.0')) { 128 | // At least lstn v0.16.0 for eavesdrop tool versions >= v0.8 129 | if (semver.lt(custom, 'v0.8.0')) { 130 | throw new Error( 131 | `custom eavesdrop tool version (${v}) cannot work with lstn versions >= v0.16.0` 132 | ); 133 | } 134 | } else { 135 | // Max lstn v0.15.0 for custom eavesdrop versions up to v0.6 136 | if (semver.gte(custom, 'v0.8.0')) { 137 | throw new Error( 138 | `custom eavesdrop tool version (${v}) cannot work with lstn versions < v0.16.0` 139 | ); 140 | } 141 | } 142 | } else { 143 | // Nightly (v0.0) only works with lstn >= v0.16.0 144 | if (semver.lt(lstnv, 'v0.16.0')) { 145 | throw new Error( 146 | `nightly eavesdrop tool version (${v}) cannot work with lstn versions < v0.16.0` 147 | ); 148 | } 149 | } 150 | 151 | const res = custom.format(); 152 | 153 | return res.startsWith('v') ? res : `v${res}`; 154 | } 155 | 156 | private initName(): string { 157 | if (!EavesdropMustRun) return ''; 158 | 159 | const version = semver.coerce(this.version); 160 | if (!version || !semver.valid(version)) { 161 | throw new Error(`invalid eavesdrop tool version (${this.version})`); 162 | } 163 | 164 | // Switch to jibril from v0.8 onwards 165 | // Also, use jibril nightly for v0.0 166 | if (semver.eq(version, 'v0.0.0') || semver.gte(version, 'v0.8.0')) { 167 | return 'jibril'; 168 | } 169 | 170 | return 'argus'; 171 | } 172 | 173 | private initCliEnablingCommand(): string[] { 174 | if (!EavesdropMustRun) return []; 175 | 176 | if (this.lstn === 'dev') { 177 | // skip check with dev lstn CLI 178 | return ['ci', 'enable']; 179 | } 180 | 181 | const lstnv = semver.coerce(this.lstn); 182 | if (!lstnv || !semver.valid(lstnv)) { 183 | throw new Error(`invalid lstn version (${this.lstn})`); 184 | } 185 | 186 | // Switch to `ci enable` from lstn v0.16.0 onwards 187 | if (semver.gte(lstnv, 'v0.16.0')) { 188 | return ['ci', 'enable']; 189 | } 190 | 191 | return ['ci']; 192 | } 193 | 194 | private async getEnvironmentFile() { 195 | const environmentFile = `/var/run/${this.name}/default`; 196 | const res = await checkPath(environmentFile, true); 197 | if (!res.exists) { 198 | return {exists: false, content: ''}; 199 | } 200 | 201 | if (!res.isFile) { 202 | return {exists: false, content: ''}; 203 | } 204 | 205 | let file = ''; 206 | const options: exec.ExecOptions = { 207 | // Redirect stdout to the writable stream 208 | outStream: new Writable({ 209 | write(chunk, encoding, callback) { 210 | file += chunk.toString(); 211 | callback(); 212 | } 213 | }) 214 | }; 215 | try { 216 | await exec.exec('sudo', ['cat', environmentFile], options); 217 | } catch (error) { 218 | return {exists: true, content: ''}; 219 | } 220 | 221 | return {exists: true, content: file}; 222 | } 223 | 224 | private async download(directory: string) { 225 | // The eavesdrop tool only runs on linux amd64 226 | const plat = getPlat(process.platform.toString()); 227 | switch (plat) { 228 | case 'linux': 229 | break; 230 | default: 231 | throw new Error(`unsupported platform: ${plat}`); 232 | } 233 | const arch = getArch(process.arch.toString()); 234 | switch (arch) { 235 | case 'amd64': 236 | break; 237 | default: 238 | throw new Error(`unsupported arch: ${arch}`); 239 | } 240 | 241 | const tag = semver.coerce(this.version); 242 | if (!tag || !semver.valid(tag)) { 243 | throw new Error(`invalid eavesdrop version to download (${tag})`); 244 | } 245 | 246 | const owner = 'listendev'; 247 | const repo = `${this.name}-releases`; 248 | const vers = await tagToVersion( 249 | `v${semver.major(tag)}.${semver.minor(tag)}`, 250 | owner, 251 | repo 252 | ); 253 | const url = `https://github.com/${owner}/${repo}/releases/download/v${vers}/loader`; 254 | 255 | core.info(`downloading from ${url}`); 256 | 257 | const download = await tc.downloadTool(url); 258 | 259 | core.info(`preparing binary...`); 260 | 261 | const dest = path.join(directory, this.name); 262 | await io.mv(download, dest); 263 | fs.chmodSync(dest, 0o755); 264 | 265 | return dest; 266 | } 267 | 268 | constructor() { 269 | this.lstn = this.initCliVersion(); 270 | core.info(`lstn version: ${this.lstn}`); 271 | 272 | this.version = this.initVersion(); 273 | core.info(`eavesdrop version: ${this.version}`); 274 | 275 | this.name = this.initName(); 276 | core.info(`eavesdrop name: ${this.name}`); 277 | 278 | this.cliEnablingCommand = this.initCliEnablingCommand(); 279 | } 280 | 281 | public getVersion(): string { 282 | return this.version; 283 | } 284 | 285 | public getName(): string { 286 | return this.name; 287 | } 288 | 289 | public getCliEnablingCommand(): string[] { 290 | return this.cliEnablingCommand; 291 | } 292 | 293 | public isInstalled(): boolean { 294 | return this.installed; 295 | } 296 | 297 | public async install(tmpdir: string, into = '/usr/bin/') { 298 | if (!EavesdropMustRun) { 299 | return ''; 300 | } 301 | 302 | return await core.group( 303 | `👁️‍🗨️ Installing ${this.name}... https://listen.dev`, 304 | async () => { 305 | // Install the eavesdrop tool for lstn 306 | const location = await this.download(tmpdir); 307 | // Moving the eavesdrop tool binary to /usr/bin 308 | const dest = `${into}${this.name}`; 309 | core.info(`moving ${this.name} to ${path.dirname(dest)}`); 310 | const code = await exec.exec('sudo', ['mv', location, dest]); 311 | if (code !== 0) { 312 | throw new Error( 313 | `couldn't move ${this.name} to ${path.dirname(dest)}` 314 | ); 315 | } 316 | this.installed = true; 317 | store(this); 318 | 319 | return dest; 320 | } 321 | ); 322 | } 323 | 324 | public async isActive() { 325 | if (!EavesdropMustRun || !this.installed) { 326 | return false; 327 | } 328 | 329 | const res = await core.group( 330 | 'Check whether the CI eavesdrop tool is active', 331 | async (): Promise => { 332 | return await exec.exec('sudo', ['systemctl', 'is-active', this.name], { 333 | ignoreReturnCode: true 334 | }); 335 | } 336 | ); 337 | 338 | return res === 0; 339 | } 340 | 341 | private async needsRealod() { 342 | return await core.group( 343 | 'Check whether the CI eavesdrop tool needs reload', 344 | async (): Promise => { 345 | const opts: exec.ExecOptions = { 346 | ignoreReturnCode: true 347 | }; 348 | 349 | const {stderr, stdout, exitCode} = await exec.getExecOutput( 350 | 'sudo', 351 | ['systemctl', 'show', this.name, '--property=NeedDaemonReload'], 352 | opts 353 | ); 354 | 355 | if (exitCode !== 0) { 356 | core.warning(stderr); 357 | 358 | return false; 359 | } 360 | 361 | return stdout.trim().endsWith('=yes'); 362 | } 363 | ); 364 | } 365 | 366 | public async stop() { 367 | if (!EavesdropMustRun || !this.installed) { 368 | return 0; // Nothing to stop 369 | } 370 | 371 | const needsReload = await this.needsRealod(); 372 | if (needsReload) { 373 | await daemonsReload(); 374 | } 375 | 376 | return await core.group( 377 | 'Stopping the CI eavesdrop tool', 378 | async (): Promise => { 379 | return await exec.exec('sudo', ['systemctl', 'stop', this.name]); 380 | } 381 | ); 382 | } 383 | 384 | public async classifyEnvironmentFile() { 385 | if (!EavesdropMustRun || !this.installed) { 386 | return true; 387 | } 388 | 389 | const {exists, content} = await this.getEnvironmentFile(); 390 | if (!exists) { 391 | return false; 392 | } 393 | if (content.length == 0) { 394 | return false; 395 | } 396 | const lines = content.split('\n'); 397 | 398 | const secrets = new Set(['OPENAI_TOKEN']); 399 | 400 | for (const line of lines) { 401 | const l = line.trim(); 402 | if (!l || l.startsWith('#')) continue; 403 | 404 | const match = l.match(/^([a-zA-Z_][a-zA-Z0-9_]*)=(.*)$/); 405 | if (match) { 406 | const name = match[1].trim(); 407 | let value = match[2].trim(); 408 | 409 | // Handle quoted values 410 | if (value.startsWith('"') && value.endsWith('"')) { 411 | // Remove quotes and handle escaped quotes 412 | value = value.slice(1, -1).replace(/\\"/g, '"'); 413 | } else if (value.startsWith("'") && value.endsWith("'")) { 414 | // Remove quotes and handle escaped quotes 415 | value = value.slice(1, -1).replace(/\\'/g, "'"); 416 | } 417 | 418 | if (secrets.has(name)) { 419 | core.setSecret(value); 420 | } 421 | } 422 | } 423 | 424 | return true; 425 | } 426 | } 427 | 428 | const s = new Serializer({classes: {Tool}}); 429 | 430 | function deserialize(data: string): Tool { 431 | return s.deserialize(data); 432 | } 433 | 434 | function store(instance: Tool) { 435 | core.saveState(STATE_ID, instance.serialize()); 436 | } 437 | 438 | export function get(): Tool { 439 | if (!state.IsPost) { 440 | try { 441 | const i = new Tool(); 442 | store(i); 443 | 444 | return i; 445 | } catch (error: any) { 446 | core.setFailed(`Could not instantiate the eavesdrop tool.`); 447 | throw error; 448 | } 449 | } 450 | 451 | try { 452 | return deserialize(core.getState(STATE_ID)); 453 | } catch (error: any) { 454 | throw new Error(`Could not deserialize the eavesdrop tool instance.`); 455 | } 456 | } 457 | -------------------------------------------------------------------------------- /src/flags.ts: -------------------------------------------------------------------------------- 1 | export function parse(flags: string): string[] { 2 | flags = flags.trim(); 3 | // (?= # Beginning of a positive lookahead 4 | // ( # Beginning of the first capturing group 5 | // -(?:-\w+|\w)(?:=| ) # Matches a flag name (a dash followed by a single char or two dashes follower by a word) followed by an equal sign or a space 6 | // ) # End of the first capturing group 7 | // ) # End of the positive lookahead 8 | // \1 # Backreference to the first capturing group to match the flag name followed by an equal sign or by a space 9 | // | # Or 10 | // "" # Matches an empty double quote 11 | // | # Or 12 | // '' # Matches an empty single quote 13 | // | # Or 14 | // (["']) # A capturing group (the second one) matching the opening quote (either both or single) 15 | // [^]* # Matches any character (including newlines) or or more times 16 | // [^\\] # Matches the last character preceeding the ending quote that is not a backslash 17 | // (?:\\\\)* # Matches only if the number of backslashes is a multiple of 2 (including zero) so that escaped backslashes are not counted 18 | // \2 # Backreference to match the same opening quote 19 | // | # Or 20 | // [^ "']+ # Matches any character without quotes or spaces one or more times (flag values without quotes) 21 | const parts = flags 22 | .match( 23 | /(?=(-(?:-\w+|\w)(?:=| )))\1|""|''|(["'])[^]*?[^\\](?:\\\\)*\2|[^ "']+/g 24 | ) 25 | // Removing matching quotes 26 | ?.map(arg => arg.replace(/^"(.*)"$/, '$1')) 27 | ?.map(arg => arg.replace(/^'(.*)'$/, '$1')) 28 | // Removing trailing equal sign or trailing space from parts starting with a dash 29 | ?.map(arg => arg.replace(/^-(.*)(=| )$/, '-$1')); 30 | 31 | return parts || []; 32 | } 33 | -------------------------------------------------------------------------------- /src/install.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core'; 2 | import * as http from '@actions/http-client'; 3 | 4 | // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires 5 | const packageJSON = require('../package.json'); 6 | 7 | export function getPlat(os: string): string { 8 | os = os.trim().toLowerCase(); 9 | 10 | if ( 11 | os.startsWith('win') || 12 | os.startsWith('cygwin') || 13 | os.startsWith('mingw') || 14 | os.startsWith('msys') 15 | ) { 16 | os = 'windows'; 17 | } 18 | 19 | if (os.startsWith('darwin')) { 20 | os = 'macos'; 21 | } 22 | 23 | switch (os) { 24 | case 'macos': 25 | break; 26 | case 'linux': 27 | break; 28 | default: 29 | throw new Error(`unsupported platform: ${os}`); 30 | } 31 | 32 | return os; 33 | } 34 | 35 | export function getArch(arch: string): string { 36 | arch = arch.trim().toLowerCase(); 37 | 38 | switch (arch) { 39 | case 'x64': 40 | arch = 'amd64'; 41 | break; 42 | case 'x32': 43 | arch = '386'; 44 | break; 45 | case 'arm64': 46 | break; 47 | case 'armv6': 48 | break; 49 | default: 50 | throw new Error(`unsupported arch: ${arch}`); 51 | } 52 | 53 | return arch; 54 | } 55 | 56 | export function getFormat(platform: string): string { 57 | if (platform == 'windows') { 58 | return 'zip'; 59 | } 60 | return 'tar.gz'; 61 | } 62 | 63 | export async function tagToVersion( 64 | tag: string, 65 | owner: string, 66 | repo: string 67 | ): Promise { 68 | core.info(`looking for ${repo}/${tag}`); 69 | 70 | interface Release { 71 | tag_name: string; 72 | } 73 | 74 | const version = 75 | process.env.npm_package_version || packageJSON.version || 'unknown'; 76 | const ua = `listendev-action/${version}; ${repo}/${tag}`; 77 | const url = `https://github.com/${owner}/${repo}/releases/${tag}`; 78 | const client = new http.HttpClient(ua); 79 | const headers = {[http.Headers.Accept]: 'application/json'}; 80 | const response = await client.getJson(url, headers); 81 | 82 | core.info(`looking for release ${url}`); 83 | core.info(`using user agent "${ua}"`); 84 | 85 | if (response.statusCode != http.HttpCodes.OK) { 86 | core.error( 87 | `${url} returns unexpected HTTP status code: ${response.statusCode}` 88 | ); 89 | } 90 | if (!response.result) { 91 | throw new Error( 92 | `unable to find '${tag}': use 'latest' or see https://github.com/${owner}/${repo}/releases for details` 93 | ); 94 | } 95 | let realTag = response.result.tag_name; 96 | 97 | // if version starts with 'v', remove it 98 | realTag = realTag.replace(/^v/, ''); 99 | 100 | return realTag; 101 | } 102 | -------------------------------------------------------------------------------- /src/lstn.ts: -------------------------------------------------------------------------------- 1 | import {Serializer, toSerialize, toDeserialize} from 'superserial'; 2 | import * as state from './state'; 3 | import * as core from '@actions/core'; 4 | import {EavesdropMustRun, EavesdropMustRunAlone} from './constants'; 5 | import {getArch, getFormat, getPlat, tagToVersion} from './install'; 6 | import * as tc from '@actions/tool-cache'; 7 | import * as path from 'path'; 8 | import * as exec from '@actions/exec'; 9 | import * as flags from './flags'; 10 | import {Tool as Eavesdrop} from './eavesdrop'; 11 | import * as semver from 'semver'; 12 | import axios, {AxiosResponse} from 'axios'; 13 | import {Octokit} from '@octokit/rest'; 14 | import fs from 'fs'; 15 | 16 | const STATE_ID = 'lstn'; 17 | 18 | export class Tool { 19 | private version: string; 20 | private jwt: string; 21 | private path = ''; 22 | private command: string; 23 | private args: string[]; 24 | private cwd: string; 25 | private extraFlags: string[]; 26 | 27 | serialize() { 28 | return s.serialize(this); 29 | } 30 | 31 | [toSerialize]() { 32 | return { 33 | version: this.version, 34 | jwt: this.jwt, 35 | path: this.path, 36 | command: this.command, 37 | args: this.args, 38 | cwd: this.cwd, 39 | extraFlags: this.extraFlags 40 | }; 41 | } 42 | 43 | [toDeserialize](value: { 44 | version: string; 45 | jwt: string; 46 | path: string; 47 | command: string; 48 | args: string[]; 49 | cwd: string; 50 | extraFlags: string[]; 51 | }) { 52 | this.version = value.version; 53 | this.jwt = value.jwt; 54 | this.path = value.path; 55 | this.command = value.command; 56 | this.args = value.args; 57 | this.cwd = value.cwd; 58 | this.extraFlags = value.extraFlags; 59 | } 60 | 61 | constructor() { 62 | const versions = Object.keys(Eavesdrop.tagMap); 63 | const v = core.getInput('lstn'); 64 | this.version = v == 'latest' ? versions[0] : v; 65 | 66 | this.jwt = core.getInput('jwt', {required: EavesdropMustRun}); 67 | 68 | this.command = this.jwt !== '' ? 'in' : 'scan'; 69 | 70 | const reporter = core.getInput('reporter'); 71 | const select = core.getInput('select'); 72 | this.args = ['--reporter', `${this.jwt != '' ? 'pro' : reporter}`]; // There's always a reporter (default) 73 | if (select != '') { 74 | this.args.push(...['--select', `${select}`]); 75 | } 76 | 77 | this.cwd = path.relative( 78 | process.env['GITHUB_WORKSPACE'] || process.cwd(), 79 | core.getInput('workdir') 80 | ); 81 | 82 | // The `lstn_flags` option is only meant for expert users and tests. 83 | this.extraFlags = flags.parse(core.getInput('lstn_flags')); 84 | } 85 | 86 | public setConfig(file: string) { 87 | this.args.push(...['--config', file]); 88 | store(this); 89 | } 90 | 91 | public isInstalled(): boolean { 92 | return this.path !== ''; 93 | } 94 | 95 | public getVersion(): string { 96 | return this.version; 97 | } 98 | 99 | // It returns the URL to download the LSTN CLI based on the parameter value `lstn`. 100 | // In `dev` mode it will pick the latest release from the `listendev/lstn-dev` repository. 101 | // Otherwise, it will use the public CLI from the `listendev/lstn` repository. 102 | private async buildURL() { 103 | const v = core.getInput('lstn'); 104 | if (v == 'dev') { 105 | return 'https://github.com/listendev/lstn-dev/releases/download/v0.0.0/lstn_0.0.0_linux_amd64.tar.gz'; 106 | } 107 | 108 | const owner = 'listendev'; 109 | const repo = 'lstn'; 110 | const vers = await tagToVersion(this.version, owner, repo); 111 | const plat = getPlat(process.platform.toString()); 112 | const arch = getArch(process.arch.toString()); 113 | const archive = getFormat(plat); 114 | const name = `lstn_${vers}_${plat}_${arch}`; 115 | const url = `https://github.com/${owner}/${repo}/releases/download/v${vers}/${name}.${archive}`; 116 | 117 | return url; 118 | } 119 | 120 | public async install(tmpdir: string) { 121 | const where = await core.group( 122 | '🐬 Installing lstn... https://github.com/listendev/lstn', 123 | async () => { 124 | const v = core.getInput('lstn'); 125 | core.info(`Installing version ${v}...`); 126 | const repo = 'lstn'; 127 | const owner = 'listendev'; 128 | const vers = 129 | v === 'dev' ? '0.0.0' : await tagToVersion(this.version, owner, repo); 130 | 131 | const plat = getPlat(process.platform.toString()); 132 | const arch = getArch(process.arch.toString()); 133 | const archive = getFormat(plat); 134 | 135 | const url = await this.buildURL(); 136 | core.info(`Downloading from ${url}`); 137 | 138 | let download = ''; 139 | 140 | if (v === 'dev') { 141 | const token = process.env['pat_pvt_repo']; 142 | if (!token) { 143 | core.warning('Missing private repo PAT'); 144 | } 145 | 146 | const octokit = new Octokit({ 147 | auth: token 148 | }); 149 | 150 | try { 151 | // Request list of assets for release v0.0.0 152 | const res = await octokit.rest.repos.getReleaseByTag({ 153 | owner: 'listendev', 154 | repo: 'lstn-dev', 155 | tag: 'v0.0.0' 156 | }); 157 | 158 | // Find asset id for lstn_0.0.0_linux_amd64.tar.gz 159 | let asset_id = 0; 160 | const name = 'lstn_0.0.0_linux_amd64.tar.gz'; 161 | for (const asset of res.data.assets) { 162 | if (asset.name === name) { 163 | asset_id = asset.id; 164 | break; 165 | } 166 | } 167 | 168 | if (asset_id === 0) { 169 | core.warning( 170 | 'Could not find asset id for lstn_0.0.0_linux_amd64.tar.gz' 171 | ); 172 | 173 | throw new Error( 174 | 'Could not find asset id for lstn_0.0.0_linux_amd64.tar.gz' 175 | ); 176 | } 177 | 178 | // Find URL to download asset 179 | const resp = await octokit.rest.repos.getReleaseAsset({ 180 | owner: 'listendev', 181 | repo: 'lstn-dev', 182 | asset_id: asset_id, 183 | headers: { 184 | Accept: 'application/octet-stream' 185 | } 186 | }); 187 | 188 | // Start downloading the asset (wrap in Promise) 189 | const downloadUrl = resp.url; 190 | const filePath = path.resolve(__dirname, name); 191 | const writer = fs.createWriteStream(filePath); 192 | 193 | download = await new Promise((resolve, reject) => { 194 | // Use axios to download the file 195 | axios({ 196 | method: 'get', 197 | url: downloadUrl, 198 | responseType: 'stream' 199 | }) 200 | .then((downloadResponse: AxiosResponse) => { 201 | downloadResponse.data.pipe(writer); 202 | 203 | writer.on('finish', () => { 204 | core.info(`Download completed: ${filePath}`); 205 | resolve(filePath); // Resolve the Promise when the download is complete 206 | }); 207 | 208 | writer.on('error', (e: any) => { 209 | core.warning('Error downloading file:', e); 210 | reject(e); // Reject the Promise if there's an error 211 | }); 212 | }) 213 | .catch((error: any) => { 214 | core.warning('Error downloading file with axios:', error); 215 | reject(error); // Reject if axios request fails 216 | }); 217 | }); 218 | } catch { 219 | core.error('Error downloading file'); 220 | throw new Error('Error downloading file'); 221 | } 222 | } else { 223 | try { 224 | download = await tc.downloadTool(url); 225 | core.info(`Download completed: ${download}`); 226 | } catch (error) { 227 | core.error(`Error downloading file: ${error}`); 228 | throw error; 229 | } 230 | } 231 | 232 | core.info(`Extracting ${download}...`); 233 | 234 | let res = ''; 235 | try { 236 | if (archive === 'zip') { 237 | res = await tc.extractZip(download, tmpdir); 238 | } else { 239 | res = await tc.extractTar(download, tmpdir); 240 | } 241 | } catch (error) { 242 | core.error(`Error extracting archive: ${error}`); 243 | throw error; 244 | } 245 | 246 | const name = `lstn_${vers}_${plat}_${arch}`; 247 | const extractedPath = path.join( 248 | res, 249 | name, 250 | `lstn${archive === 'zip' ? '.exe' : ''}` 251 | ); 252 | return extractedPath; 253 | } 254 | ); 255 | 256 | this.path = where; 257 | store(this); 258 | 259 | return where; 260 | } 261 | 262 | public async exec() { 263 | if (EavesdropMustRunAlone || !this.isInstalled()) { 264 | return 0; 265 | } 266 | 267 | this.setEnv(); 268 | 269 | return await exec.exec( 270 | this.path, 271 | [this.command, ...this.args, ...this.extraFlags], 272 | { 273 | cwd: this.cwd 274 | // TODO: ignoreReturnCode 275 | // TODO: outStream 276 | } 277 | ); 278 | } 279 | 280 | public async report() { 281 | if (!EavesdropMustRun) { 282 | return 0; 283 | } 284 | 285 | if (!this.isInstalled()) { 286 | core.warning('missing lstn CLI installation'); 287 | return 0; 288 | } 289 | 290 | // Check CLI version >= 0.16.0 291 | const version = semver.coerce(this.version); 292 | if (this.version !== 'dev') { 293 | if (!version || !semver.valid(version)) { 294 | throw new Error(`invalid lstn version (${this.version})`); 295 | } 296 | if (semver.lt(version, 'v0.16.0')) { 297 | core.warning( 298 | `Coulnd't report because lstn ${this.version} lacks this ability` 299 | ); 300 | return 0; 301 | } 302 | } 303 | 304 | this.setEnv(); 305 | 306 | const res = await core.group( 307 | 'Report runtime threats if possible', 308 | async (): Promise => { 309 | return await exec.exec(this.path, ['ci', 'report']); 310 | } 311 | ); 312 | 313 | return res; 314 | } 315 | 316 | public async eavesdrop(eavesdrop: Eavesdrop) { 317 | if (!EavesdropMustRun) { 318 | return 0; 319 | } 320 | 321 | if (!this.isInstalled()) { 322 | core.warning('missing lstn CLI installation'); 323 | return 0; 324 | } 325 | 326 | this.setEnv(); 327 | 328 | const exit = await exec.exec('sudo', [ 329 | '-E', 330 | this.path, 331 | ...eavesdrop.getCliEnablingCommand(), 332 | ...this.extraFlags 333 | ]); 334 | 335 | if (exit === 0) { 336 | const didClassify = await eavesdrop.classifyEnvironmentFile(); 337 | if (!didClassify) { 338 | core.warning( 339 | "couldn't classify the CI eavesdrop configuration variables" 340 | ); 341 | } 342 | } 343 | 344 | return exit; 345 | } 346 | 347 | private setEnv() { 348 | // Pass tokens down 349 | process.env['LSTN_GH_TOKEN'] = core.getInput('token'); 350 | process.env['LSTN_JWT_TOKEN'] = this.jwt; 351 | // Ensure $PATH contains /usr/bin 352 | process.env['PATH'] = !process.env['PATH'] 353 | ? '/usr/bin' 354 | : `${process.env['PATH']}:/usr/bin`; 355 | } 356 | } 357 | 358 | const s = new Serializer({classes: {Tool}}); 359 | 360 | function deserialize(data: string): Tool { 361 | return s.deserialize(data); 362 | } 363 | 364 | function store(instance: Tool) { 365 | core.saveState(STATE_ID, instance.serialize()); 366 | } 367 | 368 | export function get(): Tool { 369 | if (!state.IsPost) { 370 | try { 371 | const i = new Tool(); 372 | store(i); 373 | 374 | return i; 375 | } catch (error: any) { 376 | core.setFailed(`Could not instantiate the lstn tool.`); 377 | throw error; 378 | } 379 | } 380 | 381 | try { 382 | return deserialize(core.getState(STATE_ID)); 383 | } catch (error: any) { 384 | throw new Error(`Could not deserialize the lstn tool instance.`); 385 | } 386 | } 387 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core'; 2 | import * as utils from './utils'; 3 | import * as state from './state'; 4 | import * as eavesdropcli from './eavesdrop'; 5 | import * as lstncli from './lstn'; 6 | import {EavesdropMustRun, EavesdropMustRunAlone} from './constants'; 7 | import * as path from 'path'; 8 | import * as io from '@actions/io'; 9 | 10 | async function run() { 11 | const tmpdir = await state.tmpdir(); 12 | try { 13 | const lstn = lstncli.get(); 14 | await lstn.install(tmpdir); 15 | 16 | const eavesdrop = eavesdropcli.get(); 17 | await eavesdrop.install(tmpdir); 18 | 19 | // TODO: restore cache here 20 | 21 | // Handle lstn config 22 | const config = core.getInput('config'); 23 | if (config != '') { 24 | const res = await utils.checkPath(config); 25 | if (!res.exists) { 26 | core.setFailed(`${config} does not exists`); 27 | 28 | return; 29 | } 30 | if (res.isFile) { 31 | lstn.setConfig(config); 32 | } else { 33 | // The input config is a directory 34 | const defaultFile = path.join(config, '.lstn.yaml'); 35 | const fallback = await utils.checkPath(defaultFile); 36 | if (!fallback.exists) { 37 | core.setFailed(`${defaultFile} config file does not exists`); 38 | 39 | return; 40 | } 41 | // Assuming that defaultFile is a proper file now 42 | lstn.setConfig(defaultFile); 43 | } 44 | } 45 | 46 | const exit = await core.group( 47 | `🐬 Running lstn${EavesdropMustRun ? ' with CI eavesdropper' : '...'}${ 48 | EavesdropMustRunAlone ? ' only' : '' 49 | }`, 50 | async (): Promise => { 51 | // TODO: what to do when status code != 0 52 | let code = await lstn.eavesdrop(eavesdrop); 53 | code = await lstn.exec(); 54 | 55 | return code; 56 | } 57 | ); 58 | 59 | // TODO: save cache here 60 | 61 | if (exit !== 0) { 62 | core.setFailed(`status code: ${exit}`); 63 | } 64 | } catch (error: any) { 65 | core.setFailed(error); 66 | } 67 | } 68 | 69 | async function post() { 70 | const tmpdir = await state.tmpdir(); 71 | try { 72 | const eavesdrop = eavesdropcli.get(); 73 | const isActive = await eavesdrop.isActive(); 74 | if (!isActive) { 75 | core.info(`Moving on since the CI eavesdrop tool isn't active`); 76 | 77 | return; 78 | } 79 | 80 | const exit = await eavesdrop.stop(); 81 | if (exit !== 0) { 82 | core.warning(`Couldn't properly stop the CI eavesdrop tool`); 83 | } 84 | 85 | const lstn = lstncli.get(); 86 | const reportExitCode = await lstn.report(); 87 | if (reportExitCode !== 0) { 88 | core.warning(`Couldn't comment on the pull request`); 89 | } 90 | } catch (error: any) { 91 | core.setFailed(error); 92 | } finally { 93 | // Cleanup 94 | try { 95 | core.info('Cleaning up'); 96 | await io.rmRF(tmpdir); 97 | } catch (error) { 98 | // Suppress these errors 99 | if (error instanceof Error) { 100 | core.warning(`Couldn't clean up: ${error.message}`); 101 | } else { 102 | core.warning(`Couldn't clean up: ${error}`); 103 | } 104 | } 105 | } 106 | } 107 | 108 | if (!state.IsPost) { 109 | run(); 110 | } else { 111 | post(); 112 | } 113 | -------------------------------------------------------------------------------- /src/state.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core'; 2 | import * as os from 'os'; 3 | import {promises as fs} from 'fs'; 4 | import * as path from 'path'; 5 | 6 | /** 7 | * Indicates whether the POST action is running 8 | */ 9 | export const IsPost = !!core.getState('isPost'); 10 | 11 | // Publish a variable so that when the POST action runs, it can determine it should run the cleanup logic. 12 | // This is necessary since we don't have a separate entry point. 13 | if (!IsPost) { 14 | core.saveState('isPost', 'true'); 15 | } 16 | 17 | export async function tmpdir() { 18 | if (!IsPost) { 19 | const tmpdir = await fs.mkdtemp( 20 | path.join(process.env['RUNNER_TEMP'] || os.tmpdir(), 'lstn-') 21 | ); 22 | core.saveState('LSTN_ACTION_TMPDIR', tmpdir); 23 | 24 | return tmpdir; 25 | } 26 | 27 | return core.getState('LSTN_ACTION_TMPDIR'); 28 | } 29 | -------------------------------------------------------------------------------- /src/systemctl.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core'; 2 | import * as exec from '@actions/exec'; 3 | 4 | export async function daemonsReload() { 5 | return await core.group('Reload daemons', async (): Promise => { 6 | const opts: exec.ExecOptions = { 7 | ignoreReturnCode: true 8 | }; 9 | 10 | const {stderr, exitCode} = await exec.getExecOutput( 11 | 'sudo', 12 | ['systemctl', 'daemon-reload'], 13 | opts 14 | ); 15 | 16 | if (exitCode !== 0) { 17 | // Handle error case, you can log stderr or throw an error 18 | core.warning(stderr); 19 | } else { 20 | core.info('Successfull reload'); 21 | } 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import {PathLike, promises as fs} from 'fs'; 2 | import * as exec from '@actions/exec'; 3 | 4 | export async function checkPath(path: PathLike, withSudo = false) { 5 | try { 6 | if (withSudo) { 7 | let isFile = false; 8 | const opts: exec.ExecOptions = { 9 | silent: true, 10 | ignoreReturnCode: true, 11 | listeners: { 12 | stdout: (data: Buffer) => { 13 | const res = data.toString().trim(); 14 | isFile = res.startsWith('-') || res.includes('File:'); 15 | } 16 | } 17 | }; 18 | 19 | const exit = await exec.exec('sudo', ['stat', path.toString()], opts); 20 | if (exit !== 0) { 21 | return {exists: false}; 22 | } 23 | 24 | return {exists: true, isFile: isFile}; 25 | } else { 26 | const stats = await fs.stat(path); 27 | if (stats.isFile()) { 28 | return {exists: true, isFile: true}; 29 | } else if (stats.isDirectory()) { 30 | return {exists: true, isFile: false}; 31 | } else { 32 | // Handle other types (unlikely in most cases) 33 | return {exists: true, isFile: undefined}; 34 | } 35 | } 36 | } catch (error: any) { 37 | if (error.code === 'ENOENT') { 38 | return {exists: false}; 39 | } else if (error.code === 'EACCES') { 40 | return {exists: false}; 41 | } else { 42 | throw error; // Re-throw other errors 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2021", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ 4 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 5 | "outDir": "./lib", /* Redirect output structure to the directory. */ 6 | "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 7 | "strict": true, /* Enable all strict type-checking options. */ 8 | "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 9 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 10 | "resolveJsonModule": true, 11 | "moduleResolution": "node" 12 | }, 13 | "exclude": ["node_modules", "__tests__/*.test.ts", "lib"], 14 | "files": [ 15 | "node_modules/jest-os-detection/index.d.ts" 16 | ] 17 | } --------------------------------------------------------------------------------