diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 659b1b2..2f93c8d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -43,3 +43,11 @@ updates: # bump it by hand when moving to the next Node LTS. - dependency-name: "@types/node" update-types: ["version-update:semver-major"] + + - package-ecosystem: "github-actions" # bumps SHA-pinned actions, keeps # vX comment + directory: "/" + schedule: + interval: "weekly" + cooldown: + default-days: 7 # min-release-age equivalent for GHA: wait out same-day yanks + open-pull-requests-limit: 10 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f1c9d4..ba2f584 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,21 +5,26 @@ on: branches: [main] pull_request: +# Least privilege: this workflow only reads the repo. +permissions: + contents: read + jobs: validate: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: # Full history so diff-cover can find the merge-base with the PR base branch. fetch-depth: 0 + persist-credentials: false - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version-file: .nvmrc # Reads the pnpm version from the "packageManager" field in package.json. - - uses: pnpm/action-setup@v6 + - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 # Manual cache (instead of setup-node's built-in cache: pnpm) so we can # use restore-keys for warm/partial restores when the lockfile changes. @@ -27,7 +32,7 @@ jobs: shell: bash run: echo "STORE_PATH=$(pnpm store path --silent)" >> "$GITHUB_ENV" - - uses: actions/cache@v5 + - uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0 with: path: ${{ env.STORE_PATH }} key: ${{ runner.os }}-pnpm-store-${{ hashFiles('pnpm-lock.yaml') }} @@ -64,7 +69,7 @@ jobs: # the git diff against the base branch (no baseline or second run needed). - name: Diff coverage run: | - pipx run diff-cover coverage/lcov.info \ + pipx run diff-cover==10.5.1 coverage/lcov.info \ --compare-branch origin/${{ github.base_ref || 'main' }} \ --fail-under 80 @@ -72,7 +77,7 @@ jobs: run: pnpm build - name: Cache Playwright browsers - uses: actions/cache@v5 + uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0 with: path: ~/.cache/ms-playwright key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }} @@ -87,7 +92,7 @@ jobs: - name: E2E run: pnpm test:e2e - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: ${{ failure() }} with: name: playwright-report diff --git a/.github/workflows/update-pnpm.yml b/.github/workflows/update-pnpm.yml index 1ec68cb..56c148d 100644 --- a/.github/workflows/update-pnpm.yml +++ b/.github/workflows/update-pnpm.yml @@ -18,10 +18,13 @@ jobs: update: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + with: + # create-pull-request authenticates with the App token, not persisted creds. + persist-credentials: false # Pin Node to the repo's version so the registry query runs deterministically. - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version-file: .nvmrc @@ -54,7 +57,7 @@ jobs: - name: Generate App token if: steps.versions.outputs.changed == 'true' id: app-token - uses: actions/create-github-app-token@v3 + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 with: client-id: ${{ vars.APP_CLIENT_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} @@ -63,7 +66,7 @@ jobs: - name: Create pull request if: steps.versions.outputs.changed == 'true' - uses: peter-evans/create-pull-request@v8 + uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 with: token: ${{ steps.app-token.outputs.token }} commit-message: "chore: update pnpm to ${{ steps.versions.outputs.latest }}" diff --git a/package.json b/package.json index 6ee88b9..ec990c7 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,8 @@ "typescript": "npm:@typescript/typescript6@^6.0.2", "vite": "^8.3.0", "vitest": "^4.1.11", - "vitest-axe": "^0.1.0" + "vitest-axe": "^0.1.0", + "yaml": "^2.9.0" }, "packageManager": "pnpm@11.9.0" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0d225a8..c79b994 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,10 +19,10 @@ importers: version: 1.167.2(@tanstack/react-router@1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(@tanstack/router-core@1.171.32)(csstype@3.2.3)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@tanstack/react-start': specifier: ^1.168.56 - version: 1.168.56(crossws@0.4.12(srvx@1.0.5))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2)) + version: 1.168.56(crossws@0.4.12(srvx@1.0.5))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1)) '@tanstack/router-plugin': specifier: ^1.168.40 - version: 1.168.40(@tanstack/react-router@1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2)) + version: 1.168.40(@tanstack/react-router@1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1)) react: specifier: ^19.3.0 version: 19.3.0 @@ -38,10 +38,10 @@ importers: version: 1.63.0 '@tailwindcss/vite': specifier: ^4.3.3 - version: 4.3.3(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2)) + version: 4.3.3(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1)) '@tanstack/devtools-vite': specifier: ^0.8.5 - version: 0.8.5(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2)) + version: 0.8.5(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1)) '@tanstack/eslint-plugin-router': specifier: ^1.162.0 version: 1.162.0(@typescript/typescript6@6.0.2)(eslint@10.4.1(jiti@2.7.0)) @@ -71,7 +71,7 @@ importers: version: typescript@7.0.2 '@vitejs/plugin-react': specifier: ^6.1.1 - version: 6.1.1(oxc-transform-react@0.145.0)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2)) + version: 6.1.1(oxc-transform-react@0.145.0)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1)) '@vitest/coverage-v8': specifier: ^4.1.11 version: 4.1.11(vitest@4.1.11) @@ -128,13 +128,16 @@ importers: version: '@typescript/typescript6@6.0.2' vite: specifier: ^8.3.0 - version: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2) + version: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1) vitest: specifier: ^4.1.11 - version: 4.1.11(@types/node@24.13.6)(@vitest/coverage-v8@4.1.11)(jsdom@30.1.0)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2)) + version: 4.1.11(@types/node@24.13.6)(@vitest/coverage-v8@4.1.11)(jsdom@30.1.0)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1)) vitest-axe: specifier: ^0.1.0 version: 0.1.0(vitest@4.1.11) + yaml: + specifier: ^2.9.0 + version: 2.9.1 packages: @@ -3616,8 +3619,8 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yaml@2.8.2: - resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} + yaml@2.9.1: + resolution: {integrity: sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==} engines: {node: '>= 14.6'} hasBin: true @@ -4500,12 +4503,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3 '@tailwindcss/oxide-win32-x64-msvc': 4.3.3 - '@tailwindcss/vite@4.3.3(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2))': + '@tailwindcss/vite@4.3.3(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1))': dependencies: '@tailwindcss/node': 4.3.3 '@tailwindcss/oxide': 4.3.3 tailwindcss: 4.3.3 - vite: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2) + vite: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1) '@tanstack/devtools-bundler-core@0.1.3(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)': dependencies: @@ -4544,13 +4547,13 @@ snapshots: transitivePeerDependencies: - csstype - '@tanstack/devtools-vite@0.8.5(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2))': + '@tanstack/devtools-vite@0.8.5(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1))': dependencies: '@tanstack/devtools-bundler-core': 0.1.3(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0) '@tanstack/devtools-client': 0.0.8 '@tanstack/devtools-event-bus': 0.4.3 chalk: 5.6.2 - vite: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2) + vite: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1) transitivePeerDependencies: - '@emnapi/core' - '@emnapi/runtime' @@ -4626,14 +4629,14 @@ snapshots: react: 19.3.0 react-dom: 19.3.0(react@19.3.0) - '@tanstack/react-start-rsc@0.1.55(crossws@0.4.12(srvx@1.0.5))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2))': + '@tanstack/react-start-rsc@0.1.55(crossws@0.4.12(srvx@1.0.5))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1))': dependencies: '@tanstack/react-router': 1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@tanstack/router-core': 1.171.32 '@tanstack/router-utils': 1.162.3 '@tanstack/start-client-core': 1.170.32 '@tanstack/start-fn-stubs': 1.162.0 - '@tanstack/start-plugin-core': 1.171.46(@tanstack/react-router@1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(crossws@0.4.12(srvx@1.0.5))(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2)) + '@tanstack/start-plugin-core': 1.171.46(@tanstack/react-router@1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(crossws@0.4.12(srvx@1.0.5))(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1)) '@tanstack/start-storage-context': 1.167.34 pathe: 2.0.3 react: 19.3.0 @@ -4662,21 +4665,21 @@ snapshots: transitivePeerDependencies: - crossws - '@tanstack/react-start@1.168.56(crossws@0.4.12(srvx@1.0.5))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2))': + '@tanstack/react-start@1.168.56(crossws@0.4.12(srvx@1.0.5))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1))': dependencies: '@tanstack/react-router': 1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@tanstack/react-start-client': 1.168.36(react-dom@19.3.0(react@19.3.0))(react@19.3.0) - '@tanstack/react-start-rsc': 0.1.55(crossws@0.4.12(srvx@1.0.5))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2)) + '@tanstack/react-start-rsc': 0.1.55(crossws@0.4.12(srvx@1.0.5))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1)) '@tanstack/react-start-server': 1.167.43(crossws@0.4.12(srvx@1.0.5))(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@tanstack/router-utils': 1.162.3 '@tanstack/start-client-core': 1.170.32 - '@tanstack/start-plugin-core': 1.171.46(@tanstack/react-router@1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(crossws@0.4.12(srvx@1.0.5))(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2)) + '@tanstack/start-plugin-core': 1.171.46(@tanstack/react-router@1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(crossws@0.4.12(srvx@1.0.5))(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1)) '@tanstack/start-server-core': 1.169.37(crossws@0.4.12(srvx@1.0.5)) pathe: 2.0.3 react: 19.3.0 react-dom: 19.3.0(react@19.3.0) optionalDependencies: - vite: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2) + vite: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1) transitivePeerDependencies: - '@farmfe/core' - '@rspack/core' @@ -4726,7 +4729,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.168.40(@tanstack/react-router@1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2))': + '@tanstack/router-plugin@1.168.40(@tanstack/react-router@1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1))': dependencies: '@babel/core': 7.29.7 '@babel/template': 7.29.7 @@ -4735,11 +4738,11 @@ snapshots: '@tanstack/router-generator': 1.167.38 '@tanstack/router-utils': 1.162.3 chokidar: 5.0.0 - unplugin: 3.4.0(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2)) + unplugin: 3.4.0(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1)) zod: 4.6.5 optionalDependencies: '@tanstack/react-router': 1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0) - vite: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2) + vite: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1) transitivePeerDependencies: - '@farmfe/core' - '@rspack/core' @@ -4772,7 +4775,7 @@ snapshots: '@tanstack/start-fn-stubs@1.162.0': {} - '@tanstack/start-plugin-core@1.171.46(@tanstack/react-router@1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(crossws@0.4.12(srvx@1.0.5))(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2))': + '@tanstack/start-plugin-core@1.171.46(@tanstack/react-router@1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(crossws@0.4.12(srvx@1.0.5))(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1))': dependencies: '@babel/code-frame': 7.29.7 '@babel/core': 7.29.7 @@ -4780,7 +4783,7 @@ snapshots: '@jridgewell/remapping': 2.3.5 '@tanstack/router-core': 1.171.32 '@tanstack/router-generator': 1.167.38 - '@tanstack/router-plugin': 1.168.40(@tanstack/react-router@1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2)) + '@tanstack/router-plugin': 1.168.40(@tanstack/react-router@1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1)) '@tanstack/router-utils': 1.162.3 '@tanstack/start-server-core': 1.169.37(crossws@0.4.12(srvx@1.0.5)) exsolve: 1.1.1 @@ -4792,11 +4795,11 @@ snapshots: srvx: 0.11.22 tinyglobby: 0.2.17 ufo: 1.6.4 - vitefu: 1.1.3(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2)) + vitefu: 1.1.3(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1)) xmlbuilder2: 4.0.3 zod: 4.6.5 optionalDependencies: - vite: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2) + vite: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1) transitivePeerDependencies: - '@farmfe/core' - '@rspack/core' @@ -4852,7 +4855,7 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 optionalDependencies: - vitest: 4.1.11(@types/node@24.13.6)(@vitest/coverage-v8@4.1.11)(jsdom@30.1.0)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2)) + vitest: 4.1.11(@types/node@24.13.6)(@vitest/coverage-v8@4.1.11)(jsdom@30.1.0)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1)) '@testing-library/react@16.3.3(@testing-library/dom@10.4.2)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: @@ -5015,10 +5018,10 @@ snapshots: dependencies: '@typescript/old': typescript@6.0.3 - '@vitejs/plugin-react@6.1.1(oxc-transform-react@0.145.0)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2))': + '@vitejs/plugin-react@6.1.1(oxc-transform-react@0.145.0)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1))': dependencies: '@rolldown/pluginutils': 1.0.1 - vite: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2) + vite: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1) optionalDependencies: oxc-transform-react: 0.145.0 @@ -5034,7 +5037,7 @@ snapshots: obug: 2.1.1 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.11(@types/node@24.13.6)(@vitest/coverage-v8@4.1.11)(jsdom@30.1.0)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2)) + vitest: 4.1.11(@types/node@24.13.6)(@vitest/coverage-v8@4.1.11)(jsdom@30.1.0)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1)) '@vitest/expect@4.1.11': dependencies: @@ -5045,13 +5048,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.11(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2))': + '@vitest/mocker@4.1.11(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1))': dependencies: '@vitest/spy': 4.1.11 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2) + vite: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1) '@vitest/pretty-format@4.1.11': dependencies: @@ -6519,14 +6522,14 @@ snapshots: unicorn-magic@0.4.0: {} - unplugin@3.4.0(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2)): + unplugin@3.4.0(rolldown@1.2.9)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1)): dependencies: '@jridgewell/remapping': 2.3.5 picomatch: 4.0.7 webpack-virtual-modules: 0.6.2 optionalDependencies: rolldown: 1.2.9 - vite: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2) + vite: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1) unstorage@2.0.0-alpha.10: {} @@ -6546,7 +6549,7 @@ snapshots: util-deprecate@1.0.2: {} - vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2): + vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1): dependencies: lightningcss: 1.33.0 picomatch: 4.0.7 @@ -6558,11 +6561,11 @@ snapshots: fsevents: 2.3.3 jiti: 2.7.0 tsx: 4.20.6 - yaml: 2.8.2 + yaml: 2.9.1 - vitefu@1.1.3(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2)): + vitefu@1.1.3(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1)): optionalDependencies: - vite: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2) + vite: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1) vitest-axe@0.1.0(vitest@4.1.11): dependencies: @@ -6572,12 +6575,12 @@ snapshots: dom-accessibility-api: 0.5.16 lodash-es: 4.18.1 redent: 3.0.0 - vitest: 4.1.11(@types/node@24.13.6)(@vitest/coverage-v8@4.1.11)(jsdom@30.1.0)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2)) + vitest: 4.1.11(@types/node@24.13.6)(@vitest/coverage-v8@4.1.11)(jsdom@30.1.0)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1)) - vitest@4.1.11(@types/node@24.13.6)(@vitest/coverage-v8@4.1.11)(jsdom@30.1.0)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2)): + vitest@4.1.11(@types/node@24.13.6)(@vitest/coverage-v8@4.1.11)(jsdom@30.1.0)(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1)): dependencies: '@vitest/expect': 4.1.11 - '@vitest/mocker': 4.1.11(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2)) + '@vitest/mocker': 4.1.11(vite@8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1)) '@vitest/pretty-format': 4.1.11 '@vitest/runner': 4.1.11 '@vitest/snapshot': 4.1.11 @@ -6594,7 +6597,7 @@ snapshots: tinyexec: 1.2.3 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.8.2) + vite: 8.3.0(@types/node@24.13.6)(jiti@2.7.0)(tsx@4.20.6)(yaml@2.9.1) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.13.6 @@ -6676,8 +6679,7 @@ snapshots: yallist@3.1.1: {} - yaml@2.8.2: - optional: true + yaml@2.9.1: {} yargs-parser@22.0.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index b70488b..61ff136 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -4,7 +4,11 @@ allowBuilds: unrs-resolver: true # Ignore versions published < 7 days ago, giving time to vet/yank releases. minimumReleaseAge: 10080 +# Fail resolution rather than fall back to a version inside the cooldown. +minimumReleaseAgeStrict: true # Block versions with weaker trust attestation than prior releases. trustPolicy: no-downgrade trustPolicyExclude: - semver@6.3.1 # legacy transitive dep predating npm provenance; false positive +# Forbid transitive deps from resolving via git/tarball URLs (registry only). +blockExoticSubdeps: true diff --git a/src/lib/supply-chain-config.test.ts b/src/lib/supply-chain-config.test.ts new file mode 100644 index 0000000..ac5b301 --- /dev/null +++ b/src/lib/supply-chain-config.test.ts @@ -0,0 +1,41 @@ +import { readFileSync } from "node:fs"; +import path from "node:path"; +import process from "node:process"; + +import { describe, expect, it } from "vitest"; +import { parse } from "yaml"; + +// Guard the supply-chain settings in pnpm-workspace.yaml against silent +// regression. pnpm ignores unknown keys, so a removed or misspelled setting +// disables its protection with no error -- these assertions fail CI instead. + +const config = parse(readFileSync(path.join(process.cwd(), "pnpm-workspace.yaml"), "utf8")) as { + trustPolicy?: string; + blockExoticSubdeps?: boolean; + minimumReleaseAge?: number; + minimumReleaseAgeStrict?: boolean; + dangerouslyAllowAllBuilds?: boolean; +}; + +describe("pnpm supply-chain config", () => { + it("blocks trust-level downgrades", () => { + expect(config.trustPolicy).toBe("no-downgrade"); + }); + + it("blocks transitive git/tarball dependencies", () => { + expect(config.blockExoticSubdeps).toBe(true); + }); + + it("enforces at least a 7-day release-age cooldown", () => { + expect(config.minimumReleaseAge).toBeGreaterThanOrEqual(10080); + }); + + it("fails resolution instead of falling back to immature versions", () => { + expect(config.minimumReleaseAgeStrict).toBe(true); + }); + + it("does not globally allow dependency build scripts", () => { + // allowBuilds is an explicit allowlist; this catches the escape hatch. + expect(config.dangerouslyAllowAllBuilds).not.toBe(true); + }); +});