# Releasing AutistMask This is the procedure that turns a green `main` into a tagged, packaged release. It gathers into one place what is otherwise spread across the `Makefile` and three `README.md` sections, so the person cutting a release does not have to reconstruct the order from them. There is one version, declared in three files (`package.json`, `manifest/chrome.json`, `manifest/firefox.json`), and `make package` builds and packages but publishes nothing. `make build` and `make package` can be run by anyone; tagging, signing, packing a CRX and any upload need credentials only the owner ([@sneak](https://sneak.berlin)) holds and are marked **owner-only** below. Releases are tagged from `main` (see the Workflow section of `TODO.md`), so the "release commit" throughout is the `main` commit the milestone PR merged. ## Procedure 1. **Confirm `main` is green in CI.** The `check` workflow (`.gitea/workflows/check.yml`) runs `script/cibuild`, i.e. `docker build .`, and the `Dockerfile` runs `make check` as a build step, so a green `check` run is a green `make check`. Find the run for the exact release commit on the tracker's Actions view. _Check:_ that commit's `check` run succeeded; running `make check` on a clean checkout of the commit reproduces it and exits 0. 2. **Confirm the version matches the intended tag.** `package.json`, `manifest/chrome.json` and `manifest/firefox.json` must all declare the same `X.Y.Z`. `make build` fails when they disagree, but nothing checks that they equal the tag you mean to create — that is this manual step. _Check:_ all three files read the same `X.Y.Z`, and it is the version you intend to tag `vX.Y.Z`. 3. **Build and package from a clean checkout of that commit.** From a fresh clone, or a working tree with no local modifications (`git status` clean), checked out at the release commit: run `make setup`, then `make package`. `make package` runs `make build` first, so the archives can only be made from a `dist/` verified against that build's own receipt as a release (not debug) build. It writes three files into `release/`: `autistmask-chrome-.zip`, `autistmask-firefox-.xpi`, and `SHA256SUMS`. _Check:_ those three files exist and `` in the archive names is the version confirmed in step 2. The Firefox `.xpi` is **unsigned** (see step 6 and "Installing on Firefox" in `README.md`). 4. **Verify `SHA256SUMS`.** The archives are deterministic — sorted entries, fixed timestamps, fixed compression — so a second `make package` from another clean checkout of the same commit produces byte-identical files. Verify the recorded digests against the files with `sha256sum -c SHA256SUMS`, run from `release/`. To confirm reproducibility, run `make package` again on a separate clean checkout and compare the digests. _Check:_ `sha256sum -c` reports `OK` for every file, and an independent build's digests match. 5. **Tag the release commit.** _(owner-only)_ Create an annotated tag `vX.Y.Z` on the release commit and push it: `git tag -a vX.Y.Z` (with a message), then `git push origin vX.Y.Z`. _Check:_ `git tag` lists `vX.Y.Z`, and `git rev-parse vX.Y.Z^{commit}` resolves to the release commit. 6. **Distribute per browser.** _(owner-only; pending the owner's choice on https://git.eeqj.de/sneak/AutistMask/issues/386)_ How 1.0.0 is distributed on each browser is not yet decided; it is the open question on that issue, and the concrete steps cannot be written until the owner records a choice there. These steps need credentials only the owner holds. The options under consideration are: - **Firefox** — the packaged `.xpi` is unsigned, and release Firefox and ESR refuse an unsigned add-on: - (a) AMO self-distribution signing (unlisted): submit the `.xpi` to AMO with the owner's credentials; AMO returns a signed `.xpi` installable on every Firefox, with nothing listed publicly. - (b) AMO listed: as (a), plus a public AMO listing and review. - (c) Ship the unsigned `.xpi` and state that Firefox support means Developer Edition, Nightly, or an Unbranded build with `xpinstall.signatures.required` set to `false`. - **Chrome** — the repo packs no CRX and publishes nothing; the extension id is fixed by the `key` in `manifest/chrome.json`: - (a) Chrome Web Store (unlisted): upload the `.zip` with the owner's developer account; the store delivers installs and updates. - (b) Self-hosted CRX signed with the private key the owner holds (`chrome --pack-extension=dist/chrome --pack-extension-key=`), installable only via enterprise policy on Windows and macOS, so realistically Linux-only. - (c) "Load unpacked" from `dist/chrome/` only, as today. Once the owner decides, the chosen steps — including which credentials they need and who holds them — are written into this section and `README.md`'s installation sections are updated to match, which is part of the definition of done of https://git.eeqj.de/sneak/AutistMask/issues/386. _Check:_ for a store or AMO route, the artifact installs from the store or AMO on a clean browser profile; for the CRX or unpacked route, the documented load succeeds and Chrome reports the extension id `gipbhkogfopeahplcjhipkgpcimdpkip`.