From 3f7bfd4d31b2056abdf19d393dc8295d92a83529 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 14 Jul 2026 18:15:47 +0000 Subject: [PATCH 1/2] Release workflow: sign .xpi via AMO and publish to Chrome Web Store Both steps are gated on their secrets being configured, so the workflow keeps producing a plain GitHub Release until AMO_JWT_ISSUER/SECRET and the CWS_* secrets are added. With secrets present, the .xpi attached to the release is the Mozilla-signed (unlisted channel) file, and the .zip is uploaded to the Chrome Web Store and submitted for publication. Co-authored-by: Julius Walton --- .github/workflows/release.yml | 54 +++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f3c23fb..a883b1c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,6 +12,23 @@ permissions: jobs: release: runs-on: ubuntu-latest + # Store-publishing credentials. Both publishing steps below are skipped + # when their secrets are absent, so the workflow degrades gracefully to + # a plain GitHub Release until the secrets are configured + # (repo Settings -> Secrets and variables -> Actions): + # AMO_JWT_ISSUER / AMO_JWT_SECRET + # addons.mozilla.org -> Tools -> Manage API Keys. Must belong to the + # AMO account that owns the gecko id in manifest.json. + # CWS_EXTENSION_ID / CWS_CLIENT_ID / CWS_CLIENT_SECRET / CWS_REFRESH_TOKEN + # Chrome Web Store item id + OAuth credentials for the CWS API + # (see https://developer.chrome.com/docs/webstore/using-api). + env: + AMO_JWT_ISSUER: ${{ secrets.AMO_JWT_ISSUER }} + AMO_JWT_SECRET: ${{ secrets.AMO_JWT_SECRET }} + CWS_EXTENSION_ID: ${{ secrets.CWS_EXTENSION_ID }} + CWS_CLIENT_ID: ${{ secrets.CWS_CLIENT_ID }} + CWS_CLIENT_SECRET: ${{ secrets.CWS_CLIENT_SECRET }} + CWS_REFRESH_TOKEN: ${{ secrets.CWS_REFRESH_TOKEN }} steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 @@ -32,6 +49,43 @@ jobs: - run: npm run build + # Sign the .xpi with Mozilla so Firefox installs it permanently. + # `unlisted` is the self-distribution channel (installed by dragging + # the .xpi into Firefox, as the README describes) — switch to + # `--channel listed` only if the add-on moves to addons.mozilla.org, + # and note that listed submissions go through human review instead of + # returning a signed file immediately. AMO refuses to sign the same + # version twice, so re-running this workflow for an existing tag will + # fail here — bump the version instead. + - name: Sign the Firefox .xpi with Mozilla (AMO) + if: env.AMO_JWT_ISSUER != '' + run: | + version="$(node -p "require('./manifest.json').version")" + mkdir -p /tmp/xpi-src /tmp/xpi-signed + unzip -q "github-pr-reverse-comments-${version}.xpi" -d /tmp/xpi-src + npx web-ext@8 sign \ + --source-dir /tmp/xpi-src \ + --channel unlisted \ + --api-key "$AMO_JWT_ISSUER" \ + --api-secret "$AMO_JWT_SECRET" \ + --artifacts-dir /tmp/xpi-signed + # Ship the signed file under the same name the Release step uploads. + mv /tmp/xpi-signed/*.xpi "github-pr-reverse-comments-${version}.xpi" + + # Upload the .zip to the Chrome Web Store and publish. Google's + # review still happens asynchronously on their side afterwards. + - name: Publish to the Chrome Web Store + if: env.CWS_EXTENSION_ID != '' + env: + EXTENSION_ID: ${{ env.CWS_EXTENSION_ID }} + CLIENT_ID: ${{ env.CWS_CLIENT_ID }} + CLIENT_SECRET: ${{ env.CWS_CLIENT_SECRET }} + REFRESH_TOKEN: ${{ env.CWS_REFRESH_TOKEN }} + run: | + npx chrome-webstore-upload-cli@3 upload \ + --source github-pr-reverse-comments.zip \ + --auto-publish + - name: Create GitHub Release with build artifacts env: GH_TOKEN: ${{ github.token }} From 1e77cc1c8dc621d8b4dbd62e1f756461c111a19b Mon Sep 17 00:00:00 2001 From: Julius Walton <31512984+ShiosOS@users.noreply.github.com> Date: Tue, 14 Jul 2026 14:40:08 -0400 Subject: [PATCH 2/2] Skip store publishing steps unless all required secrets are set (#18) Co-authored-by: Cursor Agent --- .github/workflows/ci.yml | 25 ++++- .github/workflows/release.yml | 6 +- CHANGELOG.md | 36 +++++++ README.md | 28 ++++-- background.js | 129 +++++++++++++++--------- checks.js | 17 +++- constants.js | 20 ++-- content.js | 153 ++++++---------------------- eslint.config.mjs | 8 +- manifest.json | 5 +- package-lock.json | 6 +- package.json | 8 ++ pages.js | 156 +++++++++++++++++++++++++++++ popup.html | 40 ++++++-- popup.js | 12 ++- scripts/build.mjs | 71 +++++++++---- test/background.test.mjs | 148 +++++++++++++++++++++++++++ test/build.test.mjs | 70 +++++++++++++ test/checks.test.mjs | 18 ++++ test/constants.test.mjs | 19 ++++ test/pages.test.mjs | 182 ++++++++++++++++++++++++++++++++++ tsconfig.json | 1 + types/globals.d.ts | 25 +++-- vitest.config.mjs | 9 +- 24 files changed, 945 insertions(+), 247 deletions(-) create mode 100644 pages.js create mode 100644 test/background.test.mjs create mode 100644 test/build.test.mjs create mode 100644 test/constants.test.mjs create mode 100644 test/pages.test.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ace7f57..8d1b7fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,15 +17,25 @@ concurrency: jobs: check: runs-on: ubuntu-latest + strategy: + # Test the oldest Node we claim to support (package.json engines) + # alongside current, so "works on my machine" can't hide an engines + # violation. + matrix: + node-version: [22, 24] steps: # Actions are pinned to commit SHAs (supply-chain hardening); the # trailing comment records the human-readable version. v6 runs on the # Node 24 action runtime, clearing the Node 20 deprecation warning. - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + # No step here pushes or calls the API; don't leave the token in + # .git/config for the rest of the job. + persist-credentials: false - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: 24 + node-version: ${{ matrix.node-version }} cache: npm - run: npm ci @@ -42,3 +52,16 @@ jobs: - run: npm run coverage - run: npm run build + + # Merge gate: branch protection requires a single status named "check". + # Reporting that name from an aggregate job (instead of the matrix legs, + # whose names carry the Node version) keeps the required-check name + # stable no matter how the matrix changes. + ci-ok: + name: check + needs: check + if: always() + runs-on: ubuntu-latest + steps: + - name: Fail unless every matrix leg succeeded + run: test "${{ needs.check.result }}" = "success" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a883b1c..11ba793 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -58,7 +58,7 @@ jobs: # version twice, so re-running this workflow for an existing tag will # fail here — bump the version instead. - name: Sign the Firefox .xpi with Mozilla (AMO) - if: env.AMO_JWT_ISSUER != '' + if: env.AMO_JWT_ISSUER != '' && env.AMO_JWT_SECRET != '' run: | version="$(node -p "require('./manifest.json').version")" mkdir -p /tmp/xpi-src /tmp/xpi-signed @@ -75,7 +75,9 @@ jobs: # Upload the .zip to the Chrome Web Store and publish. Google's # review still happens asynchronously on their side afterwards. - name: Publish to the Chrome Web Store - if: env.CWS_EXTENSION_ID != '' + if: >- + env.CWS_EXTENSION_ID != '' && env.CWS_CLIENT_ID != '' && + env.CWS_CLIENT_SECRET != '' && env.CWS_REFRESH_TOKEN != '' env: EXTENSION_ID: ${{ env.CWS_EXTENSION_ID }} CLIENT_ID: ${{ env.CWS_CLIENT_ID }} diff --git a/CHANGELOG.md b/CHANGELOG.md index fa786e2..42210ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- Release packaging omitted `checks.js`, so published `.zip`/`.xpi` builds + shipped without the status-checks helpers the content script depends on. + The packaged file list is now derived from `manifest.json` (plus popup + `