Compare commits

...
Author SHA1 Message Date
joshua 30a2142085 Merge branch 'fix/hub-public-key'
CI / Backend tests (push) Canceled after 0s
CI / Frontend lint, typecheck, build (push) Canceled after 0s
CI / End-to-end tests (push) Canceled after 0s
CI / Deploy tagged release (push) Canceled after 0s
2026-10-27 14:28:49 +02:00
joshuaandClaude Opus 5.5 95913a5bd5 Build the production Hub public key in (1.42.1)
CI / Backend tests (push) Canceled after 0s
CI / Frontend lint, typecheck, build (push) Canceled after 0s
CI / End-to-end tests (push) Canceled after 0s
CI / Deploy tagged release (push) Canceled after 0s
PRODUCTION_PUBLIC_KEY is the key the production Hub serves at
/api/public-key, normalised to PEM, so installs no longer need
HUB_PUBLIC_KEY. Test covers the built-in key with the env var unset.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 14:28:48 +02:00
joshua f7e0ec8bc1 Merge branch 'docs/handover-roadmap'
CI / Backend tests (push) Canceled after 0s
CI / Frontend lint, typecheck, build (push) Canceled after 0s
CI / End-to-end tests (push) Canceled after 0s
CI / Deploy tagged release (push) Canceled after 0s
2026-10-27 14:03:01 +02:00
10 changed files with 40 additions and 19 deletions
+8
View File
@@ -7,6 +7,14 @@ and this project follows [Semantic Versioning](https://semver.org/).
## [Unreleased]
## [1.42.1] - 2026-10-27
### Changed
- **The production Hub's public key is built in** (`backend/src/hub/publicKey.js`), so sites can
check licences without `HUB_PUBLIC_KEY` in their `.env`. `HUB_PUBLIC_KEY` still overrides it (for
a local Hub while developing).
## [1.42.0] - 2026-10-27
### Changed
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "event-management-backend",
"version": "1.42.0",
"version": "1.42.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "event-management-backend",
"version": "1.42.0",
"version": "1.42.1",
"hasInstallScript": true,
"dependencies": {
"@prisma/adapter-pg": "^7.10.1",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "event-management-backend",
"version": "1.42.0",
"version": "1.42.1",
"description": "Event Management System Backend",
"main": "src/index.js",
"scripts": {
+4 -4
View File
@@ -3,11 +3,11 @@
* it, so a licence can't be faked by editing the database. The matching private key exists
* only on the Hub server (events-hub repo, `npm run generate-keys`).
*
* Set PRODUCTION_PUBLIC_KEY to the key the production Hub prints, before the release that ships
* the Hub connection. HUB_PUBLIC_KEY (env) overrides it — for a local Hub while developing.
* PRODUCTION_PUBLIC_KEY is the key the production Hub prints (also served at /api/public-key); if
* the Hub key is regenerated, update it here. HUB_PUBLIC_KEY (env) overrides it — for a local Hub.
*/
const PRODUCTION_PUBLIC_KEY = null;
const PRODUCTION_PUBLIC_KEY = "MCowBQYDK2VwAyEAcKpEo/JdS96wR3r9yh8uFUxBlzPUd2YKbC60fNRUhoU=";
/**
* A public key as proper PEM, however it was pasted: with real line breaks, with "\n", all on
@@ -26,7 +26,7 @@ function normalisePem(input) {
}
function hubPublicKey() {
return normalisePem(process.env.HUB_PUBLIC_KEY) || PRODUCTION_PUBLIC_KEY;
return normalisePem(process.env.HUB_PUBLIC_KEY) || normalisePem(PRODUCTION_PUBLIC_KEY);
}
module.exports = { hubPublicKey, normalisePem, PRODUCTION_PUBLIC_KEY };
+12
View File
@@ -124,6 +124,18 @@ describe('pasting the Hub public key', () => {
expect(normalisePem('')).toBeNull();
expect(normalisePem(undefined)).toBeNull();
});
test('without HUB_PUBLIC_KEY the built-in production key is used', () => {
const { hubPublicKey, PRODUCTION_PUBLIC_KEY } = require('../src/hub/publicKey');
const saved = process.env.HUB_PUBLIC_KEY;
delete process.env.HUB_PUBLIC_KEY;
try {
expect(PRODUCTION_PUBLIC_KEY).toBeTruthy();
expect(crypto.createPublicKey(hubPublicKey()).asymmetricKeyType).toBe('ed25519');
} finally {
if (saved !== undefined) process.env.HUB_PUBLIC_KEY = saved;
}
});
});
test('version comparison for "update available"', () => {
+7 -6
View File
@@ -1,6 +1,6 @@
# Handover — where things stand and how to carry on
Last updated: 2026-10-27, after **1.42.0** (and Hub 1.1.0). The plan itself is in
Last updated: 2026-10-27, after **1.42.1** (and Hub 1.1.0). The plan itself is in
[ROADMAP-v2.md](./ROADMAP-v2.md) (decisions table at the end); the previous round of
features is in [FEATURES-ROUND-1.md](./FEATURES-ROUND-1.md).
@@ -14,6 +14,7 @@ encrypted settings unreadable or break existing installs.
| Version | What |
|---------|------|
| 1.42.1 | Production Hub public key built in (`publicKey.js`); `HUB_PUBLIC_KEY` only needed for a local Hub |
| 1.42.0 | **Request update** instead of the deploy command: Site settings → Licence sends a signed update request to the Hub (protocol §3a), which opens an alert and emails Joshua; "Update requested on …" until the site runs that version, and the admin update banner hides meanwhile. Audit action `hub_update_requested`. Needs Hub 1.1.0 |
| 1.41.3 | Renamed Hope Events → **Cross Events** in all UI text and docs (technical identifiers unchanged, see above) |
| 1.41.2 | Background jobs page: last-run times were 2 h ahead (Prisma's pg adapter drops the offset of timestamptz in raw queries — read pg-boss times `AT TIME ZONE 'UTC'`); `APP_TIMEZONE` documented |
@@ -39,9 +40,8 @@ encrypted settings unreadable or break existing installs.
1. **Roll out the update requests:** deploy **Hub 1.1.0**, then set "Latest Cross Events release"
to `1.42.0` in Hub → Settings, then update the sites to 1.42.0 (the last update done without a
request). A 1.42.0 site talking to an older Hub shows "The Hub doesn't take update requests yet".
2. **Build the Hub key in:** `PRODUCTION_PUBLIC_KEY` in `backend/src/hub/publicKey.js` is still
`null`, so each install needs `HUB_PUBLIC_KEY` in its `.env` to verify licences. Put the
production Hub's public key there in a release. Try `scripts/install.sh` on a test server.
2. **Try `scripts/install.sh` on a test server.** The production Hub key is built in since
1.42.1, so a fresh install needs no `HUB_PUBLIC_KEY`; existing installs can drop it from `.env`.
3. **1.43.0 — Multi-campus** (§12).
## Working on this repo
@@ -170,8 +170,9 @@ encrypted settings unreadable or break existing installs.
- Protocol: `docs/hub-protocol.md` — the same file is in the Hub repo (`joshua/events-hub`,
developed at `../events-hub`); change both together.
- `backend/src/hub/`: `publicKey.js` (the production Hub key — **must be set before releasing**;
`HUB_PUBLIC_KEY` env overrides it for a local Hub), `licence.js` (verify tokens, work out
- `backend/src/hub/`: `publicKey.js` (the production Hub key, built in since 1.42.1 — if the Hub's
signing key is ever regenerated, update it here in a release; `HUB_PUBLIC_KEY` env overrides it
for a local Hub), `licence.js` (verify tokens, work out
active / grace / suspended / revoked / unlicensed, cached 30 s), `client.js` (connect, heartbeat,
update request — the last two share `signedPost`; AppSetting `hub_*` keys, which the generic
settings endpoints never touch), `report.js` (health,
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "hope-events-frontend",
"version": "1.42.0",
"version": "1.42.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "hope-events-frontend",
"version": "1.42.0",
"version": "1.42.1",
"dependencies": {
"@dnd-kit/core": "^6.3.1",
"@hookform/resolvers": "^5.2.1",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "hope-events-frontend",
"version": "1.42.0",
"version": "1.42.1",
"private": true,
"scripts": {
"dev": "next dev --turbopack",
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "hope-events",
"version": "1.42.0",
"version": "1.42.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "hope-events",
"version": "1.42.0",
"version": "1.42.1",
"license": "ISC",
"devDependencies": {
"@playwright/test": "^1.64.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "hope-events",
"version": "1.42.0",
"version": "1.42.1",
"main": "index.js",
"scripts": {
"dev:backend": "cd backend && npm run dev",