diff --git a/README.md b/README.md index 925ac1d..1563171 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,9 @@ release/SHA256SUMS ``` Nothing is published by this. Tagging, CRX packing and any upload are -outward-facing acts and are the owner's alone. +outward-facing acts and are the owner's alone. The full procedure that turns a +green `main` into a tagged, packaged release — the order of steps, who performs +each, and how to check it worked — is in [docs/RELEASE.md](docs/RELEASE.md). The archives are deterministic — entries sorted, timestamps fixed, compression level fixed — so two builds of one commit produce byte-identical files and the diff --git a/TODO.md b/TODO.md index 5fba454..2e60669 100644 --- a/TODO.md +++ b/TODO.md @@ -90,6 +90,16 @@ but the review is broader than any of them. approve, reject and disconnect paths against a transaction approval broadcasting behind them: each is declined and the dApp still receives its broadcast result. +- 2026-09-21: `docs/RELEASE.md`, linked from `README.md`, states the release + procedure as a numbered list a newcomer can follow: confirm `main` is green in + CI, confirm the one version in the three files matches the intended tag, + `make package` from a clean checkout, verify `SHA256SUMS`, tag `vX.Y.Z`, then + distribute per browser. Each step names who performs it (owner-only steps + marked) and the check that it worked. The distribution step is written as + pending the owner's choice on + [#386](https://git.eeqj.de/sneak/AutistMask/issues/386), with the Firefox and + Chrome options named but none settled. Docs only + ([#387](https://git.eeqj.de/sneak/AutistMask/issues/387)). - 2026-09-21: Adding a second wallet no longer accepts a different password with nothing saying it is a separate one diff --git a/docs/RELEASE.md b/docs/RELEASE.md new file mode 100644 index 0000000..0e3d363 --- /dev/null +++ b/docs/RELEASE.md @@ -0,0 +1,87 @@ +# 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`.