From 2bfbb5a8367567369ed4708d7559e42e1110a974 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Aug 2026 23:24:42 +0000 Subject: [PATCH 1/5] Bump super-linter/super-linter from 5 to 8 Bumps [super-linter/super-linter](https://github.com/super-linter/super-linter) from 5 to 8. - [Release notes](https://github.com/super-linter/super-linter/releases) - [Changelog](https://github.com/super-linter/super-linter/blob/main/CHANGELOG.md) - [Commits](https://github.com/super-linter/super-linter/compare/v5...v8) --- updated-dependencies: - dependency-name: super-linter/super-linter dependency-version: '8' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/linter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index b24fe88..de1f602 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -34,7 +34,7 @@ jobs: - name: Lint Codebase id: super-linter - uses: super-linter/super-linter/slim@v5 + uses: super-linter/super-linter/slim@v8 env: DEFAULT_BRANCH: main FILTER_REGEX_EXCLUDE: dist/**/* From c39836a23758e3e46072a8d48edec754fc501388 Mon Sep 17 00:00:00 2001 From: Brandon White Date: Tue, 1 Sep 2026 16:07:11 -0500 Subject: [PATCH 2/5] ci: give super-linter the full git history super-linter v6 and later resolve the default branch by running `git rev-parse --verify main` (then `origin/main`) inside the workspace. A shallow PR checkout creates neither ref, so v8 aborted with "Neither main, nor origin/main exist in /github/workspace". Also drop JAVASCRIPT_DEFAULT_STYLE, deprecated in super-linter v6.8.0 and now only emitting a warning; JAVASCRIPT_PRETTIER covers it. Co-Authored-By: Claude Opus 5 --- .github/workflows/linter.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index de1f602..8e3a867 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -20,6 +20,10 @@ jobs: - name: Checkout id: checkout uses: actions/checkout@v7 + with: + # super-linter resolves the default branch with `git rev-parse`, so it + # needs the full git history rather than a shallow clone. + fetch-depth: 0 - name: Setup Node.js id: setup-node @@ -39,7 +43,6 @@ jobs: DEFAULT_BRANCH: main FILTER_REGEX_EXCLUDE: dist/**/* GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - JAVASCRIPT_DEFAULT_STYLE: prettier VALIDATE_ALL_CODEBASE: true VALIDATE_JSCPD: false VALIDATE_HTML: false From 1a409e648c1399f08c4038a39013bf8bc9b2f187 Mon Sep 17 00:00:00 2001 From: Brandon White Date: Tue, 1 Sep 2026 16:24:16 -0500 Subject: [PATCH 3/5] ci: resolve the linter findings super-linter v8 newly reports v8 enables linters v5 did not run, and ships newer versions of ones it did. Working through what they found: zizmor (new in v8), 28 findings, all fixed: - pinned all 16 action references to commit SHAs with version comments - added persist-credentials: false to all 7 checkouts - moved pages/id-token write scopes off the Jekyll workflow and onto the deploy job that actually needs them - added a 7-day Dependabot cooldown so a release settles before we take it FILTER_REGEX_EXCLUDE held a glob (dist/**/*) in a field super-linter treats as a regex. Unanchored, it matched any path containing "dist", so .github/workflows/check-dist.yml was silently excluded from every linter - which is why zizmor never reported its 4 findings. Anchored to ^dist/.* and fixed the findings that surfaced. codespell (new in v8): fixed "Converage" in README.md, "pacakge" in action.yml and "Comfirm" in the act fixture. Added .codespellrc for thirdParty, which is a rollup-plugin-license option name. checkov (new in v8) flagged the act fixture for having no top-level permissions; gave it contents: read rather than suppressing the check. trivy (new in v8) secret-scans generated dist/index.js and hits the Azurite emulator's public dev credentials vendored in @azure/storage-blob. Added trivy.yaml mirroring super-linter's template plus skip-dirs: dist, keeping the useful package-lock.json vulnerability scan. Biome is disabled: it wants semicolons and double quotes, while .prettierrc.yml sets semi: false and singleQuote: true. Prettier and eslint are this repo's formatter and linter. textlint in v8 is newer and flags two more terminology errors in the ESM migration spec. Co-Authored-By: Claude Opus 5 --- .github/dependabot.yml | 6 ++++++ .github/linters/.codespellrc | 2 ++ .github/linters/trivy.yaml | 11 ++++++++++ .github/workflows/check-dist.yml | 8 ++++--- .github/workflows/ci.yml | 14 +++++++++---- .github/workflows/jekyll-gh-pages.yml | 21 ++++++++++++------- .github/workflows/linter.yml | 16 ++++++++++---- README.md | 2 +- .../.github/workflows/test-workflow-1.yml | 10 +++++++-- action.yml | 2 +- .../specs/2026-08-13-esm-migration-design.md | 4 ++-- 11 files changed, 71 insertions(+), 25 deletions(-) create mode 100644 .github/linters/.codespellrc create mode 100644 .github/linters/trivy.yaml diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 742ec57..049ee6d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,6 +4,10 @@ updates: directory: / schedule: interval: weekly + # Let a release settle before opening a PR for it, so a compromised or + # promptly-yanked version is less likely to be picked up. + cooldown: + default-days: 7 groups: actions-minor: update-types: @@ -14,6 +18,8 @@ updates: directory: / schedule: interval: weekly + cooldown: + default-days: 7 groups: npm-development: dependency-type: development diff --git a/.github/linters/.codespellrc b/.github/linters/.codespellrc new file mode 100644 index 0000000..5838502 --- /dev/null +++ b/.github/linters/.codespellrc @@ -0,0 +1,2 @@ +[codespell] +ignore-words-list = thirdparty diff --git a/.github/linters/trivy.yaml b/.github/linters/trivy.yaml new file mode 100644 index 0000000..dae4525 --- /dev/null +++ b/.github/linters/trivy.yaml @@ -0,0 +1,11 @@ +--- +exit-code: 1 +exit-on-eol: 2 +scan: + disable-telemetry: true + scanners: + - vuln + - misconfig + - secret + skip-dirs: + - dist diff --git a/.github/workflows/check-dist.yml b/.github/workflows/check-dist.yml index 55dcb53..8fb8065 100644 --- a/.github/workflows/check-dist.yml +++ b/.github/workflows/check-dist.yml @@ -26,11 +26,13 @@ jobs: steps: - name: Checkout id: checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup Node.js id: setup-node - uses: actions/setup-node@v7 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version-file: package.json cache: npm @@ -58,7 +60,7 @@ jobs: - if: ${{ failure() && steps.diff.outcome == 'failure' }} name: Upload Artifact id: upload - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: dist path: dist/ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e6c4d29..1a12356 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,11 +17,13 @@ jobs: steps: - name: Checkout id: checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup Node.js id: setup-node - uses: actions/setup-node@v7 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version-file: package.json cache: npm @@ -49,7 +51,9 @@ jobs: steps: - name: Checkout id: checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - run: cp __tests__/data/pyproject.test1.toml pyproject.toml @@ -64,7 +68,9 @@ jobs: steps: - name: Checkout id: checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - run: cp __tests__/data/pyproject.test1.toml pyproject.toml diff --git a/.github/workflows/jekyll-gh-pages.yml b/.github/workflows/jekyll-gh-pages.yml index 7894ece..4ed848e 100644 --- a/.github/workflows/jekyll-gh-pages.yml +++ b/.github/workflows/jekyll-gh-pages.yml @@ -9,11 +9,8 @@ on: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: contents: read - pages: write - id-token: write # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. @@ -27,19 +24,27 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup Pages - uses: actions/configure-pages@v6 + uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 - name: Build with Jekyll - uses: actions/jekyll-build-pages@v1 + uses: actions/jekyll-build-pages@44a6e6beabd48582f863aeeb6cb2151cc1716697 # v1.0.13 with: source: ./ destination: ./_site - name: Upload artifact - uses: actions/upload-pages-artifact@v5 + uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 # Deployment job deploy: + # Only this job deploys, so the GITHUB_TOKEN write scopes it needs to reach + # GitHub Pages are granted here rather than to every job in the workflow. + permissions: + contents: read + pages: write + id-token: write environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} @@ -48,4 +53,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v5 + uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0 diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 8e3a867..839e0d4 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -19,15 +19,16 @@ jobs: steps: - name: Checkout id: checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: # super-linter resolves the default branch with `git rev-parse`, so it # needs the full git history rather than a shallow clone. fetch-depth: 0 + persist-credentials: false - name: Setup Node.js id: setup-node - uses: actions/setup-node@v7 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version-file: package.json cache: npm @@ -38,11 +39,18 @@ jobs: - name: Lint Codebase id: super-linter - uses: super-linter/super-linter/slim@v8 + uses: super-linter/super-linter/slim@4ce20838b8ab83717e78138c5b3a1407148e0918 # v8.7.0 env: DEFAULT_BRANCH: main - FILTER_REGEX_EXCLUDE: dist/**/* + # This is a regex, not a glob: the previous value (dist/**/*) also + # matched check-dist.yml and excluded it from every linter. + FILTER_REGEX_EXCLUDE: ^dist/.* GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} VALIDATE_ALL_CODEBASE: true VALIDATE_JSCPD: false VALIDATE_HTML: false + # Biome is a competing formatter/linter: it wants semicolons and + # double quotes, while .prettierrc.yml sets semi: false and + # singleQuote: true. Prettier and eslint are this repo's tools. + VALIDATE_BIOME_FORMAT: false + VALIDATE_BIOME_LINT: false diff --git a/README.md b/README.md index c9014ae..7ba4702 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![GitHub Super-Linter](https://github.com/python-build-tools/pipx-install-action/actions/workflows/linter.yml/badge.svg)](https://github.com/super-linter/super-linter) ![CI](https://github.com/python-build-tools/pipx-install-action/actions/workflows/ci.yml/badge.svg) -![Test Converage](https://raw.githubusercontent.com/python-build-tools/pipx-install-action/main/badges/coverage.svg) +![Test Coverage](https://raw.githubusercontent.com/python-build-tools/pipx-install-action/main/badges/coverage.svg) This action installs Python tools using [pipx](https://github.com/pypa/pipx). diff --git a/__tests__/data/.github/workflows/test-workflow-1.yml b/__tests__/data/.github/workflows/test-workflow-1.yml index 738a572..ac5926a 100644 --- a/__tests__/data/.github/workflows/test-workflow-1.yml +++ b/__tests__/data/.github/workflows/test-workflow-1.yml @@ -1,4 +1,8 @@ on: push + +permissions: + contents: read + jobs: test: runs-on: ubuntu-latest @@ -16,11 +20,13 @@ jobs: - run: echo "/root/.local/bin" >> "$GITHUB_PATH" # Test the pipx-install action - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + with: + persist-credentials: false - run: cp __tests__/data/pyproject.test1.toml pyproject.toml - uses: './' # Run this repo's action. - # Comfirm that expected tools are installed and runnable. + # Confirm that expected tools are installed and runnable. - run: poetry --version - run: poetry bundle venv --help - run: tox --version diff --git a/action.yml b/action.yml index 5be05bb..3c09abf 100644 --- a/action.yml +++ b/action.yml @@ -16,7 +16,7 @@ inputs: description: When 'true', packages will be saved to the repository's GitHub Action cache and restored whenever possible to avoid downloading from the - upstream pacakge repository (eg. PyPI) + upstream package repository (eg. PyPI) default: true runs: diff --git a/docs/superpowers/specs/2026-08-13-esm-migration-design.md b/docs/superpowers/specs/2026-08-13-esm-migration-design.md index ebc427c..98bf543 100644 --- a/docs/superpowers/specs/2026-08-13-esm-migration-design.md +++ b/docs/superpowers/specs/2026-08-13-esm-migration-design.md @@ -89,7 +89,7 @@ Two consequences deserve explicit note. **`pipx-install.test.js` needs a partial mock of `node:fs/promises`.** It mocks `symlink` and `stat` but relies on `readFile` being real so the TOML fixtures in `__tests__/data/` still load. `unstable_mockModule` replaces a whole module, so -the fixture re-exports the real module and overrides only those two functions: +the fixture reexports the real module and overrides only those two functions: ```js const real = await import('node:fs/promises') @@ -170,7 +170,7 @@ Three deliberate deviations from the upstream template's configuration: dependency is `@actions/core`. Here, `@actions/cache` imports its own `package.json`, and the build fails outright without this plugin. - **`sourcemap: false`.** The generated source map is roughly 16.5 MB. Because - `dist/` is committed, enabling it would add that volume to git history on + `dist/` is committed, enabling it would add that volume to Git history on every dependency bump and would bury the `dist/` diff that `check-dist.yml` reports. With source maps off, `dist/` keeps exactly the two files it holds today, `index.js` and `licenses.txt`, so the migration introduces no new From a73a4a36b8e4927b0d5c9abd529bd198d1ece8e3 Mon Sep 17 00:00:00 2001 From: Brandon White Date: Tue, 1 Sep 2026 16:27:26 -0500 Subject: [PATCH 4/5] ci: stop super-linter from linting JS under a second rule set super-linter never used this repo's eslint config: JAVASCRIPT_ES_CONFIG_FILE resolves under LINTER_RULES_PATH (.github/linters), which has markdown and yaml configs but no eslint one, so it fell back to its own bundled config - eslint-plugin-react rules and all. That is why it reported a no-unused-vars error that eslint.config.mjs deliberately sets to off. Pointing it at our config is not viable: super-linter shares JAVASCRIPT_ES_LINTER_RULES between the JAVASCRIPT_ES, JSON, JSONC and VUE linters, and our config has no JSON language support, so an invalid .json file comes back "File ignored because no matching configuration was supplied" with exit 0 - JSON linting would silently stop. ci.yml already runs `npm run lint` with the real eslint and the real config as a required check, so JS linting defers to it and super-linter keeps its own config for JSON/JSONC. (eslint 9.39.4 in the container does load our eslint 10 flat config fine; that was not the obstacle.) The one real finding it surfaced is fixed rather than dropped: the caught error in checkForPipxSharedPreExists was unused, so it uses an optional catch binding now. Also stop super-linter posting a pull request summary comment. That is new in v8 and needs pull-requests or issues write, which this workflow deliberately does not grant; the attempt logged a non-fatal 403 on every run. Results remain visible as status checks and in the job summary. Co-Authored-By: Claude Opus 5 --- .github/workflows/linter.yml | 13 +++++++++++++ dist/index.js | 2 +- src/pipx-install.js | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 839e0d4..18832b7 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -42,11 +42,24 @@ jobs: uses: super-linter/super-linter/slim@4ce20838b8ab83717e78138c5b3a1407148e0918 # v8.7.0 env: DEFAULT_BRANCH: main + # v8 posts a summary comment by default, which needs pull-requests or + # issues write. Not worth broadening the token for: results already + # show up as status checks and in the job summary. Left enabled it + # only logs a non-fatal 403 on every run. + ENABLE_GITHUB_PULL_REQUEST_SUMMARY_COMMENT: false # This is a regex, not a glob: the previous value (dist/**/*) also # matched check-dist.yml and excluded it from every linter. FILTER_REGEX_EXCLUDE: ^dist/.* GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} VALIDATE_ALL_CODEBASE: true + # ci.yml already runs `npm run lint`, which is this repo's eslint and + # this repo's eslint.config.mjs. super-linter cannot be pointed at that + # config instead: JAVASCRIPT_ES_CONFIG_FILE is shared with the JSON, + # JSONC and VUE linters, and our config has no JSON language support, + # so reusing it would silently stop linting JSON. Rather than lint JS + # twice under two different rule sets, defer to ci.yml and let + # super-linter keep its own config for JSON/JSONC. + VALIDATE_JAVASCRIPT_ES: false VALIDATE_JSCPD: false VALIDATE_HTML: false # Biome is a competing formatter/linter: it wants semicolons and diff --git a/dist/index.js b/dist/index.js index a5284e6..f6a87b6 100644 --- a/dist/index.js +++ b/dist/index.js @@ -85241,7 +85241,7 @@ async function checkForPipxSharedPreExists(pipxSharedDir) { try { await fs$2.stat(pipxSharedDir); return true - } catch (error) { + } catch { return false } } diff --git a/src/pipx-install.js b/src/pipx-install.js index 46622a5..262893d 100644 --- a/src/pipx-install.js +++ b/src/pipx-install.js @@ -173,7 +173,7 @@ async function checkForPipxSharedPreExists(pipxSharedDir) { try { await fs.stat(pipxSharedDir) return true - } catch (error) { + } catch { return false } } From b271c930c3720e12e173151e2e66eef2a996047d Mon Sep 17 00:00:00 2001 From: Brandon White Date: Wed, 2 Sep 2026 08:58:36 -0500 Subject: [PATCH 5/5] ci: strip the workspace prefix before matching the exclude regex FILTER_REGEX_EXCLUDE is matched against the full path (/github/workspace/dist/index.js) unless STRIP_DEFAULT_WORKSPACE_FOR_REGEX is true, so the anchored ^dist/.* from the previous commit never matched and dist/ stopped being excluded. Gitleaks and codespell then scanned the generated bundle and reported vendored findings: the Azurite emulator credentials in @azure/storage-blob and "re-use"/"get's" in dependency code. Setting the flag is what super-linter's docs recommend for anchored regexes, and keeps check-dist.yml linted while excluding dist/. Co-Authored-By: Claude Opus 5 --- .github/workflows/linter.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 18832b7..672c867 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -48,8 +48,11 @@ jobs: # only logs a non-fatal 403 on every run. ENABLE_GITHUB_PULL_REQUEST_SUMMARY_COMMENT: false # This is a regex, not a glob: the previous value (dist/**/*) also - # matched check-dist.yml and excluded it from every linter. + # matched check-dist.yml and excluded it from every linter. Anchoring + # needs STRIP_DEFAULT_WORKSPACE_FOR_REGEX, because otherwise the regex + # is matched against /github/workspace/... and ^ never matches. FILTER_REGEX_EXCLUDE: ^dist/.* + STRIP_DEFAULT_WORKSPACE_FOR_REGEX: true GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} VALIDATE_ALL_CODEBASE: true # ci.yml already runs `npm run lint`, which is this repo's eslint and