Skip to content

docs: repoint the release channels off the archived repos - #125

Merged
rubenhensen merged 1 commit into
mainfrom
docs/312-repoint-archived-release-channels
Aug 10, 2026
Merged

docs: repoint the release channels off the archived repos#125
rubenhensen merged 1 commit into
mainfrom
docs/312-repoint-archived-release-channels

Conversation

@rubenhensen

Copy link
Copy Markdown
Contributor

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

Page Claimed Actually
cryptify "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; the old repo's build/push jobs were retired before it was archived
postguard-tb-addon Bump three files by hand, push a v* tag, build.yml cuts the release changesets + sync-version, tags are tb-addon-v*, and the auto-update channel is the raw updates.json on postguard-js@main, not a release asset
postguard-outlook-addon release-please on master via .github/workflows/release.yml changesets, outlook-addin-v* tags, outlook-addon.yml in postguard-js. That release.yml cannot run — the repo is read-only
postguard-website release-please; "two submodules: Cryptify and the Thunderbird addon" changesets + website.yml. The submodules are cryptify and postguard; the .xpi arrives via sync-addons.mjs

Two things added rather than corrected

Why channel-migration-0.9.4 exists. 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 a v prefix, and why the new channel is a raw file on main rather than releases/latest (that resolves to whichever package released most recently, and a pg-js release has no updates.json). This is the part of the move nobody would reconstruct from the workflows.

The cryptify version with no image. cryptify-v0.1.28 was released from the workspace before the publish job existed, so no 0.1.28 image was ever built and none can be. Anyone pinning a version out of the changelog hits this, so the cryptify page says so.

Also

  • The Outlook page's store/admin-center note now says which manifest to point at, and that the archived repo's releases/latest/download/manifest.xml still serves v0.5.0 and always will.
  • CLAUDE.md gains the VitePress trap this change ran into: {{ }} is a Vue interpolation even inside an inline code span, so documenting a GitHub Actions expression fails docs:build with a stack trace naming only the compiled .vitepress/.temp/ file.
  • CLAUDE.md's canonical-hosts source of truth pointed at postguard-examples/pg-*; now postguard-js/examples/pg-*.
  • The website page records that the cryptify submodule 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:build completes, and npm run check:links reports all 45 pinned source links resolving (needs GH_TOKEN, or one link 403s on the unauthenticated rate limit).

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).
@dobby-coder

dobby-coder Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

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.

@rubenhensen
rubenhensen merged commit db7352b into main Aug 10, 2026
3 checks passed

@dobby-coder dobby-coder Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. postguard-outlook-addon.md step 2 describes the PR path as pushing :edge with a sha-<commit> tag using staging hosts. I read outlook-addon.yml: the PR path is the docker job (if: github.event_name == 'pull_request') which sets push: false, it builds with the production build args, and there is no sha- tag anywhere in the file. The only tags emitted are :edge and :${version},:latest.

  2. postguard-outlook-addon.md says 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 current outlook-addin-v1.0.0 asset. 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 sees 1.0.0.0 either way. The page promises a signal the reader does not have, on the page whose entire point is that frozen artifacts give no signal.

  3. postguard-website.md says the version tag is applied "on a release commit". It is the opposite, and website.yml says so in a comment on the finalize job: "The version tag is unconditional on main rather than gated on a release step." The metadata step is type=raw,value=<version> with no enable=. For contrast, delivery.yml in 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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 docker job, if: github.event_name == 'pull_request', and it sets push: false. Pushing only happens in the image job, 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. grep for sha- across the workflow returns nothing. The only tags emitted are ${IMAGE}:edge on main and ${IMAGE}:${version},${IMAGE}:latest on 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."

Suggested change
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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"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.

Suggested change
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) |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"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 != '' }}.

Suggested change
| 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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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, and POSTGUARD_WEBSITE_URL build 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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

Suggested change
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 releasesbuilds 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` |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
| 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` |

Comment thread docs/repos/cryptify.md
[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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested 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.
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.

@dobby-coder

dobby-coder Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

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 channel-migration-0.9.4 note and the cryptify-v0.1.28-has-no-image gap) are genuinely useful additions. But three factual errors made it into the live docs, two of which are the same stale-channel problem this PR set out to fix:

  • postguard-outlook-addon.md step 2 — the PR path actually pushes with production build args and push: false, not :edge/sha-<commit> against staging hosts.
  • postguard-outlook-addon.md — claims the archived repo's manifest "still serves v0.5.0," but it's actually 1.0.0.0 with the same <Id> as the current asset (only stray staging <AppDomain> entries differ) — so the page's suggested way to spot a frozen manifest doesn't work.
  • postguard-website.md — the version tag is unconditional on main, not tied to "a release commit."

Plus four smaller nits: a stale release.yml pointer left near the fix for the same issue, a missing Playwright test-e2e row in the website CI table, postguard#293 linked as a PR when it's an issue, and the em-dash/bold budget from CLAUDE.md exceeded on all three edited pages.

Should be a quick follow-up PR to land the fixes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant