From d145222a8a5011cd1a40f3fc0e225b9704310c17 Mon Sep 17 00:00:00 2001 From: dominikg Date: Wed, 24 Sep 2025 21:46:41 +0200 Subject: [PATCH 1/7] harden release workflow --- .github/actions/setup-node/action.yml | 33 +++++++ .github/workflows/release.yml | 121 ++++++++++++++++++-------- 2 files changed, 116 insertions(+), 38 deletions(-) create mode 100644 .github/actions/setup-node/action.yml diff --git a/.github/actions/setup-node/action.yml b/.github/actions/setup-node/action.yml new file mode 100644 index 000000000..daf47ee61 --- /dev/null +++ b/.github/actions/setup-node/action.yml @@ -0,0 +1,33 @@ +name: 'setup' +description: 'composite for shared job setup' +inputs: + node-version: + description: 'node version' + default: '24' + install-deps: + description: 'install deps' + default: 'true' + +runs: + using: composite + steps: + # the following 2 steps are a replacement for pnpms own setup action that contains a lot of code + - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 + with: + node-version: ${{inputs.node-version}} + package-manager-cache: false + - name: install pnpm + shell: bash + run: | + PNPM_VER=$(jq -r '.packageManager | if .[0:5] == "pnpm@" then .[5:] else "packageManager in package.json does not start with pnpm@\n" | halt_error(1) end' package.json) + echo installing pnpm version $PNPM_VER + npm i --ignore-scripts -g pnpm@$PNPM_VER + - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 + if: ${{inputs.install-deps == 'true'}} + with: + node-version: ${{inputs.node-version}} + package-manager-cache: true + - name: install dependencies + if: ${{inputs.install-deps == 'true'}} + shell: bash + run: pnpm install --frozen-lockfile --ignore-scripts diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e3015e754..da62f39b3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,57 +4,102 @@ on: push: branches: - main + permissions: {} jobs: - release: + checks: permissions: - contents: write # to create release (changesets/action) - id-token: write # OpenID Connect token needed for provenance - pull-requests: write # to create pull request (changesets/action) - # prevents this action from running on forks + contents: read if: github.repository == 'sveltejs/vite-plugin-svelte' - name: Release - runs-on: ${{ matrix.os }} - strategy: - matrix: - # pseudo-matrix for convenience, NEVER use more than a single combination - node: [24] - os: [ubuntu-latest] + name: Checks + runs-on: ubuntu-latest steps: - - name: checkout - uses: actions/checkout@v5 + - name: Harden the runner + uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 with: - # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits - fetch-depth: 0 - - uses: actions/setup-node@v5 + egress-policy: block + allowed-endpoints: > + api.github.com:443 + github.com:443 + release-assets.githubusercontent.com:443 + registry.npmjs.org:443 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: - node-version: ${{ matrix.node }} - package-manager-cache: false # pnpm is not installed yet - - name: install pnpm - shell: bash - run: | - PNPM_VER=$(jq -r '.packageManager | if .[0:5] == "pnpm@" then .[5:] else "packageManager in package.json does not start with pnpm@\n" | halt_error(1) end' package.json) - echo installing pnpm version $PNPM_VER - npm i -g pnpm@$PNPM_VER - - uses: actions/setup-node@v5 - with: - node-version: ${{ matrix.node }} - package-manager-cache: true # caches pnpm via packageManager field in package.json - - name: install - run: pnpm install --frozen-lockfile --prefer-offline --ignore-scripts + persist-credentials: 'false' + - uses: ./.github/actions/setup-node - name: generated types are up to date run: pnpm generate:types && [ "`git status --porcelain=v1`" == "" ] - name: publint run: pnpm check:publint - - name: Create Release Pull Request or Publish to npm + changesets: + needs: checks + permissions: + contents: write # to create releases (changesets/action) + pull-requests: write # to create version pull requests (changesets/action) + name: Changesets + runs-on: ubuntu-latest + outputs: + published: ${{steps.changesets.outputs.published}} + publishedPackages: ${{steps.changesets.outputs.publishedPackages}} + steps: + - name: Harden the runner + uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + with: + egress-policy: block + allowed-endpoints: > + api.github.com:443 + github.com:443 + release-assets.githubusercontent.com:443 + registry.npmjs.org:443 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: 'false' + - uses: ./.github/actions/setup-node + - uses: changesets/action@e0145edc7d9d8679003495b11f87bd8ef63c0cba # v1.5.3 id: changesets - # pinned for security, always review third party action code before updating - uses: changesets/action@e0145edc7d9d8679003495b11f87bd8ef63c0cba # v1.5.3 with: - # This expects you to have a script called release which does a build for your packages and calls changeset publish - publish: pnpm release + publish: pnpm exec changeset tag #only create git tag, publish to registry happens later env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NPM_CONFIG_PROVENANCE: true + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # needed for some github api calls changesets makes + publish: + needs: changesets + if: needs.changesets.outputs.published == 'true' + permissions: + contents: read + id-token: write + environment: release + name: Publish + runs-on: ubuntu-latest + steps: + - name: Harden the runner + uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + with: + egress-policy: block + allowed-endpoints: > + api.github.com:443 + github.com:443 + release-assets.githubusercontent.com:443 + registry.npmjs.org:443 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: 'false' + - uses: ./.github/actions/setup-node + with: + install-deps: 'false' + - name: publish + shell: bash + run: | + echo 'publishing ${{needs.changesets.outputs.publishedPackages}}' + + # generate "--filter package1 --filter package2" + PUBLISH_PACKAGES_FILTER=$(echo '${{needs.changesets.outputs.publishedPackages}}' | jq -r '.[] | " --filter " + "\"" + .name+ "\""' | xargs) + + if [[ -f .changeset/pre.json ]]; then + TAG=$(jq -r '.tag' .changeset/pre.json) + else + TAG=latest + fi + # publish + pnpm -r --no-bail $PUBLISH_PACKAGES_FILTER publish --no-git-checks --tag $TAG --access public From eb280eb52b3afa5680d2a7a4faf62909dc29ac57 Mon Sep 17 00:00:00 2001 From: dominikg Date: Wed, 24 Sep 2025 21:55:58 +0200 Subject: [PATCH 2/7] fix release workflow and update ci workflow to use the shared setup-node action --- .github/workflows/ci.yml | 37 ++++++++--------------------------- .github/workflows/release.yml | 1 + 2 files changed, 9 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 598c51057..893437636 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,24 +29,15 @@ jobs: strategy: matrix: # pseudo-matrix for convenience, NEVER use more than a single combination - node: [22] + node: [24] os: [ubuntu-latest] steps: - - uses: actions/checkout@v5 - - uses: actions/setup-node@v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: - node-version: ${{ matrix.node }} - package-manager-cache: false # pnpm is not installed yet - - name: install pnpm - shell: bash - run: | - PNPM_VER=$(jq -r '.packageManager | if .[0:5] == "pnpm@" then .[5:] else "packageManager in package.json does not start with pnpm@\n" | halt_error(1) end' package.json) - echo installing pnpm version $PNPM_VER - npm i -g pnpm@$PNPM_VER - - uses: actions/setup-node@v5 + persist-credentials: 'false' + - uses: ./.github/actions/setup-node with: node-version: ${{ matrix.node }} - package-manager-cache: true # caches pnpm via packageManager field in package.json - name: install run: pnpm install --frozen-lockfile --prefer-offline --ignore-scripts - name: sync @@ -100,24 +91,12 @@ jobs: vite: 'rolldown-vite' svelte: 'current' steps: - - uses: actions/checkout@v5 - - uses: actions/checkout@v5 - - uses: actions/setup-node@v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: - node-version: ${{ matrix.node }} - package-manager-cache: false # pnpm is not installed yet - - name: install pnpm - shell: bash - run: | - PNPM_VER=$(jq -r '.packageManager | if .[0:5] == "pnpm@" then .[5:] else "packageManager in package.json does not start with pnpm@\n" | halt_error(1) end' package.json) - echo installing pnpm version $PNPM_VER - npm i -g pnpm@$PNPM_VER - - uses: actions/setup-node@v5 + persist-credentials: 'false' + - uses: ./.github/actions/setup-node with: node-version: ${{ matrix.node }} - package-manager-cache: true # caches pnpm via packageManager field in package.json - - name: install - run: pnpm install --frozen-lockfile --ignore-scripts - name: downgrade vite to baseline if: matrix.vite == 'baseline' run: | @@ -144,7 +123,7 @@ jobs: if: failure() shell: bash run: tar -cvf test-temp.tar --exclude="node_modules" temp/ - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 if: failure() with: name: test-failure-${{github.run_id}}-os_${{ matrix.os }}-node_${{ matrix.node }}-vite_${{ matrix.vite }}-svelte_${{matrix.svelte}} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index da62f39b3..25556354a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -82,6 +82,7 @@ jobs: github.com:443 release-assets.githubusercontent.com:443 registry.npmjs.org:443 + *.sigstore.dev:443 - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: 'false' From c5c32125b5a49bbc3e2b2d0252c096a49fe44ce5 Mon Sep 17 00:00:00 2001 From: dominikg Date: Wed, 24 Sep 2025 22:04:33 +0200 Subject: [PATCH 3/7] add git status check before publish --- .github/workflows/release.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 25556354a..5bb872137 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -102,5 +102,12 @@ jobs: else TAG=latest fi + + if [[ "$GIT_STATUS" != "" ]]; then + echo "dirty git state, aborting publish" + echo "$GIT_STATUS"; + exit 1 + fi + # publish pnpm -r --no-bail $PUBLISH_PACKAGES_FILTER publish --no-git-checks --tag $TAG --access public From fa6eb8c8a092c7505565ed073e50c27722b9410e Mon Sep 17 00:00:00 2001 From: dominikg Date: Thu, 25 Sep 2025 11:42:57 +0200 Subject: [PATCH 4/7] use harden runner in ci, fix publish --- .github/workflows/ci.yml | 18 ++++++++++++++++++ .github/workflows/release.yml | 2 ++ package.json | 1 - 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 893437636..c84cdbc01 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,6 +32,15 @@ jobs: node: [24] os: [ubuntu-latest] steps: + - name: Harden the runner + uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + with: + egress-policy: block + allowed-endpoints: > + api.github.com:443 + github.com:443 + release-assets.githubusercontent.com:443 + registry.npmjs.org:443 - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: 'false' @@ -91,6 +100,15 @@ jobs: vite: 'rolldown-vite' svelte: 'current' steps: + - name: Harden the runner + uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + with: + egress-policy: block + allowed-endpoints: > + api.github.com:443 + github.com:443 + release-assets.githubusercontent.com:443 + registry.npmjs.org:443 - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: 'false' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5bb872137..3ee56518c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -63,6 +63,7 @@ jobs: publish: pnpm exec changeset tag #only create git tag, publish to registry happens later env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # needed for some github api calls changesets makes + publish: needs: changesets if: needs.changesets.outputs.published == 'true' @@ -103,6 +104,7 @@ jobs: TAG=latest fi + GIT_STATUS=$(git status --porcelain=v1) if [[ "$GIT_STATUS" != "" ]]; then echo "dirty git state, aborting publish" echo "$GIT_STATUS"; diff --git a/package.json b/package.json index a0655ee26..407b72135 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,6 @@ "lint": "pnpm check:lint --fix", "format": "pnpm check:format --write", "fixup": "run-s lint format", - "release": "pnpm changeset publish", "prepare": "husky", "playwright": "playwright-core", "generate:types": "pnpm --filter \"./packages/*\" --parallel generate:types", From 4204aedd4518dd7240dba63fa8caa4df41483fa5 Mon Sep 17 00:00:00 2001 From: dominikg Date: Thu, 25 Sep 2025 21:31:23 +0200 Subject: [PATCH 5/7] fix: allow downloading playwright in ci --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c84cdbc01..8585435ca 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -109,6 +109,7 @@ jobs: github.com:443 release-assets.githubusercontent.com:443 registry.npmjs.org:443 + cdn.playwright.dev:443 - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: 'false' From aed5007dfe59fd33740681eb769bccde14a7ffeb Mon Sep 17 00:00:00 2001 From: dominikg Date: Tue, 30 Sep 2025 15:46:47 +0200 Subject: [PATCH 6/7] remove duplicate install --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8585435ca..889d9c519 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,8 +47,6 @@ jobs: - uses: ./.github/actions/setup-node with: node-version: ${{ matrix.node }} - - name: install - run: pnpm install --frozen-lockfile --prefer-offline --ignore-scripts - name: sync run: pnpm -r sync # required to ensure sveltekit test project have tsconfig.json which may be required by the checks below - name: format From 38a73c34f4621527a809b63dae1d42e653047810 Mon Sep 17 00:00:00 2001 From: dominikg Date: Tue, 30 Sep 2025 16:23:44 +0200 Subject: [PATCH 7/7] fix: work around minimumReleaseAge issue when installing rolldown-vite@latest --- .github/workflows/ci.yml | 2 ++ pnpm-workspace.yaml | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 889d9c519..626773c59 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -127,6 +127,8 @@ jobs: - name: update vite to rolldown-vite if: matrix.vite == 'rolldown-vite' run: | + # disable minimumReleaseAge as rolldown-vite often uses deps with age less than 3 days + sed -i 's/minimumReleaseAge:/#minimumReleaseAge:/g' pnpm-workspace.yaml pnpm update -r --no-save vite@npm:rolldown-vite@latest pnpm ls rolldown-vite - name: install playwright chromium diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 48cd3fd1b..5624dcaba 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -12,10 +12,6 @@ minimumReleaseAgeExclude: - '@vitejs/*' - 'svelte' - '@sveltejs/*' - - 'rolldown-vite' - - 'rolldown' - - '@rolldown/*' - - '@oxc-project/*' onlyBuiltDependencies: - esbuild