From ea0121618bb39abc1cff180c258978a02d4e04fd Mon Sep 17 00:00:00 2001 From: Parker Brown <17183625+parkerbxyz@users.noreply.github.com> Date: Fri, 10 Apr 2026 23:01:59 -0700 Subject: [PATCH 01/29] ci: remove publish-immutable-action workflow (#361) The `publish-immutable-action` workflow uses `actions/publish-immutable-action@v0.0.4`. The Immutable Actions Publishing feature (OCI-based) has been paused with no GA timeline. This removes the workflow; it can be re-added when the feature becomes generally available. To fully address #352, the repository-level **immutable releases** setting has also be enabled. This [feature](https://github.blog/changelog/2025-10-28-immutable-releases-are-now-generally-available/) locks release tags and assets after publication, directly preventing the class of attack described in [GHSA-mrrh-fwg8-r2c3](https://github.com/advisories/GHSA-mrrh-fwg8-r2c3). The existing release workflow is compatible with immutable releases. Build artifacts are committed via `@semantic-release/git` before the tag is created, and major version tags (`v3`, etc.) are plain git tags (not releases) so they remain updatable. --- .github/workflows/publish-immutable-action.yml | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 .github/workflows/publish-immutable-action.yml diff --git a/.github/workflows/publish-immutable-action.yml b/.github/workflows/publish-immutable-action.yml deleted file mode 100644 index dd783deb..00000000 --- a/.github/workflows/publish-immutable-action.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: 'Publish Immutable Action' - -on: - release: - types: [published] - -jobs: - publish: - runs-on: ubuntu-latest - permissions: - contents: read - id-token: write - packages: write - steps: - - uses: actions/checkout@v6 - - name: Publish Immutable Action - uses: actions/publish-immutable-action@v0.0.4 From 07e2b760664f080c40eec4eacf7477256582db36 Mon Sep 17 00:00:00 2001 From: Parker Brown <17183625+parkerbxyz@users.noreply.github.com> Date: Fri, 10 Apr 2026 23:42:53 -0700 Subject: [PATCH 02/29] fix: improve error message when app identifier is empty (#362) When `client-id` (or the deprecated `app-id`) resolves to an empty string, for example because a secret or variable is not available in the workflow context, the error message from `@octokit/auth-app` is not very helpful: ``` [@octokit/auth-app] appId option is required ``` A validation check was added recently to catch this earlier, but its message could be more informative: ``` Either 'client-id' or 'app-id' input must be set ``` This updates the message to clarify that the value resolved to empty and nudges users toward checking their secret or variable availability: ``` The 'client-id' input must be set to a non-empty string. If using a secret or variable, ensure it is available in this workflow context. ``` Closes #249 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- dist/main.cjs | 2 +- main.js | 2 +- tests/index.js.snapshot | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/main.cjs b/dist/main.cjs index c7cf562d..b9dc6211 100644 --- a/dist/main.cjs +++ b/dist/main.cjs @@ -23352,7 +23352,7 @@ async function run() { ensureNativeProxySupport(); const clientId = getInput("client-id") || getInput("app-id"); if (!clientId) { - throw new Error("Either 'client-id' or 'app-id' input must be set"); + throw new Error("The 'client-id' (or deprecated 'app-id') input must be set to a non-empty string. If using a secret or variable, ensure it is available in this workflow context."); } const privateKey = getInput("private-key"); const owner = getInput("owner"); diff --git a/main.js b/main.js index b6851268..32696dda 100644 --- a/main.js +++ b/main.js @@ -20,7 +20,7 @@ async function run() { const clientId = core.getInput("client-id") || core.getInput("app-id"); if (!clientId) { - throw new Error("Either 'client-id' or 'app-id' input must be set"); + throw new Error("The 'client-id' (or deprecated 'app-id') input must be set to a non-empty string. If using a secret or variable, ensure it is available in this workflow context."); } const privateKey = core.getInput("private-key"); const owner = core.getInput("owner"); diff --git a/tests/index.js.snapshot b/tests/index.js.snapshot index d5d5f9b3..4789f44b 100644 --- a/tests/index.js.snapshot +++ b/tests/index.js.snapshot @@ -56,11 +56,11 @@ POST /api/v3/app/installations/123456/access_tokens `; exports[`main-missing-client-and-app-id.test.js > stderr 1`] = ` -Either 'client-id' or 'app-id' input must be set +The 'client-id' (or deprecated 'app-id') input must be set to a non-empty string. If using a secret or variable, ensure it is available in this workflow context. `; exports[`main-missing-client-and-app-id.test.js > stdout 1`] = ` -::error::Either 'client-id' or 'app-id' input must be set +::error::The 'client-id' (or deprecated 'app-id') input must be set to a non-empty string. If using a secret or variable, ensure it is available in this workflow context. `; exports[`main-missing-owner.test.js > stderr 1`] = ` From 1b10c78c7865c340bc4f6099eb2f838309f1e8c3 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 11 Apr 2026 06:43:26 +0000 Subject: [PATCH 03/29] build(release): 3.1.1 [skip ci] ## [3.1.1](https://github.com/actions/create-github-app-token/compare/v3.1.0...v3.1.1) (2026-04-11) ### Bug Fixes * improve error message when app identifier is empty ([#362](https://github.com/actions/create-github-app-token/issues/362)) ([07e2b76](https://github.com/actions/create-github-app-token/commit/07e2b760664f080c40eec4eacf7477256582db36)), closes [#249](https://github.com/actions/create-github-app-token/issues/249) --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index dddbca7f..e37edd3b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "create-github-app-token", - "version": "3.1.0", + "version": "3.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "create-github-app-token", - "version": "3.1.0", + "version": "3.1.1", "license": "MIT", "dependencies": { "@actions/core": "^3.0.0", diff --git a/package.json b/package.json index 4fb277f0..fbe04802 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "create-github-app-token", "private": true, "type": "module", - "version": "3.1.0", + "version": "3.1.1", "description": "GitHub Action for creating a GitHub App Installation Access Token", "engines": { "node": ">=24.4.0" From 7989d206df2ffdd9fc88b0eb6d2f0eebee835fd6 Mon Sep 17 00:00:00 2001 From: Josh Johanning Date: Tue, 21 Apr 2026 11:56:11 -0500 Subject: [PATCH 04/29] docs: use `APP_` prefix instead of reserved `GITHUB_` prefix (#363) Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- README.md | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index c75538ad..2073f975 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,10 @@ GitHub Action for creating a GitHub App installation access token. In order to use this action, you need to: 1. [Register new GitHub App](https://docs.github.com/apps/creating-github-apps/setting-up-a-github-app/creating-a-github-app). -2. [Store the App's Client ID in your repository environment variables](https://docs.github.com/actions/how-tos/write-workflows/choose-what-workflows-do/use-variables#defining-configuration-variables-for-multiple-workflows) (example: `GITHUB_APP_CLIENT_ID`). -3. [Store the App's private key in your repository secrets](https://docs.github.com/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets?tool=webui#creating-secrets-for-a-repository) (example: `GITHUB_APP_PRIVATE_KEY`). +2. [Store the App's Client ID in your repository variables](https://docs.github.com/actions/how-tos/write-workflows/choose-what-workflows-do/use-variables#defining-configuration-variables-for-multiple-workflows) (example: `APP_CLIENT_ID`). +3. [Store the App's private key in your repository secrets](https://docs.github.com/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets?tool=webui#creating-secrets-for-a-repository) (example: `APP_PRIVATE_KEY`). -> [!IMPORTANT] +> [!IMPORTANT] > An installation access token expires after 1 hour. Please [see this comment](https://github.com/actions/create-github-app-token/issues/121#issuecomment-2043214796) for alternative approaches if you have long-running processes. ### Create a token for the current repository @@ -31,8 +31,8 @@ jobs: - uses: actions/create-github-app-token@v3 id: app-token with: - client-id: ${{ vars.GITHUB_APP_CLIENT_ID }} - private-key: ${{ secrets.GITHUB_APP_PRIVATE_KEY }} + client-id: ${{ vars.APP_CLIENT_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} - uses: ./actions/staging-tests with: token: ${{ steps.app-token.outputs.token }} @@ -51,8 +51,8 @@ jobs: id: app-token with: # required - client-id: ${{ vars.GITHUB_APP_CLIENT_ID }} - private-key: ${{ secrets.GITHUB_APP_PRIVATE_KEY }} + client-id: ${{ vars.APP_CLIENT_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} - uses: actions/checkout@v6 with: token: ${{ steps.app-token.outputs.token }} @@ -77,8 +77,8 @@ jobs: id: app-token with: # required - client-id: ${{ vars.GITHUB_APP_CLIENT_ID }} - private-key: ${{ secrets.GITHUB_APP_PRIVATE_KEY }} + client-id: ${{ vars.APP_CLIENT_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} - name: Get GitHub App User ID id: get-user-id run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT" @@ -102,8 +102,8 @@ jobs: id: app-token with: # required - client-id: ${{ vars.GITHUB_APP_CLIENT_ID }} - private-key: ${{ secrets.GITHUB_APP_PRIVATE_KEY }} + client-id: ${{ vars.APP_CLIENT_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} - name: Get GitHub App User ID id: get-user-id run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT" @@ -138,8 +138,8 @@ jobs: - uses: actions/create-github-app-token@v3 id: app-token with: - client-id: ${{ vars.GITHUB_APP_CLIENT_ID }} - private-key: ${{ secrets.GITHUB_APP_PRIVATE_KEY }} + client-id: ${{ vars.APP_CLIENT_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} owner: ${{ github.repository_owner }} - uses: peter-evans/create-or-update-comment@v4 with: @@ -160,8 +160,8 @@ jobs: - uses: actions/create-github-app-token@v3 id: app-token with: - client-id: ${{ vars.GITHUB_APP_CLIENT_ID }} - private-key: ${{ secrets.GITHUB_APP_PRIVATE_KEY }} + client-id: ${{ vars.APP_CLIENT_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} owner: ${{ github.repository_owner }} repositories: | repo1 @@ -185,8 +185,8 @@ jobs: - uses: actions/create-github-app-token@v3 id: app-token with: - client-id: ${{ vars.GITHUB_APP_CLIENT_ID }} - private-key: ${{ secrets.GITHUB_APP_PRIVATE_KEY }} + client-id: ${{ vars.APP_CLIENT_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} owner: another-owner - uses: peter-evans/create-or-update-comment@v4 with: @@ -210,8 +210,8 @@ jobs: - uses: actions/create-github-app-token@v3 id: app-token with: - client-id: ${{ vars.GITHUB_APP_CLIENT_ID }} - private-key: ${{ secrets.GITHUB_APP_PRIVATE_KEY }} + client-id: ${{ vars.APP_CLIENT_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} owner: ${{ github.repository_owner }} permission-issues: write - uses: peter-evans/create-or-update-comment@v4 @@ -252,8 +252,8 @@ jobs: - uses: actions/create-github-app-token@v3 id: app-token with: - client-id: ${{ vars.GITHUB_APP_CLIENT_ID }} - private-key: ${{ secrets.GITHUB_APP_PRIVATE_KEY }} + client-id: ${{ vars.APP_CLIENT_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} owner: ${{ matrix.owners-and-repos.owner }} repositories: ${{ join(matrix.owners-and-repos.repos) }} - uses: octokit/request-action@v2.x @@ -310,8 +310,8 @@ If you set `HTTP_PROXY` or `HTTPS_PROXY`, also set `NODE_USE_ENV_PROXY: "1"` on NO_PROXY: github.example.com NODE_USE_ENV_PROXY: "1" with: - client-id: ${{ vars.GITHUB_APP_CLIENT_ID }} - private-key: ${{ secrets.GITHUB_APP_PRIVATE_KEY }} + client-id: ${{ vars.APP_CLIENT_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} ``` ## Inputs @@ -334,14 +334,14 @@ steps: - name: Decode the GitHub App Private Key id: decode run: | - private_key=$(echo "${{ secrets.GITHUB_APP_PRIVATE_KEY }}" | base64 -d | awk 'BEGIN {ORS="\\n"} {print}' | head -c -2) &> /dev/null + private_key=$(echo "${{ secrets.APP_PRIVATE_KEY }}" | base64 -d | awk 'BEGIN {ORS="\\n"} {print}' | head -c -2) &> /dev/null echo "::add-mask::$private_key" echo "private-key=$private_key" >> "$GITHUB_OUTPUT" - name: Generate GitHub App Token id: app-token uses: actions/create-github-app-token@v3 with: - client-id: ${{ vars.GITHUB_APP_CLIENT_ID }} + client-id: ${{ vars.APP_CLIENT_ID }} private-key: ${{ steps.decode.outputs.private-key }} ``` From 6be28c6ca7b413964816a53dc1739dff50d559b5 Mon Sep 17 00:00:00 2001 From: Parker Brown <17183625+parkerbxyz@users.noreply.github.com> Date: Thu, 7 May 2026 18:13:10 -0700 Subject: [PATCH 05/29] ci: migrate releases to release-please (#367) ## Summary This updates release automation so the repository can enforce signed commits. Release version and changelog updates now happen through release-please PRs instead of direct workflow commits, which allows them to use the repository's normal signed-commit path. ## Changes - Replaces semantic-release configuration with release-please manifest configuration for stable releases and beta prereleases. - Builds committed `dist/**` assets from the trusted release workflow after release-please creates or updates a release PR, then commits those assets back to the release PR branch. - Keeps floating major version tags, such as `v3`, updated with the GitHub API after a release is created. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/release.yml | 59 ++++++++++++++++++++++++++++----- .release-please-manifest.json | 3 ++ package.json | 28 ---------------- release-please-config.beta.json | 11 ++++++ release-please-config.json | 8 +++++ 5 files changed, 72 insertions(+), 37 deletions(-) create mode 100644 .release-please-manifest.json create mode 100644 release-please-config.beta.json create mode 100644 release-please-config.json diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c632f2d7..ac5d7c4f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,6 +1,7 @@ name: release on: + workflow_dispatch: push: branches: - "*.x" @@ -17,24 +18,64 @@ jobs: name: release runs-on: ubuntu-latest steps: - # build local version to create token - uses: actions/checkout@v6 + + - uses: ./ + id: app-token with: - persist-credentials: false + app-id: ${{ vars.RELEASER_APP_ID }} + private-key: ${{ secrets.RELEASER_APP_PRIVATE_KEY }} + + - uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5.0.0 + id: release-please + with: + token: ${{ steps.app-token.outputs.token }} + config-file: ${{ github.ref_name == 'beta' && 'release-please-config.beta.json' || 'release-please-config.json' }} + manifest-file: .release-please-manifest.json + target-branch: ${{ github.ref_name }} + + - uses: actions/checkout@v6 + if: steps.release-please.outputs.prs_created == 'true' + with: + ref: ${{ fromJSON(steps.release-please.outputs.pr).headBranchName }} + token: ${{ steps.app-token.outputs.token }} - uses: actions/setup-node@v6 + if: steps.release-please.outputs.prs_created == 'true' with: node-version-file: package.json - run: npm ci + if: steps.release-please.outputs.prs_created == 'true' + - run: npm run build - - uses: ./ - id: app-token + if: steps.release-please.outputs.prs_created == 'true' + + - uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0 + if: steps.release-please.outputs.prs_created == 'true' with: - app-id: ${{ vars.RELEASER_APP_ID }} - private-key: ${{ secrets.RELEASER_APP_PRIVATE_KEY }} - # install release dependencies and release - - run: npm install --no-save @semantic-release/git semantic-release-plugin-github-breaking-version-tag - - run: npx semantic-release --debug + commit_author: "${{ github.actor }} <${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com>" + commit_message: "chore: update dist files" + file_pattern: dist/** + + - name: Update major version tag + id: update-major-tag + if: steps.release-please.outputs.release_created == 'true' && github.ref_name != 'beta' + uses: octokit/request-action@b91aabaa861c777dcdb14e2387e30eddf04619ae # v3.0.0 + continue-on-error: true + with: + route: PATCH /repos/${{ github.repository }}/git/refs/tags/v${{ steps.release-please.outputs.major }} + sha: ${{ steps.release-please.outputs.sha }} + force: true + env: + GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} + + - name: Create major version tag + if: steps.release-please.outputs.release_created == 'true' && github.ref_name != 'beta' && steps.update-major-tag.outcome == 'failure' + uses: octokit/request-action@b91aabaa861c777dcdb14e2387e30eddf04619ae # v3.0.0 + with: + route: POST /repos/${{ github.repository }}/git/refs + ref: refs/tags/v${{ steps.release-please.outputs.major }} + sha: ${{ steps.release-please.outputs.sha }} env: GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 00000000..b4b8d0ff --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "3.1.1" +} diff --git a/package.json b/package.json index fbe04802..d12043d9 100644 --- a/package.json +++ b/package.json @@ -28,33 +28,5 @@ "open-cli": "^9.0.0", "undici": "^7.24.6", "yaml": "^2.8.3" - }, - "release": { - "branches": [ - "+([0-9]).x", - "main", - { - "name": "beta", - "prerelease": true - } - ], - "plugins": [ - "@semantic-release/commit-analyzer", - "@semantic-release/release-notes-generator", - "@semantic-release/github", - "@semantic-release/npm", - "semantic-release-plugin-github-breaking-version-tag", - [ - "@semantic-release/git", - { - "assets": [ - "package.json", - "package-lock.json", - "dist/*" - ], - "message": "build(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" - } - ] - ] } } diff --git a/release-please-config.beta.json b/release-please-config.beta.json new file mode 100644 index 00000000..c05cb93c --- /dev/null +++ b/release-please-config.beta.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "packages": { + ".": { + "prerelease": true, + "prerelease-type": "beta", + "release-type": "node", + "versioning": "prerelease" + } + } +} diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 00000000..ee4d8052 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "packages": { + ".": { + "release-type": "node" + } + } +} From 6dbbbb1419df9d7e7445c08c9e69e7a0e5b4acde Mon Sep 17 00:00:00 2001 From: Parker Brown <17183625+parkerbxyz@users.noreply.github.com> Date: Thu, 7 May 2026 18:58:55 -0700 Subject: [PATCH 06/29] ci: use existing release tag format (#369) ## Summary This updates the release-please manifest configuration to use the repository's existing `vX.Y.Z` tag format. Without this setting, manifest mode looks for component-prefixed tags like `create-github-app-token-v3.1.1`, which do not exist in this repository and can cause release-please to include already-released commits in a new release PR. ## Changes - Sets `include-component-in-tag` to `false` for stable releases. - Sets `include-component-in-tag` to `false` for beta prereleases. This should make release-please use tags like `v3.1.1` as the previous release boundary. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- release-please-config.beta.json | 1 + release-please-config.json | 1 + 2 files changed, 2 insertions(+) diff --git a/release-please-config.beta.json b/release-please-config.beta.json index c05cb93c..a94e3387 100644 --- a/release-please-config.beta.json +++ b/release-please-config.beta.json @@ -4,6 +4,7 @@ ".": { "prerelease": true, "prerelease-type": "beta", + "include-component-in-tag": false, "release-type": "node", "versioning": "prerelease" } diff --git a/release-please-config.json b/release-please-config.json index ee4d8052..280e4000 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -2,6 +2,7 @@ "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", "packages": { ".": { + "include-component-in-tag": false, "release-type": "node" } } From 43e5c345bfd4d4f3ecea019ad0042001a09dd857 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 19:09:31 -0700 Subject: [PATCH 07/29] fix(deps): bump @actions/core from 3.0.0 to 3.0.1 in the production-dependencies group (#364) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the production-dependencies group with 1 update: [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core). Updates `@actions/core` from 3.0.0 to 3.0.1
Changelog

Sourced from @​actions/core's changelog.

3.0.1

  • Bump undici from 6.23.0 to 6.24.1 #2348
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@actions/core&package-manager=npm_and_yarn&previous-version=3.0.0&new-version=3.0.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index e37edd3b..83791b4d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "3.1.1", "license": "MIT", "dependencies": { - "@actions/core": "^3.0.0", + "@actions/core": "^3.0.1", "@octokit/auth-app": "^8.2.0", "@octokit/request": "^10.0.8", "p-retry": "^8.0.0" @@ -27,9 +27,9 @@ } }, "node_modules/@actions/core": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-3.0.0.tgz", - "integrity": "sha512-zYt6cz+ivnTmiT/ksRVriMBOiuoUpDCJJlZ5KPl2/FRdvwU3f7MPh9qftvbkXJThragzUZieit2nyHUyw53Seg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-3.0.1.tgz", + "integrity": "sha512-a6d/Nwahm9fliVGRhdhofo40HjHQasUPusmc7vBfyky+7Z+P2A1J68zyFVaNcEclc/Se+eO595oAr5nwEIoIUA==", "license": "MIT", "dependencies": { "@actions/exec": "^3.0.0", diff --git a/package.json b/package.json index d12043d9..5a36f79c 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ }, "license": "MIT", "dependencies": { - "@actions/core": "^3.0.0", + "@actions/core": "^3.0.1", "@octokit/auth-app": "^8.2.0", "@octokit/request": "^10.0.8", "p-retry": "^8.0.0" From 952a2a7073df6bfa5f49bc469ec895b6ec1acea4 Mon Sep 17 00:00:00 2001 From: Stefan Date: Fri, 8 May 2026 20:56:11 +0200 Subject: [PATCH 08/29] feat: add support for enterprise-level GitHub Apps (#263) This pull request adds support for generating GitHub App installation tokens for enterprise-level installations. ### What changed - Added a new `enterprise` input to `action.yml`. - Wired `enterprise` through `main.js` and `lib/main.js`. - Added validation so `enterprise` cannot be combined with `owner` or `repositories`. - Implemented enterprise installation lookup using the direct GitHub API route `GET /enterprises/{enterprise}/installation`, then used the returned installation ID to mint an installation token through `@octokit/auth-app`. - Updated `README.md` with enterprise installation usage and input documentation. - Updated `dist/main.cjs` for the bundled action. - Shared token creation retry behavior across repository, owner, and enterprise paths so server errors and transient network errors are retried, while client errors fail immediately. ### Tests Added focused test coverage for: - enterprise token creation - enterprise token creation with explicit permissions - enterprise installation not found - mutual exclusivity with `owner` - mutual exclusivity with `repositories` - owner installation client errors are not retried - transient network errors are retried during token creation ### Notes - This keeps the existing repository-scoped token behavior unchanged. - Owner, repository, and enterprise token creation now share the same retry policy: server errors and recognized transient network errors are retried, while client errors fail immediately. This intentionally fixes the previous owner-path behavior that retried client errors. Refs: - https://github.blog/changelog/2025-07-01-enterprise-level-access-for-github-apps-and-installation-automation-apis/ - https://docs.github.com/en/rest/apps/apps?apiVersion=2022-11-28#get-an-enterprise-installation-for-the-authenticated-app --------- Co-authored-by: Parker Brown <17183625+parkerbxyz@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .gitignore | 1 + README.md | 44 +++- action.yml | 3 + dist/main.cjs | 200 ++++++++------ lib/main.js | 244 +++++++++++------- main.js | 2 + package-lock.json | 7 +- package.json | 1 + tests/index.js | 24 +- tests/index.js.snapshot | 166 +++++++++++- tests/main-enterprise-fail-response.test.js | 39 +++ ...-enterprise-installation-not-found.test.js | 25 ++ ...nterprise-mutual-exclusivity-owner.test.js | 13 + ...se-mutual-exclusivity-repositories.test.js | 13 + tests/main-enterprise-only-success.test.js | 30 +++ ...n-enterprise-token-permissions-set.test.js | 34 +++ ...n-token-get-owner-set-client-error.test.js | 23 ++ ...n-get-owner-set-repo-network-error.test.js | 39 +++ 18 files changed, 714 insertions(+), 194 deletions(-) create mode 100644 tests/main-enterprise-fail-response.test.js create mode 100644 tests/main-enterprise-installation-not-found.test.js create mode 100644 tests/main-enterprise-mutual-exclusivity-owner.test.js create mode 100644 tests/main-enterprise-mutual-exclusivity-repositories.test.js create mode 100644 tests/main-enterprise-only-success.test.js create mode 100644 tests/main-enterprise-token-permissions-set.test.js create mode 100644 tests/main-token-get-owner-set-client-error.test.js create mode 100644 tests/main-token-get-owner-set-repo-network-error.test.js diff --git a/.gitignore b/.gitignore index b443287f..87966f68 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .env coverage node_modules/ +.DS_Store diff --git a/README.md b/README.md index 2073f975..43257164 100644 --- a/README.md +++ b/README.md @@ -195,10 +195,32 @@ jobs: body: "Hello, World!" ``` +### Create a token for an enterprise installation + +```yaml +on: [workflow_dispatch] + +jobs: + hello-world: + runs-on: ubuntu-latest + steps: + - uses: actions/create-github-app-token@v3 + id: app-token + with: + client-id: ${{ vars.APP_CLIENT_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + enterprise: my-enterprise-slug + - name: Call enterprise management REST API with gh + run: | + gh api /enterprises/my-enterprise-slug/apps/installable_organizations + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} +``` + ### Create a token with specific permissions > [!NOTE] -> Selected permissions must be granted to the installation of the specified app and repository owner. Setting a permission that the installation does not have will result in an error. +> Selected permissions must be granted to the specified app installation. Setting a permission that the installation does not have will result in an error. ```yaml on: [issues] @@ -356,6 +378,13 @@ steps: > [!NOTE] > If `owner` is set and `repositories` is empty, access will be scoped to all repositories in the provided repository owner's installation. If `owner` and `repositories` are empty, access will be scoped to only the current repository. +### `enterprise` + +**Optional:** The slug of the enterprise account to generate a token for an enterprise installation. + +> [!NOTE] +> The `enterprise` input is mutually exclusive with `owner` and `repositories`. Use it when the GitHub App is installed on an enterprise account. Enterprise installation tokens can call enterprise APIs, but do not grant organization or repository access. + ### `permission-` **Optional:** The permissions to grant to the token. By default, the token inherits all of the installation's permissions. We recommend to explicitly list the permissions that are required for a use case. This follows GitHub's own recommendation to [control permissions of `GITHUB_TOKEN` in workflows](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token). The documentation also lists all available permissions, just prefix the permission key with `permission-` (e.g., `pull-requests` → `permission-pull-requests`). @@ -386,13 +415,14 @@ GitHub App slug. ## How it works -The action creates an installation access token using [the `POST /app/installations/{installation_id}/access_tokens` endpoint](https://docs.github.com/rest/apps/apps?apiVersion=2022-11-28#create-an-installation-access-token-for-an-app). By default, +The action creates an installation access token using [the `POST /app/installations/{installation_id}/access_tokens` endpoint](https://docs.github.com/rest/apps/apps?apiVersion=2022-11-28#create-an-installation-access-token-for-an-app). + +The token target depends on the inputs: `enterprise` creates a token for an enterprise installation, `owner` without `repositories` creates a token for all repositories in the owner's installation, `repositories` scopes the token to those repositories, and no target inputs scopes the token to the current repository. -1. The token is scoped to the current repository or `repositories` if set. -2. The token inherits all the installation's permissions. -3. The token is set as output `token` which can be used in subsequent steps. -4. Unless the `skip-token-revoke` input is set to true, the token is revoked in the `post` step of the action, which means it cannot be passed to another job. -5. The token is masked, it cannot be logged accidentally. +1. The token inherits all the installation's permissions. +2. The token is set as output `token` which can be used in subsequent steps. +3. Unless the `skip-token-revoke` input is set to true, the token is revoked in the `post` step of the action, which means it cannot be passed to another job. +4. The token is masked, it cannot be logged accidentally. > [!NOTE] > Installation permissions can differ from the app's permissions they belong to. Installation permissions are set when an app is installed on an account. When the app adds more permissions after the installation, an account administrator will have to approve the new permissions before they are set on the installation. diff --git a/action.yml b/action.yml index ce9b276c..a4e11487 100644 --- a/action.yml +++ b/action.yml @@ -21,6 +21,9 @@ inputs: repositories: description: "Comma or newline-separated list of repositories to install the GitHub App on (defaults to current repository if owner is unset)" required: false + enterprise: + description: "The slug of the enterprise account where the GitHub App is installed (cannot be used with 'owner' or 'repositories')" + required: false skip-token-revoke: description: "If true, the token will not be revoked when the current job is complete" required: false diff --git a/dist/main.cjs b/dist/main.cjs index b9dc6211..dc716995 100644 --- a/dist/main.cjs +++ b/dist/main.cjs @@ -22985,7 +22985,7 @@ function isNetworkError(error2) { return false; } const { message, stack } = error2; - if (message === "Load failed") { + if (message === "Load failed" || message.startsWith("Load failed (") && message.endsWith(")")) { return stack === void 0 || "__sentry_captured__" in error2; } if (message.startsWith("error sending request for url")) { @@ -23196,89 +23196,125 @@ async function pRetry(input, options = {}) { } // lib/main.js -async function main(clientId, privateKey, owner, repositories, permissions, core, createAppAuth2, request2, skipTokenRevoke) { - let parsedOwner = ""; - let parsedRepositoryNames = []; +async function main(clientId, privateKey, enterprise, owner, repositories, permissions, core, createAppAuth2, request2, skipTokenRevoke) { + if (enterprise && (owner || repositories.length > 0)) { + throw new Error("Cannot use 'enterprise' input with 'owner' or 'repositories' inputs"); + } + const target = resolveInstallationTarget(enterprise, owner, repositories, core); + const auth5 = createAppAuth2({ + appId: clientId, + privateKey, + request: request2 + }); + const { authentication, installationId, appSlug } = await pRetry( + () => getTokenFromTarget(request2, auth5, target, permissions), + createTokenRetryOptions(core, getTokenRetryDescription(target)) + ); + core.setSecret(authentication.token); + core.setOutput("token", authentication.token); + core.setOutput("installation-id", installationId); + core.setOutput("app-slug", appSlug); + if (!skipTokenRevoke) { + core.saveState("token", authentication.token); + core.saveState("expiresAt", authentication.expiresAt); + } +} +function resolveInstallationTarget(enterprise, owner, repositories, core) { + if (enterprise) { + core.info(`Creating enterprise installation token for enterprise "${enterprise}".`); + return { type: "enterprise", enterprise }; + } if (!owner && repositories.length === 0) { - const [owner2, repo] = String(process.env.GITHUB_REPOSITORY).split("/"); - parsedOwner = owner2; - parsedRepositoryNames = [repo]; + const [defaultOwner, repo] = String(process.env.GITHUB_REPOSITORY).split("/"); core.info( - `Inputs 'owner' and 'repositories' are not set. Creating token for this repository (${owner2}/${repo}).` + `Inputs 'owner' and 'repositories' are not set. Creating token for this repository (${defaultOwner}/${repo}).` ); + return { + type: "repository", + owner: defaultOwner, + repositories: [repo] + }; } if (owner && repositories.length === 0) { - parsedOwner = owner; core.info( `Input 'repositories' is not set. Creating token for all repositories owned by ${owner}.` ); + return { type: "owner", owner }; } - if (!owner && repositories.length > 0) { - parsedOwner = String(process.env.GITHUB_REPOSITORY_OWNER); - parsedRepositoryNames = repositories; + const parsedOwner = owner || String(process.env.GITHUB_REPOSITORY_OWNER); + if (!owner) { core.info( `No 'owner' input provided. Using default owner '${parsedOwner}' to create token for the following repositories:${repositories.map((repo) => ` - ${parsedOwner}/${repo}`).join("")}` ); - } - if (owner && repositories.length > 0) { - parsedOwner = owner; - parsedRepositoryNames = repositories; + } else { core.info( - `Inputs 'owner' and 'repositories' are set. Creating token for the following repositories: - ${repositories.map((repo) => ` + `Inputs 'owner' and 'repositories' are set. Creating token for the following repositories:${repositories.map((repo) => ` - ${parsedOwner}/${repo}`).join("")}` ); } - const auth5 = createAppAuth2({ - appId: clientId, - privateKey, - request: request2 - }); - let authentication, installationId, appSlug; - if (parsedRepositoryNames.length > 0) { - ({ authentication, installationId, appSlug } = await pRetry( - () => getTokenFromRepository( + return { + type: "repository", + owner: parsedOwner, + repositories + }; +} +function getTokenRetryDescription(target) { + switch (target.type) { + case "enterprise": + return `enterprise "${target.enterprise}"`; + case "repository": + return `"${target.repositories.map((repository) => `${target.owner}/${repository}`).join(",")}"`; + case "owner": + return `"${target.owner}"`; + /* c8 ignore next 2 */ + default: + throw new Error(`Unsupported installation target type: ${target.type}`); + } +} +function getTokenFromTarget(request2, auth5, target, permissions) { + switch (target.type) { + case "enterprise": + return getTokenFromEnterprise(request2, auth5, target.enterprise, permissions); + case "repository": + return getTokenFromRepository( request2, auth5, - parsedOwner, - parsedRepositoryNames, + target.owner, + target.repositories, permissions - ), - { - shouldRetry: ({ error: error2 }) => error2.status >= 500, - onFailedAttempt: (context) => { - core.info( - `Failed to create token for "${parsedRepositoryNames.join( - "," - )}" (attempt ${context.attemptNumber}): ${context.error.message}` - ); - }, - retries: 3 - } - )); - } else { - ({ authentication, installationId, appSlug } = await pRetry( - () => getTokenFromOwner(request2, auth5, parsedOwner, permissions), - { - onFailedAttempt: (context) => { - core.info( - `Failed to create token for "${parsedOwner}" (attempt ${context.attemptNumber}): ${context.error.message}` - ); - }, - retries: 3 - } - )); - } - core.setSecret(authentication.token); - core.setOutput("token", authentication.token); - core.setOutput("installation-id", installationId); - core.setOutput("app-slug", appSlug); - if (!skipTokenRevoke) { - core.saveState("token", authentication.token); - core.saveState("expiresAt", authentication.expiresAt); + ); + case "owner": + return getTokenFromOwner(request2, auth5, target.owner, permissions); + /* c8 ignore next 2 */ + default: + throw new Error(`Unsupported installation target type: ${target.type}`); } } +function createTokenRetryOptions(core, targetDescription) { + return { + shouldRetry: ({ error: error2 }) => error2.status >= 500 || isNetworkError(error2), + onFailedAttempt: (context) => { + core.info( + `Failed to create token for ${targetDescription} (attempt ${context.attemptNumber}): ${context.error.message}` + ); + }, + retries: 3 + }; +} +async function createInstallationAuthResult(auth5, installation, permissions, options = {}) { + const authentication = await auth5({ + type: "installation", + installationId: installation.id, + permissions, + ...options + }); + return { + authentication, + installationId: installation.id, + appSlug: installation["app_slug"] + }; +} async function getTokenFromOwner(request2, auth5, parsedOwner, permissions) { const response = await request2("GET /users/{username}/installation", { username: parsedOwner, @@ -23286,14 +23322,7 @@ async function getTokenFromOwner(request2, auth5, parsedOwner, permissions) { hook: auth5.hook } }); - const authentication = await auth5({ - type: "installation", - installationId: response.data.id, - permissions - }); - const installationId = response.data.id; - const appSlug = response.data["app_slug"]; - return { authentication, installationId, appSlug }; + return createInstallationAuthResult(auth5, response.data, permissions); } async function getTokenFromRepository(request2, auth5, parsedOwner, parsedRepositoryNames, permissions) { const response = await request2("GET /repos/{owner}/{repo}/installation", { @@ -23303,15 +23332,28 @@ async function getTokenFromRepository(request2, auth5, parsedOwner, parsedReposi hook: auth5.hook } }); - const authentication = await auth5({ - type: "installation", - installationId: response.data.id, - repositoryNames: parsedRepositoryNames, - permissions + return createInstallationAuthResult(auth5, response.data, permissions, { + repositoryNames: parsedRepositoryNames }); - const installationId = response.data.id; - const appSlug = response.data["app_slug"]; - return { authentication, installationId, appSlug }; +} +async function getTokenFromEnterprise(request2, auth5, enterprise, permissions) { + let response; + try { + response = await request2("GET /enterprises/{enterprise}/installation", { + enterprise, + request: { + hook: auth5.hook + } + }); + } catch (error2) { + if (error2.status === 404) { + throw new Error( + `No enterprise installation found matching the enterprise slug "${enterprise}".` + ); + } + throw error2; + } + return createInstallationAuthResult(auth5, response.data, permissions); } // lib/request.js @@ -23355,6 +23397,7 @@ async function run() { throw new Error("The 'client-id' (or deprecated 'app-id') input must be set to a non-empty string. If using a secret or variable, ensure it is available in this workflow context."); } const privateKey = getInput("private-key"); + const enterprise = getInput("enterprise"); const owner = getInput("owner"); const repositories = getInput("repositories").split(/[\n,]+/).map((s) => s.trim()).filter((x) => x !== ""); const skipTokenRevoke = getBooleanInput("skip-token-revoke"); @@ -23362,6 +23405,7 @@ async function run() { return main( clientId, privateKey, + enterprise, owner, repositories, permissions, diff --git a/lib/main.js b/lib/main.js index 8f5ef9a0..8fe0942a 100644 --- a/lib/main.js +++ b/lib/main.js @@ -1,9 +1,11 @@ import pRetry from "p-retry"; +import isNetworkError from "is-network-error"; // @ts-check /** * @param {string} clientId * @param {string} privateKey + * @param {string} enterprise * @param {string} owner * @param {string[]} repositories * @param {undefined | Record} permissions @@ -15,118 +17,164 @@ import pRetry from "p-retry"; export async function main( clientId, privateKey, + enterprise, owner, repositories, permissions, core, createAppAuth, request, - skipTokenRevoke + skipTokenRevoke, ) { - let parsedOwner = ""; - let parsedRepositoryNames = []; + // Validate mutual exclusivity of enterprise with owner/repositories + if (enterprise && (owner || repositories.length > 0)) { + throw new Error("Cannot use 'enterprise' input with 'owner' or 'repositories' inputs"); + } + + const target = resolveInstallationTarget(enterprise, owner, repositories, core); + + const auth = createAppAuth({ + appId: clientId, + privateKey, + request, + }); + + const { authentication, installationId, appSlug } = await pRetry( + () => getTokenFromTarget(request, auth, target, permissions), + createTokenRetryOptions(core, getTokenRetryDescription(target)) + ); + + // Register the token with the runner as a secret to ensure it is masked in logs + core.setSecret(authentication.token); + + core.setOutput("token", authentication.token); + core.setOutput("installation-id", installationId); + core.setOutput("app-slug", appSlug); + + // Make token accessible to post function (so we can invalidate it) + if (!skipTokenRevoke) { + core.saveState("token", authentication.token); + core.saveState("expiresAt", authentication.expiresAt); + } +} + +function resolveInstallationTarget(enterprise, owner, repositories, core) { + if (enterprise) { + core.info(`Creating enterprise installation token for enterprise "${enterprise}".`); + return { type: "enterprise", enterprise }; + } - // If neither owner nor repositories are set, default to current repository if (!owner && repositories.length === 0) { - const [owner, repo] = String(process.env.GITHUB_REPOSITORY).split("/"); - parsedOwner = owner; - parsedRepositoryNames = [repo]; + const [defaultOwner, repo] = String(process.env.GITHUB_REPOSITORY).split("/"); core.info( - `Inputs 'owner' and 'repositories' are not set. Creating token for this repository (${owner}/${repo}).` + `Inputs 'owner' and 'repositories' are not set. Creating token for this repository (${defaultOwner}/${repo}).` ); + + return { + type: "repository", + owner: defaultOwner, + repositories: [repo], + }; } - // If only an owner is set, default to all repositories from that owner if (owner && repositories.length === 0) { - parsedOwner = owner; - core.info( `Input 'repositories' is not set. Creating token for all repositories owned by ${owner}.` ); + + return { type: "owner", owner }; } - // If repositories are set, but no owner, default to `GITHUB_REPOSITORY_OWNER` - if (!owner && repositories.length > 0) { - parsedOwner = String(process.env.GITHUB_REPOSITORY_OWNER); - parsedRepositoryNames = repositories; + const parsedOwner = owner || String(process.env.GITHUB_REPOSITORY_OWNER); + if (!owner) { core.info( `No 'owner' input provided. Using default owner '${parsedOwner}' to create token for the following repositories:${repositories .map((repo) => `\n- ${parsedOwner}/${repo}`) .join("")}` ); - } - - // If both owner and repositories are set, use those values - if (owner && repositories.length > 0) { - parsedOwner = owner; - parsedRepositoryNames = repositories; - + } else { core.info( - `Inputs 'owner' and 'repositories' are set. Creating token for the following repositories: - ${repositories.map((repo) => `\n- ${parsedOwner}/${repo}`).join("")}` + `Inputs 'owner' and 'repositories' are set. Creating token for the following repositories:${repositories + .map((repo) => `\n- ${parsedOwner}/${repo}`) + .join("")}` ); } - const auth = createAppAuth({ - appId: clientId, - privateKey, - request, - }); + return { + type: "repository", + owner: parsedOwner, + repositories, + }; +} - let authentication, installationId, appSlug; - // If at least one repository is set, get installation ID from that repository - - if (parsedRepositoryNames.length > 0) { - ({ authentication, installationId, appSlug } = await pRetry( - () => - getTokenFromRepository( - request, - auth, - parsedOwner, - parsedRepositoryNames, - permissions - ), - { - shouldRetry: ({ error }) => error.status >= 500, - onFailedAttempt: (context) => { - core.info( - `Failed to create token for "${parsedRepositoryNames.join( - "," - )}" (attempt ${context.attemptNumber}): ${context.error.message}` - ); - }, - retries: 3, - } - )); - } else { - // Otherwise get the installation for the owner, which can either be an organization or a user account - ({ authentication, installationId, appSlug } = await pRetry( - () => getTokenFromOwner(request, auth, parsedOwner, permissions), - { - onFailedAttempt: (context) => { - core.info( - `Failed to create token for "${parsedOwner}" (attempt ${context.attemptNumber}): ${context.error.message}` - ); - }, - retries: 3, - } - )); +function getTokenRetryDescription(target) { + switch (target.type) { + case "enterprise": + return `enterprise "${target.enterprise}"`; + case "repository": + return `"${target.repositories + .map((repository) => `${target.owner}/${repository}`) + .join(",")}"`; + case "owner": + return `"${target.owner}"`; + /* c8 ignore next 2 */ + default: + throw new Error(`Unsupported installation target type: ${target.type}`); } +} - // Register the token with the runner as a secret to ensure it is masked in logs - core.setSecret(authentication.token); +function getTokenFromTarget(request, auth, target, permissions) { + switch (target.type) { + case "enterprise": + return getTokenFromEnterprise(request, auth, target.enterprise, permissions); + case "repository": + return getTokenFromRepository( + request, + auth, + target.owner, + target.repositories, + permissions + ); + case "owner": + return getTokenFromOwner(request, auth, target.owner, permissions); + /* c8 ignore next 2 */ + default: + throw new Error(`Unsupported installation target type: ${target.type}`); + } +} - core.setOutput("token", authentication.token); - core.setOutput("installation-id", installationId); - core.setOutput("app-slug", appSlug); +function createTokenRetryOptions(core, targetDescription) { + return { + shouldRetry: ({ error }) => error.status >= 500 || isNetworkError(error), + onFailedAttempt: (context) => { + core.info( + `Failed to create token for ${targetDescription} (attempt ${context.attemptNumber}): ${context.error.message}` + ); + }, + retries: 3, + }; +} - // Make token accessible to post function (so we can invalidate it) - if (!skipTokenRevoke) { - core.saveState("token", authentication.token); - core.saveState("expiresAt", authentication.expiresAt); - } +async function createInstallationAuthResult( + auth, + installation, + permissions, + options = {}, +) { + const authentication = await auth({ + type: "installation", + installationId: installation.id, + permissions, + ...options, + }); + + return { + authentication, + installationId: installation.id, + appSlug: installation["app_slug"], + }; } async function getTokenFromOwner(request, auth, parsedOwner, permissions) { @@ -139,17 +187,8 @@ async function getTokenFromOwner(request, auth, parsedOwner, permissions) { }, }); - // Get token for for all repositories of the given installation - const authentication = await auth({ - type: "installation", - installationId: response.data.id, - permissions, - }); - - const installationId = response.data.id; - const appSlug = response.data["app_slug"]; - - return { authentication, installationId, appSlug }; + // Get token for all repositories of the given installation + return createInstallationAuthResult(auth, response.data, permissions); } async function getTokenFromRepository( @@ -169,15 +208,30 @@ async function getTokenFromRepository( }); // Get token for given repositories - const authentication = await auth({ - type: "installation", - installationId: response.data.id, + return createInstallationAuthResult(auth, response.data, permissions, { repositoryNames: parsedRepositoryNames, - permissions, }); +} - const installationId = response.data.id; - const appSlug = response.data["app_slug"]; +async function getTokenFromEnterprise(request, auth, enterprise, permissions) { + let response; + try { + response = await request("GET /enterprises/{enterprise}/installation", { + enterprise, + request: { + hook: auth.hook, + }, + }); + } catch (error) { + if (error.status === 404) { + throw new Error( + `No enterprise installation found matching the enterprise slug "${enterprise}".` + ); + } + + throw error; + } - return { authentication, installationId, appSlug }; + // Get token for the enterprise installation + return createInstallationAuthResult(auth, response.data, permissions); } diff --git a/main.js b/main.js index 32696dda..a44409ab 100644 --- a/main.js +++ b/main.js @@ -23,6 +23,7 @@ async function run() { throw new Error("The 'client-id' (or deprecated 'app-id') input must be set to a non-empty string. If using a secret or variable, ensure it is available in this workflow context."); } const privateKey = core.getInput("private-key"); + const enterprise = core.getInput("enterprise"); const owner = core.getInput("owner"); const repositories = core .getInput("repositories") @@ -37,6 +38,7 @@ async function run() { return main( clientId, privateKey, + enterprise, owner, repositories, permissions, diff --git a/package-lock.json b/package-lock.json index 83791b4d..aa183a77 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@actions/core": "^3.0.1", "@octokit/auth-app": "^8.2.0", "@octokit/request": "^10.0.8", + "is-network-error": "^1.3.2", "p-retry": "^8.0.0" }, "devDependencies": { @@ -1252,9 +1253,9 @@ } }, "node_modules/is-network-error": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.1.tgz", - "integrity": "sha512-6QCxa49rQbmUWLfk0nuGqzql9U8uaV2H6279bRErPBHe/109hCzsLUBUHfbEtvLIHBd6hyXbgedBSHevm43Edw==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.2.tgz", + "integrity": "sha512-PhBY86zaxNZUuWP6h13Vu5oFe0XY6/UlKzQnYFELzGVHygP3MxmvTfYSG7GN3aIab/iWudSMgjSnG9Dq+nHrgA==", "license": "MIT", "engines": { "node": ">=16" diff --git a/package.json b/package.json index 5a36f79c..60bceff9 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@actions/core": "^3.0.1", "@octokit/auth-app": "^8.2.0", "@octokit/request": "^10.0.8", + "is-network-error": "^1.3.2", "p-retry": "^8.0.0" }, "devDependencies": { diff --git a/tests/index.js b/tests/index.js index d3e25211..74cf2723 100644 --- a/tests/index.js +++ b/tests/index.js @@ -11,6 +11,13 @@ snapshot.setDefaultSnapshotSerializers([ (value) => (typeof value === "string" ? value : undefined), ]); +function normalizeStderr(stderr) { + return stderr + .replaceAll(/\u001B\[[0-9;]*m/g, "") + .replaceAll(process.cwd(), "") + .replaceAll(/:\d+:\d+/g, "::"); +} + // Get all files in tests directory const files = readdirSync("tests"); @@ -39,10 +46,19 @@ for (const file of testFiles) { NODE_USE_ENV_PROXY, ...env } = process.env; - const { stderr, stdout } = await execFileAsync("node", [`tests/${file}`], { - env, - }); - const trimmedStderr = stderr.replace(/\r?\n$/, ""); + let stderr, stdout; + try { + ({ stderr, stdout } = await execFileAsync("node", [`tests/${file}`], { + env, + })); + } catch (error) { + if (!(error instanceof Error) || !("stderr" in error) || !("stdout" in error)) { + throw error; + } + + ({ stderr, stdout } = error); + } + const trimmedStderr = normalizeStderr(stderr).replace(/\r?\n$/, ""); const trimmedStdout = stdout.replace(/\r?\n$/, ""); await t.test("stderr", (t) => { if (trimmedStderr) t.assert.snapshot(trimmedStderr); diff --git a/tests/index.js.snapshot b/tests/index.js.snapshot index 4789f44b..a77b6fa1 100644 --- a/tests/index.js.snapshot +++ b/tests/index.js.snapshot @@ -38,7 +38,6 @@ POST /app/installations/123456/access_tokens exports[`main-custom-github-api-url.test.js > stdout 1`] = ` Inputs 'owner' and 'repositories' are set. Creating token for the following repositories: - - actions/create-github-app-token ::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a @@ -55,6 +54,105 @@ POST /api/v3/app/installations/123456/access_tokens {"repositories":["create-github-app-token"]} `; +exports[`main-enterprise-fail-response.test.js > stdout 1`] = ` +Creating enterprise installation token for enterprise "test-enterprise". +Failed to create token for enterprise "test-enterprise" (attempt 1): GitHub API not available +::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a + +::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a + +::set-output name=installation-id::123456 + +::set-output name=app-slug::github-actions +::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a +::save-state name=expiresAt::2016-07-11T22:14:10Z +--- REQUESTS --- +GET /enterprises/test-enterprise/installation +GET /enterprises/test-enterprise/installation +POST /app/installations/123456/access_tokens +null +`; + +exports[`main-enterprise-installation-not-found.test.js > stderr 1`] = ` +Error: No enterprise installation found matching the enterprise slug "test-enterprise". + at getTokenFromEnterprise (file:///lib/main.js::) + at process.processTicksAndRejections (node:internal/process/task_queues::) + at async pRetry (file:///node_modules/p-retry/index.js::) + at async main (file:///lib/main.js::) + at async test (file:///tests/main.js::) + at async file:///tests/main-enterprise-installation-not-found.test.js:: +`; + +exports[`main-enterprise-installation-not-found.test.js > stdout 1`] = ` +Creating enterprise installation token for enterprise "test-enterprise". +Failed to create token for enterprise "test-enterprise" (attempt 1): No enterprise installation found matching the enterprise slug "test-enterprise". +::error::No enterprise installation found matching the enterprise slug "test-enterprise". +--- REQUESTS --- +GET /enterprises/test-enterprise/installation +`; + +exports[`main-enterprise-mutual-exclusivity-owner.test.js > stderr 1`] = ` +Error: Cannot use 'enterprise' input with 'owner' or 'repositories' inputs + at main (file:///lib/main.js::) + at run (file:///main.js::) + at file:///main.js:: + at ModuleJob.run (node:internal/modules/esm/module_job::) + at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader::) + at async file:///tests/main-enterprise-mutual-exclusivity-owner.test.js:: +`; + +exports[`main-enterprise-mutual-exclusivity-owner.test.js > stdout 1`] = ` +::error::Cannot use 'enterprise' input with 'owner' or 'repositories' inputs +`; + +exports[`main-enterprise-mutual-exclusivity-repositories.test.js > stderr 1`] = ` +Error: Cannot use 'enterprise' input with 'owner' or 'repositories' inputs + at main (file:///lib/main.js::) + at run (file:///main.js::) + at file:///main.js:: + at ModuleJob.run (node:internal/modules/esm/module_job::) + at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader::) + at async file:///tests/main-enterprise-mutual-exclusivity-repositories.test.js:: +`; + +exports[`main-enterprise-mutual-exclusivity-repositories.test.js > stdout 1`] = ` +::error::Cannot use 'enterprise' input with 'owner' or 'repositories' inputs +`; + +exports[`main-enterprise-only-success.test.js > stdout 1`] = ` +Creating enterprise installation token for enterprise "test-enterprise". +::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a + +::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a + +::set-output name=installation-id::123456 + +::set-output name=app-slug::github-actions +::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a +::save-state name=expiresAt::2016-07-11T22:14:10Z +--- REQUESTS --- +GET /enterprises/test-enterprise/installation +POST /app/installations/123456/access_tokens +null +`; + +exports[`main-enterprise-token-permissions-set.test.js > stdout 1`] = ` +Creating enterprise installation token for enterprise "test-enterprise". +::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a + +::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a + +::set-output name=installation-id::123456 + +::set-output name=app-slug::github-actions +::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a +::save-state name=expiresAt::2016-07-11T22:14:10Z +--- REQUESTS --- +GET /enterprises/test-enterprise/installation +POST /app/installations/123456/access_tokens +{"permissions":{"enterprise_custom_properties_for_organizations":"read"}} +`; + exports[`main-missing-client-and-app-id.test.js > stderr 1`] = ` The 'client-id' (or deprecated 'app-id') input must be set to a non-empty string. If using a secret or variable, ensure it is available in this workflow context. `; @@ -103,7 +201,6 @@ exports[`main-repo-skew.test.js > stderr 1`] = ` exports[`main-repo-skew.test.js > stdout 1`] = ` Inputs 'owner' and 'repositories' are set. Creating token for the following repositories: - - actions/failed-repo ::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a @@ -121,6 +218,45 @@ POST /app/installations/123456/access_tokens {"repositories":["failed-repo"]} `; +exports[`main-token-get-owner-set-client-error.test.js > stderr 1`] = ` +RequestError [HttpError]: Forbidden + at fetchWrapper (file:///node_modules/@octokit/request/dist-bundle/index.js::) + at process.processTicksAndRejections (node:internal/process/task_queues::) + at async hook (file:///node_modules/@octokit/auth-app/dist-node/index.js::) + at async getTokenFromOwner (file:///lib/main.js::) + at async pRetry (file:///node_modules/p-retry/index.js::) + at async main (file:///lib/main.js::) + at async test (file:///tests/main.js::) + at async file:///tests/main-token-get-owner-set-client-error.test.js:: { + status: 403, + request: { + method: 'GET', + url: 'https://api.github.com/users/smockle/installation', + headers: { + accept: 'application/vnd.github.v3+json', + 'user-agent': 'actions/create-github-app-token', + authorization: 'bearer [REDACTED]' + }, + request: { hook: [Function: bound hook] AsyncFunction } + }, + response: { + url: 'https://api.github.com/users/smockle/installation', + status: 403, + headers: { 'content-type': 'application/json' }, + data: { message: 'Forbidden' } + }, + [cause]: undefined +} +`; + +exports[`main-token-get-owner-set-client-error.test.js > stdout 1`] = ` +Input 'repositories' is not set. Creating token for all repositories owned by smockle. +Failed to create token for "smockle" (attempt 1): Forbidden +::error::Forbidden +--- REQUESTS --- +GET /users/smockle/installation +`; + exports[`main-token-get-owner-set-fail-response.test.js > stdout 1`] = ` Input 'repositories' is not set. Creating token for all repositories owned by smockle. Failed to create token for "smockle" (attempt 1): GitHub API not available @@ -142,9 +278,8 @@ null exports[`main-token-get-owner-set-repo-fail-response.test.js > stdout 1`] = ` Inputs 'owner' and 'repositories' are set. Creating token for the following repositories: - - actions/failed-repo -Failed to create token for "failed-repo" (attempt 1): GitHub API not available +Failed to create token for "actions/failed-repo" (attempt 1): GitHub API not available ::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a ::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a @@ -161,9 +296,28 @@ POST /app/installations/123456/access_tokens {"repositories":["failed-repo"]} `; +exports[`main-token-get-owner-set-repo-network-error.test.js > stdout 1`] = ` +Inputs 'owner' and 'repositories' are set. Creating token for the following repositories: +- actions/network-repo +Failed to create token for "actions/network-repo" (attempt 1): fetch failed +::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a + +::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a + +::set-output name=installation-id::123456 + +::set-output name=app-slug::github-actions +::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a +::save-state name=expiresAt::2016-07-11T22:14:10Z +--- REQUESTS --- +GET /repos/actions/network-repo/installation +GET /repos/actions/network-repo/installation +POST /app/installations/123456/access_tokens +{"repositories":["network-repo"]} +`; + exports[`main-token-get-owner-set-repo-set-to-many-newline.test.js > stdout 1`] = ` Inputs 'owner' and 'repositories' are set. Creating token for the following repositories: - - actions/create-github-app-token - actions/toolkit - actions/checkout @@ -184,7 +338,6 @@ POST /app/installations/123456/access_tokens exports[`main-token-get-owner-set-repo-set-to-many.test.js > stdout 1`] = ` Inputs 'owner' and 'repositories' are set. Creating token for the following repositories: - - actions/create-github-app-token - actions/toolkit - actions/checkout @@ -205,7 +358,6 @@ POST /app/installations/123456/access_tokens exports[`main-token-get-owner-set-repo-set-to-one.test.js > stdout 1`] = ` Inputs 'owner' and 'repositories' are set. Creating token for the following repositories: - - actions/create-github-app-token ::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a diff --git a/tests/main-enterprise-fail-response.test.js b/tests/main-enterprise-fail-response.test.js new file mode 100644 index 00000000..068e2cba --- /dev/null +++ b/tests/main-enterprise-fail-response.test.js @@ -0,0 +1,39 @@ +import { test } from "./main.js"; + +// Verify enterprise installation lookup retries when the GitHub API returns a 500 error. +await test((mockPool) => { + process.env.INPUT_ENTERPRISE = "test-enterprise"; + delete process.env.INPUT_OWNER; + delete process.env.INPUT_REPOSITORIES; + + const mockInstallationId = "123456"; + const mockAppSlug = "github-actions"; + + mockPool + .intercept({ + path: "/enterprises/test-enterprise/installation", + method: "GET", + headers: { + accept: "application/vnd.github.v3+json", + "user-agent": "actions/create-github-app-token", + // Intentionally omitting the `authorization` header, since JWT creation is not idempotent. + }, + }) + .reply(500, "GitHub API not available"); + + mockPool + .intercept({ + path: "/enterprises/test-enterprise/installation", + method: "GET", + headers: { + accept: "application/vnd.github.v3+json", + "user-agent": "actions/create-github-app-token", + // Intentionally omitting the `authorization` header, since JWT creation is not idempotent. + }, + }) + .reply( + 200, + { id: mockInstallationId, app_slug: mockAppSlug }, + { headers: { "content-type": "application/json" } }, + ); +}); diff --git a/tests/main-enterprise-installation-not-found.test.js b/tests/main-enterprise-installation-not-found.test.js new file mode 100644 index 00000000..a578967c --- /dev/null +++ b/tests/main-enterprise-installation-not-found.test.js @@ -0,0 +1,25 @@ +import { test } from "./main.js"; + +// Verify `main` handles when no enterprise installation is found. +await test((mockPool) => { + delete process.env.INPUT_OWNER; + delete process.env.INPUT_REPOSITORIES; + process.env.INPUT_ENTERPRISE = "test-enterprise"; + + // Mock the enterprise installation endpoint to return no matching installation + mockPool + .intercept({ + path: "/enterprises/test-enterprise/installation", + method: "GET", + headers: { + accept: "application/vnd.github.v3+json", + "user-agent": "actions/create-github-app-token", + // Intentionally omitting the `authorization` header, since JWT creation is not idempotent. + }, + }) + .reply( + 404, + { message: "Not Found" }, + { headers: { "content-type": "application/json" } } + ); +}); diff --git a/tests/main-enterprise-mutual-exclusivity-owner.test.js b/tests/main-enterprise-mutual-exclusivity-owner.test.js new file mode 100644 index 00000000..2c2b4131 --- /dev/null +++ b/tests/main-enterprise-mutual-exclusivity-owner.test.js @@ -0,0 +1,13 @@ +import { DEFAULT_ENV } from "./main.js"; + +// Verify `main` exits with an error when `enterprise` is used with `owner` input. +// Set up environment with enterprise and owner set +for (const [key, value] of Object.entries(DEFAULT_ENV)) { + process.env[key] = value; +} + +process.env.INPUT_ENTERPRISE = "test-enterprise"; +process.env.INPUT_OWNER = "test-owner"; + +const { default: promise } = await import("../main.js"); +await promise; diff --git a/tests/main-enterprise-mutual-exclusivity-repositories.test.js b/tests/main-enterprise-mutual-exclusivity-repositories.test.js new file mode 100644 index 00000000..795a82cc --- /dev/null +++ b/tests/main-enterprise-mutual-exclusivity-repositories.test.js @@ -0,0 +1,13 @@ +import { DEFAULT_ENV } from "./main.js"; + +// Verify `main` exits with an error when `enterprise` is used with `repositories` input. +// Set up environment with enterprise and repositories set +for (const [key, value] of Object.entries(DEFAULT_ENV)) { + process.env[key] = value; +} + +process.env.INPUT_ENTERPRISE = "test-enterprise"; +process.env.INPUT_REPOSITORIES = "repo1,repo2"; + +const { default: promise } = await import("../main.js"); +await promise; diff --git a/tests/main-enterprise-only-success.test.js b/tests/main-enterprise-only-success.test.js new file mode 100644 index 00000000..5008375e --- /dev/null +++ b/tests/main-enterprise-only-success.test.js @@ -0,0 +1,30 @@ +import { test } from "./main.js"; + +// Verify `main` successfully obtains a token when only the `enterprise` input is set. +await test((mockPool) => { + process.env.INPUT_ENTERPRISE = "test-enterprise"; + delete process.env.INPUT_OWNER; + delete process.env.INPUT_REPOSITORIES; + + // Mock the enterprise installation endpoint + const mockInstallationId = "123456"; + const mockAppSlug = "github-actions"; + mockPool + .intercept({ + path: "/enterprises/test-enterprise/installation", + method: "GET", + headers: { + accept: "application/vnd.github.v3+json", + "user-agent": "actions/create-github-app-token", + // Intentionally omitting the `authorization` header, since JWT creation is not idempotent. + }, + }) + .reply( + 200, + { + id: mockInstallationId, + app_slug: mockAppSlug, + }, + { headers: { "content-type": "application/json" } } + ); +}); diff --git a/tests/main-enterprise-token-permissions-set.test.js b/tests/main-enterprise-token-permissions-set.test.js new file mode 100644 index 00000000..2073e7b3 --- /dev/null +++ b/tests/main-enterprise-token-permissions-set.test.js @@ -0,0 +1,34 @@ +import { test } from "./main.js"; + +// Use a declared enterprise permission from the generated schema to verify +// enterprise token requests forward permission inputs to token creation. +await test((mockPool) => { + process.env.INPUT_ENTERPRISE = "test-enterprise"; + delete process.env.INPUT_OWNER; + delete process.env.INPUT_REPOSITORIES; + process.env[ + "INPUT_PERMISSION-ENTERPRISE-CUSTOM-PROPERTIES-FOR-ORGANIZATIONS" + ] = "read"; + + // Mock the enterprise installation endpoint + const mockInstallationId = "123456"; + const mockAppSlug = "github-actions"; + mockPool + .intercept({ + path: "/enterprises/test-enterprise/installation", + method: "GET", + headers: { + accept: "application/vnd.github.v3+json", + "user-agent": "actions/create-github-app-token", + // Intentionally omitting the `authorization` header, since JWT creation is not idempotent. + }, + }) + .reply( + 200, + { + id: mockInstallationId, + app_slug: mockAppSlug, + }, + { headers: { "content-type": "application/json" } } + ); +}); diff --git a/tests/main-token-get-owner-set-client-error.test.js b/tests/main-token-get-owner-set-client-error.test.js new file mode 100644 index 00000000..237b405f --- /dev/null +++ b/tests/main-token-get-owner-set-client-error.test.js @@ -0,0 +1,23 @@ +import { test } from "./main.js"; + +// Verify client errors are not retried when getting a token for a user or organization. +await test((mockPool) => { + process.env.INPUT_OWNER = "smockle"; + delete process.env.INPUT_REPOSITORIES; + + mockPool + .intercept({ + path: "/users/smockle/installation", + method: "GET", + headers: { + accept: "application/vnd.github.v3+json", + "user-agent": "actions/create-github-app-token", + // Intentionally omitting the `authorization` header, since JWT creation is not idempotent. + }, + }) + .reply( + 403, + { message: "Forbidden" }, + { headers: { "content-type": "application/json" } }, + ); +}); diff --git a/tests/main-token-get-owner-set-repo-network-error.test.js b/tests/main-token-get-owner-set-repo-network-error.test.js new file mode 100644 index 00000000..3da78f9e --- /dev/null +++ b/tests/main-token-get-owner-set-repo-network-error.test.js @@ -0,0 +1,39 @@ +import { test } from "./main.js"; + +// Verify transient network errors are retried when getting a repository token. +await test((mockPool) => { + process.env.INPUT_OWNER = "actions"; + process.env.INPUT_REPOSITORIES = "network-repo"; + const owner = process.env.INPUT_OWNER; + const repo = process.env.INPUT_REPOSITORIES; + const mockInstallationId = "123456"; + const mockAppSlug = "github-actions"; + + mockPool + .intercept({ + path: `/repos/${owner}/${repo}/installation`, + method: "GET", + headers: { + accept: "application/vnd.github.v3+json", + "user-agent": "actions/create-github-app-token", + // Intentionally omitting the `authorization` header, since JWT creation is not idempotent. + }, + }) + .replyWithError(new TypeError("fetch failed")); + + mockPool + .intercept({ + path: `/repos/${owner}/${repo}/installation`, + method: "GET", + headers: { + accept: "application/vnd.github.v3+json", + "user-agent": "actions/create-github-app-token", + // Intentionally omitting the `authorization` header, since JWT creation is not idempotent. + }, + }) + .reply( + 200, + { id: mockInstallationId, app_slug: mockAppSlug }, + { headers: { "content-type": "application/json" } }, + ); +}); From 8d835bfd37aa48fcb8e709925115857568d98bc4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 12:30:30 -0700 Subject: [PATCH 09/29] build(deps-dev): bump esbuild from 0.27.4 to 0.28.0 in the development-dependencies group (#365) Bumps the development-dependencies group with 1 update: [esbuild](https://github.com/evanw/esbuild). Updates `esbuild` from 0.27.4 to 0.28.0
Release notes

Sourced from esbuild's releases.

v0.28.0

  • Add support for with { type: 'text' } imports (#4435)

    The import text proposal has reached stage 3 in the TC39 process, which means that it's recommended for implementation. It has also already been implemented by Deno and Bun. So with this release, esbuild also adds support for it. This behaves exactly the same as esbuild's existing text loader. Here's an example:

    import string from './example.txt' with { type:
    'text' }
    console.log(string)
    
  • Add integrity checks to fallback download path (#4343)

    Installing esbuild via npm is somewhat complicated with several different edge cases (see esbuild's documentation for details). If the regular installation of esbuild's platform-specific package fails, esbuild's install script attempts to download the platform-specific package itself (first with the npm command, and then with a HTTP request to registry.npmjs.org as a last resort).

    This last resort path previously didn't have any integrity checks. With this release, esbuild will now verify that the hash of the downloaded binary matches the expected hash for the current release. This means the hashes for all of esbuild's platform-specific binary packages will now be embedded in the top-level esbuild package. Hopefully this should work without any problems. But just in case, this change is being done as a breaking change release.

  • Update the Go compiler from 1.25.7 to 1.26.1

    This upgrade should not affect anything. However, there have been some significant internal changes to the Go compiler, so esbuild could potentially behave differently in certain edge cases:

    • It now uses the new garbage collector that comes with Go 1.26.
    • The Go compiler is now more aggressive with allocating memory on the stack.
    • The executable format that the Go linker uses has undergone several changes.
    • The WebAssembly build now unconditionally makes use of the sign extension and non-trapping floating-point to integer conversion instructions.

    You can read the Go 1.26 release notes for more information.

v0.27.7

  • Fix lowering of define semantics for TypeScript parameter properties (#4421)

    The previous release incorrectly generated class fields for TypeScript parameter properties even when the configured target environment does not support class fields. With this release, the generated class fields will now be correctly lowered in this case:

    // Original code
    class Foo {
      constructor(public x = 1) {}
      y = 2
    }
    

    // Old output (with --loader=ts --target=es2021)
    class Foo {
    constructor(x = 1) {
    this.x = x;
    __publicField(this, "y", 2);
    }
    x;
    }

    // New output (with --loader=ts --target=es2021)
    class Foo {

... (truncated)

Changelog

Sourced from esbuild's changelog.

0.28.0

  • Add support for with { type: 'text' } imports (#4435)

    The import text proposal has reached stage 3 in the TC39 process, which means that it's recommended for implementation. It has also already been implemented by Deno and Bun. So with this release, esbuild also adds support for it. This behaves exactly the same as esbuild's existing text loader. Here's an example:

    import string from './example.txt' with { type:
    'text' }
    console.log(string)
    
  • Add integrity checks to fallback download path (#4343)

    Installing esbuild via npm is somewhat complicated with several different edge cases (see esbuild's documentation for details). If the regular installation of esbuild's platform-specific package fails, esbuild's install script attempts to download the platform-specific package itself (first with the npm command, and then with a HTTP request to registry.npmjs.org as a last resort).

    This last resort path previously didn't have any integrity checks. With this release, esbuild will now verify that the hash of the downloaded binary matches the expected hash for the current release. This means the hashes for all of esbuild's platform-specific binary packages will now be embedded in the top-level esbuild package. Hopefully this should work without any problems. But just in case, this change is being done as a breaking change release.

  • Update the Go compiler from 1.25.7 to 1.26.1

    This upgrade should not affect anything. However, there have been some significant internal changes to the Go compiler, so esbuild could potentially behave differently in certain edge cases:

    • It now uses the new garbage collector that comes with Go 1.26.
    • The Go compiler is now more aggressive with allocating memory on the stack.
    • The executable format that the Go linker uses has undergone several changes.
    • The WebAssembly build now unconditionally makes use of the sign extension and non-trapping floating-point to integer conversion instructions.

    You can read the Go 1.26 release notes for more information.

0.27.7

  • Fix lowering of define semantics for TypeScript parameter properties (#4421)

    The previous release incorrectly generated class fields for TypeScript parameter properties even when the configured target environment does not support class fields. With this release, the generated class fields will now be correctly lowered in this case:

    // Original code
    class Foo {
      constructor(public x = 1) {}
      y = 2
    }
    

    // Old output (with --loader=ts --target=es2021)
    class Foo {
    constructor(x = 1) {
    this.x = x;
    __publicField(this, "y", 2);
    }
    x;
    }

... (truncated)

Commits
  • 6a794df publish 0.28.0 to npm
  • 64ee0ea fix #4435: support with { type: text } imports
  • ef65aee fix sort order in snapshots_packagejson.txt
  • 1a26a8e try to fix test-old-ts, also shuffle CI tasks
  • 556ce6c use '' instead of null to omit build hashes
  • 8e675a8 ci: allow missing binary hashes for tests
  • 7067763 Reapply "update go 1.25.7 => 1.26.1"
  • 39473a9 fix #4343: integrity check for binary download
  • 2025c9f publish 0.27.7 to npm
  • c6b586e fix typo in Makefile for @esbuild/win32-x64
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=esbuild&package-manager=npm_and_yarn&previous-version=0.27.4&new-version=0.28.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 216 +++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 109 insertions(+), 109 deletions(-) diff --git a/package-lock.json b/package-lock.json index aa183a77..46e6b4b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "devDependencies": { "@octokit/openapi": "^22.0.0", "c8": "^11.0.0", - "esbuild": "^0.27.4", + "esbuild": "^0.28.0", "open-cli": "^9.0.0", "undici": "^7.24.6", "yaml": "^2.8.3" @@ -92,9 +92,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz", - "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", + "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", "cpu": [ "ppc64" ], @@ -109,9 +109,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz", - "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", + "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", "cpu": [ "arm" ], @@ -126,9 +126,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz", - "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", + "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", "cpu": [ "arm64" ], @@ -143,9 +143,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz", - "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", + "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", "cpu": [ "x64" ], @@ -160,9 +160,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz", - "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", + "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", "cpu": [ "arm64" ], @@ -177,9 +177,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz", - "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", + "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", "cpu": [ "x64" ], @@ -194,9 +194,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz", - "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", + "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", "cpu": [ "arm64" ], @@ -211,9 +211,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz", - "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", + "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", "cpu": [ "x64" ], @@ -228,9 +228,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz", - "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", + "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", "cpu": [ "arm" ], @@ -245,9 +245,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz", - "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", + "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", "cpu": [ "arm64" ], @@ -262,9 +262,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz", - "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", + "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", "cpu": [ "ia32" ], @@ -279,9 +279,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz", - "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", + "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", "cpu": [ "loong64" ], @@ -296,9 +296,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz", - "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", + "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", "cpu": [ "mips64el" ], @@ -313,9 +313,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz", - "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", + "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", "cpu": [ "ppc64" ], @@ -330,9 +330,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz", - "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", + "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", "cpu": [ "riscv64" ], @@ -347,9 +347,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz", - "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", + "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", "cpu": [ "s390x" ], @@ -364,9 +364,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz", - "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", + "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", "cpu": [ "x64" ], @@ -381,9 +381,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz", - "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", + "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", "cpu": [ "arm64" ], @@ -398,9 +398,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz", - "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", + "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", "cpu": [ "x64" ], @@ -415,9 +415,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz", - "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", + "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", "cpu": [ "arm64" ], @@ -432,9 +432,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz", - "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", + "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", "cpu": [ "x64" ], @@ -449,9 +449,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz", - "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", + "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", "cpu": [ "arm64" ], @@ -466,9 +466,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz", - "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", + "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", "cpu": [ "x64" ], @@ -483,9 +483,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz", - "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", + "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", "cpu": [ "arm64" ], @@ -500,9 +500,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz", - "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", + "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", "cpu": [ "ia32" ], @@ -517,9 +517,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz", - "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", + "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", "cpu": [ "x64" ], @@ -1023,9 +1023,9 @@ } }, "node_modules/esbuild": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz", - "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", + "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1036,32 +1036,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.4", - "@esbuild/android-arm": "0.27.4", - "@esbuild/android-arm64": "0.27.4", - "@esbuild/android-x64": "0.27.4", - "@esbuild/darwin-arm64": "0.27.4", - "@esbuild/darwin-x64": "0.27.4", - "@esbuild/freebsd-arm64": "0.27.4", - "@esbuild/freebsd-x64": "0.27.4", - "@esbuild/linux-arm": "0.27.4", - "@esbuild/linux-arm64": "0.27.4", - "@esbuild/linux-ia32": "0.27.4", - "@esbuild/linux-loong64": "0.27.4", - "@esbuild/linux-mips64el": "0.27.4", - "@esbuild/linux-ppc64": "0.27.4", - "@esbuild/linux-riscv64": "0.27.4", - "@esbuild/linux-s390x": "0.27.4", - "@esbuild/linux-x64": "0.27.4", - "@esbuild/netbsd-arm64": "0.27.4", - "@esbuild/netbsd-x64": "0.27.4", - "@esbuild/openbsd-arm64": "0.27.4", - "@esbuild/openbsd-x64": "0.27.4", - "@esbuild/openharmony-arm64": "0.27.4", - "@esbuild/sunos-x64": "0.27.4", - "@esbuild/win32-arm64": "0.27.4", - "@esbuild/win32-ia32": "0.27.4", - "@esbuild/win32-x64": "0.27.4" + "@esbuild/aix-ppc64": "0.28.0", + "@esbuild/android-arm": "0.28.0", + "@esbuild/android-arm64": "0.28.0", + "@esbuild/android-x64": "0.28.0", + "@esbuild/darwin-arm64": "0.28.0", + "@esbuild/darwin-x64": "0.28.0", + "@esbuild/freebsd-arm64": "0.28.0", + "@esbuild/freebsd-x64": "0.28.0", + "@esbuild/linux-arm": "0.28.0", + "@esbuild/linux-arm64": "0.28.0", + "@esbuild/linux-ia32": "0.28.0", + "@esbuild/linux-loong64": "0.28.0", + "@esbuild/linux-mips64el": "0.28.0", + "@esbuild/linux-ppc64": "0.28.0", + "@esbuild/linux-riscv64": "0.28.0", + "@esbuild/linux-s390x": "0.28.0", + "@esbuild/linux-x64": "0.28.0", + "@esbuild/netbsd-arm64": "0.28.0", + "@esbuild/netbsd-x64": "0.28.0", + "@esbuild/openbsd-arm64": "0.28.0", + "@esbuild/openbsd-x64": "0.28.0", + "@esbuild/openharmony-arm64": "0.28.0", + "@esbuild/sunos-x64": "0.28.0", + "@esbuild/win32-arm64": "0.28.0", + "@esbuild/win32-ia32": "0.28.0", + "@esbuild/win32-x64": "0.28.0" } }, "node_modules/escalade": { diff --git a/package.json b/package.json index 60bceff9..e3d31548 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "devDependencies": { "@octokit/openapi": "^22.0.0", "c8": "^11.0.0", - "esbuild": "^0.27.4", + "esbuild": "^0.28.0", "open-cli": "^9.0.0", "undici": "^7.24.6", "yaml": "^2.8.3" From e02e816e5591415258a53bf735aff57977dcd5e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 14:40:33 -0700 Subject: [PATCH 10/29] build(deps-dev): bump undici from 7.24.6 to 8.2.0 (#366) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [undici](https://github.com/nodejs/undici) from 7.24.6 to 8.2.0.
Release notes

Sourced from undici's releases.

v8.2.0

What's Changed

... (truncated)

Commits
  • bf684f7 Bumped v8.2.0 (#5152)
  • 0ca054a fix: replace stale pool clients under connection limit (#5145)
  • 7af90e9 perf: avoid redundant scans in BalancedPool dispatcher selection (#5146)
  • abb9d06 fix: validate H2CClient maxConcurrentStreams option (#5143)
  • 72a7591 perf(http2): avoid cloning headers when removing status (#5127)
  • 96fd5e9 fix(cache): allow streamed entries at maxEntrySize limit (#5129)
  • f41e53f perf: use byteLength property for binary body chunks (#5126)
  • bec4961 chore(deps): add lockfile (#5139)
  • 86f1242 perf(http2): reduce writeH2 per-request callback allocations (#5138)
  • cad3f70 perf(client): parse h1 content-length statelessly (#5124)
  • Additional commits viewable in compare view

--------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Parker Brown <17183625+parkerbxyz@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- package-lock.json | 10 +++++----- package.json | 2 +- tests/index.js | 8 +++++++- tests/main.js | 6 ++---- tests/mock-agent.js | 12 ++++++++++++ tests/post-revoke-token-fail-response.test.js | 6 ++---- tests/post-token-expired.test.js | 6 ++---- tests/post-token-set.test.js | 6 ++---- tests/post-token-skipped.test.js | 6 ++---- 9 files changed, 35 insertions(+), 27 deletions(-) create mode 100644 tests/mock-agent.js diff --git a/package-lock.json b/package-lock.json index 46e6b4b6..fca2c7ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "c8": "^11.0.0", "esbuild": "^0.28.0", "open-cli": "^9.0.0", - "undici": "^7.24.6", + "undici": "^8.2.0", "yaml": "^2.8.3" }, "engines": { @@ -1786,13 +1786,13 @@ } }, "node_modules/undici": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.6.tgz", - "integrity": "sha512-Xi4agocCbRzt0yYMZGMA6ApD7gvtUFaxm4ZmeacWI4cZxaF6C+8I8QfofC20NAePiB/IcvZmzkJ7XPa471AEtA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.2.0.tgz", + "integrity": "sha512-Z+4Hx9GE26Lh9Upwfnc8C7SsrpBPGaM/Gm6kMFtiG7c+5IvQKlXi/t+9x9DrrCh29cww5TSP9YdVaBcnLDs5fQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=20.18.1" + "node": ">=22.19.0" } }, "node_modules/unique-string": { diff --git a/package.json b/package.json index e3d31548..c616cfe4 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "c8": "^11.0.0", "esbuild": "^0.28.0", "open-cli": "^9.0.0", - "undici": "^7.24.6", + "undici": "^8.2.0", "yaml": "^2.8.3" } } diff --git a/tests/index.js b/tests/index.js index 74cf2723..159c21c7 100644 --- a/tests/index.js +++ b/tests/index.js @@ -22,7 +22,13 @@ function normalizeStderr(stderr) { const files = readdirSync("tests"); // Files to ignore -const ignore = ["index.js", "index.js.snapshot", "main.js", "README.md"]; +const ignore = [ + "index.js", + "index.js.snapshot", + "main.js", + "mock-agent.js", + "README.md", +]; const testFiles = files.filter((file) => !ignore.includes(file)).sort(); diff --git a/tests/main.js b/tests/main.js index a76c39a4..1edc6433 100644 --- a/tests/main.js +++ b/tests/main.js @@ -1,6 +1,6 @@ // Base for all `main` tests. // @ts-check -import { MockAgent, setGlobalDispatcher } from "undici"; +import { createMockAgent } from "./mock-agent.js"; export const DEFAULT_ENV = { GITHUB_REPOSITORY_OWNER: "actions", @@ -50,9 +50,7 @@ export async function test(cb = (_mockPool) => {}, env = DEFAULT_ENV) { // Set up mocking const baseUrl = new URL(env["INPUT_GITHUB-API-URL"]); const basePath = baseUrl.pathname === "/" ? "" : baseUrl.pathname; - const mockAgent = new MockAgent({ enableCallHistory: true }); - mockAgent.disableNetConnect(); - setGlobalDispatcher(mockAgent); + const mockAgent = createMockAgent({ enableCallHistory: true }); const mockPool = mockAgent.get(baseUrl.origin); // Calling `auth({ type: "app" })` to obtain a JWT doesn’t make network requests, so no need to intercept. diff --git a/tests/mock-agent.js b/tests/mock-agent.js new file mode 100644 index 00000000..fb93d502 --- /dev/null +++ b/tests/mock-agent.js @@ -0,0 +1,12 @@ +import { install, MockAgent, setGlobalDispatcher } from "undici"; + +// Ensure MockAgent intercepts requests made through global fetch. +install(); + +export function createMockAgent(options) { + const mockAgent = new MockAgent(options); + mockAgent.disableNetConnect(); + setGlobalDispatcher(mockAgent); + + return mockAgent; +} diff --git a/tests/post-revoke-token-fail-response.test.js b/tests/post-revoke-token-fail-response.test.js index b729b556..6318182d 100644 --- a/tests/post-revoke-token-fail-response.test.js +++ b/tests/post-revoke-token-fail-response.test.js @@ -1,4 +1,4 @@ -import { MockAgent, setGlobalDispatcher } from "undici"; +import { createMockAgent } from "./mock-agent.js"; // state variables are set as environment variables with the prefix STATE_ // https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#sending-values-to-the-pre-and-post-actions @@ -14,9 +14,7 @@ process.env.STATE_expiresAt = new Date( Date.now() + 1000 * 60 * 60 ).toISOString(); -const mockAgent = new MockAgent(); - -setGlobalDispatcher(mockAgent); +const mockAgent = createMockAgent(); // Provide the base url to the request const mockPool = mockAgent.get("https://api.github.com"); diff --git a/tests/post-token-expired.test.js b/tests/post-token-expired.test.js index 62caa6d8..beae3f2e 100644 --- a/tests/post-token-expired.test.js +++ b/tests/post-token-expired.test.js @@ -1,4 +1,4 @@ -import { MockAgent, setGlobalDispatcher } from "undici"; +import { createMockAgent } from "./mock-agent.js"; // state variables are set as environment variables with the prefix STATE_ // https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#sending-values-to-the-pre-and-post-actions @@ -11,9 +11,7 @@ process.env.STATE_expiresAt = new Date(Date.now() - 1000 * 60 * 60).toISOString( // https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#example-specifying-inputs process.env["INPUT_SKIP-TOKEN-REVOKE"] = "false"; -const mockAgent = new MockAgent(); - -setGlobalDispatcher(mockAgent); +const mockAgent = createMockAgent(); // Provide the base url to the request const mockPool = mockAgent.get("https://api.github.com"); diff --git a/tests/post-token-set.test.js b/tests/post-token-set.test.js index 8ae8c361..c90b4377 100644 --- a/tests/post-token-set.test.js +++ b/tests/post-token-set.test.js @@ -1,4 +1,4 @@ -import { MockAgent, setGlobalDispatcher } from "undici"; +import { createMockAgent } from "./mock-agent.js"; // state variables are set as environment variables with the prefix STATE_ // https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#sending-values-to-the-pre-and-post-actions @@ -12,9 +12,7 @@ process.env["INPUT_SKIP-TOKEN-REVOKE"] = "false"; // 1 hour in the future, not expired process.env.STATE_expiresAt = new Date(Date.now() + 1000 * 60 * 60).toISOString(); -const mockAgent = new MockAgent(); - -setGlobalDispatcher(mockAgent); +const mockAgent = createMockAgent(); // Provide the base url to the request const mockPool = mockAgent.get("https://api.github.com"); diff --git a/tests/post-token-skipped.test.js b/tests/post-token-skipped.test.js index f7560522..7c40d5b9 100644 --- a/tests/post-token-skipped.test.js +++ b/tests/post-token-skipped.test.js @@ -1,4 +1,4 @@ -import { MockAgent, setGlobalDispatcher } from "undici"; +import { createMockAgent } from "./mock-agent.js"; // state variables are set as environment variables with the prefix STATE_ // https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#sending-values-to-the-pre-and-post-actions @@ -8,9 +8,7 @@ process.env.STATE_token = "secret123"; // https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#example-specifying-inputs process.env["INPUT_SKIP-TOKEN-REVOKE"] = "true"; -const mockAgent = new MockAgent(); - -setGlobalDispatcher(mockAgent); +const mockAgent = createMockAgent(); // Provide the base url to the request const mockPool = mockAgent.get("https://api.github.com"); From c9aabb83728c3bd519212fa657ebc07e1f2a5dec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 14:51:43 -0700 Subject: [PATCH 11/29] build(deps-dev): bump yaml from 2.8.3 to 2.8.4 in the development-dependencies group (#371) Bumps the development-dependencies group with 1 update: [yaml](https://github.com/eemeli/yaml). Updates `yaml` from 2.8.3 to 2.8.4
Release notes

Sourced from yaml's releases.

v2.8.4

  • Disable alias resolution with maxAliasCount:0 (#677)
  • Handle invalid unicode escapes (e1a1a77)
  • Apply minFractionDigits only to decimal strings (#676)
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=yaml&package-manager=npm_and_yarn&previous-version=2.8.3&new-version=2.8.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index fca2c7ee..0ae4bcb0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "esbuild": "^0.28.0", "open-cli": "^9.0.0", "undici": "^8.2.0", - "yaml": "^2.8.3" + "yaml": "^2.8.4" }, "engines": { "node": ">=24.4.0" @@ -1966,9 +1966,9 @@ "dev": true }, "node_modules/yaml": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", - "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.4.tgz", + "integrity": "sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==", "dev": true, "license": "ISC", "bin": { diff --git a/package.json b/package.json index c616cfe4..0fd488c5 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,6 @@ "esbuild": "^0.28.0", "open-cli": "^9.0.0", "undici": "^8.2.0", - "yaml": "^2.8.3" + "yaml": "^2.8.4" } } From 85eb8dd41472213aed25d1a126460e0069138ab6 Mon Sep 17 00:00:00 2001 From: Parker Brown <17183625+parkerbxyz@users.noreply.github.com> Date: Mon, 11 May 2026 12:10:57 -0700 Subject: [PATCH 12/29] feat: support full repository names in `repositories` input (#372) The `repositories` input currently treats values like `${{ github.repository }}` as a repository name, which can produce a duplicated owner in the installation lookup. This changes repository target resolution so entries may be bare repository names or full `owner/repository` names, while preserving the existing resolved owner behavior. Full repository names are accepted only when their owner matches the `owner` input, or the current repository owner when `owner` is unset. The action still creates a single installation token for one owner, and generated `dist` artifacts are left unchanged for release. Fixes: #177 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- README.md | 8 ++ action.yml | 2 +- lib/main.js | 50 ++++++++- tests/index.js.snapshot | 106 ++++++++++++++++++ ...token-get-owner-set-repo-full-name.test.js | 8 ++ ...-get-owner-set-repo-invalid-format.test.js | 13 +++ ...ner-set-repo-non-current-full-name.test.js | 12 ++ ...-get-owner-set-repo-owner-mismatch.test.js | 13 +++ ...wner-unset-repo-full-name-and-bare.test.js | 8 ++ ...et-owner-unset-repo-owner-mismatch.test.js | 13 +++ tests/main.js | 7 +- 11 files changed, 232 insertions(+), 8 deletions(-) create mode 100644 tests/main-token-get-owner-set-repo-full-name.test.js create mode 100644 tests/main-token-get-owner-set-repo-invalid-format.test.js create mode 100644 tests/main-token-get-owner-set-repo-non-current-full-name.test.js create mode 100644 tests/main-token-get-owner-set-repo-owner-mismatch.test.js create mode 100644 tests/main-token-get-owner-unset-repo-full-name-and-bare.test.js create mode 100644 tests/main-token-get-owner-unset-repo-owner-mismatch.test.js diff --git a/README.md b/README.md index 43257164..849dc84e 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,12 @@ jobs: body: "Hello, World!" ``` +You can include the current repository in the list with `${{ github.repository }}`: + +```yaml +repositories: ${{ github.repository }},repo2 +``` + ### Create a token for all repositories in another owner's installation ```yaml @@ -377,6 +383,8 @@ steps: > [!NOTE] > If `owner` is set and `repositories` is empty, access will be scoped to all repositories in the provided repository owner's installation. If `owner` and `repositories` are empty, access will be scoped to only the current repository. +> +> Repository entries may include an owner, for example `owner/repo1`. The owner portion must match the `owner` input, or the current repository owner if `owner` is unset. ### `enterprise` diff --git a/action.yml b/action.yml index a4e11487..9f45ab3e 100644 --- a/action.yml +++ b/action.yml @@ -19,7 +19,7 @@ inputs: description: "The owner of the GitHub App installation (defaults to current repository owner)" required: false repositories: - description: "Comma or newline-separated list of repositories to install the GitHub App on (defaults to current repository if owner is unset)" + description: "Comma or newline-separated list of repositories to grant the token access to (defaults to current repository if owner is unset)" required: false enterprise: description: "The slug of the enterprise account where the GitHub App is installed (cannot be used with 'owner' or 'repositories')" diff --git a/lib/main.js b/lib/main.js index 8fe0942a..7108c3e5 100644 --- a/lib/main.js +++ b/lib/main.js @@ -86,29 +86,67 @@ function resolveInstallationTarget(enterprise, owner, repositories, core) { return { type: "owner", owner }; } - const parsedOwner = owner || String(process.env.GITHUB_REPOSITORY_OWNER); + const target = normalizeRepositoryTarget(owner, repositories); if (!owner) { core.info( - `No 'owner' input provided. Using default owner '${parsedOwner}' to create token for the following repositories:${repositories - .map((repo) => `\n- ${parsedOwner}/${repo}`) + `No 'owner' input provided. Using default owner '${target.owner}' to create token for the following repositories:${target.repositories + .map((repo) => `\n- ${target.owner}/${repo}`) .join("")}` ); } else { core.info( - `Inputs 'owner' and 'repositories' are set. Creating token for the following repositories:${repositories - .map((repo) => `\n- ${parsedOwner}/${repo}`) + `Inputs 'owner' and 'repositories' are set. Creating token for the following repositories:${target.repositories + .map((repo) => `\n- ${target.owner}/${repo}`) .join("")}` ); } return { type: "repository", + owner: target.owner, + repositories: target.repositories, + }; +} + +function normalizeRepositoryTarget(owner, repositories) { + const parsedOwner = owner || String(process.env.GITHUB_REPOSITORY_OWNER); + const parsedRepositories = repositories.map(parseRepositoryInput); + + const mismatchedRepository = parsedRepositories.find( + (repository) => + repository.owner && + repository.owner.toLowerCase() !== parsedOwner.toLowerCase() + ); + + if (mismatchedRepository) { + throw new Error( + `Repository '${mismatchedRepository.input}' includes owner '${mismatchedRepository.owner}', which does not match the resolved owner '${parsedOwner}'.` + ); + } + + return { owner: parsedOwner, - repositories, + repositories: parsedRepositories.map((repository) => repository.name), }; } +function parseRepositoryInput(input) { + const parts = input.split("/"); + + if (parts.length === 1 && parts[0]) { + return { input, owner: "", name: parts[0] }; + } + + if (parts.length === 2 && parts[0] && parts[1]) { + return { input, owner: parts[0], name: parts[1] }; + } + + throw new Error( + `Invalid repository '${input}'. Expected 'repository' or 'owner/repository'.` + ); +} + function getTokenRetryDescription(target) { switch (target.type) { case "enterprise": diff --git a/tests/index.js.snapshot b/tests/index.js.snapshot index a77b6fa1..10372182 100644 --- a/tests/index.js.snapshot +++ b/tests/index.js.snapshot @@ -296,6 +296,42 @@ POST /app/installations/123456/access_tokens {"repositories":["failed-repo"]} `; +exports[`main-token-get-owner-set-repo-full-name.test.js > stdout 1`] = ` +Inputs 'owner' and 'repositories' are set. Creating token for the following repositories: +- actions/create-github-app-token +::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a + +::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a + +::set-output name=installation-id::123456 + +::set-output name=app-slug::github-actions +::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a +::save-state name=expiresAt::2016-07-11T22:14:10Z +--- REQUESTS --- +GET /repos/actions/create-github-app-token/installation +POST /app/installations/123456/access_tokens +{"repositories":["create-github-app-token"]} +`; + +exports[`main-token-get-owner-set-repo-invalid-format.test.js > stderr 1`] = ` +Error: Invalid repository 'octocat/hello-world/extra'. Expected 'repository' or 'owner/repository'. + at parseRepositoryInput (file:///lib/main.js::) + at Array.map () + at normalizeRepositoryTarget (file:///lib/main.js::) + at resolveInstallationTarget (file:///lib/main.js::) + at main (file:///lib/main.js::) + at run (file:///main.js::) + at file:///main.js:: + at ModuleJob.run (node:internal/modules/esm/module_job::) + at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader::) + at async file:///tests/main-token-get-owner-set-repo-invalid-format.test.js:: +`; + +exports[`main-token-get-owner-set-repo-invalid-format.test.js > stdout 1`] = ` +::error::Invalid repository 'octocat/hello-world/extra'. Expected 'repository' or 'owner/repository'. +`; + exports[`main-token-get-owner-set-repo-network-error.test.js > stdout 1`] = ` Inputs 'owner' and 'repositories' are set. Creating token for the following repositories: - actions/network-repo @@ -316,6 +352,41 @@ POST /app/installations/123456/access_tokens {"repositories":["network-repo"]} `; +exports[`main-token-get-owner-set-repo-non-current-full-name.test.js > stdout 1`] = ` +Inputs 'owner' and 'repositories' are set. Creating token for the following repositories: +- actions/toolkit +- actions/checkout +::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a + +::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a + +::set-output name=installation-id::123456 + +::set-output name=app-slug::github-actions +::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a +::save-state name=expiresAt::2016-07-11T22:14:10Z +--- REQUESTS --- +GET /repos/actions/toolkit/installation +POST /app/installations/123456/access_tokens +{"repositories":["toolkit","checkout"]} +`; + +exports[`main-token-get-owner-set-repo-owner-mismatch.test.js > stderr 1`] = ` +Error: Repository 'octocat/hello-world' includes owner 'octocat', which does not match the resolved owner 'actions'. + at normalizeRepositoryTarget (file:///lib/main.js::) + at resolveInstallationTarget (file:///lib/main.js::) + at main (file:///lib/main.js::) + at run (file:///main.js::) + at file:///main.js:: + at ModuleJob.run (node:internal/modules/esm/module_job::) + at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader::) + at async file:///tests/main-token-get-owner-set-repo-owner-mismatch.test.js:: +`; + +exports[`main-token-get-owner-set-repo-owner-mismatch.test.js > stdout 1`] = ` +::error::Repository 'octocat/hello-world' includes owner 'octocat', which does not match the resolved owner 'actions'. +`; + exports[`main-token-get-owner-set-repo-set-to-many-newline.test.js > stdout 1`] = ` Inputs 'owner' and 'repositories' are set. Creating token for the following repositories: - actions/create-github-app-token @@ -391,6 +462,41 @@ POST /app/installations/123456/access_tokens null `; +exports[`main-token-get-owner-unset-repo-full-name-and-bare.test.js > stdout 1`] = ` +No 'owner' input provided. Using default owner 'actions' to create token for the following repositories: +- actions/create-github-app-token +- actions/toolkit +::add-mask::ghs_16C7e42F292c6912E7710c838347Ae178B4a + +::set-output name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a + +::set-output name=installation-id::123456 + +::set-output name=app-slug::github-actions +::save-state name=token::ghs_16C7e42F292c6912E7710c838347Ae178B4a +::save-state name=expiresAt::2016-07-11T22:14:10Z +--- REQUESTS --- +GET /repos/actions/create-github-app-token/installation +POST /app/installations/123456/access_tokens +{"repositories":["create-github-app-token","toolkit"]} +`; + +exports[`main-token-get-owner-unset-repo-owner-mismatch.test.js > stderr 1`] = ` +Error: Repository 'octocat/hello-world' includes owner 'octocat', which does not match the resolved owner 'actions'. + at normalizeRepositoryTarget (file:///lib/main.js::) + at resolveInstallationTarget (file:///lib/main.js::) + at main (file:///lib/main.js::) + at run (file:///main.js::) + at file:///main.js:: + at ModuleJob.run (node:internal/modules/esm/module_job::) + at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader::) + at async file:///tests/main-token-get-owner-unset-repo-owner-mismatch.test.js:: +`; + +exports[`main-token-get-owner-unset-repo-owner-mismatch.test.js > stdout 1`] = ` +::error::Repository 'octocat/hello-world' includes owner 'octocat', which does not match the resolved owner 'actions'. +`; + exports[`main-token-get-owner-unset-repo-set.test.js > stdout 1`] = ` No 'owner' input provided. Using default owner 'actions' to create token for the following repositories: - actions/create-github-app-token diff --git a/tests/main-token-get-owner-set-repo-full-name.test.js b/tests/main-token-get-owner-set-repo-full-name.test.js new file mode 100644 index 00000000..856a910b --- /dev/null +++ b/tests/main-token-get-owner-set-repo-full-name.test.js @@ -0,0 +1,8 @@ +import { test } from "./main.js"; + +// Verify `main` successfully obtains a token when the `owner` and `repositories` inputs are set, and `repositories` contains a full repository name. +await test(() => { + process.env.INPUT_OWNER = process.env.GITHUB_REPOSITORY_OWNER; + process.env.INPUT_REPOSITORIES = process.env.GITHUB_REPOSITORY; +}); + diff --git a/tests/main-token-get-owner-set-repo-invalid-format.test.js b/tests/main-token-get-owner-set-repo-invalid-format.test.js new file mode 100644 index 00000000..78014eda --- /dev/null +++ b/tests/main-token-get-owner-set-repo-invalid-format.test.js @@ -0,0 +1,13 @@ +import { DEFAULT_ENV } from "./main.js"; + +// Verify `main` exits with an error when a repository entry is neither a repository name nor an owner/repository name. +for (const [key, value] of Object.entries(DEFAULT_ENV)) { + process.env[key] = value; +} + +process.env.INPUT_OWNER = process.env.GITHUB_REPOSITORY_OWNER; +process.env.INPUT_REPOSITORIES = "octocat/hello-world/extra"; + +const { default: promise } = await import("../main.js"); +await promise; + diff --git a/tests/main-token-get-owner-set-repo-non-current-full-name.test.js b/tests/main-token-get-owner-set-repo-non-current-full-name.test.js new file mode 100644 index 00000000..d73c3472 --- /dev/null +++ b/tests/main-token-get-owner-set-repo-non-current-full-name.test.js @@ -0,0 +1,12 @@ +import { DEFAULT_ENV, test } from "./main.js"; + +// Verify `main` normalizes full repository names before installation lookup and token scoping. +await test( + () => {}, + { + ...DEFAULT_ENV, + INPUT_OWNER: DEFAULT_ENV.GITHUB_REPOSITORY_OWNER, + INPUT_REPOSITORIES: `${DEFAULT_ENV.GITHUB_REPOSITORY_OWNER}/toolkit,checkout`, + }, +); + diff --git a/tests/main-token-get-owner-set-repo-owner-mismatch.test.js b/tests/main-token-get-owner-set-repo-owner-mismatch.test.js new file mode 100644 index 00000000..2a7897b6 --- /dev/null +++ b/tests/main-token-get-owner-set-repo-owner-mismatch.test.js @@ -0,0 +1,13 @@ +import { DEFAULT_ENV } from "./main.js"; + +// Verify `main` exits with an error when a full repository name does not match the `owner` input. +for (const [key, value] of Object.entries(DEFAULT_ENV)) { + process.env[key] = value; +} + +process.env.INPUT_OWNER = process.env.GITHUB_REPOSITORY_OWNER; +process.env.INPUT_REPOSITORIES = "octocat/hello-world"; + +const { default: promise } = await import("../main.js"); +await promise; + diff --git a/tests/main-token-get-owner-unset-repo-full-name-and-bare.test.js b/tests/main-token-get-owner-unset-repo-full-name-and-bare.test.js new file mode 100644 index 00000000..5fff1689 --- /dev/null +++ b/tests/main-token-get-owner-unset-repo-full-name-and-bare.test.js @@ -0,0 +1,8 @@ +import { test } from "./main.js"; + +// Verify `main` successfully obtains a token when `owner` is omitted and `repositories` mixes a full repository name with bare repository names. +await test(() => { + delete process.env.INPUT_OWNER; + process.env.INPUT_REPOSITORIES = `${process.env.GITHUB_REPOSITORY},toolkit`; +}); + diff --git a/tests/main-token-get-owner-unset-repo-owner-mismatch.test.js b/tests/main-token-get-owner-unset-repo-owner-mismatch.test.js new file mode 100644 index 00000000..b7ba367a --- /dev/null +++ b/tests/main-token-get-owner-unset-repo-owner-mismatch.test.js @@ -0,0 +1,13 @@ +import { DEFAULT_ENV } from "./main.js"; + +// Verify `main` exits with an error when a full repository name does not match the default owner. +for (const [key, value] of Object.entries(DEFAULT_ENV)) { + process.env[key] = value; +} + +delete process.env.INPUT_OWNER; +process.env.INPUT_REPOSITORIES = "octocat/hello-world"; + +const { default: promise } = await import("../main.js"); +await promise; + diff --git a/tests/main.js b/tests/main.js index 1edc6433..3874dbc6 100644 --- a/tests/main.js +++ b/tests/main.js @@ -60,8 +60,13 @@ export async function test(cb = (_mockPool) => {}, env = DEFAULT_ENV) { const mockAppSlug = "github-actions"; const owner = env.INPUT_OWNER ?? env.GITHUB_REPOSITORY_OWNER; const currentRepoName = env.GITHUB_REPOSITORY.split("/")[1]; + const firstRepositoryInput = + (env.INPUT_REPOSITORIES ?? currentRepoName) + .split(/[\n,]+/) + .map((repository) => repository.trim()) + .find(Boolean) ?? currentRepoName; const repo = encodeURIComponent( - (env.INPUT_REPOSITORIES ?? currentRepoName).split(",")[0] + firstRepositoryInput.split("/").pop() || firstRepositoryInput ); mockPool From fd2801133e469d2950f2c5af5e591d6b2ad833c8 Mon Sep 17 00:00:00 2001 From: "Yamamoto, Hirotaka" Date: Tue, 12 May 2026 12:09:36 +0900 Subject: [PATCH 13/29] docs: update procedure to configure Git (#287) The current procedure for configuring `git` does not allow it to push commits besides the current repository, even if the app token may have access to other repositories. It also does not allow `git` to clone such a repository. This new procedure configures `gh` first and then calls `gh auth setup-git` to configure `git` so it will work for any repository that the token has access to. --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 849dc84e..5882413c 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,7 @@ jobs: # required client-id: ${{ vars.APP_CLIENT_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} + permission-contents: write - name: Get GitHub App User ID id: get-user-id run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT" @@ -112,7 +113,10 @@ jobs: - run: | git config --global user.name '${{ steps.app-token.outputs.app-slug }}[bot]' git config --global user.email '${{ steps.get-user-id.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com' - # git commands like commit work using the bot user + gh auth setup-git + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + # git commands like commit and push work using the bot user - run: | git add . git commit -m "Auto-generated changes" From 363531b6d972a60a00b3f1e6bb139e5e6c764cd9 Mon Sep 17 00:00:00 2001 From: Parker Brown <17183625+parkerbxyz@users.noreply.github.com> Date: Mon, 11 May 2026 20:21:09 -0700 Subject: [PATCH 14/29] docs: capitalize Git as a proper noun in README (#374) Capitalizes "Git" in three README locations where it refers to the version control system as a proper noun; lowercase `git` command invocations are unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5882413c..00ca19dd 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ jobs: github_token: ${{ steps.app-token.outputs.token }} ``` -### Create a git committer string for an app installation +### Create a Git committer string for an app installation ```yaml on: [pull_request] @@ -89,7 +89,7 @@ jobs: - run: echo "committer string is ${{ steps.committer.outputs.string }}" ``` -### Configure git CLI for an app's bot user +### Configure Git CLI for an app's bot user ```yaml on: [pull_request] @@ -116,7 +116,7 @@ jobs: gh auth setup-git env: GH_TOKEN: ${{ steps.app-token.outputs.token }} - # git commands like commit and push work using the bot user + # Git commands like commit and push work using the bot user - run: | git add . git commit -m "Auto-generated changes" From f24bbd89643991c0de27ae823c01791b2c6bafdd Mon Sep 17 00:00:00 2001 From: Parker Brown <17183625+parkerbxyz@users.noreply.github.com> Date: Tue, 12 May 2026 16:05:46 -0700 Subject: [PATCH 15/29] fix: validate private-key input (#376) ## Summary When `private-key` resolves to an empty value, the action currently lets Octokit fail with `[@octokit/auth-app] privateKey option is required`, which points at an implementation detail instead of the action input. This adds action-level validation so users get the same non-empty input guidance used for missing `client-id` or `app-id`. - Validate `private-key` before creating app auth - Add a regression test and snapshot for the missing private key path - Leave valid private key handling unchanged, including escaped newlines Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- main.js | 3 +++ tests/index.js.snapshot | 8 ++++++++ tests/main-missing-private-key.test.js | 19 +++++++++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 tests/main-missing-private-key.test.js diff --git a/main.js b/main.js index a44409ab..19730411 100644 --- a/main.js +++ b/main.js @@ -23,6 +23,9 @@ async function run() { throw new Error("The 'client-id' (or deprecated 'app-id') input must be set to a non-empty string. If using a secret or variable, ensure it is available in this workflow context."); } const privateKey = core.getInput("private-key"); + if (!privateKey) { + throw new Error("The 'private-key' input must be set to a non-empty string. If using a secret or variable, ensure it is available in this workflow context."); + } const enterprise = core.getInput("enterprise"); const owner = core.getInput("owner"); const repositories = core diff --git a/tests/index.js.snapshot b/tests/index.js.snapshot index 10372182..2c88dc4e 100644 --- a/tests/index.js.snapshot +++ b/tests/index.js.snapshot @@ -165,6 +165,14 @@ exports[`main-missing-owner.test.js > stderr 1`] = ` GITHUB_REPOSITORY_OWNER missing, must be set to '' `; +exports[`main-missing-private-key.test.js > stderr 1`] = ` +The 'private-key' input must be set to a non-empty string. If using a secret or variable, ensure it is available in this workflow context. +`; + +exports[`main-missing-private-key.test.js > stdout 1`] = ` +::error::The 'private-key' input must be set to a non-empty string. If using a secret or variable, ensure it is available in this workflow context. +`; + exports[`main-missing-repository.test.js > stderr 1`] = ` GITHUB_REPOSITORY missing, must be set to '/' `; diff --git a/tests/main-missing-private-key.test.js b/tests/main-missing-private-key.test.js new file mode 100644 index 00000000..95be5132 --- /dev/null +++ b/tests/main-missing-private-key.test.js @@ -0,0 +1,19 @@ +import { DEFAULT_ENV } from "./main.js"; + +for (const [key, value] of Object.entries({ + ...DEFAULT_ENV, + "INPUT_PRIVATE-KEY": "", +})) { + process.env[key] = value; +} + +// Log only the error message, not the full stack trace, because the stack +// trace contains environment-specific paths and ANSI codes that differ +// between local and CI environments. +const _error = console.error; +console.error = (err) => _error(err?.message ?? err); + +// Verify `main` exits with an error when `private-key` is not set. +const { default: promise } = await import("../main.js"); +await promise; +process.exitCode = 0; From bcd2ba49218906704ab6c1aa796996da409d3eb1 Mon Sep 17 00:00:00 2001 From: "create-app-token-action-releaser[bot]" <135574722+create-app-token-action-releaser[bot]@users.noreply.github.com> Date: Tue, 12 May 2026 16:31:18 -0700 Subject: [PATCH 16/29] chore(main): release 3.2.0 (#370) :robot: I have created a release *beep* *boop* --- ## [3.2.0](https://github.com/actions/create-github-app-token/compare/v3.1.1...v3.2.0) (2026-05-12) ### Features * add support for enterprise-level GitHub Apps ([#263](https://github.com/actions/create-github-app-token/issues/263)) ([952a2a7](https://github.com/actions/create-github-app-token/commit/952a2a7073df6bfa5f49bc469ec895b6ec1acea4)) * support full repository names in `repositories` input ([#372](https://github.com/actions/create-github-app-token/issues/372)) ([85eb8dd](https://github.com/actions/create-github-app-token/commit/85eb8dd41472213aed25d1a126460e0069138ab6)) ### Bug Fixes * **deps:** bump @actions/core from 3.0.0 to 3.0.1 in the production-dependencies group ([#364](https://github.com/actions/create-github-app-token/issues/364)) ([43e5c34](https://github.com/actions/create-github-app-token/commit/43e5c345bfd4d4f3ecea019ad0042001a09dd857)) * validate private-key input ([#376](https://github.com/actions/create-github-app-token/issues/376)) ([f24bbd8](https://github.com/actions/create-github-app-token/commit/f24bbd89643991c0de27ae823c01791b2c6bafdd)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: create-app-token-action-releaser[bot] <135574722+create-app-token-action-releaser[bot]@users.noreply.github.com> Co-authored-by: parkerbxyz <17183625+parkerbxyz@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 15 ++++++++++++ dist/main.cjs | 43 ++++++++++++++++++++++++++++++----- package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 56 insertions(+), 10 deletions(-) create mode 100644 CHANGELOG.md diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b4b8d0ff..95a37e3e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "3.1.1" + ".": "3.2.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..3dfff070 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,15 @@ +# Changelog + +## [3.2.0](https://github.com/actions/create-github-app-token/compare/v3.1.1...v3.2.0) (2026-05-12) + + +### Features + +* add support for enterprise-level GitHub Apps ([#263](https://github.com/actions/create-github-app-token/issues/263)) ([952a2a7](https://github.com/actions/create-github-app-token/commit/952a2a7073df6bfa5f49bc469ec895b6ec1acea4)) +* support full repository names in `repositories` input ([#372](https://github.com/actions/create-github-app-token/issues/372)) ([85eb8dd](https://github.com/actions/create-github-app-token/commit/85eb8dd41472213aed25d1a126460e0069138ab6)) + + +### Bug Fixes + +* **deps:** bump @actions/core from 3.0.0 to 3.0.1 in the production-dependencies group ([#364](https://github.com/actions/create-github-app-token/issues/364)) ([43e5c34](https://github.com/actions/create-github-app-token/commit/43e5c345bfd4d4f3ecea019ad0042001a09dd857)) +* validate private-key input ([#376](https://github.com/actions/create-github-app-token/issues/376)) ([f24bbd8](https://github.com/actions/create-github-app-token/commit/f24bbd89643991c0de27ae823c01791b2c6bafdd)) diff --git a/dist/main.cjs b/dist/main.cjs index dc716995..20b90dce 100644 --- a/dist/main.cjs +++ b/dist/main.cjs @@ -23241,24 +23241,52 @@ function resolveInstallationTarget(enterprise, owner, repositories, core) { ); return { type: "owner", owner }; } - const parsedOwner = owner || String(process.env.GITHUB_REPOSITORY_OWNER); + const target = normalizeRepositoryTarget(owner, repositories); if (!owner) { core.info( - `No 'owner' input provided. Using default owner '${parsedOwner}' to create token for the following repositories:${repositories.map((repo) => ` -- ${parsedOwner}/${repo}`).join("")}` + `No 'owner' input provided. Using default owner '${target.owner}' to create token for the following repositories:${target.repositories.map((repo) => ` +- ${target.owner}/${repo}`).join("")}` ); } else { core.info( - `Inputs 'owner' and 'repositories' are set. Creating token for the following repositories:${repositories.map((repo) => ` -- ${parsedOwner}/${repo}`).join("")}` + `Inputs 'owner' and 'repositories' are set. Creating token for the following repositories:${target.repositories.map((repo) => ` +- ${target.owner}/${repo}`).join("")}` ); } return { type: "repository", + owner: target.owner, + repositories: target.repositories + }; +} +function normalizeRepositoryTarget(owner, repositories) { + const parsedOwner = owner || String(process.env.GITHUB_REPOSITORY_OWNER); + const parsedRepositories = repositories.map(parseRepositoryInput); + const mismatchedRepository = parsedRepositories.find( + (repository) => repository.owner && repository.owner.toLowerCase() !== parsedOwner.toLowerCase() + ); + if (mismatchedRepository) { + throw new Error( + `Repository '${mismatchedRepository.input}' includes owner '${mismatchedRepository.owner}', which does not match the resolved owner '${parsedOwner}'.` + ); + } + return { owner: parsedOwner, - repositories + repositories: parsedRepositories.map((repository) => repository.name) }; } +function parseRepositoryInput(input) { + const parts = input.split("/"); + if (parts.length === 1 && parts[0]) { + return { input, owner: "", name: parts[0] }; + } + if (parts.length === 2 && parts[0] && parts[1]) { + return { input, owner: parts[0], name: parts[1] }; + } + throw new Error( + `Invalid repository '${input}'. Expected 'repository' or 'owner/repository'.` + ); +} function getTokenRetryDescription(target) { switch (target.type) { case "enterprise": @@ -23397,6 +23425,9 @@ async function run() { throw new Error("The 'client-id' (or deprecated 'app-id') input must be set to a non-empty string. If using a secret or variable, ensure it is available in this workflow context."); } const privateKey = getInput("private-key"); + if (!privateKey) { + throw new Error("The 'private-key' input must be set to a non-empty string. If using a secret or variable, ensure it is available in this workflow context."); + } const enterprise = getInput("enterprise"); const owner = getInput("owner"); const repositories = getInput("repositories").split(/[\n,]+/).map((s) => s.trim()).filter((x) => x !== ""); diff --git a/package-lock.json b/package-lock.json index 0ae4bcb0..6120d7e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "create-github-app-token", - "version": "3.1.1", + "version": "3.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "create-github-app-token", - "version": "3.1.1", + "version": "3.2.0", "license": "MIT", "dependencies": { "@actions/core": "^3.0.1", diff --git a/package.json b/package.json index 0fd488c5..0584f703 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "create-github-app-token", "private": true, "type": "module", - "version": "3.1.1", + "version": "3.2.0", "description": "GitHub Action for creating a GitHub App Installation Access Token", "engines": { "node": ">=24.4.0" From d6ebfe3883ae9ebb719ed86c99c1d83daa3a8b9a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2026 14:43:24 -0700 Subject: [PATCH 17/29] build(deps-dev): bump the development-dependencies group across 1 directory with 3 updates (#385) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the development-dependencies group with 3 updates in the / directory: [esbuild](https://github.com/evanw/esbuild), [undici](https://github.com/nodejs/undici) and [yaml](https://github.com/eemeli/yaml). Updates `esbuild` from 0.28.0 to 0.28.1
Release notes

Sourced from esbuild's releases.

v0.28.1

  • Disallow \ in local development server HTTP requests (GHSA-g7r4-m6w7-qqqr)

    This release fixes a security issue where HTTP requests to esbuild's local development server could traverse outside of the serve directory on Windows using a \ backslash character. It happened due to the use of Go's path.Clean() function, which only handles Unix-style / characters. HTTP requests with paths containing \ are no longer allowed.

    Thanks to @​dellalibera for reporting this issue.

  • Add integrity checks to the Deno API (GHSA-gv7w-rqvm-qjhr)

    The previous release of esbuild added integrity checks to esbuild's npm install script. This release also adds integrity checks to esbuild's Deno install script. Now esbuild's Deno API will also fail with an error if the downloaded esbuild binary contains something other than the expected content.

    Note that esbuild's Deno API installs from registry.npmjs.org by default, but allows the NPM_CONFIG_REGISTRY environment variable to override this with a custom package registry. This change means that the esbuild executable served by NPM_CONFIG_REGISTRY must now match the expected content.

    Thanks to @​sondt99 for reporting this issue.

  • Avoid inlining using and await using declarations (#4482)

    Previously esbuild's minifier sometimes incorrectly inlined using and await using declarations into subsequent uses of that declaration, which then fails to dispose of the resource correctly. This bug happened because inlining was done for let and const declarations by avoiding doing it for var declarations, which no longer worked when more declaration types were added. Here's an example:

    // Original code
    {
      using x = new Resource()
      x.activate()
    }
    

    // Old output (with --minify)
    new Resource().activate();

    // New output (with --minify)
    {using e=new Resource;e.activate()}

  • Fix module evaluation when an error is thrown (#4461, #4467)

    If an error is thrown during module evaluation, esbuild previously didn't preserve the state of the module for subsequent module references. This was observable if import() or require() is used to import a module multiple times. The thrown error is supposed to be thrown by every call to import() or require(), not just the first. With this release, esbuild will now throw the same error every time you call import() or require() on a module that throws during its evaluation.

  • Fix some edge cases around the new operator (#4477)

    Previously esbuild incorrectly printed certain edge cases involving complex expressions inside the target of a new expression (specifically an optional chain and/or a tagged template literal). The generated code for the new target was not correctly wrapped with parentheses, and either contained a syntax error or had different semantics. These edge cases have been fixed so that they now correctly wrap the new target in parentheses. Here is an example of some affected code:

    // Original code
    new (foo()`bar`)()
    new (foo()?.bar)()
    

    // Old output
    new foo()bar();
    new (foo())?.bar();

... (truncated)

Changelog

Sourced from esbuild's changelog.

0.28.1

  • Disallow \ in local development server HTTP requests (GHSA-g7r4-m6w7-qqqr)

    This release fixes a security issue where HTTP requests to esbuild's local development server could traverse outside of the serve directory on Windows using a \ backslash character. It happened due to the use of Go's path.Clean() function, which only handles Unix-style / characters. HTTP requests with paths containing \ are no longer allowed.

    Thanks to @​dellalibera for reporting this issue.

  • Add integrity checks to the Deno API (GHSA-gv7w-rqvm-qjhr)

    The previous release of esbuild added integrity checks to esbuild's npm install script. This release also adds integrity checks to esbuild's Deno install script. Now esbuild's Deno API will also fail with an error if the downloaded esbuild binary contains something other than the expected content.

    Note that esbuild's Deno API installs from registry.npmjs.org by default, but allows the NPM_CONFIG_REGISTRY environment variable to override this with a custom package registry. This change means that the esbuild executable served by NPM_CONFIG_REGISTRY must now match the expected content.

    Thanks to @​sondt99 for reporting this issue.

  • Avoid inlining using and await using declarations (#4482)

    Previously esbuild's minifier sometimes incorrectly inlined using and await using declarations into subsequent uses of that declaration, which then fails to dispose of the resource correctly. This bug happened because inlining was done for let and const declarations by avoiding doing it for var declarations, which no longer worked when more declaration types were added. Here's an example:

    // Original code
    {
      using x = new Resource()
      x.activate()
    }
    

    // Old output (with --minify)
    new Resource().activate();

    // New output (with --minify)
    {using e=new Resource;e.activate()}

  • Fix module evaluation when an error is thrown (#4461, #4467)

    If an error is thrown during module evaluation, esbuild previously didn't preserve the state of the module for subsequent module references. This was observable if import() or require() is used to import a module multiple times. The thrown error is supposed to be thrown by every call to import() or require(), not just the first. With this release, esbuild will now throw the same error every time you call import() or require() on a module that throws during its evaluation.

  • Fix some edge cases around the new operator (#4477)

    Previously esbuild incorrectly printed certain edge cases involving complex expressions inside the target of a new expression (specifically an optional chain and/or a tagged template literal). The generated code for the new target was not correctly wrapped with parentheses, and either contained a syntax error or had different semantics. These edge cases have been fixed so that they now correctly wrap the new target in parentheses. Here is an example of some affected code:

    // Original code
    new (foo()`bar`)()
    new (foo()?.bar)()
    

    // Old output
    new foo()bar();
    new (foo())?.bar();

... (truncated)

Commits

Updates `undici` from 8.2.0 to 8.5.0
Release notes

Sourced from undici's releases.

v8.5.0

⚠️ Security Release

This release line addresses 8 security advisories. Most are fixed in v8.5.0; the SOCKS5 pool-reuse issue was fixed earlier in v8.2.0.

Action required: Upgrade to undici 8.5.0 or later.

npm install undici@^8.5.0

Summary

Advisory CVE Severity (CVSS) Fixed in Fix commit
GHSA-vxpw-j846-p89q CVE-2026-12151 High (7.5) 8.5.0 32dbf0b3
GHSA-38rv-x7px-6hhq CVE-2026-9675 High (7.5) 8.5.0 b4c287b3
GHSA-vmh5-mc38-953g CVE-2026-9697 High (7.4) 8.5.0 42d49559
GHSA-hm92-r4w5-c3mj CVE-2026-6734 High (7.5) 8.2.0 a516f870
GHSA-pr7r-676h-xcf6 CVE-2026-9678 Moderate (5.9) 8.5.0 cb105d7c
GHSA-p88m-4jfj-68fv CVE-2026-9679 Moderate (5.9) 8.5.0 5655ea43
GHSA-g8m3-5g58-fq7m CVE-2026-11525 Low (3.7) 8.5.0 5655ea43
GHSA-35p6-xmwp-9g52 CVE-2026-6733 Low (3.7) 8.5.0 6ea54ef8

High severity

WebSocket DoS via fragment count bypass — CVE-2026-12151

GHSA-vxpw-j846-p89q · CWE-400, CWE-770 Fix: 32dbf0b3 websocket: limit the number of fragments in a message (also c5ed7875 handle empty fragments and stream limits)

A malicious WebSocket server can stream a large number of small or empty continuation frames. Undici enforced a limit on cumulative payload size but did not limit the number of fragments per message, leading to unbounded memory growth and denial of service.

  • Affected: applications using new WebSocket(...) or WebSocketStream against untrusted endpoints.
  • Workaround: none — upgrade is required.

WebSocket DoS via cumulative fragment bypass — CVE-2026-9675

GHSA-38rv-x7px-6hhq · CWE-400, CWE-770 Fix: b4c287b3 fix(websocket): enforce max payload size across fragments

Undici validated the size of individual frames but did not track cumulative size across a fragmented message. An attacker could send many small fragments that each pass per-frame validation but collectively exceed the configured limit, causing memory exhaustion. This is a regression introduced in 8.1.0 (the

... (truncated)

Commits
  • a0806e1 Bumped v8.5.0 (#5429)
  • 8a0392c test: detect available python command in wpt runner (#5427)
  • f4045b9 ci: increase Node.js workflow timeout (#5426)
  • 363e44f chore: removed repro-h2-pipelining-default.mjs and lint (#5420)
  • c5ed787 websocket: handle empty fragments and stream limits
  • e114e77 align EventSource with spec (#5418)
  • 6df53c5 fix: preserve h2 queue on out-of-order completion (#5410)
  • 32dbf0b websocket: limit the number of fragments in a message
  • 0d6ecc5 add bodymixin.textStream() (#5416)
  • 42d4955 fix: honor requestTls when proxy is SOCKS5
  • Additional commits viewable in compare view

Updates `yaml` from 2.8.4 to 2.9.0
Release notes

Sourced from yaml's releases.

v2.9.0

The changes here are really only patches, but I'm releasing this as a minor version to note a small change to the documentation of parseDocument() and parseAllDocuments(): I've removed the claim that they'll "never throw".

It remains the case that practically all non-malicious inputs will be handled without emitting an error, but there is a decent chance that code paths remain where e.g. a RangeError due to call stack exhaustion can be triggered by malicious inputs. Up to now, I've considered these as security vulnerabilities, and in fact it's the only category of error for which yaml CVEs have been issued so far.

Starting from this release, I'll be considering such errors as bugs, but not vulnerabilities. I do welcome people and/or LLMs looking for them, but please report them as normal issues rather than suspected security vulnerabilities. This also applies to previously undiscovered bugs in earlier releases.

  • fix: Avoid calling Array.prototype.push.apply() with large source array
  • fix(lexer): Avoid recursive calls that may exhaust the call stack
Commits
  • ddb21b0 2.9.0
  • 167365b docs: Clarify that not all errors can be avoided
  • 6eca2a7 fix: Avoid calling Array.prototype.push.apply() with large source array
  • 0543cd5 fix(lexer): Avoid recursive calls that may exhaust the call stack
  • See full diff in compare view

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 232 +++++++++++++++++++++++----------------------- package.json | 6 +- 2 files changed, 119 insertions(+), 119 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6120d7e4..6cf6282b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,10 +18,10 @@ "devDependencies": { "@octokit/openapi": "^22.0.0", "c8": "^11.0.0", - "esbuild": "^0.28.0", + "esbuild": "^0.28.1", "open-cli": "^9.0.0", - "undici": "^8.2.0", - "yaml": "^2.8.4" + "undici": "^8.5.0", + "yaml": "^2.9.0" }, "engines": { "node": ">=24.4.0" @@ -92,9 +92,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", - "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", "cpu": [ "ppc64" ], @@ -109,9 +109,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", - "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", "cpu": [ "arm" ], @@ -126,9 +126,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", - "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", "cpu": [ "arm64" ], @@ -143,9 +143,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", - "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", "cpu": [ "x64" ], @@ -160,9 +160,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", - "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", "cpu": [ "arm64" ], @@ -177,9 +177,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", - "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", "cpu": [ "x64" ], @@ -194,9 +194,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", - "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", "cpu": [ "arm64" ], @@ -211,9 +211,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", - "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", "cpu": [ "x64" ], @@ -228,9 +228,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", - "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", "cpu": [ "arm" ], @@ -245,9 +245,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", - "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", "cpu": [ "arm64" ], @@ -262,9 +262,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", - "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", "cpu": [ "ia32" ], @@ -279,9 +279,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", - "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", "cpu": [ "loong64" ], @@ -296,9 +296,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", - "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", "cpu": [ "mips64el" ], @@ -313,9 +313,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", - "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", "cpu": [ "ppc64" ], @@ -330,9 +330,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", - "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", "cpu": [ "riscv64" ], @@ -347,9 +347,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", - "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", "cpu": [ "s390x" ], @@ -364,9 +364,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", - "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", "cpu": [ "x64" ], @@ -381,9 +381,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", - "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", "cpu": [ "arm64" ], @@ -398,9 +398,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", - "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", "cpu": [ "x64" ], @@ -415,9 +415,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", - "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", "cpu": [ "arm64" ], @@ -432,9 +432,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", - "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", "cpu": [ "x64" ], @@ -449,9 +449,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", - "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", "cpu": [ "arm64" ], @@ -466,9 +466,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", - "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", "cpu": [ "x64" ], @@ -483,9 +483,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", - "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", "cpu": [ "arm64" ], @@ -500,9 +500,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", - "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", "cpu": [ "ia32" ], @@ -517,9 +517,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", - "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", "cpu": [ "x64" ], @@ -1023,9 +1023,9 @@ } }, "node_modules/esbuild": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", - "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1036,32 +1036,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.0", - "@esbuild/android-arm": "0.28.0", - "@esbuild/android-arm64": "0.28.0", - "@esbuild/android-x64": "0.28.0", - "@esbuild/darwin-arm64": "0.28.0", - "@esbuild/darwin-x64": "0.28.0", - "@esbuild/freebsd-arm64": "0.28.0", - "@esbuild/freebsd-x64": "0.28.0", - "@esbuild/linux-arm": "0.28.0", - "@esbuild/linux-arm64": "0.28.0", - "@esbuild/linux-ia32": "0.28.0", - "@esbuild/linux-loong64": "0.28.0", - "@esbuild/linux-mips64el": "0.28.0", - "@esbuild/linux-ppc64": "0.28.0", - "@esbuild/linux-riscv64": "0.28.0", - "@esbuild/linux-s390x": "0.28.0", - "@esbuild/linux-x64": "0.28.0", - "@esbuild/netbsd-arm64": "0.28.0", - "@esbuild/netbsd-x64": "0.28.0", - "@esbuild/openbsd-arm64": "0.28.0", - "@esbuild/openbsd-x64": "0.28.0", - "@esbuild/openharmony-arm64": "0.28.0", - "@esbuild/sunos-x64": "0.28.0", - "@esbuild/win32-arm64": "0.28.0", - "@esbuild/win32-ia32": "0.28.0", - "@esbuild/win32-x64": "0.28.0" + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" } }, "node_modules/escalade": { @@ -1786,9 +1786,9 @@ } }, "node_modules/undici": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-8.2.0.tgz", - "integrity": "sha512-Z+4Hx9GE26Lh9Upwfnc8C7SsrpBPGaM/Gm6kMFtiG7c+5IvQKlXi/t+9x9DrrCh29cww5TSP9YdVaBcnLDs5fQ==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.5.0.tgz", + "integrity": "sha512-xamtWoB1EshgjpmlXd7GGm2VfdDtw1+rD8uhry8pSNW3If6S8E0m2T2+orSKeZXEn/aPJMviCpDBA65WJt8zhg==", "dev": true, "license": "MIT", "engines": { @@ -1966,9 +1966,9 @@ "dev": true }, "node_modules/yaml": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.4.tgz", - "integrity": "sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", "dev": true, "license": "ISC", "bin": { diff --git a/package.json b/package.json index 0584f703..e8f59d41 100644 --- a/package.json +++ b/package.json @@ -25,9 +25,9 @@ "devDependencies": { "@octokit/openapi": "^22.0.0", "c8": "^11.0.0", - "esbuild": "^0.28.0", + "esbuild": "^0.28.1", "open-cli": "^9.0.0", - "undici": "^8.2.0", - "yaml": "^2.8.4" + "undici": "^8.5.0", + "yaml": "^2.9.0" } } From 7e4e05d60a5a2b2f6ef6cd0466c7fa7a6aaa7b41 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2026 14:55:18 -0700 Subject: [PATCH 18/29] build(deps-dev): bump brace-expansion from 5.0.5 to 5.0.12 (#397) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 5.0.5 to 5.0.12.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=brace-expansion&package-manager=npm_and_yarn&previous-version=5.0.5&new-version=5.0.12)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/actions/create-github-app-token/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6cf6282b..657416e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -767,16 +767,16 @@ } }, "node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, "engines": { - "node": "18 || 20 || >=22" + "node": "20 || >=22" } }, "node_modules/bundle-name": { From 941de883d0fba88f65049e42176b418b82e7c7e7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2026 15:00:21 -0700 Subject: [PATCH 19/29] build(deps-dev): bump the development-dependencies group across 1 directory with 3 updates (#398) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the development-dependencies group with 3 updates in the / directory: [esbuild](https://github.com/evanw/esbuild), [undici](https://github.com/nodejs/undici) and [yaml](https://github.com/eemeli/yaml). Updates `esbuild` from 0.28.1 to 0.28.2
Release notes

Sourced from esbuild's releases.

v0.28.2

  • Fix tree shaking bug due to TypeScript import alias (#4507)

    This release fixes a bug that could cause esbuild to incorrectly tree-shake imports that are used in a TypeScript type alias under certain circumstances. Affected code uses a TypeScript-specific import assignment and looks something like this:

    import Base from './dep.js';
    import Alias = Base.SomeType;
    
  • Fix CSS minification bug involving & (#4497)

    This release fixes a bug where esbuild's CSS minifier incorrectly removed a & when it was unsafe to do so. Here is an example:

    /* Original code */
    .a .b {
      & .b:not(& .c) {
        color: red;
      }
    }
    

    /* Old output (with --minify) */
    .a .b{.b:not(& .c){color:red}}

    /* New output (with --minify) */
    .a .b{& .b:not(& .c){color:red}}

    This should match <span class="a"><span class="b"><span class="b">yes</span></span></span> but not <span class="a"><span class="b">no</span></span>. The old output incorrectly matched both.

  • Avoid overwriting input files without --allow-overwrite (#4484)

    For example: esbuild input.js --outfile=input.js tells esbuild to overwrite input.js with the output of running esbuild on it. This was supposed to already be prevented by default, but it accidentally regressed in version 0.17.0 and apparently didn't have any test coverage. The error message was being printed but the input file was still being overwritten. Oops.

    This release puts the original behavior back. With this release, esbuild should now actually avoid overwriting input files unless --allow-overwrite is explicitly present. This is done by not writing out any files when a build error is encountered.

  • Fix incorrect code generated when using top-level await (#4498)

    Previously esbuild could generate code containing a syntax error in complex scenarios involving top-level await used in a dependency cycle. The problem was a missing async on one or more module wrapper closures. With this release, esbuild now uses a fixed-point iteration algorithm to correctly annotate all dependencies in the cycle as needing an async module wrapper.

  • Fix a minification bug with lowered logical assignment operators (#4508)

    This release fixes a bug that could cause esbuild to generate incorrect code for logical assignment operators when lowering them to an older target environment. Specifically the lowering process requires duplicating the left-hand side, but esbuild incorrectly failed to count the duplicate as a new usage when the left-hand side is an identifier. That then caused the minifier to believe that the left-hand side was only used once and could attempt to incorrectly inline an initializer into the first usage. This bug has now been fixed:

    // Original code
    function foo() {
      let x
      bar(x ||= {})
    

... (truncated)

Changelog

Sourced from esbuild's changelog.

0.28.2

  • Fix tree shaking bug due to TypeScript import alias (#4507)

    This release fixes a bug that could cause esbuild to incorrectly tree-shake imports that are used in a TypeScript type alias under certain circumstances. Affected code uses a TypeScript-specific import assignment and looks something like this:

    import Base from './dep.js';
    import Alias = Base.SomeType;
    
  • Fix CSS minification bug involving & (#4497)

    This release fixes a bug where esbuild's CSS minifier incorrectly removed a & when it was unsafe to do so. Here is an example:

    /* Original code */
    .a .b {
      & .b:not(& .c) {
        color: red;
      }
    }
    

    /* Old output (with --minify) */
    .a .b{.b:not(& .c){color:red}}

    /* New output (with --minify) */
    .a .b{& .b:not(& .c){color:red}}

    This should match <span class="a"><span class="b"><span class="b">yes</span></span></span> but not <span class="a"><span class="b">no</span></span>. The old output incorrectly matched both.

  • Avoid overwriting input files without --allow-overwrite (#4484)

    For example: esbuild input.js --outfile=input.js tells esbuild to overwrite input.js with the output of running esbuild on it. This was supposed to already be prevented by default, but it accidentally regressed in version 0.17.0 and apparently didn't have any test coverage. The error message was being printed but the input file was still being overwritten. Oops.

    This release puts the original behavior back. With this release, esbuild should now actually avoid overwriting input files unless --allow-overwrite is explicitly present. This is done by not writing out any files when a build error is encountered.

  • Fix incorrect code generated when using top-level await (#4498)

    Previously esbuild could generate code containing a syntax error in complex scenarios involving top-level await used in a dependency cycle. The problem was a missing async on one or more module wrapper closures. With this release, esbuild now uses a fixed-point iteration algorithm to correctly annotate all dependencies in the cycle as needing an async module wrapper.

  • Fix a minification bug with lowered logical assignment operators (#4508)

    This release fixes a bug that could cause esbuild to generate incorrect code for logical assignment operators when lowering them to an older target environment. Specifically the lowering process requires duplicating the left-hand side, but esbuild incorrectly failed to count the duplicate as a new usage when the left-hand side is an identifier. That then caused the minifier to believe that the left-hand side was only used once and could attempt to incorrectly inline an initializer into the first usage. This bug has now been fixed:

    // Original code
    function foo() {
      let x
    

... (truncated)

Commits
  • 609683d publish 0.28.2 to npm
  • 11b1fe4 add to release notes
  • ab50d91 css: fix green/blue channel swap in oklch gamut mapping (#4488)
  • 04627b6 fix #4498: async TLA checks need a worklist
  • 5c15177 disable gopls in the go folder
  • fc2ee9b css: adjust parser to allow --foo: {...}
  • 209db54 release notes for css nesting bugfix
  • c625d31 fix #4497: preserve nested ampersands during minification (#4500)
  • 34474e2 better isolation of current part in js parser
  • 07f6e8c fix #4507: import assignment tree-shaking bug
  • Additional commits viewable in compare view

Updates `undici` from 8.5.0 to 8.11.2
Release notes

Sourced from undici's releases.

v8.11.2

What's Changed

New Contributors

Full Changelog: https://github.com/nodejs/undici/compare/v8.11.1...v8.11.2

v8.11.1

What's Changed

Full Changelog: https://github.com/nodejs/undici/compare/v8.11.0...v8.11.1

v8.11.0

What's Changed

... (truncated)

Commits

Updates `yaml` from 2.9.0 to 2.9.1
Release notes

Sourced from yaml's releases.

v2.9.1

  • Limit recursive merge aliases (#685, #713)
  • Simplify line unfolding during quoted string parsing (#714)
Commits

Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 232 +++++++++++++++++++++++----------------------- package.json | 6 +- 2 files changed, 119 insertions(+), 119 deletions(-) diff --git a/package-lock.json b/package-lock.json index 657416e0..ba52a1c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,10 +18,10 @@ "devDependencies": { "@octokit/openapi": "^22.0.0", "c8": "^11.0.0", - "esbuild": "^0.28.1", + "esbuild": "^0.28.2", "open-cli": "^9.0.0", - "undici": "^8.5.0", - "yaml": "^2.9.0" + "undici": "^8.11.2", + "yaml": "^2.9.1" }, "engines": { "node": ">=24.4.0" @@ -92,9 +92,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", - "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", "cpu": [ "ppc64" ], @@ -109,9 +109,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", - "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", "cpu": [ "arm" ], @@ -126,9 +126,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", - "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", "cpu": [ "arm64" ], @@ -143,9 +143,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", - "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", "cpu": [ "x64" ], @@ -160,9 +160,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", - "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", "cpu": [ "arm64" ], @@ -177,9 +177,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", - "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", "cpu": [ "x64" ], @@ -194,9 +194,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", - "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", "cpu": [ "arm64" ], @@ -211,9 +211,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", - "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", "cpu": [ "x64" ], @@ -228,9 +228,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", - "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", "cpu": [ "arm" ], @@ -245,9 +245,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", - "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", "cpu": [ "arm64" ], @@ -262,9 +262,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", - "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", "cpu": [ "ia32" ], @@ -279,9 +279,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", - "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", "cpu": [ "loong64" ], @@ -296,9 +296,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", - "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", "cpu": [ "mips64el" ], @@ -313,9 +313,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", - "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", "cpu": [ "ppc64" ], @@ -330,9 +330,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", - "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", "cpu": [ "riscv64" ], @@ -347,9 +347,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", - "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", "cpu": [ "s390x" ], @@ -364,9 +364,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", - "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", "cpu": [ "x64" ], @@ -381,9 +381,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", - "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", "cpu": [ "arm64" ], @@ -398,9 +398,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", - "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", "cpu": [ "x64" ], @@ -415,9 +415,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", - "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", "cpu": [ "arm64" ], @@ -432,9 +432,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", - "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", "cpu": [ "x64" ], @@ -449,9 +449,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", - "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", "cpu": [ "arm64" ], @@ -466,9 +466,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", - "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", "cpu": [ "x64" ], @@ -483,9 +483,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", - "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", "cpu": [ "arm64" ], @@ -500,9 +500,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", - "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", "cpu": [ "ia32" ], @@ -517,9 +517,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", - "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", "cpu": [ "x64" ], @@ -1023,9 +1023,9 @@ } }, "node_modules/esbuild": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", - "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1036,32 +1036,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.1", - "@esbuild/android-arm": "0.28.1", - "@esbuild/android-arm64": "0.28.1", - "@esbuild/android-x64": "0.28.1", - "@esbuild/darwin-arm64": "0.28.1", - "@esbuild/darwin-x64": "0.28.1", - "@esbuild/freebsd-arm64": "0.28.1", - "@esbuild/freebsd-x64": "0.28.1", - "@esbuild/linux-arm": "0.28.1", - "@esbuild/linux-arm64": "0.28.1", - "@esbuild/linux-ia32": "0.28.1", - "@esbuild/linux-loong64": "0.28.1", - "@esbuild/linux-mips64el": "0.28.1", - "@esbuild/linux-ppc64": "0.28.1", - "@esbuild/linux-riscv64": "0.28.1", - "@esbuild/linux-s390x": "0.28.1", - "@esbuild/linux-x64": "0.28.1", - "@esbuild/netbsd-arm64": "0.28.1", - "@esbuild/netbsd-x64": "0.28.1", - "@esbuild/openbsd-arm64": "0.28.1", - "@esbuild/openbsd-x64": "0.28.1", - "@esbuild/openharmony-arm64": "0.28.1", - "@esbuild/sunos-x64": "0.28.1", - "@esbuild/win32-arm64": "0.28.1", - "@esbuild/win32-ia32": "0.28.1", - "@esbuild/win32-x64": "0.28.1" + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" } }, "node_modules/escalade": { @@ -1786,9 +1786,9 @@ } }, "node_modules/undici": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-8.5.0.tgz", - "integrity": "sha512-xamtWoB1EshgjpmlXd7GGm2VfdDtw1+rD8uhry8pSNW3If6S8E0m2T2+orSKeZXEn/aPJMviCpDBA65WJt8zhg==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.11.2.tgz", + "integrity": "sha512-u4UB2/IrKdU6lFxumHmmo1a3fCQO5tzQllRorfoRS63txhrB7xTpSn1PftwC4qEHkOaqP95fCWW4lJzwErwzhQ==", "dev": true, "license": "MIT", "engines": { @@ -1966,9 +1966,9 @@ "dev": true }, "node_modules/yaml": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", "dev": true, "license": "ISC", "bin": { diff --git a/package.json b/package.json index e8f59d41..0437832c 100644 --- a/package.json +++ b/package.json @@ -25,9 +25,9 @@ "devDependencies": { "@octokit/openapi": "^22.0.0", "c8": "^11.0.0", - "esbuild": "^0.28.1", + "esbuild": "^0.28.2", "open-cli": "^9.0.0", - "undici": "^8.5.0", - "yaml": "^2.9.0" + "undici": "^8.11.2", + "yaml": "^2.9.1" } } From 9419396df4d5672241cfb593dadc19758e54a204 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2026 15:25:53 -0700 Subject: [PATCH 20/29] build(deps-dev): bump c8 from 11.0.0 to 12.0.0 (#400) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [c8](https://github.com/bcoe/c8) from 11.0.0 to 12.0.0.
Release notes

Sourced from c8's releases.

v12.0.0

12.0.0 (2026-07-14)

⚠ BREAKING CHANGES

  • yargs enforces a stricter range of Node versions ^20.19.0 || ^22.12.0 || >=23

Features

Changelog

Sourced from c8's changelog.

12.0.0 (2026-07-14)

⚠ BREAKING CHANGES

  • yargs enforces a stricter range of Node versions ^20.19.0 || ^22.12.0 || >=23

Features

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=c8&package-manager=npm_and_yarn&previous-version=11.0.0&new-version=12.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 345 +++++++++++++++++++--------------------------- package.json | 2 +- 2 files changed, 143 insertions(+), 204 deletions(-) diff --git a/package-lock.json b/package-lock.json index ba52a1c8..b8fd0445 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ }, "devDependencies": { "@octokit/openapi": "^22.0.0", - "c8": "^11.0.0", + "c8": "^12.0.0", "esbuild": "^0.28.2", "open-cli": "^9.0.0", "undici": "^8.11.2", @@ -756,6 +756,32 @@ "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", "dev": true }, + "node_modules/ansi-regex": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.4.0.tgz", + "integrity": "sha512-KzTVk2tCWAHtYrvvvaP8bJKJq2pVinhLcGEQdtLIYPbmNGNyYe8QwNaTUYQp2J7/vIsUKt5QCqAfUkYyG9DkOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", @@ -796,9 +822,9 @@ } }, "node_modules/c8": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/c8/-/c8-11.0.0.tgz", - "integrity": "sha512-e/uRViGHSVIJv7zsaDKM7VRn2390TgHXqUSvYwPHBQaU6L7E9L0n9JbdkwdYPvshDT0KymBmmlwSpms3yBaMNg==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-12.0.0.tgz", + "integrity": "sha512-4zpJvrd1nKWutnnKC2pXkFmb6iM1l+ffN//o1CzlTNwW7GSOs9a1xrLqkC48nU8oEkjmPZLPiwMsIaOvoF4Pqg==", "dev": true, "license": "ISC", "dependencies": { @@ -811,14 +837,14 @@ "istanbul-reports": "^3.1.6", "test-exclude": "^8.0.0", "v8-to-istanbul": "^9.0.0", - "yargs": "^17.7.2", + "yargs": "^18.0.0", "yargs-parser": "^21.1.1" }, "bin": { "c8": "bin/c8.js" }, "engines": { - "node": "20 || >=22" + "node": "^20.19.0 || ^22.12.0 || >=23" }, "peerDependencies": { "monocart-coverage-reports": "^2" @@ -830,87 +856,38 @@ } }, "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", "dev": true, + "license": "ISC", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=12" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" + "node": ">=20" } }, "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" + "node": ">=18" }, - "engines": { - "node": ">=7.0.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -1022,6 +999,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, "node_modules/esbuild": { "version": "0.28.2", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", @@ -1065,10 +1049,11 @@ } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1146,10 +1131,24 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.7.0.tgz", + "integrity": "sha512-XjH1AECxf0giL2V1aU8vKyRR2ppRUb5c0EvT7zuJTokQ74bNo52zOtghqdWIqrhUD79fo3x0WfKZdOqxF6LG1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/glob": { "version": "13.0.6", "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", @@ -1565,15 +1564,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/run-applescript": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", @@ -1650,6 +1640,39 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/string-width": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.3.0.tgz", + "integrity": "sha512-ZbmZM0JCihQN91dWnxoipT2KOEyHqEyfRXUyjuRhW8b/xnqPDoq4gWEVApTVa9db2wN8mmoikgFBbjh71+cGeQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/strtok3": { "version": "10.3.5", "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.5.tgz", @@ -1852,85 +1875,39 @@ } }, "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/wrap-ansi/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, + "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" + "node": ">=18" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/wsl-utils": { @@ -1955,6 +1932,7 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } @@ -1982,21 +1960,21 @@ } }, "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.2.0.tgz", + "integrity": "sha512-9OpKOLeaoNFecEp7P6iYbzze/5CqWoH7N3SMs/6y1XF4nMvFMspEGZzJ6uFi9MmQwXhyzqYoSEKO3tvA3Z/o2w==", "dev": true, + "license": "MIT", "dependencies": { - "cliui": "^8.0.1", + "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", + "string-width": "^8.2.1", "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "yargs-parser": "^22.0.0" }, "engines": { - "node": ">=12" + "node": "^20.19.0 || ^22.12.0 || >=23" } }, "node_modules/yargs-parser": { @@ -2004,58 +1982,19 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/yargs/node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, + "license": "ISC", "engines": { - "node": ">=8" + "node": "^20.19.0 || ^22.12.0 || >=23" } }, "node_modules/yocto-queue": { diff --git a/package.json b/package.json index 0437832c..45f336e8 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ }, "devDependencies": { "@octokit/openapi": "^22.0.0", - "c8": "^11.0.0", + "c8": "^12.0.0", "esbuild": "^0.28.2", "open-cli": "^9.0.0", "undici": "^8.11.2", From e85f677b44da0d1f08115ce52cdfd8fd2c69874a Mon Sep 17 00:00:00 2001 From: Parker Brown <17183625+parkerbxyz@users.noreply.github.com> Date: Mon, 12 Oct 2026 15:35:22 -0700 Subject: [PATCH 21/29] test: omit stack traces from snapshots (#401) The `integration` check fails on `main` because 10 snapshots include Node.js internal stack frames, and their names changed between Node.js versions. CI installs the latest Node.js that matches `>=24.4.0`, so these snapshots can break without any change to the action. This PR runs each test with `--stack-trace-limit=0`, so error output no longer includes stack traces. Snapshots still capture the error message, any HTTP error details, and the `::error::` output users see. Code coverage is still enforced by `c8 --100`. Without stack traces, `normalizeStderr` is no longer needed, so this removes it. All 120 tests pass with 100% coverage on Node.js 24 and 26. --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b91f96b7-a7f3-4ff3-8f52-3a617307ede2 --- tests/index.js | 18 +++++------ tests/index.js.snapshot | 66 +++++------------------------------------ 2 files changed, 14 insertions(+), 70 deletions(-) diff --git a/tests/index.js b/tests/index.js index 159c21c7..33ec9147 100644 --- a/tests/index.js +++ b/tests/index.js @@ -11,13 +11,6 @@ snapshot.setDefaultSnapshotSerializers([ (value) => (typeof value === "string" ? value : undefined), ]); -function normalizeStderr(stderr) { - return stderr - .replaceAll(/\u001B\[[0-9;]*m/g, "") - .replaceAll(process.cwd(), "") - .replaceAll(/:\d+:\d+/g, "::"); -} - // Get all files in tests directory const files = readdirSync("tests"); @@ -54,9 +47,12 @@ for (const file of testFiles) { } = process.env; let stderr, stdout; try { - ({ stderr, stdout } = await execFileAsync("node", [`tests/${file}`], { - env, - })); + // Omit stack traces so snapshots don't change with Node.js or dependency updates + ({ stderr, stdout } = await execFileAsync( + "node", + ["--stack-trace-limit=0", `tests/${file}`], + { env }, + )); } catch (error) { if (!(error instanceof Error) || !("stderr" in error) || !("stdout" in error)) { throw error; @@ -64,7 +60,7 @@ for (const file of testFiles) { ({ stderr, stdout } = error); } - const trimmedStderr = normalizeStderr(stderr).replace(/\r?\n$/, ""); + const trimmedStderr = stderr.replace(/\r?\n$/, ""); const trimmedStdout = stdout.replace(/\r?\n$/, ""); await t.test("stderr", (t) => { if (trimmedStderr) t.assert.snapshot(trimmedStderr); diff --git a/tests/index.js.snapshot b/tests/index.js.snapshot index 2c88dc4e..541d4b3b 100644 --- a/tests/index.js.snapshot +++ b/tests/index.js.snapshot @@ -74,13 +74,7 @@ null `; exports[`main-enterprise-installation-not-found.test.js > stderr 1`] = ` -Error: No enterprise installation found matching the enterprise slug "test-enterprise". - at getTokenFromEnterprise (file:///lib/main.js::) - at process.processTicksAndRejections (node:internal/process/task_queues::) - at async pRetry (file:///node_modules/p-retry/index.js::) - at async main (file:///lib/main.js::) - at async test (file:///tests/main.js::) - at async file:///tests/main-enterprise-installation-not-found.test.js:: +[Error: No enterprise installation found matching the enterprise slug "test-enterprise".] `; exports[`main-enterprise-installation-not-found.test.js > stdout 1`] = ` @@ -92,13 +86,7 @@ GET /enterprises/test-enterprise/installation `; exports[`main-enterprise-mutual-exclusivity-owner.test.js > stderr 1`] = ` -Error: Cannot use 'enterprise' input with 'owner' or 'repositories' inputs - at main (file:///lib/main.js::) - at run (file:///main.js::) - at file:///main.js:: - at ModuleJob.run (node:internal/modules/esm/module_job::) - at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader::) - at async file:///tests/main-enterprise-mutual-exclusivity-owner.test.js:: +[Error: Cannot use 'enterprise' input with 'owner' or 'repositories' inputs] `; exports[`main-enterprise-mutual-exclusivity-owner.test.js > stdout 1`] = ` @@ -106,13 +94,7 @@ exports[`main-enterprise-mutual-exclusivity-owner.test.js > stdout 1`] = ` `; exports[`main-enterprise-mutual-exclusivity-repositories.test.js > stderr 1`] = ` -Error: Cannot use 'enterprise' input with 'owner' or 'repositories' inputs - at main (file:///lib/main.js::) - at run (file:///main.js::) - at file:///main.js:: - at ModuleJob.run (node:internal/modules/esm/module_job::) - at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader::) - at async file:///tests/main-enterprise-mutual-exclusivity-repositories.test.js:: +[Error: Cannot use 'enterprise' input with 'owner' or 'repositories' inputs] `; exports[`main-enterprise-mutual-exclusivity-repositories.test.js > stdout 1`] = ` @@ -227,15 +209,7 @@ POST /app/installations/123456/access_tokens `; exports[`main-token-get-owner-set-client-error.test.js > stderr 1`] = ` -RequestError [HttpError]: Forbidden - at fetchWrapper (file:///node_modules/@octokit/request/dist-bundle/index.js::) - at process.processTicksAndRejections (node:internal/process/task_queues::) - at async hook (file:///node_modules/@octokit/auth-app/dist-node/index.js::) - at async getTokenFromOwner (file:///lib/main.js::) - at async pRetry (file:///node_modules/p-retry/index.js::) - at async main (file:///lib/main.js::) - at async test (file:///tests/main.js::) - at async file:///tests/main-token-get-owner-set-client-error.test.js:: { +[RequestError [HttpError]: Forbidden] { status: 403, request: { method: 'GET', @@ -323,17 +297,7 @@ POST /app/installations/123456/access_tokens `; exports[`main-token-get-owner-set-repo-invalid-format.test.js > stderr 1`] = ` -Error: Invalid repository 'octocat/hello-world/extra'. Expected 'repository' or 'owner/repository'. - at parseRepositoryInput (file:///lib/main.js::) - at Array.map () - at normalizeRepositoryTarget (file:///lib/main.js::) - at resolveInstallationTarget (file:///lib/main.js::) - at main (file:///lib/main.js::) - at run (file:///main.js::) - at file:///main.js:: - at ModuleJob.run (node:internal/modules/esm/module_job::) - at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader::) - at async file:///tests/main-token-get-owner-set-repo-invalid-format.test.js:: +[Error: Invalid repository 'octocat/hello-world/extra'. Expected 'repository' or 'owner/repository'.] `; exports[`main-token-get-owner-set-repo-invalid-format.test.js > stdout 1`] = ` @@ -380,15 +344,7 @@ POST /app/installations/123456/access_tokens `; exports[`main-token-get-owner-set-repo-owner-mismatch.test.js > stderr 1`] = ` -Error: Repository 'octocat/hello-world' includes owner 'octocat', which does not match the resolved owner 'actions'. - at normalizeRepositoryTarget (file:///lib/main.js::) - at resolveInstallationTarget (file:///lib/main.js::) - at main (file:///lib/main.js::) - at run (file:///main.js::) - at file:///main.js:: - at ModuleJob.run (node:internal/modules/esm/module_job::) - at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader::) - at async file:///tests/main-token-get-owner-set-repo-owner-mismatch.test.js:: +[Error: Repository 'octocat/hello-world' includes owner 'octocat', which does not match the resolved owner 'actions'.] `; exports[`main-token-get-owner-set-repo-owner-mismatch.test.js > stdout 1`] = ` @@ -490,15 +446,7 @@ POST /app/installations/123456/access_tokens `; exports[`main-token-get-owner-unset-repo-owner-mismatch.test.js > stderr 1`] = ` -Error: Repository 'octocat/hello-world' includes owner 'octocat', which does not match the resolved owner 'actions'. - at normalizeRepositoryTarget (file:///lib/main.js::) - at resolveInstallationTarget (file:///lib/main.js::) - at main (file:///lib/main.js::) - at run (file:///main.js::) - at file:///main.js:: - at ModuleJob.run (node:internal/modules/esm/module_job::) - at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader::) - at async file:///tests/main-token-get-owner-unset-repo-owner-mismatch.test.js:: +[Error: Repository 'octocat/hello-world' includes owner 'octocat', which does not match the resolved owner 'actions'.] `; exports[`main-token-get-owner-unset-repo-owner-mismatch.test.js > stdout 1`] = ` From 575da866bd0a42d7f234a8645831d55573252b09 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2026 15:41:52 -0700 Subject: [PATCH 22/29] build(deps): bump stefanzweifel/git-auto-commit-action from 7.1.0 to 7.2.0 in the github-actions group across 1 directory (#383) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the github-actions group with 1 update in the / directory: [stefanzweifel/git-auto-commit-action](https://github.com/stefanzweifel/git-auto-commit-action). Updates `stefanzweifel/git-auto-commit-action` from 7.1.0 to 7.2.0
Release notes

Sourced from stefanzweifel/git-auto-commit-action's releases.

v7.2.0

Added

Fixed

Dependency Updates

Changelog

Sourced from stefanzweifel/git-auto-commit-action's changelog.

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog and this project adheres to Semantic Versioning.

Unreleased

TBD

v7.2.0 - 2026-06-28

Added

Fixed

Dependency Updates

v7.1.0 - 2025-12-17

Added

Changes

Dependency Updates

v7.0.0 - 2025-10-12

Added

... (truncated)

Commits
  • 4a55954 Update README.md
  • 9f6c933 Add hooks to run shell snippets around git operations (#411)
  • c365a74 Emit warning for pull_request_target trigger usage (#410)
  • d28176c Bump actions/checkout from 6 to 7 (#409)
  • 25df622 Add EXAMPLES.md
  • 32e9844 docs(action): fix input and output descriptions in action.yml (#406)
  • a3ed46f docs: fix typos, grammar, and formatting across markdown files (#408)
  • b4d688c docs: fix broken and redirecting URLs in README.md (#407)
  • f53a62c README: clearify meaning of the repository field (#404)
  • 4fc4bbf Bump release-drafter/release-drafter from 6 to 7 (#403)
  • Additional commits viewable in compare view

Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- .github/workflows/update-permission-inputs.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ac5d7c4f..99a690b5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -51,7 +51,7 @@ jobs: - run: npm run build if: steps.release-please.outputs.prs_created == 'true' - - uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0 + - uses: stefanzweifel/git-auto-commit-action@4a55954c782fc1ea30b9056cd3e7a2b40ca8887d # v7.2.0 if: steps.release-please.outputs.prs_created == 'true' with: commit_author: "${{ github.actor }} <${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com>" diff --git a/.github/workflows/update-permission-inputs.yml b/.github/workflows/update-permission-inputs.yml index daad54f0..c6492bd0 100644 --- a/.github/workflows/update-permission-inputs.yml +++ b/.github/workflows/update-permission-inputs.yml @@ -31,7 +31,7 @@ jobs: run: node scripts/update-permission-inputs.js - name: Commit changes id: auto-commit - uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0 + uses: stefanzweifel/git-auto-commit-action@4a55954c782fc1ea30b9056cd3e7a2b40ca8887d # v7.2.0 with: commit_message: ${{ env.COMMIT_MESSAGE }} - name: Update PR title From d5cb7ae41d64331820d88810a4878e0942ec992a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2026 15:43:24 -0700 Subject: [PATCH 23/29] build(deps): bump actions/checkout from 6 to 7 (#384) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
Release notes

Sourced from actions/checkout's releases.

v7.0.0

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v6.0.3...v7.0.0

v6.1.0

What's Changed

https://github.blog/changelog/2026-06-18-safer-pull_request_target-defaults-for-github-actions-checkout/ for more details about this breaking change

Full Changelog: https://github.com/actions/checkout/compare/v6.0.3...v6.1.0

v6.0.3

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v6...v6.0.3

v6.0.2

What's Changed

Full Changelog: https://github.com/actions/checkout/compare/v6.0.1...v6.0.2

v6.0.1

What's Changed

... (truncated)

Changelog

Sourced from actions/checkout's changelog.

Changelog

v7.0.1

v7.0.0

v6.0.3

v6.0.2

v6.0.1

v6.0.0

v5.0.1

v5.0.0

v4.3.1

v4.3.0

v4.2.2

v4.2.1

... (truncated)

Commits

> **Note** > Automatic rebases have been disabled on this pull request as it has been open for over 30 days. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 4 ++-- .github/workflows/test.yml | 6 +++--- .github/workflows/update-permission-inputs.yml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 99a690b5..11564e82 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: name: release runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: ./ id: app-token @@ -34,7 +34,7 @@ jobs: manifest-file: .release-please-manifest.json target-branch: ${{ github.ref_name }} - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 if: steps.release-please.outputs.prs_created == 'true' with: ref: ${{ fromJSON(steps.release-please.outputs.pr).headBranchName }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bd35e0eb..717e743b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,7 +21,7 @@ jobs: name: integration runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: actions/setup-node@v6 with: @@ -36,7 +36,7 @@ jobs: # do not run from forks, as forks don’t have access to repository secrets if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.owner.login == github.event.pull_request.base.repo.owner.login steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: actions/setup-node@v6 with: node-version-file: package.json @@ -61,7 +61,7 @@ jobs: # do not run from forks, as forks don’t have access to repository secrets if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.owner.login == github.event.pull_request.base.repo.owner.login steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: actions/setup-node@v6 with: node-version-file: package.json diff --git a/.github/workflows/update-permission-inputs.yml b/.github/workflows/update-permission-inputs.yml index c6492bd0..da49f429 100644 --- a/.github/workflows/update-permission-inputs.yml +++ b/.github/workflows/update-permission-inputs.yml @@ -21,7 +21,7 @@ jobs: env: COMMIT_MESSAGE: 'feat: update permission inputs' steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: actions/setup-node@v6 with: node-version-file: package.json From a69c19ddfdf8e1ab093900e0064524ce9309c807 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2026 15:45:15 -0700 Subject: [PATCH 24/29] fix(deps): bump the production-dependencies group across 1 directory with 3 updates (#395) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the production-dependencies group with 3 updates in the / directory: [@octokit/auth-app](https://github.com/octokit/auth-app.js), [@octokit/request](https://github.com/octokit/request.js) and [p-retry](https://github.com/sindresorhus/p-retry). Updates `@octokit/auth-app` from 8.2.0 to 8.3.1
Release notes

Sourced from @​octokit/auth-app's releases.

v8.3.1

8.3.1 (2026-09-01)

Bug Fixes

  • deps: update dependency @​octokit/types to v18 (#761) (2bb6310)

v8.3.0

8.3.0 (2026-08-02)

Features

  • deps: allow bigint (int64) repository IDs and update dependency @​octokit/types to v17 (#759) (3df5506)
Commits
  • 2bb6310 fix(deps): update dependency @​octokit/types to v18 (#761)
  • 2327287 chore(deps): update dependency typescript to v7 (#755)
  • 3df5506 feat(deps): allow bigint (int64) repository IDs and update dependency @​octoki...
  • 9d2ec47 ci(action): update actions/checkout action to v7 (#754)
  • d149272 build(deps): lock file maintenance (#758)
  • 653732f build(deps): lock file maintenance (#753)
  • b898bcf chore(deps): update dependency esbuild to ^0.28.0 [security] (#751)
  • 9e34287 build(deps): lock file maintenance (#743)
  • fdf6833 chore(deps): update dependency prettier to v3.8.1 (#735)
  • 50cd126 chore(deps): update dependency fetch-mock to v12 (#649)
  • Additional commits viewable in compare view

Updates `@octokit/request` from 10.0.8 to 10.0.16
Release notes

Sourced from @​octokit/request's releases.

v10.0.16

10.0.16 (2026-08-30)

Bug Fixes

  • deps: update dependency @​octokit/types to v18 (#834) (723070e)

v10.0.15

10.0.15 (2026-08-21)

Bug Fixes

  • deps: update dependency content-type to v3 (#833) (963f5fb)

v10.0.14

10.0.14 (2026-08-17)

Bug Fixes

  • deps: update dependency json-with-bigint and undici [security] (#830) (9e5fee0), fixes #831

v10.0.13

10.0.13 (2026-08-01)

Bug Fixes

  • deps: update dependency @​octokit/types to v17 (#828) (e127cfe)

v10.0.12

10.0.12 (2026-08-01)

Bug Fixes

  • don't decode application/octet-stream as text when charset is utf-8 (#823) (facf3cb), closes #751

v10.0.11

10.0.11 (2026-06-29)

Bug Fixes

  • handle primitive JSON error bodies without throwing (#820) (554e102), closes #819

v10.0.10

10.0.10 (2026-05-26)

... (truncated)

Commits
  • 723070e fix(deps): update dependency @​octokit/types to v18 (#834)
  • 963f5fb fix(deps): update dependency content-type to v3 (#833)
  • f9b5147 chore(deps): update dependency typescript to v7 (#822)
  • 9e5fee0 fix(deps): update dependency json-with-bigint and undici [security] (#830)
  • 3a99e00 chore(deps): update dependency prettier to v3.9.6 (#794)
  • 9282200 ci(action): update actions/checkout action to v7 (#812)
  • e127cfe fix(deps): update dependency @​octokit/types to v17 (#828)
  • deadf90 ci(action): update actions/setup-node action to v7 (#824)
  • facf3cb fix: don't decode application/octet-stream as text when charset is utf-8 (#823)
  • 554e102 fix: handle primitive JSON error bodies without throwing (#820)
  • Additional commits viewable in compare view

Updates `p-retry` from 8.0.0 to 8.0.1
Release notes

Sourced from p-retry's releases.

v8.0.1

  • Fix error for invalid fractional retry counts 3c22035

https://github.com/sindresorhus/p-retry/compare/v8.0.0...v8.0.1

Commits

Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 159 +++++++++++++++++++++++----------------------- package.json | 4 +- 2 files changed, 80 insertions(+), 83 deletions(-) diff --git a/package-lock.json b/package-lock.json index b8fd0445..1da661a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,10 +10,10 @@ "license": "MIT", "dependencies": { "@actions/core": "^3.0.1", - "@octokit/auth-app": "^8.2.0", + "@octokit/auth-app": "^8.3.1", "@octokit/request": "^10.0.8", "is-network-error": "^1.3.2", - "p-retry": "^8.0.0" + "p-retry": "^8.0.1" }, "devDependencies": { "@octokit/openapi": "^22.0.0", @@ -569,16 +569,16 @@ } }, "node_modules/@octokit/auth-app": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-8.2.0.tgz", - "integrity": "sha512-vVjdtQQwomrZ4V46B9LaCsxsySxGoHsyw6IYBov/TqJVROrlYdyNgw5q6tQbB7KZt53v1l1W53RiqTvpzL907g==", + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-8.3.1.tgz", + "integrity": "sha512-XHWxZsF4mvGTQCv7AOxgby9t9OjVO19FBuKq+QmyBxFrf+B2hR/P5j/MTF8g95bITf8cRtR17KIXThpFNqiKbg==", "license": "MIT", "dependencies": { - "@octokit/auth-oauth-app": "^9.0.3", - "@octokit/auth-oauth-user": "^6.0.2", - "@octokit/request": "^10.0.6", - "@octokit/request-error": "^7.0.2", - "@octokit/types": "^16.0.0", + "@octokit/auth-oauth-app": "^9.0.5", + "@octokit/auth-oauth-user": "^6.0.4", + "@octokit/request": "^10.0.16", + "@octokit/request-error": "^7.1.2", + "@octokit/types": "^18.0.0", "toad-cache": "^3.7.0", "universal-github-app-jwt": "^2.2.0", "universal-user-agent": "^7.0.0" @@ -588,15 +588,15 @@ } }, "node_modules/@octokit/auth-oauth-app": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-app/-/auth-oauth-app-9.0.3.tgz", - "integrity": "sha512-+yoFQquaF8OxJSxTb7rnytBIC2ZLbLqA/yb71I4ZXT9+Slw4TziV9j/kyGhUFRRTF2+7WlnIWsePZCWHs+OGjg==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-app/-/auth-oauth-app-9.0.5.tgz", + "integrity": "sha512-Hn2yAlIDjFLGjAz7t+CRu7e9VYoFW1W3LLyOLyahFoJGlCf4PtDkHKtRET8w/2CJpsrC0FxIF5g5Xtx9E4O78w==", "license": "MIT", "dependencies": { - "@octokit/auth-oauth-device": "^8.0.3", - "@octokit/auth-oauth-user": "^6.0.2", - "@octokit/request": "^10.0.6", - "@octokit/types": "^16.0.0", + "@octokit/auth-oauth-device": "^8.0.5", + "@octokit/auth-oauth-user": "^6.0.4", + "@octokit/request": "^10.0.16", + "@octokit/types": "^18.0.0", "universal-user-agent": "^7.0.0" }, "engines": { @@ -604,14 +604,14 @@ } }, "node_modules/@octokit/auth-oauth-device": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-device/-/auth-oauth-device-8.0.3.tgz", - "integrity": "sha512-zh2W0mKKMh/VWZhSqlaCzY7qFyrgd9oTWmTmHaXnHNeQRCZr/CXy2jCgHo4e4dJVTiuxP5dLa0YM5p5QVhJHbw==", + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-device/-/auth-oauth-device-8.0.5.tgz", + "integrity": "sha512-kdJtjRhykMLJrMdcoC56XUBDfoUAuWEFKpkDxwYim+bNwYw1MreLolk+PLnwEYT8djm589YepeMuJ8+ECAIzVQ==", "license": "MIT", "dependencies": { - "@octokit/oauth-methods": "^6.0.2", - "@octokit/request": "^10.0.6", - "@octokit/types": "^16.0.0", + "@octokit/oauth-methods": "^6.0.5", + "@octokit/request": "^10.0.16", + "@octokit/types": "^18.0.0", "universal-user-agent": "^7.0.0" }, "engines": { @@ -619,15 +619,15 @@ } }, "node_modules/@octokit/auth-oauth-user": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-user/-/auth-oauth-user-6.0.2.tgz", - "integrity": "sha512-qLoPPc6E6GJoz3XeDG/pnDhJpTkODTGG4kY0/Py154i/I003O9NazkrwJwRuzgCalhzyIeWQ+6MDvkUmKXjg/A==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-user/-/auth-oauth-user-6.0.4.tgz", + "integrity": "sha512-eya2pMJ9pCBq1jrm1Rf6J3NI+NemEpzDMLo9J/GpRoK0KgdxIVXWX4LESIfwJ+GYeoq6QFIlUJNi1lVp5FBgmw==", "license": "MIT", "dependencies": { - "@octokit/auth-oauth-device": "^8.0.3", - "@octokit/oauth-methods": "^6.0.2", - "@octokit/request": "^10.0.6", - "@octokit/types": "^16.0.0", + "@octokit/auth-oauth-device": "^8.0.5", + "@octokit/oauth-methods": "^6.0.5", + "@octokit/request": "^10.0.16", + "@octokit/types": "^18.0.0", "universal-user-agent": "^7.0.0" }, "engines": { @@ -635,12 +635,12 @@ } }, "node_modules/@octokit/endpoint": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.3.tgz", - "integrity": "sha512-FWFlNxghg4HrXkD3ifYbS/IdL/mDHjh9QcsNyhQjN8dplUoZbejsdpmuqdA76nxj2xoWPs7p8uX2SNr9rYu0Ag==", + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.5.tgz", + "integrity": "sha512-iXa654H3yFafF/ieHkukfbgWo2rmXD2ceD0ZOtrPhw1bc3FDch1d9N/TNs0FQ1/cIbwb7kspUX8jzIs8nzb9DQ==", "license": "MIT", "dependencies": { - "@octokit/types": "^16.0.0", + "@octokit/types": "^18.0.0", "universal-user-agent": "^7.0.2" }, "engines": { @@ -657,15 +657,15 @@ } }, "node_modules/@octokit/oauth-methods": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@octokit/oauth-methods/-/oauth-methods-6.0.2.tgz", - "integrity": "sha512-HiNOO3MqLxlt5Da5bZbLV8Zarnphi4y9XehrbaFMkcoJ+FL7sMxH/UlUsCVxpddVu4qvNDrBdaTVE2o4ITK8ng==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@octokit/oauth-methods/-/oauth-methods-6.0.5.tgz", + "integrity": "sha512-/mAz7taDZD7DcV4zcG6TDw3Kr6TOldmYBRpvA62C3WIxRMmcgX8XxsTvVQomqKE7VEk/BgYhUao1aR2tYGyIKg==", "license": "MIT", "dependencies": { "@octokit/oauth-authorization-url": "^8.0.0", - "@octokit/request": "^10.0.6", - "@octokit/request-error": "^7.0.2", - "@octokit/types": "^16.0.0" + "@octokit/request": "^10.0.16", + "@octokit/request-error": "^7.1.2", + "@octokit/types": "^18.0.0" }, "engines": { "node": ">= 20" @@ -682,22 +682,22 @@ } }, "node_modules/@octokit/openapi-types": { - "version": "27.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz", - "integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==", + "version": "29.0.1", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-29.0.1.tgz", + "integrity": "sha512-9qWOMFNxxLokERcms42rU0PTLqQmVs7g5E41TI4mCOxmpFayD1rfC7XxOL55cG9MBZLFlC31BrR37myMKardwg==", "license": "MIT" }, "node_modules/@octokit/request": { - "version": "10.0.8", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.8.tgz", - "integrity": "sha512-SJZNwY9pur9Agf7l87ywFi14W+Hd9Jg6Ifivsd33+/bGUQIjNujdFiXII2/qSlN2ybqUHfp5xpekMEjIBTjlSw==", + "version": "10.0.16", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.16.tgz", + "integrity": "sha512-A0zWGjHzISIb+9ccG8s0dq7LKO5zVpJLRICjgUb+sJxEWqn8RUHB1rD3AE51+PECvXHIxqZ1VVvs4fHTSD9nUQ==", "license": "MIT", "dependencies": { - "@octokit/endpoint": "^11.0.3", - "@octokit/request-error": "^7.0.2", - "@octokit/types": "^16.0.0", - "fast-content-type-parse": "^3.0.0", - "json-with-bigint": "^3.5.3", + "@octokit/endpoint": "^11.0.5", + "@octokit/request-error": "^7.1.2", + "@octokit/types": "^18.0.0", + "content-type": "^3.0.0", + "json-with-bigint": "^3.5.12", "universal-user-agent": "^7.0.2" }, "engines": { @@ -705,24 +705,24 @@ } }, "node_modules/@octokit/request-error": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.0.tgz", - "integrity": "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.2.tgz", + "integrity": "sha512-XZRuT3xZ84D3gYErI1DZvhJ33dCWVV6uzBtWkaBB4TvA/L6eOeTZodxLFVB44bBEEo3vEx7y00UfX1tBLrtLRg==", "license": "MIT", "dependencies": { - "@octokit/types": "^16.0.0" + "@octokit/types": "^18.0.0" }, "engines": { "node": ">= 20" } }, "node_modules/@octokit/types": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz", - "integrity": "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-18.0.0.tgz", + "integrity": "sha512-l6bAF43PNxkJp6g+W4PjoUSSkxHomXw2nOum5CTftJz1NlV3vu93NImgOYtLf6CbBUb5j+fiuzW0PPQ5JTSvZA==", "license": "MIT", "dependencies": { - "@octokit/openapi-types": "^27.0.0" + "@octokit/openapi-types": "^29.0.1" } }, "node_modules/@tokenizer/inflate": { @@ -888,6 +888,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/content-type": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-3.1.1.tgz", + "integrity": "sha512-GW4qUsfFo59d0HbUibDlWv5wPz+vAAcaTWbKIuKCf0JkC7wWkSyf8f13IpXn5JkeMlB2P8iTSSIjwXljorg2vA==", + "license": "MIT", + "engines": { + "node": ">=22" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -1058,22 +1071,6 @@ "node": ">=6" } }, - "node_modules/fast-content-type-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-3.0.0.tgz", - "integrity": "sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT" - }, "node_modules/file-type": { "version": "21.3.4", "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.4.tgz", @@ -1351,9 +1348,9 @@ } }, "node_modules/json-with-bigint": { - "version": "3.5.7", - "resolved": "https://registry.npmjs.org/json-with-bigint/-/json-with-bigint-3.5.7.tgz", - "integrity": "sha512-7ei3MdAI5+fJPVnKlW77TKNKwQ5ppSzWvhPuSuINT/GYW9ZOC1eRKOuhV9yHG5aEsUPj9BBx5JIekkmoLHxZOw==", + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/json-with-bigint/-/json-with-bigint-3.5.12.tgz", + "integrity": "sha512-uwbF/wSSuOgC7qqlq27Xp5B6a2MHVug3t0idZdTqu0JnlFvgJuH7ju+KAk/J06C7GfhoYy2gnb9wz2INqcne7w==", "license": "MIT" }, "node_modules/locate-path": { @@ -1501,9 +1498,9 @@ } }, "node_modules/p-retry": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-8.0.0.tgz", - "integrity": "sha512-kFVqH1HxOHp8LupNsOys7bSV09VYTRLxarH/mokO4Rqhk6wGi70E0jh4VzvVGXfEVNggHoHLAMWsQqHyU1Ey9A==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-8.0.1.tgz", + "integrity": "sha512-NAigyu8hfvJe7MsS18mnc4is0MZtau3QMdBklaJKK23oBQb6occO3UPM3vHmTckW8KhfyjMZaUOqdTFEYliHgg==", "license": "MIT", "dependencies": { "is-network-error": "^1.3.0" diff --git a/package.json b/package.json index 45f336e8..20c2f750 100644 --- a/package.json +++ b/package.json @@ -17,10 +17,10 @@ "license": "MIT", "dependencies": { "@actions/core": "^3.0.1", - "@octokit/auth-app": "^8.2.0", + "@octokit/auth-app": "^8.3.1", "@octokit/request": "^10.0.8", "is-network-error": "^1.3.2", - "p-retry": "^8.0.0" + "p-retry": "^8.0.1" }, "devDependencies": { "@octokit/openapi": "^22.0.0", From a47236f79f79fcbc3532af49fe3a5ded89529b6e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2026 15:52:54 -0700 Subject: [PATCH 25/29] feat: update permission inputs (#399) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [@octokit/openapi](https://github.com/octokit/openapi) from 22.0.0 to 24.0.0.
Release notes

Sourced from @​octokit/openapi's releases.

v24.0.0

24.0.0 (2026-10-05)

Features

  • delete teams related endpoints, add new endpoints (as of 2026-10-05) (#542) (f1e85dc)

BREAKING CHANGES

  • Remove the Enterprise Teams REST API endpoints under /enterprises/{enterprise}/teams. Co-authored-by: octokit[bot] <171388558+octokit[bot]@​users.noreply.github.com> Co-authored-by: wolfy1339 webmaster@wolfy1339.com

v23.0.3

23.0.3 (2026-10-05)

Bug Fixes

  • patch app-installations anyOf in place instead of replacing the operation (#544) (c0c9994)

v23.0.2

23.0.2 (2026-09-09)

Bug Fixes

v23.0.1

23.0.1 (2026-08-29)

Bug Fixes

  • remove requestBody when no schema is present (#532) (a0a73ee)

v23.0.0

23.0.0 (2026-08-27)

  • feat!: remove deprecated endpoints, major additions up to 2026-08-24 (#538) (8dda528)

New Endpoints

  • GET /agents/repos/{owner}/{repo}/tasks
  • POST /agents/repos/{owner}/{repo}/tasks
  • GET /agents/repos/{owner}/{repo}/tasks/{task_id}
  • GET /agents/tasks

... (truncated)

Commits
  • f1e85dc feat: delete teams related endpoints, add new endpoints (as of 2026-10-05) (#...
  • c0c9994 fix: patch app-installations anyOf in place instead of replacing the operatio...
  • da1aaff ci(action): update actions/checkout action to v7 (#535)
  • bcfdbca fix: temporarily hardcode GHES versions (#540)
  • a0a73ee fix: remove requestBody when no schema is present (#532)
  • 8dda528 feat!: remove deprecated endpoints, major additions up to 2026-08-24 (#538)
  • 52f0709 ci(action): update actions/add-to-project action to v2 (#534)
  • dd22170 ci(action): update actions/setup-node action to v7 (#536)
  • 4c6354a ci(action): update actions/create-github-app-token action to v3 (#525)
  • 7b4325a build(deps): lock file maintenance (#526)
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@octokit/openapi&package-manager=npm_and_yarn&previous-version=22.0.0&new-version=24.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Parker Brown <17183625+parkerbxyz@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b1df02be-7b54-4bb7-b981-89dea6a89274 --- action.yml | 10 ++++--- package-lock.json | 8 +++--- package.json | 2 +- scripts/generated/app-permissions.json | 36 +++++++++++++++++++------- 4 files changed, 39 insertions(+), 17 deletions(-) diff --git a/action.yml b/action.yml index 9f45ab3e..c6c0f607 100644 --- a/action.yml +++ b/action.yml @@ -44,6 +44,8 @@ inputs: description: "The level of permission to create and retrieve the access token for repository attestations. Can be set to 'read' or 'write'." permission-checks: description: "The level of permission to grant the access token for checks on code. Can be set to 'read' or 'write'." + permission-code-quality: + description: "The level of permission to grant the access token to view and manage code quality data. Can be set to 'read' or 'write'." permission-codespaces: description: "The level of permission to grant the access token to create, edit, delete, and list Codespaces. Can be set to 'read' or 'write'." permission-contents: @@ -82,8 +84,10 @@ inputs: description: "The level of permission to grant the access token to manage access to an organization. Can be set to 'read' or 'write'." permission-organization-announcement-banners: description: "The level of permission to grant the access token to view and manage announcement banners for an organization. Can be set to 'read' or 'write'." + permission-organization-copilot-agent-settings: + description: "The level of permission to grant the access token to view and manage Copilot cloud agent settings for an organization. Can be set to 'read' or 'write'." permission-organization-copilot-seat-management: - description: "The level of permission to grant the access token for managing access to GitHub Copilot for members of an organization with a Copilot Business subscription. This property is in public preview and is subject to change. Can be set to 'write'." + description: "The level of permission to grant the access token for managing access to GitHub Copilot for members of an organization with a Copilot Business subscription. This property is in public preview and is subject to change. Can be set to 'read' or 'write'." permission-organization-custom-org-roles: description: "The level of permission to grant the access token for custom organization roles management. Can be set to 'read' or 'write'." permission-organization-custom-properties: @@ -92,6 +96,8 @@ inputs: description: "The level of permission to grant the access token for custom repository roles management. Can be set to 'read' or 'write'." permission-organization-events: description: "The level of permission to grant the access token to view events triggered by an activity in an organization. Can be set to 'read'." + permission-organization-external-properties-for-repos: + description: "The level of permission to grant the access token for managing external custom properties for repositories in an organization. Can be set to 'read', 'write', or 'admin'." permission-organization-hooks: description: "The level of permission to grant the access token to manage the post-receive hooks for an organization. Can be set to 'read' or 'write'." permission-organization-packages: @@ -136,8 +142,6 @@ inputs: description: "The level of permission to grant the access token to list and manage repositories a user is starring. Can be set to 'read' or 'write'." permission-statuses: description: "The level of permission to grant the access token for commit statuses. Can be set to 'read' or 'write'." - permission-team-discussions: - description: "The level of permission to grant the access token to manage team discussions and related comments. Can be set to 'read' or 'write'." permission-vulnerability-alerts: description: "The level of permission to grant the access token to manage Dependabot alerts. Can be set to 'read' or 'write'." permission-workflows: diff --git a/package-lock.json b/package-lock.json index 1da661a6..cad2de46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "p-retry": "^8.0.1" }, "devDependencies": { - "@octokit/openapi": "^22.0.0", + "@octokit/openapi": "^24.0.0", "c8": "^12.0.0", "esbuild": "^0.28.2", "open-cli": "^9.0.0", @@ -672,9 +672,9 @@ } }, "node_modules/@octokit/openapi": { - "version": "22.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi/-/openapi-22.0.0.tgz", - "integrity": "sha512-Rpif7FjTjFEBSU+amIRHUAIAHwgg+tVJdTiQuU2GEWDniZxmWjxZCgJ4V9GEp2GXnq/Bl+TrjEvwAl9PB29NAQ==", + "version": "24.0.0", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@octokit/openapi/-/openapi-24.0.0.tgz", + "integrity": "sha512-KIpEIm6oND1tyTT3m/xyJZVJuduifs9BKLevaIjm+MBheg4ossTzLrx2leNgJoXccoIx5SjGGH/Esu/yecjirg==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index 20c2f750..5b99346e 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "p-retry": "^8.0.1" }, "devDependencies": { - "@octokit/openapi": "^22.0.0", + "@octokit/openapi": "^24.0.0", "c8": "^12.0.0", "esbuild": "^0.28.2", "open-cli": "^9.0.0", diff --git a/scripts/generated/app-permissions.json b/scripts/generated/app-permissions.json index d66d70cb..14402029 100644 --- a/scripts/generated/app-permissions.json +++ b/scripts/generated/app-permissions.json @@ -1,7 +1,7 @@ { "title": "App Permissions", "type": "object", - "description": "The permissions granted to the user access token.", + "description": "The permissions granted to the fine-grained access token.", "properties": { "actions": { "type": "string", @@ -43,6 +43,14 @@ "write" ] }, + "code_quality": { + "type": "string", + "description": "The level of permission to grant the access token to view and manage code quality data.", + "enum": [ + "read", + "write" + ] + }, "codespaces": { "type": "string", "description": "The level of permission to grant the access token to create, edit, delete, and list Codespaces.", @@ -272,9 +280,27 @@ "type": "string", "description": "The level of permission to grant the access token for managing access to GitHub Copilot for members of an organization with a Copilot Business subscription. This property is in public preview and is subject to change.", "enum": [ + "read", + "write" + ] + }, + "organization_copilot_agent_settings": { + "type": "string", + "description": "The level of permission to grant the access token to view and manage Copilot cloud agent settings for an organization.", + "enum": [ + "read", "write" ] }, + "organization_external_properties_for_repos": { + "type": "string", + "description": "The level of permission to grant the access token for managing external custom properties for repositories in an organization.", + "enum": [ + "read", + "write", + "admin" + ] + }, "organization_announcement_banners": { "type": "string", "description": "The level of permission to grant the access token to view and manage announcement banners for an organization.", @@ -362,14 +388,6 @@ "write" ] }, - "team_discussions": { - "type": "string", - "description": "The level of permission to grant the access token to manage team discussions and related comments.", - "enum": [ - "read", - "write" - ] - }, "email_addresses": { "type": "string", "description": "The level of permission to grant the access token to manage the email addresses belonging to a user.", From 12461a3a794e67c032f1eff5bb95ece9427eb4fb Mon Sep 17 00:00:00 2001 From: Parker Brown <17183625+parkerbxyz@users.noreply.github.com> Date: Mon, 12 Oct 2026 16:05:53 -0700 Subject: [PATCH 26/29] fix(deps): bump nested undici from 6.24.0 to 6.29.0 (#403) Updates the copy of `undici` nested under `@actions/http-client`, which `@actions/core` depends on, from 6.24.0 to 6.29.0. That's still within `@actions/http-client`'s `^6.23.0` range. Dependabot can't update this copy on its own because `undici@8` is also a direct dev dependency. This PR runs `npm update undici`, which updates it. The release PR will rebuild `dist/`. - `npm ls undici` now shows `undici@6.29.0` under `@actions/http-client` and `undici@8.11.2` at the top level. - `npm test` passes with 100% coverage. --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4cae10ea-f068-4e95-983b-af39d7e7e065 --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index cad2de46..368387d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -57,9 +57,9 @@ } }, "node_modules/@actions/http-client/node_modules/undici": { - "version": "6.24.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.0.tgz", - "integrity": "sha512-lVLNosgqo5EkGqh5XUDhGfsMSoO8K0BAN0TyJLvwNRSl4xWGZlCVYsAIpa/OpA3TvmnM01GWcoKmc3ZWo5wKKA==", + "version": "6.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.29.0.tgz", + "integrity": "sha512-R+RODBqp6i2pPflGdq+xIOUkl+RNfGgHwoinecKu/JCuf2uO06cOKoDbI2P7Dn6KcswdKwrczbU6IYJ6K8X+wg==", "license": "MIT", "engines": { "node": ">=18.17" From 655017ffa7c6b0c6e4210729fa6bce35cacd8ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Str=C3=BCbe?= Date: Tue, 13 Oct 2026 01:37:47 +0200 Subject: [PATCH 27/29] docs: clarify when owner grants access to all repositories (#378) Clarifies the `repositories` note in the README: the token gets access to all repositories in the installation only when `owner` is set explicitly. Leaving `owner` empty scopes the token to the current repository, even though `owner` defaults to the current repository owner. Fixes #377. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 00ca19dd..dfe92e60 100644 --- a/README.md +++ b/README.md @@ -386,7 +386,7 @@ steps: **Optional:** Comma or newline-separated list of repositories to grant access to. > [!NOTE] -> If `owner` is set and `repositories` is empty, access will be scoped to all repositories in the provided repository owner's installation. If `owner` and `repositories` are empty, access will be scoped to only the current repository. +> If `owner` is set explicitly and `repositories` is empty, access will be scoped to all repositories in the provided repository owner's installation. If `owner` and `repositories` are empty, access will be scoped to only the current repository. > > Repository entries may include an owner, for example `owner/repo1`. The owner portion must match the `owner` input, or the current repository owner if `owner` is unset. From f3a828e4b91180d3a46ac1f4b43fa8384b0dea07 Mon Sep 17 00:00:00 2001 From: Parker Brown <17183625+parkerbxyz@users.noreply.github.com> Date: Mon, 12 Oct 2026 16:40:31 -0700 Subject: [PATCH 28/29] ci: create signed dist commits in release workflow (#404) The `main` ruleset requires verified signatures, but the "chore: update dist files" commit on release-please PRs isn't signed. `git-auto-commit-action` creates it with plain `git push`. [Unsigned commits on the head branch can block squash merges too](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets#require-signed-commits), so the dist commit itself needs a signature. This replaces `git-auto-commit-action` with [`dsanders11/github-app-commit-action`](https://github.com/dsanders11/github-app-commit-action), pinned to the v2.1.0 commit SHA. It creates the commit through the REST Git Data API with the releaser app token, and GitHub signs commits that a GitHub App creates that way. - A new `git add dist` step stages the rebuilt files. The action commits only staged changes, so this replaces `file_pattern: dist/**`. - `commit_author` is removed. GitHub signs API commits only when they don't set a custom author, so the commit is now authored by the releaser app instead of `github.actor`. - `fail-on-no-changes: false` keeps the old behavior of skipping the commit when dist didn't change. The action uploads files as blobs, so the roughly 900 KB bundles aren't a problem. The releaser app token is still needed: if the commit used `GITHUB_TOKEN`, `test` wouldn't run on release PRs. The first release run after merging will confirm the commit shows as verified. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c91009d9-b4f7-4eec-b30f-4b24ae578aa1 --- .github/workflows/release.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 11564e82..3ce40fe1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -51,12 +51,15 @@ jobs: - run: npm run build if: steps.release-please.outputs.prs_created == 'true' - - uses: stefanzweifel/git-auto-commit-action@4a55954c782fc1ea30b9056cd3e7a2b40ca8887d # v7.2.0 + - run: git add dist + if: steps.release-please.outputs.prs_created == 'true' + + - uses: dsanders11/github-app-commit-action@2bbcd331016d8c950b05a24b56e7eb9cb50d545e # v2.1.0 if: steps.release-please.outputs.prs_created == 'true' with: - commit_author: "${{ github.actor }} <${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com>" - commit_message: "chore: update dist files" - file_pattern: dist/** + message: "chore: update dist files" + token: ${{ steps.app-token.outputs.token }} + fail-on-no-changes: false - name: Update major version tag id: update-major-tag From 64ab729a6294000f5aa4a4bc0b73d1f32bc45510 Mon Sep 17 00:00:00 2001 From: "create-app-token-action-releaser[bot]" <135574722+create-app-token-action-releaser[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2026 16:42:07 -0700 Subject: [PATCH 29/29] chore(main): release 3.3.0 (#402) :robot: I have created a release *beep* *boop* --- ## [3.3.0](https://github.com/actions/create-github-app-token/compare/v3.2.0...v3.3.0) (2026-10-12) ### Features * update permission inputs ([#399](https://github.com/actions/create-github-app-token/issues/399)) ([a47236f](https://github.com/actions/create-github-app-token/commit/a47236f79f79fcbc3532af49fe3a5ded89529b6e)) ### Bug Fixes * **deps:** bump nested undici from 6.24.0 to 6.29.0 ([#403](https://github.com/actions/create-github-app-token/issues/403)) ([12461a3](https://github.com/actions/create-github-app-token/commit/12461a3a794e67c032f1eff5bb95ece9427eb4fb)) * **deps:** bump the production-dependencies group across 1 directory with 3 updates ([#395](https://github.com/actions/create-github-app-token/issues/395)) ([a69c19d](https://github.com/actions/create-github-app-token/commit/a69c19ddfdf8e1ab093900e0064524ce9309c807)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: create-app-token-action-releaser[bot] <135574722+create-app-token-action-releaser[bot]@users.noreply.github.com> Co-authored-by: parkerbxyz <17183625+parkerbxyz@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 + dist/main.cjs | 1594 +++++++++++++++++++++++++-------- dist/post.cjs | 1562 ++++++++++++++++++++++++-------- package-lock.json | 4 +- package.json | 2 +- 6 files changed, 2403 insertions(+), 774 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 95a37e3e..6110c0f0 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "3.2.0" + ".": "3.3.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 3dfff070..507d40e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## [3.3.0](https://github.com/actions/create-github-app-token/compare/v3.2.0...v3.3.0) (2026-10-12) + + +### Features + +* update permission inputs ([#399](https://github.com/actions/create-github-app-token/issues/399)) ([a47236f](https://github.com/actions/create-github-app-token/commit/a47236f79f79fcbc3532af49fe3a5ded89529b6e)) + + +### Bug Fixes + +* **deps:** bump nested undici from 6.24.0 to 6.29.0 ([#403](https://github.com/actions/create-github-app-token/issues/403)) ([12461a3](https://github.com/actions/create-github-app-token/commit/12461a3a794e67c032f1eff5bb95ece9427eb4fb)) +* **deps:** bump the production-dependencies group across 1 directory with 3 updates ([#395](https://github.com/actions/create-github-app-token/issues/395)) ([a69c19d](https://github.com/actions/create-github-app-token/commit/a69c19ddfdf8e1ab093900e0064524ce9309c807)) + ## [3.2.0](https://github.com/actions/create-github-app-token/compare/v3.1.1...v3.2.0) (2026-05-12) diff --git a/dist/main.cjs b/dist/main.cjs index 20b90dce..6158842f 100644 --- a/dist/main.cjs +++ b/dist/main.cjs @@ -5,7 +5,11 @@ var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __commonJS = (cb, mod) => function __require() { - return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + try { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + } catch (e) { + throw mod = 0, e; + } }; var __export = (target, all) => { for (var name in all) @@ -1855,10 +1859,66 @@ var require_request = __commonJS({ return false; } } - onUpgrade(statusCode, headers, socket) { + /** + * @param {number|null} statusCode + * @param {Buffer[]|null} headers + * @param {import('node:stream').Duplex} socket + * @param {string} [statusText] + */ + onUpgrade(statusCode, headers, socket, statusText = "") { + this.onFinally(); assert(!this.aborted); assert(!this.completed); - return this[kHandler].onUpgrade(statusCode, headers, socket); + if (statusCode !== null) { + this.#publishUpgradeHeaders(statusCode, headers, statusText); + } + const result = this[kHandler].onUpgrade(statusCode, headers, socket); + if (!this.aborted) { + this.completed = true; + if (statusCode !== null) { + this.#publishUpgradeTrailers(); + } + } + return result; + } + /** + * @param {number} statusCode + * @param {import('node:http2').IncomingHttpHeaders} headers + * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders + * @param {string} [statusText] + */ + onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { + assert(!this.aborted); + assert(this.completed); + if (channels.headers.hasSubscribers) { + this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); + } + this.#publishUpgradeTrailers(); + } + /** + * @param {Error} error + */ + onUpgradeError(error2) { + assert(!this.aborted); + assert(this.completed); + if (channels.error.hasSubscribers) { + channels.error.publish({ request: this, error: error2 }); + } + } + /** + * @param {number} statusCode + * @param {Buffer[]} headers + * @param {string} statusText + */ + #publishUpgradeHeaders(statusCode, headers, statusText) { + if (channels.headers.hasSubscribers) { + channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); + } + } + #publishUpgradeTrailers() { + if (channels.trailers.hasSubscribers) { + channels.trailers.publish({ request: this, trailers: [] }); + } } onComplete(trailers) { this.onFinally(); @@ -1925,7 +1985,11 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - arr.push(`${val[i]}`); + const str = `${val[i]}`; + if (!isValidHeaderValue(str)) { + throw new InvalidArgumentError(`invalid ${key} header`); + } + arr.push(str); } } val = arr; @@ -1937,6 +2001,9 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; + if (!isValidHeaderValue(val)) { + throw new InvalidArgumentError(`invalid ${key} header`); + } } if (headerName === "host") { if (request2.host !== null) { @@ -2046,13 +2113,21 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); + var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class extends Dispatcher { - constructor() { + constructor(opts) { super(); this[kDestroyed] = false; this[kOnDestroyed] = null; this[kClosed] = false; this[kOnClosed] = []; + this[kWebSocketOptions] = opts?.webSocket ?? {}; + } + get webSocketOptions() { + return { + maxFragments: this[kWebSocketOptions].maxFragments ?? 131072, + maxPayloadSize: this[kWebSocketOptions].maxPayloadSize ?? 128 * 1024 * 1024 + }; } get destroyed() { return this[kDestroyed]; @@ -5659,6 +5734,7 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, + InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5705,6 +5781,9 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; + var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); + var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); + var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5867,24 +5946,55 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(data.slice(offset)); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(data.slice(offset)); - } else if (ret !== constants3.ERROR.OK) { - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; + if (ret !== constants3.ERROR.OK) { + const body = data.subarray(offset); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(body); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(body); + } else { + throw this.createError(ret, body); } - throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } catch (err) { util.destroy(socket, err); } } + finish() { + assert(currentParser === null); + assert(this.ptr != null); + assert(!this.paused); + const { llhttp } = this; + let ret; + try { + currentParser = this; + ret = llhttp.llhttp_finish(this.ptr); + } finally { + currentParser = null; + } + if (ret === constants3.ERROR.OK) { + return null; + } + if (ret === constants3.ERROR.PAUSED || ret === constants3.ERROR.PAUSED_UPGRADE) { + this.paused = true; + return null; + } + return this.createError(ret, EMPTY_BUF); + } + createError(ret, data) { + const { llhttp, contentLength, bytesRead } = this; + if (contentLength && bytesRead !== parseInt(contentLength, 10)) { + return new ResponseContentLengthMismatchError(); + } + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; + } + return new HTTPParserError(message, constants3.ERROR[ret], data); + } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -5904,6 +6014,10 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } + if (client[kRunning] === 0) { + util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); + return -1; + } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -5947,7 +6061,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode } = this; + const { upgrade, client, socket, headers, statusCode, statusText } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -5972,9 +6086,10 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket); - } catch (err) { - util.destroy(socket, err); + request2.onUpgrade(statusCode, headers, socket, statusText); + } catch (error2) { + util.errorRequest(client, request2, error2); + util.destroy(socket, error2); } client[kResume](); } @@ -5983,6 +6098,10 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } + if (client[kRunning] === 0) { + util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); + return -1; + } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6108,6 +6227,7 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; + socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6151,12 +6271,19 @@ var require_client_h1 = __commonJS({ socket[kWriting] = false; socket[kReset] = false; socket[kBlocking] = false; + socket[kIdleSocketValidation] = 0; + socket[kIdleSocketValidationTimeout] = null; + socket[kSocketUsed] = false; socket[kParser] = new Parser(client, socket, llhttpInstance); addListener(socket, "error", function(err) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - parser.onMessageComplete(); + const parserErr = parser.finish(); + if (parserErr) { + this[kError] = parserErr; + this[kClient][kOnError](parserErr); + } return; } this[kError] = err; @@ -6171,7 +6298,10 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - parser.onMessageComplete(); + const parserErr = parser.finish(); + if (parserErr) { + util.destroy(this, parserErr); + } return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6179,9 +6309,10 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; + clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - parser.onMessageComplete(); + this[kError] = parser.finish() || this[kError]; } this[kParser].destroy(); this[kParser] = null; @@ -6230,7 +6361,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { return true; } if (request2) { @@ -6248,6 +6379,23 @@ var require_client_h1 = __commonJS({ } }; } + function clearIdleSocketValidation(socket) { + if (socket[kIdleSocketValidationTimeout]) { + clearImmediate(socket[kIdleSocketValidationTimeout]); + socket[kIdleSocketValidationTimeout] = null; + } + socket[kIdleSocketValidation] = 0; + } + function scheduleIdleSocketValidation(client, socket) { + socket[kIdleSocketValidation] = 1; + socket[kIdleSocketValidationTimeout] = setImmediate(() => { + socket[kIdleSocketValidationTimeout] = null; + socket[kIdleSocketValidation] = 2; + if (client[kSocket] === socket && !socket.destroyed) { + client[kResume](); + } + }); + } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6260,6 +6408,29 @@ var require_client_h1 = __commonJS({ socket.ref(); socket[kNoRef] = false; } + if (client[kRunning] === 0 && client[kPending] > 0 && socket[kSocketUsed]) { + if (socket[kIdleSocketValidation] === 0) { + scheduleIdleSocketValidation(client, socket); + socket[kParser].readMore(); + if (socket.destroyed) { + return; + } + return; + } + if (socket[kIdleSocketValidation] === 1) { + socket[kParser].readMore(); + if (socket.destroyed) { + return; + } + return; + } + } + if (client[kRunning] === 0) { + socket[kParser].readMore(); + if (socket.destroyed) { + return; + } + } if (client[kSize] === 0) { if (socket[kParser].timeoutType !== TIMEOUT_KEEP_ALIVE) { socket[kParser].setTimeout(client[kKeepAliveTimeoutValue], TIMEOUT_KEEP_ALIVE); @@ -6290,8 +6461,16 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { - headers.push("content-type", body.type); + } else if (util.isBlobLike(body) && request2.contentType == null) { + const contentType = body.type; + if (contentType) { + const contentTypeValue = `${contentType}`; + if (!util.isValidHeaderValue(contentTypeValue)) { + util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); + return false; + } + headers.push("content-type", contentTypeValue); + } } if (body && typeof body.read === "function") { body.read(0); @@ -6312,11 +6491,18 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - const abort = (err) => { - if (request2.aborted || request2.completed) { + clearIdleSocketValidation(socket); + const abort = (error2) => { + if (request2.aborted) { return; } - util.errorRequest(client, request2, err || new RequestAbortedError()); + if (request2.completed) { + if (request2.upgrade || request2.method === "CONNECT") { + util.destroy(socket, new InformationalError("aborted")); + } + return; + } + util.errorRequest(client, request2, error2 || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6672,6 +6858,7 @@ var require_client_h2 = __commonJS({ "node_modules/@actions/http-client/node_modules/undici/lib/dispatcher/client-h2.js"(exports2, module2) { "use strict"; var assert = require("node:assert"); + var { errorMonitor } = require("node:events"); var { pipeline } = require("node:stream"); var util = require_util(); var { @@ -6732,6 +6919,10 @@ var require_client_h2 = __commonJS({ } return result; } + function parseH2ResponseHeaders(headers) { + const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; + return parseH2Headers(realHeaders); + } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -6895,16 +7086,22 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (err) => { - if (request2.aborted || request2.completed) { + const abort = (error2) => { + if (request2.aborted) { return; } - err = err || new RequestAbortedError(); - util.errorRequest(client, request2, err); + if (request2.completed) { + if (method === "CONNECT" && stream != null) { + util.destroy(stream, error2 || new RequestAbortedError()); + } + return; + } + error2 = error2 || new RequestAbortedError(); + util.errorRequest(client, request2, error2); if (stream != null) { - util.destroy(stream, err); + util.destroy(stream, error2); } - util.destroy(body, err); + util.destroy(body, error2); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -6919,18 +7116,42 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - if (stream.id && !stream.pending) { - request2.onUpgrade(null, null, stream); - ++session[kOpenStreams]; - client[kQueue][client[kRunningIdx]++] = null; - } else { - stream.once("ready", () => { + let upgradeResponseFinished = false; + const onResponse = (headers2) => { + upgradeResponseFinished = true; + stream.off(errorMonitor, onUpgradeError); + request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); + }; + const onUpgradeError = (error2) => { + upgradeResponseFinished = true; + stream.off("response", onResponse); + request2.onUpgradeError(error2); + }; + const onReady = () => { + try { request2.onUpgrade(null, null, stream); - ++session[kOpenStreams]; - client[kQueue][client[kRunningIdx]++] = null; - }); - } + } catch (error2) { + stream.off("response", onResponse); + abort(error2); + return; + } + if (request2.aborted) { + return; + } + stream.off("error", abort); + stream.once(errorMonitor, onUpgradeError); + client[kQueue][client[kRunningIdx]++] = null; + }; + stream.once("response", onResponse); + stream.once("error", abort); + ++session[kOpenStreams]; + onReady(); stream.once("close", () => { + if (!upgradeResponseFinished && request2.completed) { + stream.off("response", onResponse); + stream.off(errorMonitor, onUpgradeError); + request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); + } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7491,9 +7712,10 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2 + allowH2, + webSocket } = {}) { - super(); + super({ webSocket }); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -7999,8 +8221,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor() { - super(); + constructor(opts) { + super(opts); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8171,7 +8393,6 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { - super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8192,6 +8413,7 @@ var require_pool = __commonJS({ ...connect }); } + super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8391,7 +8613,6 @@ var require_agent = __commonJS({ } var Agent3 = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { - super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8401,6 +8622,7 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } + super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -8841,6 +9063,24 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } + function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { + const contentLength = headers["content-length"]; + if (contentLength == null) { + return null; + } + if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { + return null; + } + const length = Number(contentLength); + const expectedLength = range.end - range.start + 1; + if (!Number.isFinite(length) || length !== expectedLength) { + return new RequestRetryError("Content-Length mismatch", statusCode, { + headers, + data: { count: retryCount } + }); + } + return null; + } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -8894,6 +9134,7 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; + this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -8903,6 +9144,17 @@ var require_retry_handler = __commonJS({ } }); } + checkpointResponseEnd(headers, resume) { + if (this.end == null && this.opts.method !== "HEAD") { + const contentLength = headers["content-length"]; + this.end = contentLength != null ? Number(contentLength) - 1 : null; + assert( + this.end == null || Number.isFinite(this.end), + "invalid content-length" + ); + } + this.resume = this.end != null ? resume : null; + } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -8964,7 +9216,9 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (this.retryOpts.statusCodes.includes(statusCode) === false) { + if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { + this.headersSent = true; + this.checkpointResponseEnd(headers, resume); return this.handler.onHeaders( statusCode, rawHeaders, @@ -9013,9 +9267,21 @@ var require_retry_handler = __commonJS({ ); return false; } + const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); + if (contentLengthError != null) { + this.abort(contentLengthError); + return false; + } const { start, size, end = size - 1 } = contentRange; - assert(this.start === start, "content-range mismatch"); - assert(this.end == null || this.end === end, "content-range mismatch"); + if (this.start !== start || this.end != null && this.end !== end) { + this.abort( + new RequestRetryError("Content-Range mismatch", statusCode, { + headers, + data: { count: this.retryCount } + }) + ); + return false; + } this.resume = resume; return true; } @@ -9023,6 +9289,7 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { + this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9030,6 +9297,11 @@ var require_retry_handler = __commonJS({ statusMessage ); } + const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); + if (contentLengthError != null) { + this.abort(contentLengthError); + return false; + } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9049,6 +9321,7 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; + this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9076,7 +9349,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body)) { + if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -15875,14 +16148,48 @@ var require_util6 = __commonJS({ for (let i = 0; i < path6.length; ++i) { const code = path6.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code === 127 || // DEL + code > 126 || // exclude DEL and non-ascii code === 59) { throw new Error("Invalid cookie path"); } } } + function isLetterOrDigit(code) { + return code >= 48 && code <= 57 || // 0-9 + code >= 65 && code <= 90 || // A-Z + code >= 97 && code <= 122; + } function validateCookieDomain(domain) { - if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { + if (domain === " ") { + return; + } + if (domain.length > 255) { + throw new Error("Invalid cookie domain"); + } + let labelLength = 0; + for (let i = 0; i < domain.length; ++i) { + const code = domain.charCodeAt(i); + if (code === 46) { + if (labelLength === 0) { + throw new Error("Invalid cookie domain"); + } + if (domain.charCodeAt(i - 1) === 45) { + throw new Error("Invalid cookie domain"); + } + labelLength = 0; + continue; + } + if (labelLength === 0 && !isLetterOrDigit(code)) { + throw new Error("Invalid cookie domain"); + } + if (!isLetterOrDigit(code) && code !== 45) { + throw new Error("Invalid cookie domain"); + } + if (++labelLength > 63) { + throw new Error("Invalid cookie domain"); + } + } + if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { throw new Error("Invalid cookie domain"); } } @@ -15965,7 +16272,11 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - out.push(`${key.trim()}=${value.join("=")}`); + const trimmedKey = key.trim(); + const joinedValue = value.join("="); + validateCookieName(trimmedKey); + validateCookieValue(joinedValue); + out.push(`${trimmedKey}=${joinedValue}`); } return out.join("; "); } @@ -16095,18 +16406,14 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { - let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase.includes("none")) { - enforcement = "None"; - } - if (attributeValueLowercase.includes("strict")) { - enforcement = "Strict"; - } - if (attributeValueLowercase.includes("lax")) { - enforcement = "Lax"; + if (attributeValueLowercase === "none") { + cookieAttributeList.sameSite = "None"; + } else if (attributeValueLowercase === "strict") { + cookieAttributeList.sameSite = "Strict"; + } else if (attributeValueLowercase === "lax") { + cookieAttributeList.sameSite = "Lax"; } - cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -16928,7 +17235,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (!requestProtocols.includes(secProtocol)) { + if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17034,31 +17341,26 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); - var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - /** @type {number} */ - #maxDecompressedSize; - /** @type {boolean} */ - #aborted = false; - /** @type {Function|null} */ - #currentCallback = null; + #maxPayloadSize = 0; /** * @param {Map} extensions - * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options = {}) { + constructor(extensions, options) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; + this.#maxPayloadSize = options.maxPayloadSize; } + /** + * Decompress a compressed payload. + * @param {Buffer} chunk Compressed data + * @param {boolean} fin Final fragment flag + * @param {Function} callback Callback function + */ decompress(chunk, fin, callback) { - if (this.#aborted) { - callback(new MessageSizeExceededError()); - return; - } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17077,20 +17379,12 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; this.#inflate[kLength] = 0; this.#inflate.on("data", (data) => { - if (this.#aborted) { - return; - } this.#inflate[kLength] += data.length; - if (this.#inflate[kLength] > this.#maxDecompressedSize) { - this.#aborted = true; + if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) { + callback(new MessageSizeExceededError()); this.#inflate.removeAllListeners(); this.#inflate.destroy(); this.#inflate = null; - if (this.#currentCallback) { - const cb = this.#currentCallback; - this.#currentCallback = null; - cb(new MessageSizeExceededError()); - } return; } this.#inflate[kBuffer].push(data); @@ -17100,19 +17394,17 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } - this.#currentCallback = callback; this.#inflate.write(chunk); if (fin) { this.#inflate.write(tail); } this.#inflate.flush(() => { - if (this.#aborted || !this.#inflate) { + if (!this.#inflate) { return; } const full = Buffer.concat(this.#inflate[kBuffer], this.#inflate[kLength]); this.#inflate[kBuffer].length = 0; this.#inflate[kLength] = 0; - this.#currentCallback = null; callback(null, full); }); } @@ -17143,8 +17435,14 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); + var { MessageSizeExceededError } = require_errors(); + function failWebsocketConnectionWithCode(ws, code, reason) { + closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); + failWebsocketConnection(ws, reason); + } var ByteParser = class extends Writable { #buffers = []; + #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17152,18 +17450,21 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {{ maxDecompressedMessageSize?: number }} */ - #options; + /** @type {number} */ + #maxFragments; + /** @type {number} */ + #maxPayloadSize; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxDecompressedMessageSize?: number }} [options] + * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#options = options; + this.#maxFragments = options.maxFragments ?? 0; + this.#maxPayloadSize = options.maxPayloadSize ?? 0; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17178,6 +17479,13 @@ var require_receiver = __commonJS({ this.#loop = true; this.run(callback); } + #validatePayloadLength() { + if (this.#maxPayloadSize > 0 && !isControlFrame(this.#info.opcode) && this.#info.payloadLength + this.#fragmentsBytes > this.#maxPayloadSize) { + failWebsocketConnectionWithCode(this.ws, 1009, "Payload size exceeds maximum allowed size"); + return false; + } + return true; + } /** * Runs whenever a new chunk is received. * Callback is called whenever there are no more chunks buffering, @@ -17237,6 +17545,9 @@ var require_receiver = __commonJS({ if (payloadLength <= 125) { this.#info.payloadLength = payloadLength; this.#state = parserStates.READ_DATA; + if (!this.#validatePayloadLength()) { + return; + } } else if (payloadLength === 126) { this.#state = parserStates.PAYLOADLENGTH_16; } else if (payloadLength === 127) { @@ -17257,6 +17568,9 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); this.#info.payloadLength = buffer.readUInt16BE(0); this.#state = parserStates.READ_DATA; + if (!this.#validatePayloadLength()) { + return; + } } else if (this.#state === parserStates.PAYLOADLENGTH_64) { if (this.#byteOffset < 8) { return callback(); @@ -17270,6 +17584,9 @@ var require_receiver = __commonJS({ } this.#info.payloadLength = lower; this.#state = parserStates.READ_DATA; + if (!this.#validatePayloadLength()) { + return; + } } else if (this.#state === parserStates.READ_DATA) { if (this.#byteOffset < this.#info.payloadLength) { return callback(); @@ -17280,32 +17597,46 @@ var require_receiver = __commonJS({ this.#state = parserStates.INFO; } else { if (!this.#info.compressed) { - this.#fragments.push(body); + if (!this.writeFragments(body)) { + return; + } + if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { + failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); + return; + } if (!this.#info.fragmented && this.#info.fin) { - const fullMessage = Buffer.concat(this.#fragments); - websocketMessageReceived(this.ws, this.#info.binaryType, fullMessage); - this.#fragments.length = 0; + websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); } this.#state = parserStates.INFO; } else { - this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { - if (error2) { - failWebsocketConnection(this.ws, error2.message); - return; - } - this.#fragments.push(data); - if (!this.#info.fin) { - this.#state = parserStates.INFO; + this.#extensions.get("permessage-deflate").decompress( + body, + this.#info.fin, + (error2, data) => { + if (error2) { + const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; + failWebsocketConnectionWithCode(this.ws, code, error2.message); + return; + } + if (!this.writeFragments(data)) { + return; + } + if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { + failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); + return; + } + if (!this.#info.fin) { + this.#state = parserStates.INFO; + this.#loop = true; + this.run(callback); + return; + } + websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); this.#loop = true; + this.#state = parserStates.INFO; this.run(callback); - return; } - websocketMessageReceived(this.ws, this.#info.binaryType, Buffer.concat(this.#fragments)); - this.#loop = true; - this.#state = parserStates.INFO; - this.#fragments.length = 0; - this.run(callback); - }); + ); this.#loop = false; break; } @@ -17348,6 +17679,26 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; return buffer; } + writeFragments(fragment) { + if (this.#maxFragments > 0 && this.#fragments.length === this.#maxFragments) { + failWebsocketConnectionWithCode(this.ws, 1008, "Too many message fragments"); + return false; + } + this.#fragmentsBytes += fragment.length; + this.#fragments.push(fragment); + return true; + } + consumeFragments() { + const fragments = this.#fragments; + if (fragments.length === 1) { + this.#fragmentsBytes = 0; + return fragments.shift(); + } + const output = Buffer.concat(fragments, this.#fragmentsBytes); + this.#fragments = []; + this.#fragmentsBytes = 0; + return output; + } parseCloseBody(data) { assert(data.length !== 1); let code; @@ -17559,8 +17910,6 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; - /** @type {{ maxDecompressedMessageSize?: number }} */ - #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17604,9 +17953,6 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); - this.#options = { - maxDecompressedMessageSize: options.maxDecompressedMessageSize - }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -17790,7 +18136,13 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { this[kResponse] = response; - const parser = new ByteParser(this, parsedExtensions, this.#options); + const webSocketOptions = this[kController]?.dispatcher?.webSocketOptions; + const maxFragments = webSocketOptions?.maxFragments; + const maxPayloadSize = webSocketOptions?.maxPayloadSize; + const parser = new ByteParser(this, parsedExtensions, { + maxFragments, + maxPayloadSize + }); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -17865,19 +18217,6 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) - }, - { - key: "maxDecompressedMessageSize", - converter: webidl.nullableConverter((V) => { - V = webidl.converters["unsigned long long"](V); - if (V <= 0) { - throw webidl.errors.exception({ - header: "WebSocket constructor", - message: "maxDecompressedMessageSize must be greater than 0" - }); - } - return V; - }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -17956,6 +18295,40 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; + var DATA = Buffer.from("data"); + var EVENT = Buffer.from("event"); + var ID = Buffer.from("id"); + var RETRY = Buffer.from("retry"); + function isASCIINumberBytes(buffer, start) { + if (start >= buffer.length) { + return false; + } + for (let i = start; i < buffer.length; i++) { + if (buffer[i] < 48 || buffer[i] > 57) { + return false; + } + } + return true; + } + function isValidLastEventIdBytes(buffer, start) { + for (let i = start; i < buffer.length; i++) { + if (buffer[i] === 0) { + return false; + } + } + return true; + } + function isFieldName(line, length, field) { + if (length !== field.length) { + return false; + } + for (let i = 0; i < length; i++) { + if (line[i] !== field[i]) { + return false; + } + } + return true; + } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -17975,10 +18348,13 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer} + * @type {Buffer[]} */ - buffer = null; + chunks = []; + chunkIndex = 0; pos = 0; + lineChunkIndex = 0; + linePos = 0; event = { data: void 0, event: void 0, @@ -18009,63 +18385,30 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - if (this.buffer) { - this.buffer = Buffer.concat([this.buffer, chunk]); - } else { - this.buffer = chunk; - } + this.chunks.push(chunk); if (this.checkBOM) { - switch (this.buffer.length) { - case 1: - if (this.buffer[0] === BOM[0]) { - callback(); - return; - } - this.checkBOM = false; - callback(); - return; - case 2: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { - callback(); - return; - } - this.checkBOM = false; - break; - case 3: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { - this.buffer = Buffer.alloc(0); - this.checkBOM = false; - callback(); - return; - } - this.checkBOM = false; - break; - default: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { - this.buffer = this.buffer.subarray(3); - } - this.checkBOM = false; - break; + if (this.handleBOM()) { + callback(); + return; } } - while (this.pos < this.buffer.length) { + while (this.hasCurrentByte()) { + const byte = this.currentByte(); if (this.eventEndCheck) { if (this.crlfCheck) { - if (this.buffer[this.pos] === LF) { - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; + if (byte === LF) { this.crlfCheck = false; + this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { - if (this.buffer[this.pos] === CR) { + if (byte === LF || byte === CR) { + if (byte === CR) { this.crlfCheck = true; } - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; - if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { + this.consumeCurrentByte(); + if (this.hasPendingEvent()) { this.processEvent(this.event); } this.clearEvent(); @@ -18074,17 +18417,16 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { - if (this.buffer[this.pos] === CR) { + if (byte === LF || byte === CR) { + if (byte === CR) { this.crlfCheck = true; } - this.parseLine(this.buffer.subarray(0, this.pos), this.event); - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; + this.parseLine(this.readLine(), this.event); + this.consumeCurrentByte(); this.eventEndCheck = true; continue; } - this.pos++; + this.advanceCursor(); } callback(); } @@ -18100,43 +18442,42 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let field = ""; - let value = ""; + let fieldLength = line.length; + let valueStart = line.length; if (colonPosition !== -1) { - field = line.subarray(0, colonPosition).toString("utf8"); - let valueStart = colonPosition + 1; + fieldLength = colonPosition; + valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } - value = line.subarray(valueStart).toString("utf8"); - } else { - field = line.toString("utf8"); - value = ""; } - switch (field) { - case "data": - if (event[field] === void 0) { - event[field] = value; - } else { - event[field] += ` + if (isFieldName(line, fieldLength, DATA)) { + const value = line.toString("utf8", valueStart); + if (event.data === void 0) { + event.data = value; + } else { + event.data += ` ${value}`; - } - break; - case "retry": - if (isASCIINumber(value)) { - event[field] = value; - } - break; - case "id": - if (isValidLastEventId(value)) { - event[field] = value; - } - break; - case "event": - if (value.length > 0) { - event[field] = value; - } - break; + } + return; + } + if (isFieldName(line, fieldLength, RETRY)) { + if (isASCIINumberBytes(line, valueStart)) { + event.retry = line.toString("utf8", valueStart); + } + return; + } + if (isFieldName(line, fieldLength, ID)) { + if (isValidLastEventIdBytes(line, valueStart)) { + event.id = line.toString("utf8", valueStart); + } + return; + } + if (isFieldName(line, fieldLength, EVENT)) { + const value = line.toString("utf8", valueStart); + if (value.length > 0) { + event.event = value; + } } } /** @@ -18161,12 +18502,120 @@ ${value}`; } } clearEvent() { - this.event = { - data: void 0, - event: void 0, - id: void 0, - retry: void 0 - }; + this.event.data = void 0; + this.event.event = void 0; + this.event.id = void 0; + this.event.retry = void 0; + } + hasPendingEvent() { + return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; + } + hasCurrentByte() { + return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; + } + currentByte() { + return this.chunks[this.chunkIndex][this.pos]; + } + consumeCurrentByte() { + this.advanceCursor(); + this.syncLineStartToCursor(); + } + advanceCursor() { + this.pos++; + while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { + this.chunkIndex++; + this.pos = 0; + } + } + syncLineStartToCursor() { + this.lineChunkIndex = this.chunkIndex; + this.linePos = this.pos; + this.dropConsumedChunks(); + } + dropConsumedChunks() { + while (this.lineChunkIndex > 0) { + this.chunks.shift(); + this.lineChunkIndex--; + this.chunkIndex--; + } + if (this.chunkIndex === this.chunks.length) { + this.chunks.length = 0; + this.chunkIndex = 0; + this.pos = 0; + this.lineChunkIndex = 0; + this.linePos = 0; + } + } + readLine() { + if (this.lineChunkIndex === this.chunkIndex) { + return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); + } + const chunks = []; + let length = 0; + for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { + const chunk = this.chunks[i]; + const start = i === this.lineChunkIndex ? this.linePos : 0; + const end = i === this.chunkIndex ? this.pos : chunk.length; + const slice = chunk.subarray(start, end); + length += slice.length; + chunks.push(slice); + } + return Buffer.concat(chunks, length); + } + peekBufferedByte(offset) { + let chunkIndex = this.lineChunkIndex; + let pos = this.linePos; + while (chunkIndex < this.chunks.length) { + const chunk = this.chunks[chunkIndex]; + const remaining = chunk.length - pos; + if (offset < remaining) { + return chunk[pos + offset]; + } + offset -= remaining; + chunkIndex++; + pos = 0; + } + } + discardLeadingBytes(count) { + while (count > 0 && this.lineChunkIndex < this.chunks.length) { + const chunk = this.chunks[this.lineChunkIndex]; + const remaining = chunk.length - this.linePos; + if (count < remaining) { + this.linePos += count; + count = 0; + } else { + count -= remaining; + this.lineChunkIndex++; + this.linePos = 0; + } + } + this.chunkIndex = this.lineChunkIndex; + this.pos = this.linePos; + this.dropConsumedChunks(); + } + handleBOM() { + const first = this.peekBufferedByte(0); + const second = this.peekBufferedByte(1); + const third = this.peekBufferedByte(2); + if (second === void 0) { + if (first === BOM[0]) { + return true; + } + this.checkBOM = false; + return true; + } + if (third === void 0) { + if (first === BOM[0] && second === BOM[1]) { + return true; + } + this.checkBOM = false; + return false; + } + if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { + this.discardLeadingBytes(3); + } + this.checkBOM = false; + return !this.hasCurrentByte(); } }; module2.exports = { @@ -18614,102 +19063,6 @@ var require_undici = __commonJS({ } }); -// node_modules/fast-content-type-parse/index.js -var require_fast_content_type_parse = __commonJS({ - "node_modules/fast-content-type-parse/index.js"(exports2, module2) { - "use strict"; - var NullObject = function NullObject2() { - }; - NullObject.prototype = /* @__PURE__ */ Object.create(null); - var paramRE = /; *([!#$%&'*+.^\w`|~-]+)=("(?:[\v\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\v\u0020-\u00ff])*"|[!#$%&'*+.^\w`|~-]+) */gu; - var quotedPairRE = /\\([\v\u0020-\u00ff])/gu; - var mediaTypeRE = /^[!#$%&'*+.^\w|~-]+\/[!#$%&'*+.^\w|~-]+$/u; - var defaultContentType = { type: "", parameters: new NullObject() }; - Object.freeze(defaultContentType.parameters); - Object.freeze(defaultContentType); - function parse2(header) { - if (typeof header !== "string") { - throw new TypeError("argument header is required and must be a string"); - } - let index = header.indexOf(";"); - const type = index !== -1 ? header.slice(0, index).trim() : header.trim(); - if (mediaTypeRE.test(type) === false) { - throw new TypeError("invalid media type"); - } - const result = { - type: type.toLowerCase(), - parameters: new NullObject() - }; - if (index === -1) { - return result; - } - let key; - let match; - let value; - paramRE.lastIndex = index; - while (match = paramRE.exec(header)) { - if (match.index !== index) { - throw new TypeError("invalid parameter format"); - } - index += match[0].length; - key = match[1].toLowerCase(); - value = match[2]; - if (value[0] === '"') { - value = value.slice(1, value.length - 1); - quotedPairRE.test(value) && (value = value.replace(quotedPairRE, "$1")); - } - result.parameters[key] = value; - } - if (index !== header.length) { - throw new TypeError("invalid parameter format"); - } - return result; - } - function safeParse2(header) { - if (typeof header !== "string") { - return defaultContentType; - } - let index = header.indexOf(";"); - const type = index !== -1 ? header.slice(0, index).trim() : header.trim(); - if (mediaTypeRE.test(type) === false) { - return defaultContentType; - } - const result = { - type: type.toLowerCase(), - parameters: new NullObject() - }; - if (index === -1) { - return result; - } - let key; - let match; - let value; - paramRE.lastIndex = index; - while (match = paramRE.exec(header)) { - if (match.index !== index) { - return defaultContentType; - } - index += match[0].length; - key = match[1].toLowerCase(); - value = match[2]; - if (value[0] === '"') { - value = value.slice(1, value.length - 1); - quotedPairRE.test(value) && (value = value.replace(quotedPairRE, "$1")); - } - result.parameters[key] = value; - } - if (index !== header.length) { - return defaultContentType; - } - return result; - } - module2.exports.default = { parse: parse2, safeParse: safeParse2 }; - module2.exports.parse = parse2; - module2.exports.safeParse = safeParse2; - module2.exports.defaultContentType = defaultContentType; - } -}); - // main.js var main_exports = {}; __export(main_exports, { @@ -21314,8 +21667,189 @@ function withDefaults(oldDefaults, newDefaults) { } var endpoint = withDefaults(null, DEFAULTS); -// node_modules/@octokit/request/dist-bundle/index.js -var import_fast_content_type_parse = __toESM(require_fast_content_type_parse(), 1); +// node_modules/content-type/dist/index.js +var SP = 32; +var HTAB = 9; +var SEMI = 59; +var EQ = 61; +var DQUOTE = 34; +var BSLASH = 92; +var COMMA = 44; +var LOWER_CASE = 1; +var OWS = 2; +var SEMI_FLAG = 4; +var COMMA_FLAG = 8; +var TOKEN_FLAG = 16; +var NON_ASCII = 65280; +var CASE_FLAGS = LOWER_CASE | NON_ASCII; +var CHAR_MAP = new Uint8Array(256); +CHAR_MAP[HTAB] |= OWS; +CHAR_MAP[SP] |= OWS; +CHAR_MAP[SEMI] |= SEMI_FLAG; +CHAR_MAP[COMMA] |= COMMA_FLAG; +for (let code = 128; code <= 255; code++) { + CHAR_MAP[code] |= LOWER_CASE; +} +for (const char of "!#$%&'*+-.^_`|~") { + CHAR_MAP[char.charCodeAt(0)] |= TOKEN_FLAG; +} +for (let code = 48; code <= 57; code++) { + CHAR_MAP[code] |= TOKEN_FLAG; +} +for (let code = 65; code <= 90; code++) { + CHAR_MAP[code] |= LOWER_CASE | TOKEN_FLAG; +} +for (let code = 97; code <= 122; code++) { + CHAR_MAP[code] |= TOKEN_FLAG; +} +var NullObject = /* @__PURE__ */ (() => { + const C = function() { + }; + C.prototype = /* @__PURE__ */ Object.create(null); + return C; +})(); +function parse2(header, options) { + const stopFlags = SEMI_FLAG | (options?.comma === true ? COMMA_FLAG : 0); + const len = header.length; + let valueStart = options?.start ?? 0; + while ((CHAR_MAP[header.charCodeAt(valueStart)] & OWS) !== 0) { + valueStart++; + } + let index = valueStart; + let typeFlags = 0; + let whitespace = -1; + let stop = options?.parameters === false ? COMMA_FLAG : 0; + while (index < len) { + const code = header.charCodeAt(index); + const flags = CHAR_MAP[code]; + if ((flags & stopFlags) !== 0) { + stop |= flags & COMMA_FLAG; + break; + } + if ((flags & OWS) !== 0) { + if (whitespace === -1) + whitespace = index; + } else { + whitespace = -1; + } + typeFlags |= code & NON_ASCII | flags; + index++; + } + const valueEnd = whitespace === -1 ? index : whitespace; + const value = header.slice(valueStart, valueEnd); + const type = (typeFlags & CASE_FLAGS) === 0 ? value : value.toLowerCase(); + if (index === len || stop !== 0) { + return { type, index, parameters: new NullObject() }; + } + return parseParameters(header, type, index, len, stopFlags); +} +function parseParameters(header, type, index, len, stopFlags) { + const parameters = new NullObject(); + parameter: while (index < len) { + index++; + while ((CHAR_MAP[header.charCodeAt(index)] & OWS) !== 0) { + index++; + } + const keyStart = index; + let keyFlags = 0; + let keyWhitespace = -1; + while (index < len) { + const code = header.charCodeAt(index); + const flags = CHAR_MAP[code]; + if ((flags & stopFlags) !== 0) { + if ((flags & COMMA_FLAG) !== 0) + break parameter; + continue parameter; + } + if (code === EQ) { + const keyEnd = keyWhitespace === -1 ? index : keyWhitespace; + const value = header.slice(keyStart, keyEnd); + const key = (keyFlags & CASE_FLAGS) === 0 ? value : value.toLowerCase(); + index++; + while ((CHAR_MAP[header.charCodeAt(index)] & OWS) !== 0) { + index++; + } + if (index < len && header.charCodeAt(index) === DQUOTE) { + const quotedStart = ++index; + let escaped = false; + while (index < len) { + const code2 = header.charCodeAt(index); + if (code2 === DQUOTE) { + if (parameters[key] === void 0) { + parameters[key] = escaped ? unescapeQuotedPairs(header, quotedStart, index) : header.slice(quotedStart, index); + } + index++; + let stop2 = 0; + while (index < len) { + const code3 = header.charCodeAt(index); + const flags2 = CHAR_MAP[code3]; + if ((flags2 & stopFlags) !== 0) { + stop2 = flags2 & COMMA_FLAG; + break; + } + index++; + } + if (stop2 !== 0) + break parameter; + continue parameter; + } + if (code2 === BSLASH && index + 1 < len) { + escaped = true; + index += 2; + continue; + } + index++; + } + continue parameter; + } + const valueStart = index; + let stop = 0; + let valueWhitespace = -1; + while (index < len) { + const code2 = header.charCodeAt(index); + const flags2 = CHAR_MAP[code2]; + if ((flags2 & stopFlags) !== 0) { + stop = flags2 & COMMA_FLAG; + break; + } + if ((flags2 & OWS) !== 0) { + if (valueWhitespace === -1) + valueWhitespace = index; + } else { + valueWhitespace = -1; + } + index++; + } + if (parameters[key] === void 0) { + const valueEnd = valueWhitespace === -1 ? index : valueWhitespace; + parameters[key] = header.slice(valueStart, valueEnd); + } + if (stop !== 0) + break parameter; + continue parameter; + } + if ((flags & OWS) !== 0) { + if (keyWhitespace === -1) + keyWhitespace = index; + } else { + keyWhitespace = -1; + } + keyFlags |= code & NON_ASCII | flags; + index++; + } + } + return { type, index, parameters }; +} +function unescapeQuotedPairs(str, start, end) { + let result = ""; + for (let index = start; index < end; index++) { + if (str.charCodeAt(index) === BSLASH) { + result += str.slice(start, index); + start = ++index; + } + } + return result + str.slice(start, end); +} // node_modules/json-with-bigint/json-with-bigint.js var intRegex = /^-?\d+$/; @@ -21323,84 +21857,333 @@ var noiseValue = /^-?\d+n+$/; var originalStringify = JSON.stringify; var originalParse = JSON.parse; var customFormat = /^-?\d+n$/; -var bigIntsStringify = /([\[:])?"(-?\d+)n"($|([\\n]|\s)*(\s|[\\n])*[,\}\]])/g; -var noiseStringify = /([\[:])?("-?\d+n+)n("$|"([\\n]|\s)*(\s|[\\n])*[,\}\]])/g; +var bigIntsStringify = /([\[:])?"(-?\d+)n"($|\s*[,\}\]])/g; +var noiseStringify = /([\[:])?("-?\d+n+)n("$|"\s*[,\}\]])/g; +var isUnstringifiable = (val) => val === void 0 || typeof val === "function" || typeof val === "symbol"; +var isRawJSON = (val) => val !== null && typeof val === "object" && val.constructor && val.constructor.name === "RawJSON"; +var stringifyIteratively = (rootValue, replacer, spaceParam) => { + let space = ""; + if (typeof spaceParam === "number") { + space = " ".repeat(Math.min(10, Math.max(0, Math.floor(spaceParam)))); + } else if (typeof spaceParam === "string") { + space = spaceParam.slice(0, 10); + } + const isFunctionReplacer = typeof replacer === "function"; + const propertyList = Array.isArray(replacer) ? new Set(replacer.map(String)) : null; + const prepareVal = (parent, key, val) => { + const isObject = val !== null && typeof val === "object"; + const hasToJSON = isObject && typeof val.toJSON === "function"; + if (hasToJSON) { + val = val.toJSON(key); + } + const isNoise = typeof val === "string" && noiseValue.test(val); + if (isNoise) return val + "n"; + const isBigInt = typeof val === "bigint"; + if (isBigInt) { + const supportsRawJSON = "rawJSON" in JSON; + if (supportsRawJSON) return JSON.rawJSON(val.toString()); + return val.toString() + "n"; + } + if (isFunctionReplacer) { + val = replacer.call(parent, key, val); + } + const isPostReplacerObject = val !== null && typeof val === "object"; + if (isPostReplacerObject) { + const isPrimitiveWrapper = val instanceof Number || val instanceof String || val instanceof Boolean; + if (isPrimitiveWrapper) { + val = val.valueOf(); + } + } + return val; + }; + const rootProcessed = prepareVal({ "": rootValue }, "", rootValue); + if (isUnstringifiable(rootProcessed)) { + return void 0; + } + const isRootPrimitive = rootProcessed === null || typeof rootProcessed !== "object"; + const isRootNativeRawJSON = isRawJSON(rootProcessed); + if (isRootPrimitive || isRootNativeRawJSON) { + return originalStringify(rootProcessed); + } + const chunks = []; + let level = 0; + const stack = [ + { + parent: { "": rootProcessed }, + key: "", + val: rootProcessed, + isArray: Array.isArray(rootProcessed), + keys: Array.isArray(rootProcessed) ? null : Object.keys(rootProcessed), + index: 0, + first: true + } + ]; + const visited = new WeakSet([rootProcessed]); + while (stack.length > 0) { + const node = stack[stack.length - 1]; + if (node.index === 0) { + chunks.push(node.isArray ? "[" : "{"); + level++; + } + let isDone = false; + if (node.isArray) { + if (node.index < node.val.length) { + if (!node.first) chunks.push(","); + if (space) chunks.push("\n" + space.repeat(level)); + const childRaw = node.val[node.index]; + const childVal = prepareVal(node.val, String(node.index), childRaw); + if (isUnstringifiable(childVal)) { + chunks.push("null"); + node.first = false; + node.index++; + } else { + const isComplexObject = childVal !== null && typeof childVal === "object"; + const isNativeRaw = isRawJSON(childVal); + if (isComplexObject && !isNativeRaw) { + if (visited.has(childVal)) { + throw new TypeError("Converting circular structure to JSON"); + } + visited.add(childVal); + stack.push({ + parent: node.val, + key: String(node.index), + val: childVal, + isArray: Array.isArray(childVal), + keys: Array.isArray(childVal) ? null : Object.keys(childVal), + index: 0, + first: true + }); + node.first = false; + node.index++; + } else { + chunks.push(originalStringify(childVal)); + node.first = false; + node.index++; + } + } + } else { + isDone = true; + } + } else { + while (node.index < node.keys.length) { + const k = node.keys[node.index++]; + const isFilteredOutByArray = propertyList && !propertyList.has(k); + if (isFilteredOutByArray) continue; + const childRaw = node.val[k]; + const childVal = prepareVal(node.val, k, childRaw); + if (isUnstringifiable(childVal)) continue; + if (!node.first) chunks.push(","); + if (space) { + chunks.push("\n" + space.repeat(level) + originalStringify(k) + ": "); + } else { + chunks.push(originalStringify(k) + ":"); + } + const isComplexObject = childVal !== null && typeof childVal === "object"; + const isNativeRaw = isRawJSON(childVal); + if (isComplexObject && !isNativeRaw) { + if (visited.has(childVal)) { + throw new TypeError("Converting circular structure to JSON"); + } + visited.add(childVal); + stack.push({ + parent: node.val, + key: k, + val: childVal, + isArray: Array.isArray(childVal), + keys: Array.isArray(childVal) ? null : Object.keys(childVal), + index: 0, + first: true + }); + node.first = false; + break; + } else { + chunks.push(originalStringify(childVal)); + node.first = false; + } + } + const isNodeFullyProcessed = node.index >= node.keys.length && stack[stack.length - 1] === node; + if (isNodeFullyProcessed) { + isDone = true; + } + } + if (isDone) { + level--; + if (!node.first && space) chunks.push("\n" + space.repeat(level)); + chunks.push(node.isArray ? "]" : "}"); + visited.delete(node.val); + stack.pop(); + } + } + return chunks.join(""); +}; var JSONStringify = (value, replacer, space) => { - if ("rawJSON" in JSON) { - return originalStringify( + try { + const supportsRawJSON = "rawJSON" in JSON; + if (supportsRawJSON) { + return originalStringify( + value, + (key, val) => { + if (typeof val === "bigint") return JSON.rawJSON(val.toString()); + const hasFunctionReplacer = typeof replacer === "function"; + if (hasFunctionReplacer) return replacer(key, val); + const isKeyInArrayReplacer = Array.isArray(replacer) && replacer.includes(key); + if (isKeyInArrayReplacer) return val; + return val; + }, + space + ); + } + if (!value) return originalStringify(value, replacer, space); + const convertedToCustomJSON = originalStringify( value, - (key, value2) => { - if (typeof value2 === "bigint") return JSON.rawJSON(value2.toString()); - if (typeof replacer === "function") return replacer(key, value2); - if (Array.isArray(replacer) && replacer.includes(key)) return value2; - return value2; + (key, val) => { + const isNoise = typeof val === "string" && noiseValue.test(val); + if (isNoise) return val.toString() + "n"; + if (typeof val === "bigint") return val.toString() + "n"; + const hasFunctionReplacer = typeof replacer === "function"; + if (hasFunctionReplacer) return replacer(key, val); + const isKeyInArrayReplacer = Array.isArray(replacer) && replacer.includes(key); + if (isKeyInArrayReplacer) return val; + return val; }, space ); + const processedJSON = convertedToCustomJSON.replace( + bigIntsStringify, + "$1$2$3" + ); + const denoisedJSON = processedJSON.replace(noiseStringify, "$1$2$3"); + return denoisedJSON; + } catch (error2) { + if (error2 instanceof RangeError) { + const convertedJSON = stringifyIteratively(value, replacer, space); + if (convertedJSON === void 0) return void 0; + const supportsRawJSON = "rawJSON" in JSON; + if (supportsRawJSON) return convertedJSON; + const processedJSON = convertedJSON.replace(bigIntsStringify, "$1$2$3"); + return processedJSON.replace(noiseStringify, "$1$2$3"); + } + throw error2; + } +}; +var featureCache = /* @__PURE__ */ new Map(); +var isContextSourceSupported = () => { + const parseFingerprint = JSON.parse.toString(); + if (featureCache.has(parseFingerprint)) { + return featureCache.get(parseFingerprint); + } + try { + const result = JSON.parse( + "1", + (_, __, context) => !!context?.source && context.source === "1" + ); + featureCache.set(parseFingerprint, result); + return result; + } catch { + featureCache.set(parseFingerprint, false); + return false; } - if (!value) return originalStringify(value, replacer, space); - const convertedToCustomJSON = originalStringify( - value, - (key, value2) => { - const isNoise = typeof value2 === "string" && Boolean(value2.match(noiseValue)); - if (isNoise) return value2.toString() + "n"; - if (typeof value2 === "bigint") return value2.toString() + "n"; - if (typeof replacer === "function") return replacer(key, value2); - if (Array.isArray(replacer) && replacer.includes(key)) return value2; - return value2; - }, - space - ); - const processedJSON = convertedToCustomJSON.replace( - bigIntsStringify, - "$1$2$3" - ); - const denoisedJSON = processedJSON.replace(noiseStringify, "$1$2$3"); - return denoisedJSON; }; -var isContextSourceSupported = () => JSON.parse("1", (_, __, context) => !!context && context.source === "1"); var convertMarkedBigIntsReviver = (key, value, context, userReviver) => { - const isCustomFormatBigInt = typeof value === "string" && value.match(customFormat); + const isCustomFormatBigInt = typeof value === "string" && customFormat.test(value); if (isCustomFormatBigInt) return BigInt(value.slice(0, -1)); - const isNoiseValue = typeof value === "string" && value.match(noiseValue); + const isNoiseValue = typeof value === "string" && noiseValue.test(value); if (isNoiseValue) return value.slice(0, -1); - if (typeof userReviver !== "function") return value; + const hasUserReviver = typeof userReviver === "function"; + if (!hasUserReviver) return value; return userReviver(key, value, context); }; var JSONParseV2 = (text, reviver) => { return JSON.parse(text, (key, value, context) => { - const isBigNumber = typeof value === "number" && (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER); + const isNumber = typeof value === "number"; + const isOutOfBounds = value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER; + const isBigNumber = isNumber && isOutOfBounds; const isInt = context && intRegex.test(context.source); const isBigInt = isBigNumber && isInt; if (isBigInt) return BigInt(context.source); - if (typeof reviver !== "function") return value; + const hasCustomReviver = typeof reviver === "function"; + if (!hasCustomReviver) return value; return reviver(key, value, context); }); }; var MAX_INT = Number.MAX_SAFE_INTEGER.toString(); var MAX_DIGITS = MAX_INT.length; -var stringsOrLargeNumbers = /"(?:\\.|[^"])*"|-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?/g; +var stringsOrLargeNumbers = /"(?:[^"\\]|\\.)*"|-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?/g; var noiseValueWithQuotes = /^"-?\d+n+"$/; -var JSONParse = (text, reviver) => { - if (!text) return originalParse(text, reviver); - if (isContextSourceSupported()) return JSONParseV2(text, reviver); - const serializedData = text.replace( +var applyReviverIteratively = (parsed, userReviver) => { + const rootHolder = { "": parsed }; + const stack = [{ parent: rootHolder, key: "", visited: false }]; + while (stack.length > 0) { + const node = stack[stack.length - 1]; + if (!node.visited) { + node.visited = true; + const value = node.parent[node.key]; + const isComplexObject = value !== null && typeof value === "object"; + if (isComplexObject) { + const keys = Object.keys(value); + for (let i = keys.length - 1; i >= 0; i--) { + stack.push({ parent: value, key: keys[i], visited: false }); + } + } + } else { + const { parent, key } = node; + let value = parent[key]; + if (typeof value === "string") { + const isCustomFormatBigInt = customFormat.test(value); + if (isCustomFormatBigInt) { + value = BigInt(value.slice(0, -1)); + } else { + const isNoise = noiseValue.test(value); + if (isNoise) value = value.slice(0, -1); + } + } + const hasUserReviver = typeof userReviver === "function"; + if (hasUserReviver) { + value = userReviver.call(parent, key, value); + } + const isDeleted = value === void 0; + if (isDeleted) { + delete parent[key]; + } else { + parent[key] = value; + } + stack.pop(); + } + } + return rootHolder[""]; +}; +var serializeBigInts = (text) => { + return text.replace( stringsOrLargeNumbers, - (text2, digits, fractional, exponential) => { - const isString = text2[0] === '"'; - const isNoise = isString && Boolean(text2.match(noiseValueWithQuotes)); - if (isNoise) return text2.substring(0, text2.length - 1) + 'n"'; - const isFractionalOrExponential = fractional || exponential; + (match, digits, fractional, exponential) => { + const isString = match[0] === '"'; + const isNoise = isString && noiseValueWithQuotes.test(match); + if (isNoise) return match.substring(0, match.length - 1) + 'n"'; + const hasFractionalOrExponential = fractional || exponential; const isLessThanMaxSafeInt = digits && (digits.length < MAX_DIGITS || digits.length === MAX_DIGITS && digits <= MAX_INT); - if (isString || isFractionalOrExponential || isLessThanMaxSafeInt) - return text2; - return '"' + text2 + 'n"'; + const isStandardValue = isString || hasFractionalOrExponential || isLessThanMaxSafeInt; + if (isStandardValue) return match; + return '"' + match + 'n"'; } ); - return originalParse( - serializedData, - (key, value, context) => convertMarkedBigIntsReviver(key, value, context, reviver) - ); +}; +var JSONParse = (text, reviver) => { + if (!text) return originalParse(text, reviver); + try { + if (isContextSourceSupported()) return JSONParseV2(text, reviver); + const serializedData = serializeBigInts(text); + return originalParse( + serializedData, + (key, value, context) => convertMarkedBigIntsReviver(key, value, context, reviver) + ); + } catch (error2) { + if (error2 instanceof RangeError) { + const serializedData = serializeBigInts(text); + const parsed = originalParse(serializedData); + return applyReviverIteratively(parsed, reviver); + } + throw error2; + } }; // node_modules/@octokit/request-error/dist-src/index.js @@ -21443,7 +22226,7 @@ var RequestError = class extends Error { }; // node_modules/@octokit/request/dist-bundle/index.js -var VERSION2 = "10.0.8"; +var VERSION2 = "10.0.16"; var defaults_default = { headers: { "user-agent": `octokit-request.js/${VERSION2} ${getUserAgent()}` @@ -21561,7 +22344,7 @@ async function getResponseData(response) { if (!contentType) { return response.text().catch(noop); } - const mimetype = (0, import_fast_content_type_parse.safeParse)(contentType); + const mimetype = parse2(contentType); if (isJSONResponse(mimetype)) { let text = ""; try { @@ -21570,7 +22353,10 @@ async function getResponseData(response) { } catch (err) { return text; } - } else if (mimetype.type.startsWith("text/") || mimetype.parameters.charset?.toLowerCase() === "utf-8") { + } else if (mimetype.type.startsWith("text/") || // `application/octet-stream` is the canonical "arbitrary binary" type + // (RFC 2046) and must never be decoded as text, even when the response + // carries a (misleading) `charset=utf-8` parameter — see #751. + mimetype.parameters.charset?.toLowerCase() === "utf-8" && mimetype.type !== "application/octet-stream") { return response.text().catch(noop); } else { return response.arrayBuffer().catch( @@ -21589,9 +22375,10 @@ function toErrorMessage(data) { if (data instanceof ArrayBuffer) { return "Unknown error"; } - if ("message" in data) { - const suffix = "documentation_url" in data ? ` - ${data.documentation_url}` : ""; - return Array.isArray(data.errors) ? `${data.message}: ${data.errors.map((v) => JSON.stringify(v)).join(", ")}${suffix}` : `${data.message}${suffix}`; + if (typeof data === "object" && data !== null && "message" in data) { + const objectData = data; + const suffix = "documentation_url" in objectData ? ` - ${objectData.documentation_url}` : ""; + return Array.isArray(objectData.errors) ? `${objectData.message}: ${objectData.errors.map((v) => JSON.stringify(v)).join(", ")}${suffix}` : `${objectData.message}${suffix}`; } return `Unknown error: ${JSON.stringify(data)}`; } @@ -21623,7 +22410,13 @@ var request = withDefaults2(endpoint, defaults_default); // node_modules/@octokit/oauth-methods/dist-bundle/index.js function requestToOAuthBaseUrl(request2) { const endpointDefaults = request2.endpoint.DEFAULTS; - return /^https:\/\/(api\.)?github\.com$/.test(endpointDefaults.baseUrl) ? "https://github.com" : endpointDefaults.baseUrl.replace("/api/v3", ""); + if (/^https:\/\/(api\.)?github\.com$/.test(endpointDefaults.baseUrl)) { + return "https://github.com"; + } + if (/^https:\/\/api\..*\.ghe\.com$/.test(endpointDefaults.baseUrl)) { + return endpointDefaults.baseUrl.replace("api.", ""); + } + return endpointDefaults.baseUrl.replace("/api/v3", ""); } async function oauthRequest(request2, route, parameters) { const withOAuthParameters = { @@ -22893,7 +23686,7 @@ async function sendRequestWithRetries(state, request2, options, createdAt, retri return sendRequestWithRetries(state, request2, options, createdAt, retries); } } -var VERSION6 = "8.2.0"; +var VERSION6 = "8.3.1"; function createAppAuth(options) { if (!options.appId) { throw new Error("[@octokit/auth-app] appId option is required"); @@ -23006,6 +23799,9 @@ function validateRetries(retries) { if (Number.isNaN(retries)) { throw new TypeError("Expected `retries` to be a valid number or Infinity, got NaN."); } + if (Number.isFinite(retries) && !Number.isInteger(retries)) { + throw new TypeError("Expected `retries` to be a non-negative integer or Infinity."); + } } else if (retries !== void 0) { throw new TypeError("Expected `retries` to be a number or Infinity."); } @@ -23458,6 +24254,13 @@ undici/lib/web/fetch/body.js: undici/lib/web/websocket/frame.js: (*! ws. MIT License. Einar Otto Stangvik *) +content-type/dist/index.js: + (*! + * content-type + * Copyright(c) 2015 Douglas Christopher Wilson + * MIT Licensed + *) + @octokit/request-error/dist-src/index.js: (* v8 ignore else -- @preserve -- Bug with vitest coverage where it sees an else branch that doesn't exist *) @@ -23465,6 +24268,19 @@ undici/lib/web/websocket/frame.js: (* v8 ignore next -- @preserve *) (* v8 ignore else -- @preserve *) +@octokit/oauth-methods/dist-bundle/index.js: + (* v8 ignore next: we always pass a custom request in tests -- @preserve *) + +@octokit/auth-oauth-device/dist-bundle/index.js: + (* v8 ignore next 2 -- @preserve *) + +@octokit/auth-oauth-user/dist-bundle/index.js: + (* v8 ignore if -- @preserve *) + (* v8 ignore next -- @preserve *) + +@octokit/auth-oauth-app/dist-bundle/index.js: + (* v8 ignore next -- @preserve *) + toad-cache/dist/toad-cache.mjs: (** * toad-cache @@ -23473,4 +24289,10 @@ toad-cache/dist/toad-cache.mjs: * @license MIT * @version 3.7.0 *) + +@octokit/auth-app/dist-node/index.js: + (* v8 ignore next - permissions are optional per OpenAPI spec, but we think that is incorrect -- @preserve *) + (* v8 ignore next - repositorySelection are optional per OpenAPI spec, but we think that is incorrect -- @preserve *) + (* v8 ignore start - due to skipped tests, see https://github.com/octokit/auth-app.js/pull/580 -- @preserve *) + (* v8 ignore end -- @preserve *) */ diff --git a/dist/post.cjs b/dist/post.cjs index 8e50446c..7dfd77e0 100644 --- a/dist/post.cjs +++ b/dist/post.cjs @@ -5,7 +5,11 @@ var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __commonJS = (cb, mod) => function __require() { - return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + try { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + } catch (e) { + throw mod = 0, e; + } }; var __export = (target, all) => { for (var name in all) @@ -1853,10 +1857,66 @@ var require_request = __commonJS({ return false; } } - onUpgrade(statusCode, headers, socket) { + /** + * @param {number|null} statusCode + * @param {Buffer[]|null} headers + * @param {import('node:stream').Duplex} socket + * @param {string} [statusText] + */ + onUpgrade(statusCode, headers, socket, statusText = "") { + this.onFinally(); assert(!this.aborted); assert(!this.completed); - return this[kHandler].onUpgrade(statusCode, headers, socket); + if (statusCode !== null) { + this.#publishUpgradeHeaders(statusCode, headers, statusText); + } + const result = this[kHandler].onUpgrade(statusCode, headers, socket); + if (!this.aborted) { + this.completed = true; + if (statusCode !== null) { + this.#publishUpgradeTrailers(); + } + } + return result; + } + /** + * @param {number} statusCode + * @param {import('node:http2').IncomingHttpHeaders} headers + * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders + * @param {string} [statusText] + */ + onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { + assert(!this.aborted); + assert(this.completed); + if (channels.headers.hasSubscribers) { + this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); + } + this.#publishUpgradeTrailers(); + } + /** + * @param {Error} error + */ + onUpgradeError(error2) { + assert(!this.aborted); + assert(this.completed); + if (channels.error.hasSubscribers) { + channels.error.publish({ request: this, error: error2 }); + } + } + /** + * @param {number} statusCode + * @param {Buffer[]} headers + * @param {string} statusText + */ + #publishUpgradeHeaders(statusCode, headers, statusText) { + if (channels.headers.hasSubscribers) { + channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); + } + } + #publishUpgradeTrailers() { + if (channels.trailers.hasSubscribers) { + channels.trailers.publish({ request: this, trailers: [] }); + } } onComplete(trailers) { this.onFinally(); @@ -1923,7 +1983,11 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - arr.push(`${val[i]}`); + const str = `${val[i]}`; + if (!isValidHeaderValue(str)) { + throw new InvalidArgumentError(`invalid ${key} header`); + } + arr.push(str); } } val = arr; @@ -1935,6 +1999,9 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; + if (!isValidHeaderValue(val)) { + throw new InvalidArgumentError(`invalid ${key} header`); + } } if (headerName === "host") { if (request2.host !== null) { @@ -2044,13 +2111,21 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); + var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class extends Dispatcher { - constructor() { + constructor(opts) { super(); this[kDestroyed] = false; this[kOnDestroyed] = null; this[kClosed] = false; this[kOnClosed] = []; + this[kWebSocketOptions] = opts?.webSocket ?? {}; + } + get webSocketOptions() { + return { + maxFragments: this[kWebSocketOptions].maxFragments ?? 131072, + maxPayloadSize: this[kWebSocketOptions].maxPayloadSize ?? 128 * 1024 * 1024 + }; } get destroyed() { return this[kDestroyed]; @@ -5657,6 +5732,7 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, + InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5703,6 +5779,9 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; + var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); + var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); + var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5865,24 +5944,55 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(data.slice(offset)); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(data.slice(offset)); - } else if (ret !== constants3.ERROR.OK) { - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; + if (ret !== constants3.ERROR.OK) { + const body = data.subarray(offset); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(body); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(body); + } else { + throw this.createError(ret, body); } - throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } catch (err) { util.destroy(socket, err); } } + finish() { + assert(currentParser === null); + assert(this.ptr != null); + assert(!this.paused); + const { llhttp } = this; + let ret; + try { + currentParser = this; + ret = llhttp.llhttp_finish(this.ptr); + } finally { + currentParser = null; + } + if (ret === constants3.ERROR.OK) { + return null; + } + if (ret === constants3.ERROR.PAUSED || ret === constants3.ERROR.PAUSED_UPGRADE) { + this.paused = true; + return null; + } + return this.createError(ret, EMPTY_BUF); + } + createError(ret, data) { + const { llhttp, contentLength, bytesRead } = this; + if (contentLength && bytesRead !== parseInt(contentLength, 10)) { + return new ResponseContentLengthMismatchError(); + } + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; + } + return new HTTPParserError(message, constants3.ERROR[ret], data); + } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -5902,6 +6012,10 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } + if (client[kRunning] === 0) { + util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); + return -1; + } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -5945,7 +6059,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode } = this; + const { upgrade, client, socket, headers, statusCode, statusText } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -5970,9 +6084,10 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket); - } catch (err) { - util.destroy(socket, err); + request2.onUpgrade(statusCode, headers, socket, statusText); + } catch (error2) { + util.errorRequest(client, request2, error2); + util.destroy(socket, error2); } client[kResume](); } @@ -5981,6 +6096,10 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } + if (client[kRunning] === 0) { + util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); + return -1; + } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6106,6 +6225,7 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; + socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6149,12 +6269,19 @@ var require_client_h1 = __commonJS({ socket[kWriting] = false; socket[kReset] = false; socket[kBlocking] = false; + socket[kIdleSocketValidation] = 0; + socket[kIdleSocketValidationTimeout] = null; + socket[kSocketUsed] = false; socket[kParser] = new Parser(client, socket, llhttpInstance); addListener(socket, "error", function(err) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - parser.onMessageComplete(); + const parserErr = parser.finish(); + if (parserErr) { + this[kError] = parserErr; + this[kClient][kOnError](parserErr); + } return; } this[kError] = err; @@ -6169,7 +6296,10 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - parser.onMessageComplete(); + const parserErr = parser.finish(); + if (parserErr) { + util.destroy(this, parserErr); + } return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6177,9 +6307,10 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; + clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - parser.onMessageComplete(); + this[kError] = parser.finish() || this[kError]; } this[kParser].destroy(); this[kParser] = null; @@ -6228,7 +6359,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { return true; } if (request2) { @@ -6246,6 +6377,23 @@ var require_client_h1 = __commonJS({ } }; } + function clearIdleSocketValidation(socket) { + if (socket[kIdleSocketValidationTimeout]) { + clearImmediate(socket[kIdleSocketValidationTimeout]); + socket[kIdleSocketValidationTimeout] = null; + } + socket[kIdleSocketValidation] = 0; + } + function scheduleIdleSocketValidation(client, socket) { + socket[kIdleSocketValidation] = 1; + socket[kIdleSocketValidationTimeout] = setImmediate(() => { + socket[kIdleSocketValidationTimeout] = null; + socket[kIdleSocketValidation] = 2; + if (client[kSocket] === socket && !socket.destroyed) { + client[kResume](); + } + }); + } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6258,6 +6406,29 @@ var require_client_h1 = __commonJS({ socket.ref(); socket[kNoRef] = false; } + if (client[kRunning] === 0 && client[kPending] > 0 && socket[kSocketUsed]) { + if (socket[kIdleSocketValidation] === 0) { + scheduleIdleSocketValidation(client, socket); + socket[kParser].readMore(); + if (socket.destroyed) { + return; + } + return; + } + if (socket[kIdleSocketValidation] === 1) { + socket[kParser].readMore(); + if (socket.destroyed) { + return; + } + return; + } + } + if (client[kRunning] === 0) { + socket[kParser].readMore(); + if (socket.destroyed) { + return; + } + } if (client[kSize] === 0) { if (socket[kParser].timeoutType !== TIMEOUT_KEEP_ALIVE) { socket[kParser].setTimeout(client[kKeepAliveTimeoutValue], TIMEOUT_KEEP_ALIVE); @@ -6288,8 +6459,16 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { - headers.push("content-type", body.type); + } else if (util.isBlobLike(body) && request2.contentType == null) { + const contentType = body.type; + if (contentType) { + const contentTypeValue = `${contentType}`; + if (!util.isValidHeaderValue(contentTypeValue)) { + util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); + return false; + } + headers.push("content-type", contentTypeValue); + } } if (body && typeof body.read === "function") { body.read(0); @@ -6310,11 +6489,18 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - const abort = (err) => { - if (request2.aborted || request2.completed) { + clearIdleSocketValidation(socket); + const abort = (error2) => { + if (request2.aborted) { + return; + } + if (request2.completed) { + if (request2.upgrade || request2.method === "CONNECT") { + util.destroy(socket, new InformationalError("aborted")); + } return; } - util.errorRequest(client, request2, err || new RequestAbortedError()); + util.errorRequest(client, request2, error2 || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6670,6 +6856,7 @@ var require_client_h2 = __commonJS({ "node_modules/@actions/http-client/node_modules/undici/lib/dispatcher/client-h2.js"(exports2, module2) { "use strict"; var assert = require("node:assert"); + var { errorMonitor } = require("node:events"); var { pipeline } = require("node:stream"); var util = require_util(); var { @@ -6730,6 +6917,10 @@ var require_client_h2 = __commonJS({ } return result; } + function parseH2ResponseHeaders(headers) { + const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; + return parseH2Headers(realHeaders); + } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -6893,16 +7084,22 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (err) => { - if (request2.aborted || request2.completed) { + const abort = (error2) => { + if (request2.aborted) { return; } - err = err || new RequestAbortedError(); - util.errorRequest(client, request2, err); + if (request2.completed) { + if (method === "CONNECT" && stream != null) { + util.destroy(stream, error2 || new RequestAbortedError()); + } + return; + } + error2 = error2 || new RequestAbortedError(); + util.errorRequest(client, request2, error2); if (stream != null) { - util.destroy(stream, err); + util.destroy(stream, error2); } - util.destroy(body, err); + util.destroy(body, error2); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -6917,18 +7114,42 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - if (stream.id && !stream.pending) { - request2.onUpgrade(null, null, stream); - ++session[kOpenStreams]; - client[kQueue][client[kRunningIdx]++] = null; - } else { - stream.once("ready", () => { + let upgradeResponseFinished = false; + const onResponse = (headers2) => { + upgradeResponseFinished = true; + stream.off(errorMonitor, onUpgradeError); + request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); + }; + const onUpgradeError = (error2) => { + upgradeResponseFinished = true; + stream.off("response", onResponse); + request2.onUpgradeError(error2); + }; + const onReady = () => { + try { request2.onUpgrade(null, null, stream); - ++session[kOpenStreams]; - client[kQueue][client[kRunningIdx]++] = null; - }); - } + } catch (error2) { + stream.off("response", onResponse); + abort(error2); + return; + } + if (request2.aborted) { + return; + } + stream.off("error", abort); + stream.once(errorMonitor, onUpgradeError); + client[kQueue][client[kRunningIdx]++] = null; + }; + stream.once("response", onResponse); + stream.once("error", abort); + ++session[kOpenStreams]; + onReady(); stream.once("close", () => { + if (!upgradeResponseFinished && request2.completed) { + stream.off("response", onResponse); + stream.off(errorMonitor, onUpgradeError); + request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); + } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7489,9 +7710,10 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2 + allowH2, + webSocket } = {}) { - super(); + super({ webSocket }); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -7997,8 +8219,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor() { - super(); + constructor(opts) { + super(opts); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8169,7 +8391,6 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { - super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8190,6 +8411,7 @@ var require_pool = __commonJS({ ...connect }); } + super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8389,7 +8611,6 @@ var require_agent = __commonJS({ } var Agent3 = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { - super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8399,6 +8620,7 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } + super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -8839,6 +9061,24 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } + function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { + const contentLength = headers["content-length"]; + if (contentLength == null) { + return null; + } + if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { + return null; + } + const length = Number(contentLength); + const expectedLength = range.end - range.start + 1; + if (!Number.isFinite(length) || length !== expectedLength) { + return new RequestRetryError("Content-Length mismatch", statusCode, { + headers, + data: { count: retryCount } + }); + } + return null; + } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -8892,6 +9132,7 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; + this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -8901,6 +9142,17 @@ var require_retry_handler = __commonJS({ } }); } + checkpointResponseEnd(headers, resume) { + if (this.end == null && this.opts.method !== "HEAD") { + const contentLength = headers["content-length"]; + this.end = contentLength != null ? Number(contentLength) - 1 : null; + assert( + this.end == null || Number.isFinite(this.end), + "invalid content-length" + ); + } + this.resume = this.end != null ? resume : null; + } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -8962,7 +9214,9 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (this.retryOpts.statusCodes.includes(statusCode) === false) { + if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { + this.headersSent = true; + this.checkpointResponseEnd(headers, resume); return this.handler.onHeaders( statusCode, rawHeaders, @@ -9011,9 +9265,21 @@ var require_retry_handler = __commonJS({ ); return false; } + const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); + if (contentLengthError != null) { + this.abort(contentLengthError); + return false; + } const { start, size, end = size - 1 } = contentRange; - assert(this.start === start, "content-range mismatch"); - assert(this.end == null || this.end === end, "content-range mismatch"); + if (this.start !== start || this.end != null && this.end !== end) { + this.abort( + new RequestRetryError("Content-Range mismatch", statusCode, { + headers, + data: { count: this.retryCount } + }) + ); + return false; + } this.resume = resume; return true; } @@ -9021,6 +9287,7 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { + this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9028,6 +9295,11 @@ var require_retry_handler = __commonJS({ statusMessage ); } + const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); + if (contentLengthError != null) { + this.abort(contentLengthError); + return false; + } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9047,6 +9319,7 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; + this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9074,7 +9347,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body)) { + if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -15873,14 +16146,48 @@ var require_util6 = __commonJS({ for (let i = 0; i < path6.length; ++i) { const code = path6.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code === 127 || // DEL + code > 126 || // exclude DEL and non-ascii code === 59) { throw new Error("Invalid cookie path"); } } } + function isLetterOrDigit(code) { + return code >= 48 && code <= 57 || // 0-9 + code >= 65 && code <= 90 || // A-Z + code >= 97 && code <= 122; + } function validateCookieDomain(domain) { - if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { + if (domain === " ") { + return; + } + if (domain.length > 255) { + throw new Error("Invalid cookie domain"); + } + let labelLength = 0; + for (let i = 0; i < domain.length; ++i) { + const code = domain.charCodeAt(i); + if (code === 46) { + if (labelLength === 0) { + throw new Error("Invalid cookie domain"); + } + if (domain.charCodeAt(i - 1) === 45) { + throw new Error("Invalid cookie domain"); + } + labelLength = 0; + continue; + } + if (labelLength === 0 && !isLetterOrDigit(code)) { + throw new Error("Invalid cookie domain"); + } + if (!isLetterOrDigit(code) && code !== 45) { + throw new Error("Invalid cookie domain"); + } + if (++labelLength > 63) { + throw new Error("Invalid cookie domain"); + } + } + if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { throw new Error("Invalid cookie domain"); } } @@ -15963,7 +16270,11 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - out.push(`${key.trim()}=${value.join("=")}`); + const trimmedKey = key.trim(); + const joinedValue = value.join("="); + validateCookieName(trimmedKey); + validateCookieValue(joinedValue); + out.push(`${trimmedKey}=${joinedValue}`); } return out.join("; "); } @@ -16093,18 +16404,14 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { - let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase.includes("none")) { - enforcement = "None"; - } - if (attributeValueLowercase.includes("strict")) { - enforcement = "Strict"; + if (attributeValueLowercase === "none") { + cookieAttributeList.sameSite = "None"; + } else if (attributeValueLowercase === "strict") { + cookieAttributeList.sameSite = "Strict"; + } else if (attributeValueLowercase === "lax") { + cookieAttributeList.sameSite = "Lax"; } - if (attributeValueLowercase.includes("lax")) { - enforcement = "Lax"; - } - cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -16926,7 +17233,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (!requestProtocols.includes(secProtocol)) { + if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17032,31 +17339,26 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); - var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - /** @type {number} */ - #maxDecompressedSize; - /** @type {boolean} */ - #aborted = false; - /** @type {Function|null} */ - #currentCallback = null; + #maxPayloadSize = 0; /** * @param {Map} extensions - * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options = {}) { + constructor(extensions, options) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; + this.#maxPayloadSize = options.maxPayloadSize; } + /** + * Decompress a compressed payload. + * @param {Buffer} chunk Compressed data + * @param {boolean} fin Final fragment flag + * @param {Function} callback Callback function + */ decompress(chunk, fin, callback) { - if (this.#aborted) { - callback(new MessageSizeExceededError()); - return; - } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17075,20 +17377,12 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; this.#inflate[kLength] = 0; this.#inflate.on("data", (data) => { - if (this.#aborted) { - return; - } this.#inflate[kLength] += data.length; - if (this.#inflate[kLength] > this.#maxDecompressedSize) { - this.#aborted = true; + if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) { + callback(new MessageSizeExceededError()); this.#inflate.removeAllListeners(); this.#inflate.destroy(); this.#inflate = null; - if (this.#currentCallback) { - const cb = this.#currentCallback; - this.#currentCallback = null; - cb(new MessageSizeExceededError()); - } return; } this.#inflate[kBuffer].push(data); @@ -17098,19 +17392,17 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } - this.#currentCallback = callback; this.#inflate.write(chunk); if (fin) { this.#inflate.write(tail); } this.#inflate.flush(() => { - if (this.#aborted || !this.#inflate) { + if (!this.#inflate) { return; } const full = Buffer.concat(this.#inflate[kBuffer], this.#inflate[kLength]); this.#inflate[kBuffer].length = 0; this.#inflate[kLength] = 0; - this.#currentCallback = null; callback(null, full); }); } @@ -17141,8 +17433,14 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); + var { MessageSizeExceededError } = require_errors(); + function failWebsocketConnectionWithCode(ws, code, reason) { + closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); + failWebsocketConnection(ws, reason); + } var ByteParser = class extends Writable { #buffers = []; + #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17150,18 +17448,21 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {{ maxDecompressedMessageSize?: number }} */ - #options; + /** @type {number} */ + #maxFragments; + /** @type {number} */ + #maxPayloadSize; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxDecompressedMessageSize?: number }} [options] + * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#options = options; + this.#maxFragments = options.maxFragments ?? 0; + this.#maxPayloadSize = options.maxPayloadSize ?? 0; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17176,6 +17477,13 @@ var require_receiver = __commonJS({ this.#loop = true; this.run(callback); } + #validatePayloadLength() { + if (this.#maxPayloadSize > 0 && !isControlFrame(this.#info.opcode) && this.#info.payloadLength + this.#fragmentsBytes > this.#maxPayloadSize) { + failWebsocketConnectionWithCode(this.ws, 1009, "Payload size exceeds maximum allowed size"); + return false; + } + return true; + } /** * Runs whenever a new chunk is received. * Callback is called whenever there are no more chunks buffering, @@ -17235,6 +17543,9 @@ var require_receiver = __commonJS({ if (payloadLength <= 125) { this.#info.payloadLength = payloadLength; this.#state = parserStates.READ_DATA; + if (!this.#validatePayloadLength()) { + return; + } } else if (payloadLength === 126) { this.#state = parserStates.PAYLOADLENGTH_16; } else if (payloadLength === 127) { @@ -17255,6 +17566,9 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); this.#info.payloadLength = buffer.readUInt16BE(0); this.#state = parserStates.READ_DATA; + if (!this.#validatePayloadLength()) { + return; + } } else if (this.#state === parserStates.PAYLOADLENGTH_64) { if (this.#byteOffset < 8) { return callback(); @@ -17268,6 +17582,9 @@ var require_receiver = __commonJS({ } this.#info.payloadLength = lower; this.#state = parserStates.READ_DATA; + if (!this.#validatePayloadLength()) { + return; + } } else if (this.#state === parserStates.READ_DATA) { if (this.#byteOffset < this.#info.payloadLength) { return callback(); @@ -17278,32 +17595,46 @@ var require_receiver = __commonJS({ this.#state = parserStates.INFO; } else { if (!this.#info.compressed) { - this.#fragments.push(body); + if (!this.writeFragments(body)) { + return; + } + if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { + failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); + return; + } if (!this.#info.fragmented && this.#info.fin) { - const fullMessage = Buffer.concat(this.#fragments); - websocketMessageReceived(this.ws, this.#info.binaryType, fullMessage); - this.#fragments.length = 0; + websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); } this.#state = parserStates.INFO; } else { - this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { - if (error2) { - failWebsocketConnection(this.ws, error2.message); - return; - } - this.#fragments.push(data); - if (!this.#info.fin) { - this.#state = parserStates.INFO; + this.#extensions.get("permessage-deflate").decompress( + body, + this.#info.fin, + (error2, data) => { + if (error2) { + const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; + failWebsocketConnectionWithCode(this.ws, code, error2.message); + return; + } + if (!this.writeFragments(data)) { + return; + } + if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { + failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); + return; + } + if (!this.#info.fin) { + this.#state = parserStates.INFO; + this.#loop = true; + this.run(callback); + return; + } + websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); this.#loop = true; + this.#state = parserStates.INFO; this.run(callback); - return; } - websocketMessageReceived(this.ws, this.#info.binaryType, Buffer.concat(this.#fragments)); - this.#loop = true; - this.#state = parserStates.INFO; - this.#fragments.length = 0; - this.run(callback); - }); + ); this.#loop = false; break; } @@ -17346,6 +17677,26 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; return buffer; } + writeFragments(fragment) { + if (this.#maxFragments > 0 && this.#fragments.length === this.#maxFragments) { + failWebsocketConnectionWithCode(this.ws, 1008, "Too many message fragments"); + return false; + } + this.#fragmentsBytes += fragment.length; + this.#fragments.push(fragment); + return true; + } + consumeFragments() { + const fragments = this.#fragments; + if (fragments.length === 1) { + this.#fragmentsBytes = 0; + return fragments.shift(); + } + const output = Buffer.concat(fragments, this.#fragmentsBytes); + this.#fragments = []; + this.#fragmentsBytes = 0; + return output; + } parseCloseBody(data) { assert(data.length !== 1); let code; @@ -17557,8 +17908,6 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; - /** @type {{ maxDecompressedMessageSize?: number }} */ - #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17602,9 +17951,6 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); - this.#options = { - maxDecompressedMessageSize: options.maxDecompressedMessageSize - }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -17788,7 +18134,13 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { this[kResponse] = response; - const parser = new ByteParser(this, parsedExtensions, this.#options); + const webSocketOptions = this[kController]?.dispatcher?.webSocketOptions; + const maxFragments = webSocketOptions?.maxFragments; + const maxPayloadSize = webSocketOptions?.maxPayloadSize; + const parser = new ByteParser(this, parsedExtensions, { + maxFragments, + maxPayloadSize + }); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -17863,19 +18215,6 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) - }, - { - key: "maxDecompressedMessageSize", - converter: webidl.nullableConverter((V) => { - V = webidl.converters["unsigned long long"](V); - if (V <= 0) { - throw webidl.errors.exception({ - header: "WebSocket constructor", - message: "maxDecompressedMessageSize must be greater than 0" - }); - } - return V; - }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -17954,6 +18293,40 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; + var DATA = Buffer.from("data"); + var EVENT = Buffer.from("event"); + var ID = Buffer.from("id"); + var RETRY = Buffer.from("retry"); + function isASCIINumberBytes(buffer, start) { + if (start >= buffer.length) { + return false; + } + for (let i = start; i < buffer.length; i++) { + if (buffer[i] < 48 || buffer[i] > 57) { + return false; + } + } + return true; + } + function isValidLastEventIdBytes(buffer, start) { + for (let i = start; i < buffer.length; i++) { + if (buffer[i] === 0) { + return false; + } + } + return true; + } + function isFieldName(line, length, field) { + if (length !== field.length) { + return false; + } + for (let i = 0; i < length; i++) { + if (line[i] !== field[i]) { + return false; + } + } + return true; + } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -17973,10 +18346,13 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer} + * @type {Buffer[]} */ - buffer = null; + chunks = []; + chunkIndex = 0; pos = 0; + lineChunkIndex = 0; + linePos = 0; event = { data: void 0, event: void 0, @@ -18007,63 +18383,30 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - if (this.buffer) { - this.buffer = Buffer.concat([this.buffer, chunk]); - } else { - this.buffer = chunk; - } + this.chunks.push(chunk); if (this.checkBOM) { - switch (this.buffer.length) { - case 1: - if (this.buffer[0] === BOM[0]) { - callback(); - return; - } - this.checkBOM = false; - callback(); - return; - case 2: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { - callback(); - return; - } - this.checkBOM = false; - break; - case 3: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { - this.buffer = Buffer.alloc(0); - this.checkBOM = false; - callback(); - return; - } - this.checkBOM = false; - break; - default: - if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { - this.buffer = this.buffer.subarray(3); - } - this.checkBOM = false; - break; + if (this.handleBOM()) { + callback(); + return; } } - while (this.pos < this.buffer.length) { + while (this.hasCurrentByte()) { + const byte = this.currentByte(); if (this.eventEndCheck) { if (this.crlfCheck) { - if (this.buffer[this.pos] === LF) { - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; + if (byte === LF) { this.crlfCheck = false; + this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { - if (this.buffer[this.pos] === CR) { + if (byte === LF || byte === CR) { + if (byte === CR) { this.crlfCheck = true; } - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; - if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { + this.consumeCurrentByte(); + if (this.hasPendingEvent()) { this.processEvent(this.event); } this.clearEvent(); @@ -18072,17 +18415,16 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { - if (this.buffer[this.pos] === CR) { + if (byte === LF || byte === CR) { + if (byte === CR) { this.crlfCheck = true; } - this.parseLine(this.buffer.subarray(0, this.pos), this.event); - this.buffer = this.buffer.subarray(this.pos + 1); - this.pos = 0; + this.parseLine(this.readLine(), this.event); + this.consumeCurrentByte(); this.eventEndCheck = true; continue; } - this.pos++; + this.advanceCursor(); } callback(); } @@ -18098,43 +18440,42 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let field = ""; - let value = ""; + let fieldLength = line.length; + let valueStart = line.length; if (colonPosition !== -1) { - field = line.subarray(0, colonPosition).toString("utf8"); - let valueStart = colonPosition + 1; + fieldLength = colonPosition; + valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } - value = line.subarray(valueStart).toString("utf8"); - } else { - field = line.toString("utf8"); - value = ""; } - switch (field) { - case "data": - if (event[field] === void 0) { - event[field] = value; - } else { - event[field] += ` + if (isFieldName(line, fieldLength, DATA)) { + const value = line.toString("utf8", valueStart); + if (event.data === void 0) { + event.data = value; + } else { + event.data += ` ${value}`; - } - break; - case "retry": - if (isASCIINumber(value)) { - event[field] = value; - } - break; - case "id": - if (isValidLastEventId(value)) { - event[field] = value; - } - break; - case "event": - if (value.length > 0) { - event[field] = value; - } - break; + } + return; + } + if (isFieldName(line, fieldLength, RETRY)) { + if (isASCIINumberBytes(line, valueStart)) { + event.retry = line.toString("utf8", valueStart); + } + return; + } + if (isFieldName(line, fieldLength, ID)) { + if (isValidLastEventIdBytes(line, valueStart)) { + event.id = line.toString("utf8", valueStart); + } + return; + } + if (isFieldName(line, fieldLength, EVENT)) { + const value = line.toString("utf8", valueStart); + if (value.length > 0) { + event.event = value; + } } } /** @@ -18159,12 +18500,120 @@ ${value}`; } } clearEvent() { - this.event = { - data: void 0, - event: void 0, - id: void 0, - retry: void 0 - }; + this.event.data = void 0; + this.event.event = void 0; + this.event.id = void 0; + this.event.retry = void 0; + } + hasPendingEvent() { + return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; + } + hasCurrentByte() { + return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; + } + currentByte() { + return this.chunks[this.chunkIndex][this.pos]; + } + consumeCurrentByte() { + this.advanceCursor(); + this.syncLineStartToCursor(); + } + advanceCursor() { + this.pos++; + while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { + this.chunkIndex++; + this.pos = 0; + } + } + syncLineStartToCursor() { + this.lineChunkIndex = this.chunkIndex; + this.linePos = this.pos; + this.dropConsumedChunks(); + } + dropConsumedChunks() { + while (this.lineChunkIndex > 0) { + this.chunks.shift(); + this.lineChunkIndex--; + this.chunkIndex--; + } + if (this.chunkIndex === this.chunks.length) { + this.chunks.length = 0; + this.chunkIndex = 0; + this.pos = 0; + this.lineChunkIndex = 0; + this.linePos = 0; + } + } + readLine() { + if (this.lineChunkIndex === this.chunkIndex) { + return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); + } + const chunks = []; + let length = 0; + for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { + const chunk = this.chunks[i]; + const start = i === this.lineChunkIndex ? this.linePos : 0; + const end = i === this.chunkIndex ? this.pos : chunk.length; + const slice = chunk.subarray(start, end); + length += slice.length; + chunks.push(slice); + } + return Buffer.concat(chunks, length); + } + peekBufferedByte(offset) { + let chunkIndex = this.lineChunkIndex; + let pos = this.linePos; + while (chunkIndex < this.chunks.length) { + const chunk = this.chunks[chunkIndex]; + const remaining = chunk.length - pos; + if (offset < remaining) { + return chunk[pos + offset]; + } + offset -= remaining; + chunkIndex++; + pos = 0; + } + } + discardLeadingBytes(count) { + while (count > 0 && this.lineChunkIndex < this.chunks.length) { + const chunk = this.chunks[this.lineChunkIndex]; + const remaining = chunk.length - this.linePos; + if (count < remaining) { + this.linePos += count; + count = 0; + } else { + count -= remaining; + this.lineChunkIndex++; + this.linePos = 0; + } + } + this.chunkIndex = this.lineChunkIndex; + this.pos = this.linePos; + this.dropConsumedChunks(); + } + handleBOM() { + const first = this.peekBufferedByte(0); + const second = this.peekBufferedByte(1); + const third = this.peekBufferedByte(2); + if (second === void 0) { + if (first === BOM[0]) { + return true; + } + this.checkBOM = false; + return true; + } + if (third === void 0) { + if (first === BOM[0] && second === BOM[1]) { + return true; + } + this.checkBOM = false; + return false; + } + if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { + this.discardLeadingBytes(3); + } + this.checkBOM = false; + return !this.hasCurrentByte(); } }; module2.exports = { @@ -18612,102 +19061,6 @@ var require_undici = __commonJS({ } }); -// node_modules/fast-content-type-parse/index.js -var require_fast_content_type_parse = __commonJS({ - "node_modules/fast-content-type-parse/index.js"(exports2, module2) { - "use strict"; - var NullObject = function NullObject2() { - }; - NullObject.prototype = /* @__PURE__ */ Object.create(null); - var paramRE = /; *([!#$%&'*+.^\w`|~-]+)=("(?:[\v\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\v\u0020-\u00ff])*"|[!#$%&'*+.^\w`|~-]+) */gu; - var quotedPairRE = /\\([\v\u0020-\u00ff])/gu; - var mediaTypeRE = /^[!#$%&'*+.^\w|~-]+\/[!#$%&'*+.^\w|~-]+$/u; - var defaultContentType = { type: "", parameters: new NullObject() }; - Object.freeze(defaultContentType.parameters); - Object.freeze(defaultContentType); - function parse2(header) { - if (typeof header !== "string") { - throw new TypeError("argument header is required and must be a string"); - } - let index = header.indexOf(";"); - const type = index !== -1 ? header.slice(0, index).trim() : header.trim(); - if (mediaTypeRE.test(type) === false) { - throw new TypeError("invalid media type"); - } - const result = { - type: type.toLowerCase(), - parameters: new NullObject() - }; - if (index === -1) { - return result; - } - let key; - let match; - let value; - paramRE.lastIndex = index; - while (match = paramRE.exec(header)) { - if (match.index !== index) { - throw new TypeError("invalid parameter format"); - } - index += match[0].length; - key = match[1].toLowerCase(); - value = match[2]; - if (value[0] === '"') { - value = value.slice(1, value.length - 1); - quotedPairRE.test(value) && (value = value.replace(quotedPairRE, "$1")); - } - result.parameters[key] = value; - } - if (index !== header.length) { - throw new TypeError("invalid parameter format"); - } - return result; - } - function safeParse2(header) { - if (typeof header !== "string") { - return defaultContentType; - } - let index = header.indexOf(";"); - const type = index !== -1 ? header.slice(0, index).trim() : header.trim(); - if (mediaTypeRE.test(type) === false) { - return defaultContentType; - } - const result = { - type: type.toLowerCase(), - parameters: new NullObject() - }; - if (index === -1) { - return result; - } - let key; - let match; - let value; - paramRE.lastIndex = index; - while (match = paramRE.exec(header)) { - if (match.index !== index) { - return defaultContentType; - } - index += match[0].length; - key = match[1].toLowerCase(); - value = match[2]; - if (value[0] === '"') { - value = value.slice(1, value.length - 1); - quotedPairRE.test(value) && (value = value.replace(quotedPairRE, "$1")); - } - result.parameters[key] = value; - } - if (index !== header.length) { - return defaultContentType; - } - return result; - } - module2.exports.default = { parse: parse2, safeParse: safeParse2 }; - module2.exports.parse = parse2; - module2.exports.safeParse = safeParse2; - module2.exports.defaultContentType = defaultContentType; - } -}); - // node_modules/@actions/core/lib/core.js var core_exports = {}; __export(core_exports, { @@ -21339,8 +21692,189 @@ function withDefaults(oldDefaults, newDefaults) { } var endpoint = withDefaults(null, DEFAULTS); -// node_modules/@octokit/request/dist-bundle/index.js -var import_fast_content_type_parse = __toESM(require_fast_content_type_parse(), 1); +// node_modules/content-type/dist/index.js +var SP = 32; +var HTAB = 9; +var SEMI = 59; +var EQ = 61; +var DQUOTE = 34; +var BSLASH = 92; +var COMMA = 44; +var LOWER_CASE = 1; +var OWS = 2; +var SEMI_FLAG = 4; +var COMMA_FLAG = 8; +var TOKEN_FLAG = 16; +var NON_ASCII = 65280; +var CASE_FLAGS = LOWER_CASE | NON_ASCII; +var CHAR_MAP = new Uint8Array(256); +CHAR_MAP[HTAB] |= OWS; +CHAR_MAP[SP] |= OWS; +CHAR_MAP[SEMI] |= SEMI_FLAG; +CHAR_MAP[COMMA] |= COMMA_FLAG; +for (let code = 128; code <= 255; code++) { + CHAR_MAP[code] |= LOWER_CASE; +} +for (const char of "!#$%&'*+-.^_`|~") { + CHAR_MAP[char.charCodeAt(0)] |= TOKEN_FLAG; +} +for (let code = 48; code <= 57; code++) { + CHAR_MAP[code] |= TOKEN_FLAG; +} +for (let code = 65; code <= 90; code++) { + CHAR_MAP[code] |= LOWER_CASE | TOKEN_FLAG; +} +for (let code = 97; code <= 122; code++) { + CHAR_MAP[code] |= TOKEN_FLAG; +} +var NullObject = /* @__PURE__ */ (() => { + const C = function() { + }; + C.prototype = /* @__PURE__ */ Object.create(null); + return C; +})(); +function parse2(header, options) { + const stopFlags = SEMI_FLAG | (options?.comma === true ? COMMA_FLAG : 0); + const len = header.length; + let valueStart = options?.start ?? 0; + while ((CHAR_MAP[header.charCodeAt(valueStart)] & OWS) !== 0) { + valueStart++; + } + let index = valueStart; + let typeFlags = 0; + let whitespace = -1; + let stop = options?.parameters === false ? COMMA_FLAG : 0; + while (index < len) { + const code = header.charCodeAt(index); + const flags = CHAR_MAP[code]; + if ((flags & stopFlags) !== 0) { + stop |= flags & COMMA_FLAG; + break; + } + if ((flags & OWS) !== 0) { + if (whitespace === -1) + whitespace = index; + } else { + whitespace = -1; + } + typeFlags |= code & NON_ASCII | flags; + index++; + } + const valueEnd = whitespace === -1 ? index : whitespace; + const value = header.slice(valueStart, valueEnd); + const type = (typeFlags & CASE_FLAGS) === 0 ? value : value.toLowerCase(); + if (index === len || stop !== 0) { + return { type, index, parameters: new NullObject() }; + } + return parseParameters(header, type, index, len, stopFlags); +} +function parseParameters(header, type, index, len, stopFlags) { + const parameters = new NullObject(); + parameter: while (index < len) { + index++; + while ((CHAR_MAP[header.charCodeAt(index)] & OWS) !== 0) { + index++; + } + const keyStart = index; + let keyFlags = 0; + let keyWhitespace = -1; + while (index < len) { + const code = header.charCodeAt(index); + const flags = CHAR_MAP[code]; + if ((flags & stopFlags) !== 0) { + if ((flags & COMMA_FLAG) !== 0) + break parameter; + continue parameter; + } + if (code === EQ) { + const keyEnd = keyWhitespace === -1 ? index : keyWhitespace; + const value = header.slice(keyStart, keyEnd); + const key = (keyFlags & CASE_FLAGS) === 0 ? value : value.toLowerCase(); + index++; + while ((CHAR_MAP[header.charCodeAt(index)] & OWS) !== 0) { + index++; + } + if (index < len && header.charCodeAt(index) === DQUOTE) { + const quotedStart = ++index; + let escaped = false; + while (index < len) { + const code2 = header.charCodeAt(index); + if (code2 === DQUOTE) { + if (parameters[key] === void 0) { + parameters[key] = escaped ? unescapeQuotedPairs(header, quotedStart, index) : header.slice(quotedStart, index); + } + index++; + let stop2 = 0; + while (index < len) { + const code3 = header.charCodeAt(index); + const flags2 = CHAR_MAP[code3]; + if ((flags2 & stopFlags) !== 0) { + stop2 = flags2 & COMMA_FLAG; + break; + } + index++; + } + if (stop2 !== 0) + break parameter; + continue parameter; + } + if (code2 === BSLASH && index + 1 < len) { + escaped = true; + index += 2; + continue; + } + index++; + } + continue parameter; + } + const valueStart = index; + let stop = 0; + let valueWhitespace = -1; + while (index < len) { + const code2 = header.charCodeAt(index); + const flags2 = CHAR_MAP[code2]; + if ((flags2 & stopFlags) !== 0) { + stop = flags2 & COMMA_FLAG; + break; + } + if ((flags2 & OWS) !== 0) { + if (valueWhitespace === -1) + valueWhitespace = index; + } else { + valueWhitespace = -1; + } + index++; + } + if (parameters[key] === void 0) { + const valueEnd = valueWhitespace === -1 ? index : valueWhitespace; + parameters[key] = header.slice(valueStart, valueEnd); + } + if (stop !== 0) + break parameter; + continue parameter; + } + if ((flags & OWS) !== 0) { + if (keyWhitespace === -1) + keyWhitespace = index; + } else { + keyWhitespace = -1; + } + keyFlags |= code & NON_ASCII | flags; + index++; + } + } + return { type, index, parameters }; +} +function unescapeQuotedPairs(str, start, end) { + let result = ""; + for (let index = start; index < end; index++) { + if (str.charCodeAt(index) === BSLASH) { + result += str.slice(start, index); + start = ++index; + } + } + return result + str.slice(start, end); +} // node_modules/json-with-bigint/json-with-bigint.js var intRegex = /^-?\d+$/; @@ -21348,84 +21882,333 @@ var noiseValue = /^-?\d+n+$/; var originalStringify = JSON.stringify; var originalParse = JSON.parse; var customFormat = /^-?\d+n$/; -var bigIntsStringify = /([\[:])?"(-?\d+)n"($|([\\n]|\s)*(\s|[\\n])*[,\}\]])/g; -var noiseStringify = /([\[:])?("-?\d+n+)n("$|"([\\n]|\s)*(\s|[\\n])*[,\}\]])/g; +var bigIntsStringify = /([\[:])?"(-?\d+)n"($|\s*[,\}\]])/g; +var noiseStringify = /([\[:])?("-?\d+n+)n("$|"\s*[,\}\]])/g; +var isUnstringifiable = (val) => val === void 0 || typeof val === "function" || typeof val === "symbol"; +var isRawJSON = (val) => val !== null && typeof val === "object" && val.constructor && val.constructor.name === "RawJSON"; +var stringifyIteratively = (rootValue, replacer, spaceParam) => { + let space = ""; + if (typeof spaceParam === "number") { + space = " ".repeat(Math.min(10, Math.max(0, Math.floor(spaceParam)))); + } else if (typeof spaceParam === "string") { + space = spaceParam.slice(0, 10); + } + const isFunctionReplacer = typeof replacer === "function"; + const propertyList = Array.isArray(replacer) ? new Set(replacer.map(String)) : null; + const prepareVal = (parent, key, val) => { + const isObject = val !== null && typeof val === "object"; + const hasToJSON = isObject && typeof val.toJSON === "function"; + if (hasToJSON) { + val = val.toJSON(key); + } + const isNoise = typeof val === "string" && noiseValue.test(val); + if (isNoise) return val + "n"; + const isBigInt = typeof val === "bigint"; + if (isBigInt) { + const supportsRawJSON = "rawJSON" in JSON; + if (supportsRawJSON) return JSON.rawJSON(val.toString()); + return val.toString() + "n"; + } + if (isFunctionReplacer) { + val = replacer.call(parent, key, val); + } + const isPostReplacerObject = val !== null && typeof val === "object"; + if (isPostReplacerObject) { + const isPrimitiveWrapper = val instanceof Number || val instanceof String || val instanceof Boolean; + if (isPrimitiveWrapper) { + val = val.valueOf(); + } + } + return val; + }; + const rootProcessed = prepareVal({ "": rootValue }, "", rootValue); + if (isUnstringifiable(rootProcessed)) { + return void 0; + } + const isRootPrimitive = rootProcessed === null || typeof rootProcessed !== "object"; + const isRootNativeRawJSON = isRawJSON(rootProcessed); + if (isRootPrimitive || isRootNativeRawJSON) { + return originalStringify(rootProcessed); + } + const chunks = []; + let level = 0; + const stack = [ + { + parent: { "": rootProcessed }, + key: "", + val: rootProcessed, + isArray: Array.isArray(rootProcessed), + keys: Array.isArray(rootProcessed) ? null : Object.keys(rootProcessed), + index: 0, + first: true + } + ]; + const visited = new WeakSet([rootProcessed]); + while (stack.length > 0) { + const node = stack[stack.length - 1]; + if (node.index === 0) { + chunks.push(node.isArray ? "[" : "{"); + level++; + } + let isDone = false; + if (node.isArray) { + if (node.index < node.val.length) { + if (!node.first) chunks.push(","); + if (space) chunks.push("\n" + space.repeat(level)); + const childRaw = node.val[node.index]; + const childVal = prepareVal(node.val, String(node.index), childRaw); + if (isUnstringifiable(childVal)) { + chunks.push("null"); + node.first = false; + node.index++; + } else { + const isComplexObject = childVal !== null && typeof childVal === "object"; + const isNativeRaw = isRawJSON(childVal); + if (isComplexObject && !isNativeRaw) { + if (visited.has(childVal)) { + throw new TypeError("Converting circular structure to JSON"); + } + visited.add(childVal); + stack.push({ + parent: node.val, + key: String(node.index), + val: childVal, + isArray: Array.isArray(childVal), + keys: Array.isArray(childVal) ? null : Object.keys(childVal), + index: 0, + first: true + }); + node.first = false; + node.index++; + } else { + chunks.push(originalStringify(childVal)); + node.first = false; + node.index++; + } + } + } else { + isDone = true; + } + } else { + while (node.index < node.keys.length) { + const k = node.keys[node.index++]; + const isFilteredOutByArray = propertyList && !propertyList.has(k); + if (isFilteredOutByArray) continue; + const childRaw = node.val[k]; + const childVal = prepareVal(node.val, k, childRaw); + if (isUnstringifiable(childVal)) continue; + if (!node.first) chunks.push(","); + if (space) { + chunks.push("\n" + space.repeat(level) + originalStringify(k) + ": "); + } else { + chunks.push(originalStringify(k) + ":"); + } + const isComplexObject = childVal !== null && typeof childVal === "object"; + const isNativeRaw = isRawJSON(childVal); + if (isComplexObject && !isNativeRaw) { + if (visited.has(childVal)) { + throw new TypeError("Converting circular structure to JSON"); + } + visited.add(childVal); + stack.push({ + parent: node.val, + key: k, + val: childVal, + isArray: Array.isArray(childVal), + keys: Array.isArray(childVal) ? null : Object.keys(childVal), + index: 0, + first: true + }); + node.first = false; + break; + } else { + chunks.push(originalStringify(childVal)); + node.first = false; + } + } + const isNodeFullyProcessed = node.index >= node.keys.length && stack[stack.length - 1] === node; + if (isNodeFullyProcessed) { + isDone = true; + } + } + if (isDone) { + level--; + if (!node.first && space) chunks.push("\n" + space.repeat(level)); + chunks.push(node.isArray ? "]" : "}"); + visited.delete(node.val); + stack.pop(); + } + } + return chunks.join(""); +}; var JSONStringify = (value, replacer, space) => { - if ("rawJSON" in JSON) { - return originalStringify( + try { + const supportsRawJSON = "rawJSON" in JSON; + if (supportsRawJSON) { + return originalStringify( + value, + (key, val) => { + if (typeof val === "bigint") return JSON.rawJSON(val.toString()); + const hasFunctionReplacer = typeof replacer === "function"; + if (hasFunctionReplacer) return replacer(key, val); + const isKeyInArrayReplacer = Array.isArray(replacer) && replacer.includes(key); + if (isKeyInArrayReplacer) return val; + return val; + }, + space + ); + } + if (!value) return originalStringify(value, replacer, space); + const convertedToCustomJSON = originalStringify( value, - (key, value2) => { - if (typeof value2 === "bigint") return JSON.rawJSON(value2.toString()); - if (typeof replacer === "function") return replacer(key, value2); - if (Array.isArray(replacer) && replacer.includes(key)) return value2; - return value2; + (key, val) => { + const isNoise = typeof val === "string" && noiseValue.test(val); + if (isNoise) return val.toString() + "n"; + if (typeof val === "bigint") return val.toString() + "n"; + const hasFunctionReplacer = typeof replacer === "function"; + if (hasFunctionReplacer) return replacer(key, val); + const isKeyInArrayReplacer = Array.isArray(replacer) && replacer.includes(key); + if (isKeyInArrayReplacer) return val; + return val; }, space ); + const processedJSON = convertedToCustomJSON.replace( + bigIntsStringify, + "$1$2$3" + ); + const denoisedJSON = processedJSON.replace(noiseStringify, "$1$2$3"); + return denoisedJSON; + } catch (error2) { + if (error2 instanceof RangeError) { + const convertedJSON = stringifyIteratively(value, replacer, space); + if (convertedJSON === void 0) return void 0; + const supportsRawJSON = "rawJSON" in JSON; + if (supportsRawJSON) return convertedJSON; + const processedJSON = convertedJSON.replace(bigIntsStringify, "$1$2$3"); + return processedJSON.replace(noiseStringify, "$1$2$3"); + } + throw error2; + } +}; +var featureCache = /* @__PURE__ */ new Map(); +var isContextSourceSupported = () => { + const parseFingerprint = JSON.parse.toString(); + if (featureCache.has(parseFingerprint)) { + return featureCache.get(parseFingerprint); + } + try { + const result = JSON.parse( + "1", + (_, __, context) => !!context?.source && context.source === "1" + ); + featureCache.set(parseFingerprint, result); + return result; + } catch { + featureCache.set(parseFingerprint, false); + return false; } - if (!value) return originalStringify(value, replacer, space); - const convertedToCustomJSON = originalStringify( - value, - (key, value2) => { - const isNoise = typeof value2 === "string" && Boolean(value2.match(noiseValue)); - if (isNoise) return value2.toString() + "n"; - if (typeof value2 === "bigint") return value2.toString() + "n"; - if (typeof replacer === "function") return replacer(key, value2); - if (Array.isArray(replacer) && replacer.includes(key)) return value2; - return value2; - }, - space - ); - const processedJSON = convertedToCustomJSON.replace( - bigIntsStringify, - "$1$2$3" - ); - const denoisedJSON = processedJSON.replace(noiseStringify, "$1$2$3"); - return denoisedJSON; }; -var isContextSourceSupported = () => JSON.parse("1", (_, __, context) => !!context && context.source === "1"); var convertMarkedBigIntsReviver = (key, value, context, userReviver) => { - const isCustomFormatBigInt = typeof value === "string" && value.match(customFormat); + const isCustomFormatBigInt = typeof value === "string" && customFormat.test(value); if (isCustomFormatBigInt) return BigInt(value.slice(0, -1)); - const isNoiseValue = typeof value === "string" && value.match(noiseValue); + const isNoiseValue = typeof value === "string" && noiseValue.test(value); if (isNoiseValue) return value.slice(0, -1); - if (typeof userReviver !== "function") return value; + const hasUserReviver = typeof userReviver === "function"; + if (!hasUserReviver) return value; return userReviver(key, value, context); }; var JSONParseV2 = (text, reviver) => { return JSON.parse(text, (key, value, context) => { - const isBigNumber = typeof value === "number" && (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER); + const isNumber = typeof value === "number"; + const isOutOfBounds = value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER; + const isBigNumber = isNumber && isOutOfBounds; const isInt = context && intRegex.test(context.source); const isBigInt = isBigNumber && isInt; if (isBigInt) return BigInt(context.source); - if (typeof reviver !== "function") return value; + const hasCustomReviver = typeof reviver === "function"; + if (!hasCustomReviver) return value; return reviver(key, value, context); }); }; var MAX_INT = Number.MAX_SAFE_INTEGER.toString(); var MAX_DIGITS = MAX_INT.length; -var stringsOrLargeNumbers = /"(?:\\.|[^"])*"|-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?/g; +var stringsOrLargeNumbers = /"(?:[^"\\]|\\.)*"|-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?/g; var noiseValueWithQuotes = /^"-?\d+n+"$/; -var JSONParse = (text, reviver) => { - if (!text) return originalParse(text, reviver); - if (isContextSourceSupported()) return JSONParseV2(text, reviver); - const serializedData = text.replace( +var applyReviverIteratively = (parsed, userReviver) => { + const rootHolder = { "": parsed }; + const stack = [{ parent: rootHolder, key: "", visited: false }]; + while (stack.length > 0) { + const node = stack[stack.length - 1]; + if (!node.visited) { + node.visited = true; + const value = node.parent[node.key]; + const isComplexObject = value !== null && typeof value === "object"; + if (isComplexObject) { + const keys = Object.keys(value); + for (let i = keys.length - 1; i >= 0; i--) { + stack.push({ parent: value, key: keys[i], visited: false }); + } + } + } else { + const { parent, key } = node; + let value = parent[key]; + if (typeof value === "string") { + const isCustomFormatBigInt = customFormat.test(value); + if (isCustomFormatBigInt) { + value = BigInt(value.slice(0, -1)); + } else { + const isNoise = noiseValue.test(value); + if (isNoise) value = value.slice(0, -1); + } + } + const hasUserReviver = typeof userReviver === "function"; + if (hasUserReviver) { + value = userReviver.call(parent, key, value); + } + const isDeleted = value === void 0; + if (isDeleted) { + delete parent[key]; + } else { + parent[key] = value; + } + stack.pop(); + } + } + return rootHolder[""]; +}; +var serializeBigInts = (text) => { + return text.replace( stringsOrLargeNumbers, - (text2, digits, fractional, exponential) => { - const isString = text2[0] === '"'; - const isNoise = isString && Boolean(text2.match(noiseValueWithQuotes)); - if (isNoise) return text2.substring(0, text2.length - 1) + 'n"'; - const isFractionalOrExponential = fractional || exponential; + (match, digits, fractional, exponential) => { + const isString = match[0] === '"'; + const isNoise = isString && noiseValueWithQuotes.test(match); + if (isNoise) return match.substring(0, match.length - 1) + 'n"'; + const hasFractionalOrExponential = fractional || exponential; const isLessThanMaxSafeInt = digits && (digits.length < MAX_DIGITS || digits.length === MAX_DIGITS && digits <= MAX_INT); - if (isString || isFractionalOrExponential || isLessThanMaxSafeInt) - return text2; - return '"' + text2 + 'n"'; + const isStandardValue = isString || hasFractionalOrExponential || isLessThanMaxSafeInt; + if (isStandardValue) return match; + return '"' + match + 'n"'; } ); - return originalParse( - serializedData, - (key, value, context) => convertMarkedBigIntsReviver(key, value, context, reviver) - ); +}; +var JSONParse = (text, reviver) => { + if (!text) return originalParse(text, reviver); + try { + if (isContextSourceSupported()) return JSONParseV2(text, reviver); + const serializedData = serializeBigInts(text); + return originalParse( + serializedData, + (key, value, context) => convertMarkedBigIntsReviver(key, value, context, reviver) + ); + } catch (error2) { + if (error2 instanceof RangeError) { + const serializedData = serializeBigInts(text); + const parsed = originalParse(serializedData); + return applyReviverIteratively(parsed, reviver); + } + throw error2; + } }; // node_modules/@octokit/request-error/dist-src/index.js @@ -21468,7 +22251,7 @@ var RequestError = class extends Error { }; // node_modules/@octokit/request/dist-bundle/index.js -var VERSION2 = "10.0.8"; +var VERSION2 = "10.0.16"; var defaults_default = { headers: { "user-agent": `octokit-request.js/${VERSION2} ${getUserAgent()}` @@ -21586,7 +22369,7 @@ async function getResponseData(response) { if (!contentType) { return response.text().catch(noop); } - const mimetype = (0, import_fast_content_type_parse.safeParse)(contentType); + const mimetype = parse2(contentType); if (isJSONResponse(mimetype)) { let text = ""; try { @@ -21595,7 +22378,10 @@ async function getResponseData(response) { } catch (err) { return text; } - } else if (mimetype.type.startsWith("text/") || mimetype.parameters.charset?.toLowerCase() === "utf-8") { + } else if (mimetype.type.startsWith("text/") || // `application/octet-stream` is the canonical "arbitrary binary" type + // (RFC 2046) and must never be decoded as text, even when the response + // carries a (misleading) `charset=utf-8` parameter — see #751. + mimetype.parameters.charset?.toLowerCase() === "utf-8" && mimetype.type !== "application/octet-stream") { return response.text().catch(noop); } else { return response.arrayBuffer().catch( @@ -21614,9 +22400,10 @@ function toErrorMessage(data) { if (data instanceof ArrayBuffer) { return "Unknown error"; } - if ("message" in data) { - const suffix = "documentation_url" in data ? ` - ${data.documentation_url}` : ""; - return Array.isArray(data.errors) ? `${data.message}: ${data.errors.map((v) => JSON.stringify(v)).join(", ")}${suffix}` : `${data.message}${suffix}`; + if (typeof data === "object" && data !== null && "message" in data) { + const objectData = data; + const suffix = "documentation_url" in objectData ? ` - ${objectData.documentation_url}` : ""; + return Array.isArray(objectData.errors) ? `${objectData.message}: ${objectData.errors.map((v) => JSON.stringify(v)).join(", ")}${suffix}` : `${objectData.message}${suffix}`; } return `Unknown error: ${JSON.stringify(data)}`; } @@ -21689,6 +22476,13 @@ undici/lib/web/fetch/body.js: undici/lib/web/websocket/frame.js: (*! ws. MIT License. Einar Otto Stangvik *) +content-type/dist/index.js: + (*! + * content-type + * Copyright(c) 2015 Douglas Christopher Wilson + * MIT Licensed + *) + @octokit/request-error/dist-src/index.js: (* v8 ignore else -- @preserve -- Bug with vitest coverage where it sees an else branch that doesn't exist *) diff --git a/package-lock.json b/package-lock.json index 368387d5..bb3e6d79 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "create-github-app-token", - "version": "3.2.0", + "version": "3.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "create-github-app-token", - "version": "3.2.0", + "version": "3.3.0", "license": "MIT", "dependencies": { "@actions/core": "^3.0.1", diff --git a/package.json b/package.json index 5b99346e..57c03041 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "create-github-app-token", "private": true, "type": "module", - "version": "3.2.0", + "version": "3.3.0", "description": "GitHub Action for creating a GitHub App Installation Access Token", "engines": { "node": ">=24.4.0"