release: there is no packaging, no artifact and no signing — the extension cannot be installed durably on either browser #310

Closed
opened 2026-08-20 11:59:45 +02:00 by clawbot · 1 comment
Collaborator

Found by the pre-1.0 deployability audit (#303). Blocker: there is no path by which the owner installs this once and keeps using it.

Checked exhaustively, all negative:

  • .gitea/workflows/ holds only check.yml and e2e.yml; neither uploads an artifact.
  • No zip/crx/xpi/pack target in Makefile, script/, package.json or Dockerfile.
  • git grep -niE '(web-ext|xpi|crx|\.pem|amo|addons\.mozilla|chrome web store|update_url|code.?sign)' returns exactly one hit: a comment at tests/e2e/firefox/driver.js:166 saying no XPI and no signing are involved.
  • manifest/chrome.json has no key and no update_url.
  • One tag exists, v0.1.0, and it is not an ancestor of HEAD — 246 commits back; git describe --tags fails outright.

Chrome

README.md:44-45 documents Load unpacked from dist/chrome/. With no key in the manifest, the extension ID is derived from the absolute directory path, so moving or re-cloning the checkout yields a different ID and therefore a different chrome.storage.local partition — the wallet silently reads as empty. No update channel, and a Developer-mode nag on every browser start. (Absence of key verified directly; the ID-derivation consequence is documented Chrome behaviour, not tested here — see the DoD.)

Firefox

README.md:46-47 documents Load Temporary Add-on as the only route. Release Firefox and ESR enforce signing with no working override, and this repo produces no XPI and has no signing key or AMO tooling, so on release Firefox this cannot be permanently installed at all. A temporary add-on is unloaded when Firefox exits — the repo says so itself at tests/e2e/firefox/driver.js:167 ("the add-on dies with the profile"). Daily use means re-adding it by hand from about:debugging on every browser start.

manifest/firefox.json:22-26 does carry a stable gecko.id, which is the right shape for storage to survive a re-add, but no test asserts that the vault survives an add-on removal and re-add — and that is exactly the property that must hold before real money goes in.

Related: dist/constants-bundles.txt and dist/styles.css sit at dist/ root, outside both browser directories, so a naive zip of dist/chrome/ would miss them. Version is triplicated and unwired — manifest/chrome.json:4 and manifest/firefox.json:4 (both hardcoded 0.1.0, copied verbatim by build.js:198-205) and package.json:3 (a separate source feeding the About screen); nothing checks they agree. BUILD_COMMIT (build.js:63,71) has no dirty check, so a build from a modified tree stamps a clean hash.

Definition of done

  • A release entrypoint produces a versioned, self-contained artifact per browser, with everything the browser needs inside the archive.
  • manifest/chrome.json carries a fixed key, so the extension ID and its storage partition are stable across checkout moves and re-clones.
  • Firefox ships a signed XPI (AMO self-distribution is sufficient), or the README states plainly that Firefox requires Developer Edition or Unbranded and that a temporary add-on does not survive a restart.
  • One version source of truth; the build fails if the manifests and package.json disagree. BUILD_COMMIT marks a dirty tree as dirty.
  • Test on the pinned Firefox harness: install, create a wallet, uninstall, re-install, assert the vault is still there.
  • Test: two unpacked Chrome loads from different paths in one profile, asserting whether storage is shared — documenting the real behaviour either way.
  • make check green.

Note: tagging a release and publishing to AMO are outward-facing acts and are sneak's call, not the implementer's. This issue covers producing and verifying the artifact, not publishing it.

Found by the pre-1.0 deployability audit (https://git.eeqj.de/sneak/AutistMask/issues/303). **Blocker: there is no path by which the owner installs this once and keeps using it.** Checked exhaustively, all negative: - `.gitea/workflows/` holds only `check.yml` and `e2e.yml`; neither uploads an artifact. - No zip/crx/xpi/pack target in `Makefile`, `script/`, `package.json` or `Dockerfile`. - `git grep -niE '(web-ext|xpi|crx|\.pem|amo|addons\.mozilla|chrome web store|update_url|code.?sign)'` returns exactly one hit: a comment at `tests/e2e/firefox/driver.js:166` saying no XPI and no signing are involved. - `manifest/chrome.json` has **no `key`** and no `update_url`. - One tag exists, `v0.1.0`, and it is **not an ancestor of HEAD** — 246 commits back; `git describe --tags` fails outright. ## Chrome `README.md:44-45` documents Load unpacked from `dist/chrome/`. With no `key` in the manifest, the extension ID is derived from the absolute directory path, so **moving or re-cloning the checkout yields a different ID and therefore a different `chrome.storage.local` partition — the wallet silently reads as empty.** No update channel, and a Developer-mode nag on every browser start. (Absence of `key` verified directly; the ID-derivation consequence is documented Chrome behaviour, not tested here — see the DoD.) ## Firefox `README.md:46-47` documents **Load Temporary Add-on** as the only route. Release Firefox and ESR enforce signing with no working override, and this repo produces no XPI and has no signing key or AMO tooling, so **on release Firefox this cannot be permanently installed at all.** A temporary add-on is unloaded when Firefox exits — the repo says so itself at `tests/e2e/firefox/driver.js:167` ("the add-on dies with the profile"). Daily use means re-adding it by hand from `about:debugging` on every browser start. `manifest/firefox.json:22-26` does carry a stable `gecko.id`, which is the right shape for storage to survive a re-add, but **no test asserts that the vault survives an add-on removal and re-add** — and that is exactly the property that must hold before real money goes in. Related: `dist/constants-bundles.txt` and `dist/styles.css` sit at `dist/` root, outside both browser directories, so a naive zip of `dist/chrome/` would miss them. Version is triplicated and unwired — `manifest/chrome.json:4` and `manifest/firefox.json:4` (both hardcoded `0.1.0`, copied verbatim by `build.js:198-205`) and `package.json:3` (a separate source feeding the About screen); nothing checks they agree. `BUILD_COMMIT` (`build.js:63,71`) has no dirty check, so a build from a modified tree stamps a clean hash. ## Definition of done - [ ] A release entrypoint produces a versioned, self-contained artifact per browser, with everything the browser needs inside the archive. - [ ] `manifest/chrome.json` carries a fixed `key`, so the extension ID and its storage partition are stable across checkout moves and re-clones. - [ ] Firefox ships a signed XPI (AMO self-distribution is sufficient), **or** the README states plainly that Firefox requires Developer Edition or Unbranded and that a temporary add-on does not survive a restart. - [ ] One version source of truth; the build fails if the manifests and `package.json` disagree. `BUILD_COMMIT` marks a dirty tree as dirty. - [ ] Test on the pinned Firefox harness: install, create a wallet, uninstall, re-install, assert the vault is still there. - [ ] Test: two unpacked Chrome loads from different paths in one profile, asserting whether storage is shared — documenting the real behaviour either way. - [ ] `make check` green. Note: tagging a release and publishing to AMO are outward-facing acts and are sneak's call, not the implementer's. This issue covers producing and verifying the artifact, not publishing it.
clawbot added this to the 1.0.0 milestone 2026-08-20 11:59:45 +02:00
Author
Collaborator

Implementation requirements, so the implementer does not stall on the two choices in here.

Chrome key. Generate an RSA keypair; commit only the public key as manifest/chrome.json's key field — that alone pins the extension ID and its chrome.storage.local partition across checkout moves, which is the DoD item. The private .pem is a credential: it must NOT be committed, must not be generated into the working tree by any build target, and CRX packing/publishing is sneak's call, not this unit's. Say in the PR body where a packer would expect the private key to come from.

Firefox. Do not attempt AMO — self-distribution needs credentials this unit does not have. Take the documented fallback: produce an unsigned XPI as the artifact, and state plainly in README.md that release Firefox and ESR will refuse it, that Developer Edition or Unbranded is required, and that a temporary add-on does not survive a browser restart. If AMO signing is wanted for 1.0, that is a separate issue and sneak's decision — flag it in your return message rather than filing it yourself.

Everything else on the DoD is unambiguous. Two things not to lose: the artifact must be self-contained, so dist/constants-bundles.txt and dist/styles.css living at dist/ root outside both browser directories must be handled rather than silently dropped by a naive zip; and the version unification must actually fail the build when manifest/chrome.json, manifest/firefox.json and package.json disagree, not merely read from one place.

Implementation requirements, so the implementer does not stall on the two choices in here. **Chrome `key`.** Generate an RSA keypair; commit **only the public key** as `manifest/chrome.json`'s `key` field — that alone pins the extension ID and its `chrome.storage.local` partition across checkout moves, which is the DoD item. The private `.pem` is a credential: it must NOT be committed, must not be generated into the working tree by any build target, and CRX packing/publishing is sneak's call, not this unit's. Say in the PR body where a packer would expect the private key to come from. **Firefox.** Do not attempt AMO — self-distribution needs credentials this unit does not have. Take the documented fallback: produce an **unsigned** XPI as the artifact, and state plainly in `README.md` that release Firefox and ESR will refuse it, that Developer Edition or Unbranded is required, and that a temporary add-on does not survive a browser restart. If AMO signing is wanted for 1.0, that is a separate issue and sneak's decision — flag it in your return message rather than filing it yourself. Everything else on the DoD is unambiguous. Two things not to lose: the artifact must be self-contained, so `dist/constants-bundles.txt` and `dist/styles.css` living at `dist/` root outside both browser directories must be handled rather than silently dropped by a naive zip; and the version unification must actually fail the build when `manifest/chrome.json`, `manifest/firefox.json` and `package.json` disagree, not merely read from one place.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/AutistMask#310