From 4809e65144cfe2351e0b6154890da9fb98533386 Mon Sep 17 00:00:00 2001 From: Timotej Zatko Date: Mon, 29 Jun 2026 12:48:54 +0200 Subject: [PATCH 1/2] ci: move GitHub Actions off the deprecated Node 20 runtime GitHub Actions runners now default JS-action runtime to Node 24 and warn on actions declaring node20. Bump the standard actions to their current node24 majors (checkout@v7, setup-node@v6, setup-python dropped, upload-artifact@v7, download-artifact@v8) and the build's node-version to 24, matching local dev. Replace the archived actions/create-release@v1 + actions/upload-release-asset@v1 (node12, unmaintained since 2020) with softprops/action-gh-release@v3, preserving the draft-release behavior so a human still publishes. This also lets the release job drop the now redundant checkout/setup-python/find-the-file steps. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/ci.yml | 61 +++++++++++++----------------------- .github/workflows/deploy.yml | 6 ++-- 2 files changed, 24 insertions(+), 43 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5fff4a3..2696215 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,12 +13,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: fetch-depth: 0 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v6 with: - node-version: 20 + node-version: 24 - run: npm ci - uses: wagoid/commitlint-github-action@v6 env: @@ -28,10 +28,10 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v7 + - uses: actions/setup-node@v6 with: - node-version: 20 + node-version: 24 - run: npm ci - run: npm run lint - run: npm run tsc @@ -42,10 +42,10 @@ jobs: needs: lint steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v7 + - uses: actions/setup-node@v6 with: - node-version: 20 + node-version: 24 - run: npm ci - run: npm run test @@ -55,15 +55,15 @@ jobs: needs: test steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v7 + - uses: actions/setup-node@v6 with: - node-version: 20 + node-version: 24 - run: npm ci - run: npm run build env: CI: true - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: dist path: dist @@ -72,35 +72,16 @@ jobs: if: startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-latest needs: build + permissions: + contents: write steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: 3.8 - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist - - name: Prepare Release - run: | - echo "USERSCRIPT_PATH=$(find . -type f -name '*.user.js')" >> $GITHUB_ENV - echo "USERSCRIPT_NAME=$(find . -type f -name '*.user.js' -exec basename {} \;)" >> $GITHUB_ENV - - name: Create Release - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + path: dist + - name: Create draft release + uses: softprops/action-gh-release@v3 with: - tag_name: ${{ github.ref }} - release_name: Release ${{ github.ref }} draft: true - prerelease: false - - name: Upload Release Asset (.user.js) - id: upload-release-asset-tar-gz - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ${{ env.USERSCRIPT_PATH }} - asset_name: ${{ env.USERSCRIPT_NAME }} - asset_content_type: application/javascript + name: Release ${{ github.ref_name }} + files: dist/*.user.js diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 4055ff1..f78dc00 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -9,10 +9,10 @@ jobs: publish: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v7 + - uses: actions/setup-node@v6 with: - node-version: 20 + node-version: 24 - name: Download release assets run: | mkdir -p dist From 37d8ff6a53ddf0441b7b5f2daee732960e381e6f Mon Sep 17 00:00:00 2001 From: Timotej Zatko Date: Mon, 29 Jun 2026 12:58:18 +0200 Subject: [PATCH 2/2] ci: fail the deploy loudly when the publish is blocked The publish step curl'd tw-calc.net with no error handling, so when the host's anti-bot protection (WEDOS Global Protection) answered with an HTTP 200 ALTCHA challenge page instead of running the publish, the Deploy job went green while the userscript was never actually published. Harden deploy.sh: set -euo pipefail, use curl --fail-with-body so HTTP >= 400 fails the job, and detect an intercepted challenge/HTML response (WEDOS/ALTCHA markers) and exit 1 with a clear ::error:: annotation. Co-Authored-By: Claude Opus 4.8 --- ci/deploy.sh | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/ci/deploy.sh b/ci/deploy.sh index f592332..7222490 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -1,12 +1,41 @@ #!/usr/bin/env bash +set -euo pipefail echo "Deploying on tw-calc.net..." VERSION="$(echo "$REF" | cut -d '/' -f3)" -curl \ - --form "apiKey=$TW_CALC_API_KEY" \ - --form "version=$VERSION" \ - --form "updateInfo=See releases." \ - --form 'userscript=@./dist/TW_Calc.user.js' \ - https://tw-calc.net/service/userscript-publish +response_file="$(mktemp)" +trap 'rm -f "$response_file"' EXIT + +# --fail-with-body makes curl exit non-zero on HTTP >= 400 while still capturing the +# body, so a rejected publish can't masquerade as a successful (green) deploy. +http_code="$( + curl \ + --silent --show-error \ + --fail-with-body \ + --output "$response_file" \ + --write-out '%{http_code}' \ + --form "apiKey=$TW_CALC_API_KEY" \ + --form "version=$VERSION" \ + --form "updateInfo=See releases." \ + --form 'userscript=@./dist/TW_Calc.user.js' \ + https://tw-calc.net/service/userscript-publish +)" || { + echo "::error::Publish request failed (HTTP ${http_code:-?})." + cat "$response_file" + exit 1 +} + +# The host (WEDOS Global Protection) can answer an automated request with an HTTP 200 +# anti-bot challenge page instead of running the publish — which previously looked like +# a successful deploy. Treat a challenge/HTML response as a failure. +if grep -qiE 'wedos|altcha|security verification|