feat(chrome-extension): automate signed release packaging - #394
Merged
Conversation
Sign and attach a .crx to GitHub Releases automatically as part of the existing release pipeline, and keep manifest.json's version in sync with the package version, instead of relying on a manual local build/sign/upload step (which was inconsistently followed and left version metadata stale).
V3RON
added a commit
that referenced
this pull request
Aug 13, 2026
…404) ## Description Fixes the release automation added in #394: after `syncChromeExtensionManifestVersion()` rewrites `packages/chrome-extension/manifest.json`'s `version` field via `JSON.stringify(manifest, null, 2)`, the file's short arrays (`permissions`, `resources`, `matches`) get expanded onto multiple lines, which doesn't match oxfmt's formatting (it collapses arrays that fit on one line). Since `commitVersionChanges()` runs a normal `git commit`, lefthook's `pre-commit` hook runs `oxfmt --check` on the staged file and fails, aborting the release commit. See the failed run: https://github.com/callstackincubator/rozenite/actions/runs/31677909005/job/94376470953 ## Related Issue N/A — no existing issue for this change. ## Context Rather than hand-matching oxfmt's array-collapsing rules in the manual `JSON.stringify` output, `syncChromeExtensionManifestVersion()` now runs `oxfmt --write` on the file immediately after writing it, so the staged file is already correctly formatted regardless of future oxfmt config changes. ## Testing - Simulated a version bump against the current `manifest.json` and confirmed the pre-existing `JSON.stringify` output fails `oxfmt --check` (arrays expand to multi-line) while the fixed code (`oxfmt --write` after writing) passes. - `pnpm exec oxfmt --check scripts/release/release.mjs` - `pnpm exec eslint scripts/release/release.mjs` — pre-existing unrelated `no-undef` errors for `console`/`Buffer` confirmed present before this change too.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Automates building, signing, and publishing the Chrome extension as part of the existing release pipeline (
scripts/release/release.mjs, triggered by.github/workflows/release.yml). Previously this was done by hand — the.crxwas inconsistently attached to past releases (missing from most, including the current latest), andmanifest.json's version had drifted from the package version.On
stableandrcreleases, after the version bump and tag push:manifest.json'sversionis synced from the package's version (sanitized to a plain dotted-integer form forrcprerelease versions, since Chrome rejects semver prerelease suffixes)..crxvia a newpack:crxscript (packages/chrome-extension/scripts/pack-crx.mjs, usingcrx3), using a private key supplied as theCHROME_EXTENSION_PEM_BASE64GitHub Actions secret (base64-encoded, decoded to a per-run temp file and removed afterward)..crxattached, marked prerelease forrctags.Reusing the same signing key on every release keeps the extension ID stable, which matters for existing installs' self-update flow (
src/update-checker.tspollsmanifest.jsononmaindirectly to detect available updates).Related Issue
N/A — no existing issue for this change.
Context
The signing key only ever existed on the maintainer's machine, and nothing in the repo created the GitHub Release itself (the release script only pushed a tag). This change folds packaging, signing, and Release creation into the same job that already runs the release, rather than adding a second tag-triggered workflow, so build/version/tag/publish/release-creation stay atomic within one job.
Requires a manual setup step: base64-encode the existing
.pemand add it as theCHROME_EXTENSION_PEM_BASE64secret in the repo's GitHub Actions settings before the next release run.Testing
Automated:
pnpm --filter @rozenite/chrome-extension buildpnpm --filter @rozenite/chrome-extension lintpnpm --filter @rozenite/chrome-extension typecheckpnpm release:plan— confirms the changeset is detectedpnpm lint:all/pnpm typecheck:all(via the pre-push hook,turbo run lint typecheckacross all 63 tasks) — all passedManual:
pnpm buildthenCHROME_EXTENSION_PEM_PATH=<disposable-test-key> pnpm pack:crxlocally — produced a valid signedbuild/rozenite.crx(verified CRX3 magic bytes).pack:crxfails loudly (rather than silently minting a new key) whenCHROME_EXTENSION_PEM_PATHpoints at a nonexistent file.2.1.0-rc.0→2.1.0) sorcbuilds don't ship an invalid, uninstallable manifest version.