docs: repoint the release channels off the archived repos - #125
Conversation
docs.postguard.eu described four release processes that no longer exist, all of
them naming an archived repository as the live channel. Nothing errored, which
is the point: an archived repo keeps serving its Releases and release assets, so
a reader following these pages lands on a frozen artifact set with no signal.
- cryptify: said "The cryptify repository still builds and publishes the
ghcr.io/encryption4all/cryptify image; moving that is a separate ops change."
False since postguard#293 — postguard's delivery.yml is the sole publisher and
the old repo's jobs were retired before it was archived. Also records that
cryptify-v0.1.28 has no image at all, since that trips up anyone pinning a
version from the changelog.
- postguard-tb-addon: documented bumping three files by hand and pushing a `v*`
tag. It is changesets plus sync-version now, tags are `tb-addon-v*`, and the
auto-update channel is the raw updates.json on postguard-js@main rather than a
release asset. Adds why the archived repo's channel-migration-0.9.4 release
exists, since that is the part nobody would guess.
- postguard-outlook-addon: documented release-please on `master` via a
release.yml that cannot run. It is changesets and `outlook-addin-v*` tags, and
the store/admin-center note now says which manifest to point at, and that the
archived repo's releases/latest still serves v0.5.0 forever.
- postguard-website: documented release-please, and claimed the two submodules
are cryptify and the Thunderbird addon. They are cryptify and postguard; the
.xpi arrives through sync-addons.mjs. Notes that the cryptify submodule still
points at the archived repo (postguard-js#225).
CLAUDE.md gains the VitePress `{{ }}` trap this change ran into: an inline code
span is still a Vue interpolation, so documenting a GitHub Actions expression
fails the build with a stack trace that names only the compiled temp file.
Verified: `npm run docs:build` completes, and `check:links` reports all 45
pinned source links resolving (it needs GH_TOKEN, or one link 403s on the
unauthenticated rate limit).
Found auditing what still fetches from the five archived repos' release and
package channels (encryption4all/postguard#312).
|
Thanks for the detailed writeup, @rubenhensen — I'm on it. I'll review PR #125 against what you found in the postguard#312 audit (the cryptify publisher, tb-addon and outlook-addon release channels, and the website submodules) and post my review shortly. |
There was a problem hiding this comment.
This PR was already merged by the time I got to it, so this is a non-blocking post-merge note rather than a gate. I skipped the rule fan-out (merged-PR fast path) but verified every finding below against the actual workflows and release assets, because these pages are live on docs.postguard.eu right now and three of them are still wrong in the same way the PR set out to fix.
The change itself is right about the big things and the two additions are the valuable part: the channel-migration-0.9.4 explanation is genuinely unreconstructable from the workflows, and the cryptify-v0.1.28-has-no-image gap is exactly the kind of thing that bites someone pinning out of a changelog. What follows are corrections on top of that, worth a small follow-up PR.
Three factual errors, all confirmed against source:
-
postguard-outlook-addon.mdstep 2 describes the PR path as pushing:edgewith asha-<commit>tag using staging hosts. I readoutlook-addon.yml: the PR path is thedockerjob (if: github.event_name == 'pull_request') which setspush: false, it builds with the production build args, and there is nosha-tag anywhere in the file. The only tags emitted are:edgeand:${version},:latest. -
postguard-outlook-addon.mdsays the archived repo's manifest "still serves v0.5.0's manifest". I fetched both assets. The archived one declares<Version>1.0.0.0</Version>and<Id>149e61a5-...</Id>— identical to the currentoutlook-addin-v1.0.0asset. A full diff shows only three leftover staging<AppDomain>entries. So an admin who checks the version to find out whether they are on the frozen manifest sees1.0.0.0either way. The page promises a signal the reader does not have, on the page whose entire point is that frozen artifacts give no signal. -
postguard-website.mdsays the version tag is applied "on a release commit". It is the opposite, andwebsite.ymlsays so in a comment on thefinalizejob: "The version tag is unconditional on main rather than gated on a release step." The metadata step istype=raw,value=<version>with noenable=. For contrast,delivery.ymlin postguard does gate its equivalent (enable=${{ ... != '' }}).
The rest are smaller: one stale pointer two lines above a hunk that fixes the same class of thing, a missing CI job, a wrong link type, and the house em-dash/bold budget. Details inline.
| 2. On non-release pushes, CI builds and pushes `ghcr.io/encryption4all/postguard-outlook-addon:edge` (and a `sha-<commit>` tag) using staging hosts. | ||
| 3. On release pushes, CI builds the same image with production hosts and tags it with the released version. | ||
| 1. [changesets](https://github.com/changesets/changesets) sets the version. It bumps `package.json` only, so `pnpm --filter postguard-outlook-addin sync-version` propagates it into `manifest.xml`'s `<Version>`. | ||
| 2. On PRs and pushes to `main`, CI builds and pushes `ghcr.io/encryption4all/postguard-outlook-addon:edge` (plus a `sha-<commit>` tag) using staging hosts. |
There was a problem hiding this comment.
Step 2 is wrong on three counts, and two of them are stale text carried over from the old release-please description.
I read outlook-addon.yml in postguard-js:
- PRs do not push. The PR path is the
dockerjob,if: github.event_name == 'pull_request', and it setspush: false. Pushing only happens in theimagejob,if: github.event_name == 'push'. - The PR build uses production hosts, not staging. Its build args are
PROD_ADDIN_HOST/PROD_PKG_URL/PROD_CRYPTIFY_URL/PROD_WEBSITE_URL. - There is no
sha-<commit>tag.grepforsha-across the workflow returns nothing. The only tags emitted are${IMAGE}:edgeon main and${IMAGE}:${version},${IMAGE}:lateston a tag.
Worth fixing because the website page in this same PR gets the equivalent sentence right: "Publishing happens on main only; PRs build without pushing."
| 2. On PRs and pushes to `main`, CI builds and pushes `ghcr.io/encryption4all/postguard-outlook-addon:edge` (plus a `sha-<commit>` tag) using staging hosts. | |
| 2. On pushes to `main`, CI builds and pushes `ghcr.io/encryption4all/postguard-outlook-addon:edge` using staging hosts. On PRs the image is built but not pushed, and with production hosts, since the build refuses staging fallbacks in production mode. |
| The image is an NGINX container serving the built add-in over HTTPS. To deploy, pull the new tag and restart the container on the host serving `addin.postguard.eu` (or `addin.staging.postguard.eu` for `:edge`). There is no automatic deploy step in CI today. | ||
|
|
||
| The Office add-in store submission and admin-center deployment still happen out of band against the published manifest. | ||
| The Office add-in store submission and admin-center deployment still happen out of band against the published manifest. Point them at the monorepo's `outlook-addin-v*` releases. The archived repository's `releases/latest/download/manifest.xml` still resolves and still serves v0.5.0's manifest, and it always will — an archived repo keeps serving its release assets, so anything left pointing there is frozen with no error to notice. |
There was a problem hiding this comment.
"still serves v0.5.0's manifest" is misleading in the one place it matters most, and I checked rather than assumed.
I fetched both assets. The archived repo's releases/latest/download/manifest.xml (HTTP 200) declares:
<Id>149e61a5-f295-4bcd-be3a-1a6114166f26</Id>
<Version>1.0.0.0</Version>
The current outlook-addin-v1.0.0 asset declares the same <Id> and the same <Version>. A full diff of the two files is three lines: the archived one carries extra staging.postguard.eu, addin.staging.postguard.eu and localhost:3000 <AppDomain> entries. Nothing else differs.
So an admin who follows this page's advice and checks the version to see whether they are on the frozen manifest reads 1.0.0.0 either way and concludes they are current. The paragraph promises a distinguishing signal that does not exist — on the page whose whole thesis is that frozen artifacts give no signal. Say that the version is identical.
| The Office add-in store submission and admin-center deployment still happen out of band against the published manifest. Point them at the monorepo's `outlook-addin-v*` releases. The archived repository's `releases/latest/download/manifest.xml` still resolves and still serves v0.5.0's manifest, and it always will — an archived repo keeps serving its release assets, so anything left pointing there is frozen with no error to notice. | |
| The Office add-in store submission and admin-center deployment still happen out of band against the published manifest. Point them at the monorepo's `outlook-addin-v*` releases. The archived repository's `releases/latest/download/manifest.xml` still resolves and always will, and it cannot be told apart by version: it declares the same `<Version>` of `1.0.0.0`, the same `<Id>`, and the same `addin.postguard.eu` `<SourceLocation>` as the current `outlook-addin-v1.0.0` asset, differing only by three leftover staging `<AppDomain>` entries. Anything left pointing there is frozen with nothing at all to notice it by. |
| | Trigger | What it does | | ||
| |---|---| | ||
| | PR / push to `main` | Svelte type checks, lint, CSS custom-property lint, unit tests, and an nginx config syntax test over both `docker/nginx.dev.conf` and `docker/default.conf.template` | | ||
| | Push to `main` | Multi-arch Docker build pushed to GHCR (`:edge`, plus the changesets version on a release commit) | |
There was a problem hiding this comment.
"plus the changesets version on a release commit" inverts what the workflow does, and website.yml calls this out explicitly in a comment on the finalize job:
The version tag is unconditional on main rather than gated on a release step: changesets bumps apps/website/package.json in its Version Packages PR, so merging that PR is what moves this tag. Re-tagging an unchanged version is a no-op.
The metadata step is type=raw,value=${{ steps.version.outputs.value }} with no enable= condition, and finalize is gated only on github.ref == 'refs/heads/main'. So every push to main re-applies the version tag.
For contrast, delivery.yml in postguard does gate its version tags: type=raw,value=...,enable=${{ needs.release-plz-release.outputs.cryptify_version != '' }}.
| | Push to `main` | Multi-arch Docker build pushed to GHCR (`:edge`, plus the changesets version on a release commit) | | |
| | Push to `main` | Multi-arch Docker build pushed to GHCR (`:edge`, plus the `apps/website/package.json` version, applied on every push to `main` rather than only on a release commit) | |
| ## Releasing | ||
|
|
||
| Releases run on every push to `master` via `.github/workflows/release.yml`: | ||
| Releases come out of the [postguard-js](https://github.com/encryption4all/postguard-js) workspace, from `apps/outlook-addon`, via `.github/workflows/outlook-addon.yml`. The standalone `postguard-outlook-addon` repository is archived: it releases nothing and its `release.yml` cannot run. |
There was a problem hiding this comment.
Line 157, two lines above this hunk, still reads:
Production hosts and PKG / Cryptify URLs are baked in at Docker build time via the
ADDIN_PUBLIC_URL,PKG_URL,CRYPTIFY_URL, andPOSTGUARD_WEBSITE_URLbuild args (see.github/workflows/release.yml).
That is the archived repo's workflow which this very line declares cannot run. Those build args now come from the PROD_* / EDGE_* env block in outlook-addon.yml and the corresponding ARGs in apps/outlook-addon/Dockerfile.
Leaving it is the exact stale-pointer failure mode the PR exists to remove, and it is two lines from the fix. (Outside the diff, so no suggestion block.)
| 3. On release pushes, CI builds the same image with production hosts and tags it with the released version. | ||
| 1. [changesets](https://github.com/changesets/changesets) sets the version. It bumps `package.json` only, so `pnpm --filter postguard-outlook-addin sync-version` propagates it into `manifest.xml`'s `<Version>`. | ||
| 2. On PRs and pushes to `main`, CI builds and pushes `ghcr.io/encryption4all/postguard-outlook-addon:edge` (plus a `sha-<commit>` tag) using staging hosts. | ||
| 3. Pushing an **app-scoped** tag — `outlook-addin-v1.0.0`, never `v*`, because the tag namespace is shared with `@e4a/pg-js`'s changesets releases — builds the same image with production hosts, tags it with the released version, and creates a GitHub release carrying `manifest.xml` as an asset. |
There was a problem hiding this comment.
Two things on this line.
The tag path also pushes :latest. The workflow emits echo "tags=${IMAGE}:${version},${IMAGE}:latest". Worth naming on a page that otherwise carefully explains which GHCR tags exist and that postguard-ops pins this package, since a moving :latest is the kind of thing an ops pin can quietly be resting on.
Em dash and bold budget. The repo's own CLAUDE.md (lines 92-93) sets "target zero, hard max one per 1,000 words" for each, and adds "Do not bold for emphasis in running prose." Counting em dashes at this commit against base:
| Page | Em dashes | Words |
|---|---|---|
postguard-website.md |
0 → 4 | 1,272 |
postguard-outlook-addon.md |
8 → 11 | 1,871 |
postguard-tb-addon.md |
1 → 3 | 2,045 |
All three land over the hard max. For reference docs/repos/postguard.md runs 2,282 words with zero, so the rule is being kept elsewhere. The bolded **sole**, **app-scoped** and **not** are emphasis in running prose, which the rule names specifically. Most of the dashes read fine as commas, parentheses or a full stop. (The new CLAUDE.md paragraph in this PR has the same issue, incidentally.)
A rewrite of this line that fixes both:
| 3. Pushing an **app-scoped** tag — `outlook-addin-v1.0.0`, never `v*`, because the tag namespace is shared with `@e4a/pg-js`'s changesets releases — builds the same image with production hosts, tags it with the released version, and creates a GitHub release carrying `manifest.xml` as an asset. | |
| 3. Pushing an app-scoped tag (`outlook-addin-v1.0.0`, never `v*`, because the tag namespace is shared with `@e4a/pg-js`'s changesets releases) builds the same image with production hosts, tags it with the released version and `:latest`, and creates a GitHub release carrying `manifest.xml` as an asset. |
|
|
||
| | Trigger | What it does | | ||
| |---|---| | ||
| | PR / push to `main` | Svelte type checks, lint, CSS custom-property lint, unit tests, and an nginx config syntax test over both `docker/nginx.dev.conf` and `docker/default.conf.template` | |
There was a problem hiding this comment.
The PR-check row omits the test-e2e job, which runs pnpm test:e2e (Playwright chromium) on the same pull_request and push triggers as the jobs listed, and uploads playwright-report/ plus test-results/ on failure.
Since this table is the page's answer to "what gates a website PR", the slowest gate is the one most worth naming.
| | PR / push to `main` | Svelte type checks, lint, CSS custom-property lint, unit tests, and an nginx config syntax test over both `docker/nginx.dev.conf` and `docker/default.conf.template` | | |
| | PR / push to `main` | Svelte type checks, lint, CSS custom-property lint, unit tests, Playwright e2e tests, and an nginx config syntax test over both `docker/nginx.dev.conf` and `docker/default.conf.template` | |
| [GitHub](https://github.com/encryption4all/postguard/tree/main/cryptify) · Rust · File Sharing Service | ||
|
|
||
| The source lives at `cryptify/` in the [postguard](https://github.com/encryption4all/postguard) Cargo workspace, compiled against the in-tree `pg-core`. The [cryptify](https://github.com/encryption4all/cryptify) repository still builds and publishes the `ghcr.io/encryption4all/cryptify` image; moving that is a separate ops change. | ||
| The source lives at `cryptify/` in the [postguard](https://github.com/encryption4all/postguard) Cargo workspace, compiled against the in-tree `pg-core`. That workspace's `delivery.yml` is now the **sole** publisher of the `ghcr.io/encryption4all/cryptify` image, unconditionally since [postguard#293](https://github.com/encryption4all/postguard/pull/293); the standalone `encryption4all/cryptify` repository had its build and push jobs retired and is archived. The GHCR package name did not change, so nothing downstream had to be repointed. |
There was a problem hiding this comment.
postguard#293 is linked as /pull/293, but 293 is an issue, not a PR: "task: cut cryptify's Docker publish pipeline over to postguard, then retire the old repo's build" (closed). I checked via the API — has("pull_request") is false.
GitHub redirects /pull/N to /issues/N, so nothing 404s and check:links will not catch it either, since it only walks the 45 pinned source links. The same number is cited correctly as /issues/312 two lines down.
| The source lives at `cryptify/` in the [postguard](https://github.com/encryption4all/postguard) Cargo workspace, compiled against the in-tree `pg-core`. That workspace's `delivery.yml` is now the **sole** publisher of the `ghcr.io/encryption4all/cryptify` image, unconditionally since [postguard#293](https://github.com/encryption4all/postguard/pull/293); the standalone `encryption4all/cryptify` repository had its build and push jobs retired and is archived. The GHCR package name did not change, so nothing downstream had to be repointed. | |
| The source lives at `cryptify/` in the [postguard](https://github.com/encryption4all/postguard) Cargo workspace, compiled against the in-tree `pg-core`. That workspace's `delivery.yml` is now the **sole** publisher of the `ghcr.io/encryption4all/cryptify` image, unconditionally since [postguard#293](https://github.com/encryption4all/postguard/issues/293); the standalone `encryption4all/cryptify` repository had its build and push jobs retired and is archived. The GHCR package name did not change, so nothing downstream had to be repointed. |
|
Thanks for the heads up — by the time I got to #125 it was already merged, so I skipped the gate and posted a non-blocking review with 7 inline comments instead (5 with ready-to-apply suggestions). The PR gets the big picture right, and the two new explanations (the
Plus four smaller nits: a stale Should be a quick follow-up PR to land the fixes. |
Found auditing what still fetches from the five archived repos' release and package channels (encryption4all/postguard#312).
docs.postguard.eu documented four release processes that no longer exist, each naming an archived repository as the live channel. Nothing errored — that is the whole failure mode. An archived repo keeps serving its Releases and release assets indefinitely, so a reader who follows these pages lands on a frozen artifact set with nothing to signal it is frozen.
What was wrong
cryptifyghcr.io/encryption4all/cryptifyimage; moving that is a separate ops change"postguard'sdelivery.ymlis the sole publisher; the old repo's build/push jobs were retired before it was archivedpostguard-tb-addonv*tag,build.ymlcuts the releasesync-version, tags aretb-addon-v*, and the auto-update channel is the rawupdates.jsononpostguard-js@main, not a release assetpostguard-outlook-addonmastervia.github/workflows/release.ymloutlook-addin-v*tags,outlook-addon.ymlin postguard-js. Thatrelease.ymlcannot run — the repo is read-onlypostguard-websitewebsite.yml. The submodules arecryptifyandpostguard; the.xpiarrives viasync-addons.mjsTwo things added rather than corrected
Why
channel-migration-0.9.4exists. The tb-addon page now explains the one-last-publish that carried installed add-ons ≤0.9.3 onto the monorepo's channel, why the tag deliberately lacks avprefix, and why the new channel is a raw file onmainrather thanreleases/latest(that resolves to whichever package released most recently, and a pg-js release has noupdates.json). This is the part of the move nobody would reconstruct from the workflows.The cryptify version with no image.
cryptify-v0.1.28was released from the workspace before the publish job existed, so no0.1.28image was ever built and none can be. Anyone pinning a version out of the changelog hits this, so the cryptify page says so.Also
releases/latest/download/manifest.xmlstill serves v0.5.0 and always will.CLAUDE.mdgains the VitePress trap this change ran into:{{ }}is a Vue interpolation even inside an inline code span, so documenting a GitHub Actions expression failsdocs:buildwith a stack trace naming only the compiled.vitepress/.temp/file.CLAUDE.md's canonical-hosts source of truth pointed atpostguard-examples/pg-*; nowpostguard-js/examples/pg-*.cryptifysubmodule still points at the archived repo — The dev stack builds cryptify from the archived cryptify repo's submodule postguard-js#225.Verified:
npm run docs:buildcompletes, andnpm run check:linksreports all 45 pinned source links resolving (needsGH_TOKEN, or one link 403s on the unauthenticated rate limit).