diff --git a/CLAUDE.md b/CLAUDE.md index 8e07044..5faff38 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -44,6 +44,18 @@ Migrated from the dobby memory repo (`encryption4all/dobby`). This file is the h - Do not hand-write changelog entries under a crate's `## [Unreleased]` heading. `release-plz.toml` sets no changelog template, so entries are generated from commit subjects and each new version section is inserted *below* the `## [Unreleased]` heading. A manual bullet there is never folded into the release that follows it — it just sits above the newest version forever, undated. To get something into a dated changelog entry, it has to ride a commit subject on a PR that bumps that crate. - `pg-wasm`'s web target: set `[package.metadata.wasm-pack.profile.release.wasm-bindgen] omit-default-module-path = true` in `pg-wasm/Cargo.toml` to drop the `new URL('index_bg.wasm', import.meta.url)` branch from generated `__wbg_init` glue (Webpack 5 otherwise statically resolves it and breaks bundler consumers that always pass an explicit `module_or_path`). Cleaner than post-build regex-stripping the generated JS. - `pg-pkg` (the postguard PKG service) CLI flags: `-t irma_token`, `-i irma_server_url`, `-d postgres_url`. Env vars: `IRMA_SERVER`, `DATABASE_URL`, `RUST_LOG`. +- **Archiving a repo retires its *code*, never its *channels*, and the two are audited separately.** #288–#291 and #293 each checked the image/build *publisher* before archiving; nobody checked who still *fetches*. A channel outlives its source repo in every direction that matters: an archived repo keeps serving GitHub Releases and release assets, a GHCR package is owned by the org rather than the repo, and `raw.githubusercontent.com` keeps serving the frozen default branch. So the failure is never an error — it is a consumer pinned to an artifact set that stops growing, reporting success forever. The full audit of the five (#312, 2026-08-09) is below; **`ghcr.io/…` names were deliberately retained on the move, so an image name matching an archived repo is not by itself a hit** — check the publisher, then check whether new tags are actually arriving. + + | Archived repo | Channels it published | Who publishes that channel now | Verdict | + |---|---|---|---| + | `postguard-website` | GitHub Releases `v1.0.0`–`v1.8.0` (no assets); GHCR `postguard-website` | postguard-js `website.yml`, **same GHCR name**; GHCR is at `1.8.2` | Clean. No assets ever existed, so nothing could pin one. | + | `postguard-outlook-addon` | GitHub Releases `v0.1.1`–`v0.5.0`, **each with a `manifest.xml` asset**; GHCR `postguard-outlook-addon` | postguard-js `outlook-addon.yml`, **same GHCR name** (`1.0.0`); manifests now ride `outlook-addin-v*` releases | `releases/latest/download/manifest.xml` still serves v0.5.0 forever. Nothing in-repo fetches it; AppSource / M365 admin-center **unverified, no access**. | + | `postguard-tb-addon` | GitHub Releases with `.xpi` + `updates.json`; **self-hosted Thunderbird auto-update channel** | postguard-js `tb-addon-v*`; `update_url` is now the raw file on `postguard-js@main` | Migration correct — `releases/latest` is `channel-migration-0.9.4`, whose `updates.json` advertises 0.9.4 pointing into postguard-js. That release has **no `.xpi`**, so anything fetching `releases/latest/download/*.xpi` from it 404s. | + | `postguard-examples` | **Zero releases**, no packages. Only raw/blob `main` URLs | postguard-js `examples/` | Pinned-commit doc links still resolve by design; unpinned `tree/main` links were repointed. | + | `cryptify` | GitHub Releases `v0.1.1`–`v0.1.27` (no assets); GHCR `cryptify` | postguard `delivery.yml`, **same GHCR name**, sole publisher since #293 | The one real gap — see the version-tag hole below. Also `ghcr.io/encryption4all/cryptify-backend` is a **dead name** (renamed to `cryptify` years ago) that two live consumers still referenced. | + + Two lessons the table does not carry. **A self-hosted add-on update channel needs one last publish from the old repo, and the successor release must not be `releases/latest`.** `postguard-tb-addon` got this right: installed builds ≤0.9.3 poll `postguard-tb-addon/releases/latest/download/updates.json`, so the old repo had to advertise 0.9.4 one final time before going read-only — hence the deliberately non-`v*` tag `channel-migration-0.9.4` (a `v*` tag would have fired the old build workflow). Archive first and every installed add-on stops updating silently. And in the monorepo the channel moved *off* `releases/latest` entirely, onto the raw file on `main`, because `releases/latest` in a repo shared with `@e4a/pg-js` is whichever package released most recently and a pg-js release carries no `updates.json`. **Verify a "verdict" release actually resolves**: `releases/latest` is not the newest `published_at` you see in the API list, so read it from `repos/{o}/{r}/releases/latest` and then `curl -L` the asset itself. +- **A release that predates its own publish job leaves a version with no artifact, and nothing reports it.** `cryptify-v0.1.28` was released from this workspace at `18e0ab0` (2026-08-03 09:38:49 +0200) carrying three security fixes — GHSA-5rhx-xgvv-h78h (unauthenticated `GET /usage`), a non-constant-time `cryptify_token` compare, and RUSTSEC-2026-0141 (lettre) — but `delivery.yml` had **no cryptify publish at all** at that commit: the jobs landed 85 minutes later in `f1b2e14` (#280), gated behind `vars.PUBLISH_CRYPTIFY_IMAGE`, ungated only in `506144c` (#309, 2026-08-07). The old repo never saw the release either, because the release happened here. So **`ghcr.io/encryption4all/cryptify:0.1.28` does not exist and cannot be built by re-running anything** — `workflow_dispatch` takes the workflow file from the ref you dispatch, and that file has no cryptify job. GHCR's highest semver tag is `0.1.27`, pushed by the *archived* repo on 2026-05-16; every tag this pipeline has pushed since taking over is `edge` or `pr-*`. Consequence for ops: `privacybydesign/postguard-ops`' `procolix/environments/prod.tfvars` pins `cryptify_image_tag = "0.1.25"`, and the newest tag it *could* move to today is still the archived repo's last build. The next cryptify release (release-plz #278 has `0.1.28 -> 0.1.29` queued) is what restores semver tagging from this repo; bump the ops pin to that, not to `0.1.28`. General rule: when moving a Docker publish between repos, land the publish job **before** the first release cut in the new home, and check the registry for the tag afterwards — a release-plz release and an image tag are separate events and only one of them is visible in the repo. ## Operations diff --git a/COMPATIBILITY.md b/COMPATIBILITY.md index 3e8acfb..fe49cf4 100644 --- a/COMPATIBILITY.md +++ b/COMPATIBILITY.md @@ -69,9 +69,13 @@ envelope tier, tested in both directions. The window is the set of published SDK versions kept working against the current server and the current wire format. -- `@e4a/pg-js` (npm): the last two majors. `1.x` leaves the window when the - Outlook migration lands ([postguard-outlook-addon#125]) and telemetry shows - no `1.x` traffic. +- `@e4a/pg-js` (npm): the last two majors. `1.x` leaves the window when + telemetry shows no `1.x` traffic. The other half of that condition, the + Outlook add-in's v1 → v2 migration, **has landed**: the add-in lives at + `apps/outlook-addon` in [postguard-js] on `@e4a/pg-js": "workspace:*"` (2.x) + and released as `outlook-addin-v1.0.0`. [postguard-outlook-addon#125] is + closed and stayed in that now-archived repo, so treat it as a historical + record rather than a tracker. - `@e4a/pg-wasm` (npm): every version a supported `pg-js` resolves. - `E4A.PostGuard` (NuGet): the last major. `0.x` counts as one line until `1.0`. @@ -167,6 +171,7 @@ Skipping step 2 is how you break the consumers you cannot see. [#262]: https://github.com/encryption4all/postguard/issues/262 [#268]: https://github.com/encryption4all/postguard/issues/268 [#272]: https://github.com/encryption4all/postguard/issues/272 +[postguard-js]: https://github.com/encryption4all/postguard-js [postguard-js#131]: https://github.com/encryption4all/postguard-js/issues/131 [postguard-e2e#19]: https://github.com/encryption4all/postguard-e2e/issues/19 [postguard-e2e#21]: https://github.com/encryption4all/postguard-e2e/issues/21