diff --git a/CLAUDE.md b/CLAUDE.md index 1f19c41..399ef5c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -138,11 +138,14 @@ Never invent examples. When fixing a source-link 404: ### Deployment pipeline (no auto-deploy) `ci.yml` only builds and pushes a Docker image to `ghcr.io/encryption4all/postguard-docs:edge` on every push to `main`. There is no deploy step. Production (docs.postguard.eu) runs an nginx container serving `docs/.vitepress/dist`; whatever host runs it must pull the new `edge` image and restart the container, or it serves the stale build. To detect a stale deployment, check the `last-modified` header on `index.html` via `curl -I https://docs.postguard.eu/` against a known commit date on `main`. +### `{{ }}` in prose breaks the build, even inside backticks +VitePress compiles every page as a Vue SFC, so `{{ ... }}` is a template interpolation wherever it appears — **including inside an inline code span**. Writing `` `${{ github.repository }}` `` while documenting a GitHub Actions expression fails `npm run docs:build` with `Cannot read properties of undefined (reading 'repository')` and a Vue server-renderer stack trace naming `.vitepress/.temp/.md.js`, which points at the compiled temp file rather than the line you wrote. Name the context instead (`the workflow's github.repository context`), or wrap the span in ``. A fenced code block is safe; an inline span is not. Always run `npm run docs:build` before pushing — this class of error does not show up in review. + ### postguard-examples drift (known gotcha) A past "consolidation" commit in postguard-examples flattened `pg-sveltekit/src/routes/download/` and `routes/send/` into a single top-level `+page.svelte`. Docs source-links pinned before that commit which point into those folders will 404. The pre-consolidation API form (`pg.decrypt({uuid, element, recipient})`) also differs from the post-consolidation one (`pg.open({uuid}).decrypt(...)`), so snippets cannot simply be repinned to a later hash without also updating the code shown. ### Canonical PKG / Cryptify hosts -Source of truth: `postguard-js/scripts/smoke.mjs`, `postguard-examples/pg-{node,dotnet,sveltekit}` configs. +Source of truth: `postguard-js/scripts/smoke.mjs`, `postguard-js/examples/pg-{node,dotnet,sveltekit}` configs (that second path was `postguard-examples/pg-*` before the repo was folded in and archived). | Env | PKG | Cryptify | |---|---|---| diff --git a/docs/repos/cryptify.md b/docs/repos/cryptify.md index 2a68a3a..4880738 100644 --- a/docs/repos/cryptify.md +++ b/docs/repos/cryptify.md @@ -2,7 +2,9 @@ [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. + +One gap to know about when pinning a version. `cryptify-v0.1.28` was released from the workspace before that publish job existed, so **no `0.1.28` image was ever built**, and it cannot be produced by re-running anything. The highest semver tag in the registry is `0.1.27`, pushed by the now-archived repo. `edge` tracks `main` and is current. See [postguard#312](https://github.com/encryption4all/postguard/issues/312). Cryptify is the file encryption and sharing service that PostGuard uses for delivering encrypted files. It allows encrypting any file with an identity attribute. Only people who can prove they have that attribute can decrypt and view the contents. diff --git a/docs/repos/postguard-outlook-addon.md b/docs/repos/postguard-outlook-addon.md index d76c24e..f3755de 100644 --- a/docs/repos/postguard-outlook-addon.md +++ b/docs/repos/postguard-outlook-addon.md @@ -158,12 +158,14 @@ Production hosts and PKG / Cryptify URLs are baked in at Docker build time via t ## 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. -1. `googleapis/release-please-action` watches conventional commits and opens a release PR. Merging that PR cuts a tagged release. -2. On non-release pushes, CI builds and pushes `ghcr.io/encryption4all/postguard-outlook-addon:edge` (and a `sha-` 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 ``. +2. On PRs and pushes to `main`, CI builds and pushes `ghcr.io/encryption4all/postguard-outlook-addon:edge` (plus a `sha-` 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. + +The image name is hardcoded rather than derived from the workflow's `github.repository` context, which resolves to `postguard-js` while [postguard-ops](https://github.com/privacybydesign/postguard-ops) pins `ghcr.io/encryption4all/postguard-outlook-addon`. The GHCR package name did not change on the move, so nothing downstream had to be repointed. 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. diff --git a/docs/repos/postguard-tb-addon.md b/docs/repos/postguard-tb-addon.md index 1e0efc3..56b1543 100644 --- a/docs/repos/postguard-tb-addon.md +++ b/docs/repos/postguard-tb-addon.md @@ -394,25 +394,29 @@ To load the extension in Thunderbird: open **Add-ons Manager** > **gear icon** > ## Releasing -The version must be updated in three files before releasing: +Releases come out of the [postguard-js](https://github.com/encryption4all/postguard-js) workspace, from `apps/tb-addon`. The standalone `postguard-tb-addon` repository is archived and releases nothing. -1. `package.json` (`"version"`) -2. `manifest.json` (`"version"`) -3. `updates.json` (add a new entry with the new version) +Versions are set by [changesets](https://github.com/changesets/changesets), which bumps `package.json` only. Thunderbird reads `manifest.json` and the auto-update channel reads `updates.json`, so `pnpm --filter postguard-tb-addon sync-version` propagates the version into both, and `pnpm check-version` fails the PR when they drift. The release job refuses a tag that does not match. -Then commit, push, and tag: +Release tags are **app-scoped**: `tb-addon-v0.9.4`, never `v*`. The tag namespace is shared with `@e4a/pg-js`'s changesets releases (and still holds the pre-monorepo `v2.3.3`-style pg-js tags), so a bare `v*` trigger would fire on another package's release. + +### The auto-update channel + +Installed add-ons poll the `update_url` baked into the build they are running. For 0.9.4 onward that is the raw file on the monorepo's default branch: -```bash -git add package.json manifest.json updates.json -git commit -m "Bump version to X.Y.Z" -git push origin main -git tag vX.Y.Z && git push origin vX.Y.Z ``` +https://raw.githubusercontent.com/encryption4all/postguard-js/main/apps/tb-addon/updates.json +``` + +It is deliberately **not** a release asset. `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` at all. -Pushing a `v*` tag triggers the CI pipeline which builds the `.xpi` file and creates a GitHub release. +Everything up to 0.9.3 baked in `postguard-tb-addon/releases/latest/download/updates.json` instead — the archived repo. Those installs are carried across by a single release there, tagged `channel-migration-0.9.4`, whose `updates.json` advertises 0.9.4 with an `update_link` into postguard-js. Taking that update moves the add-on onto the new channel permanently. The tag deliberately does not start with `v` so the old repository's build workflow did not fire for it, and the release ships no `.xpi` — it exists only to move the channel. This is why archiving a repo that hosts a self-hosted add-on update channel has to be preceded by one last publish from it; archive first and every installed add-on stops updating with no error. ## CI/CD -| Workflow | Trigger | What it does | -|---|---|---| -| `build.yml` | Tag push (`v*`) | Validates version consistency, builds, packages `.xpi`, creates GitHub release | +Workflow: `.github/workflows/tb-addon.yml` in postguard-js. + +| Trigger | What it does | +|---|---| +| PR / push to `main` | `pnpm check-version`, typecheck, tests, build the extension. Deliberately not path-filtered, so an SDK change in `packages/pg-js` is tested against the add-on in the same PR | +| Tag push (`tb-addon-v*`) | Packages the `.xpi` and creates the GitHub release carrying it and `updates.json` | diff --git a/docs/repos/postguard-website.md b/docs/repos/postguard-website.md index d2be2ce..27f63a2 100644 --- a/docs/repos/postguard-website.md +++ b/docs/repos/postguard-website.md @@ -10,12 +10,16 @@ The PostGuard web frontend for encrypting and sending files. Users pick files, c The website uses `@e4a/pg-js` with two Vite plugins for WASM support (`vite-plugin-wasm` and `vite-plugin-top-level-await`). -The website contains two submodules: Cryptify (the file sharing backend, embedded in an iframe) and the Thunderbird addon (the `.xpi` file can be downloaded from the website). To update the submodules: +`apps/website` carries two git submodules, used by the local dev stack rather than by the built site: `cryptify` and `postguard`. Initialise them with: ```bash git submodule update --init --recursive ``` +Note that the `cryptify` submodule still points at `encryption4all/cryptify`, which is archived — the service is a member of the [postguard](/repos/postguard) workspace now, so that pin can never advance. Tracked in [encryption4all/postguard-js#225](https://github.com/encryption4all/postguard-js/issues/225). + +The Thunderbird `.xpi` is **not** a submodule. `scripts/sync-addons.mjs` mirrors the add-on release artifacts into `static/downloads/` — the `.xpi` from the monorepo's `tb-addon-v*` releases and the Outlook `manifest.xml` from its `outlook-addin-v*` releases — refreshing on a 6h interval inside the container. + For a step-by-step example of building a web application with PostGuard, see the [pg-sveltekit](/repos/pg-sveltekit) example, which follows the same patterns as this website. ## Recipient URL forms @@ -155,11 +159,15 @@ The runtime tier exists because these values change per environment without rebu ## Releasing -This repository uses [Release-please](https://github.com/googleapis/release-please) for automated versioning. Merging a release PR triggers a multi-architecture Docker image build pushed to GHCR. +Releases come out of the [postguard-js](https://github.com/encryption4all/postguard-js) workspace via `.github/workflows/website.yml`. Versioning is [changesets](https://github.com/changesets/changesets), not release-please, and the standalone `postguard-website` repository is archived and releases nothing. + +The image is `ghcr.io/encryption4all/postguard-website` — the same GHCR package name the standalone repo published, hardcoded in the workflow rather than derived from the `github.repository` context (which resolves to `postguard-js`) precisely so [postguard-ops](https://github.com/privacybydesign/postguard-ops)' pin keeps working. Publishing happens on `main` only; PRs build without pushing. ## CI/CD -| Workflow | Trigger | What it does | -|---|---|---| -| `ci.yml` | Push/PR | Svelte type checks, release-please, multi-arch Docker build | -| `pr-title.yml` | PR | Validates PR title format | +Workflow: `.github/workflows/website.yml` in postguard-js. Deliberately not path-filtered to `apps/website/**`, so an SDK change in `packages/pg-js` is tested against the site in the same PR. + +| 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) |