Het relay-programma: de relay van Evolu met onze eigen allowlist

tools/evolu-relay/src/ bevat nu een eigen programma dat createRelay uit
@evolu/nodejs aanroept met de twee terugroepfuncties die het bedoelde
uitbreidpunt vormen. De relay zelf komt uit npm en wordt niet nagebouwd of
aangepast; de opstartvolgorde is overgenomen uit apps/relay/src/index.ts van
Evolu zelf.

De opzet is drie bestanden met een harde scheiding, en die scheiding is de reden
dat hier iets te testen valt. policy.js bevat het beleid als pure functies: geen
bestanden, geen netwerk, geen klok. store.js is de enige plek met schijf erin.
index.js doet niets anders dan lezen, doorgeven en opslaan.

Het beleid: de eerste eigenaar die zich meldt wordt geleerd, een schakelaar
bepaalt of er nog nieuwe bij mogen, en een eigenaar is te blokkeren, alsnog toe
te laten of te vergeten. Geweigerde pogingen worden onthouden voor de pagina,
afgekapt op twintig, want elke poging is een id dat de ander zelf verzint. Een
onleesbaar owners.json wordt opzij geschoven en de app gaat dan dicht in plaats
van open: we weten dan niet wie er toegelaten was, en met de leerstand aan zou de
eerstvolgende die verbindt de nieuwe eigenaar worden.

Met test: node tests/test_limiter.mjs, 60 toetsen, en de toetsen gaan over de
guards en niet over het gelukkige pad. De beslissende regel is muteertest gedaan
en de juiste toets viel om: een geblokkeerde eigenaar mag er niet alsnog in
doordat de leerstand aanstaat. Het bestand is .mjs omdat de repo-root geen
package.json heeft en een .js daar als CommonJS gelezen zou worden.

build.sh bouwt niet langer de repo van Trezor maar onze eigen Dockerfile, dus git
is er niet meer voor nodig en de pin zit nu in package.json. De image is
node:24-slim en niet alpine, want better-sqlite3 heeft binaries voor glibc en niet
voor musl. Er is nog geen package-lock.json; het script waarschuwt daarvoor en het
staat als taak.

Onderweg bleek een aanname van vanmiddag fout: de 1 MB uit de gepubliceerde image
geldt per schrijfactie en niet per eigenaar. Er valt dus geen labelgeschiedenis
tegenaan te lopen. Dat is rechtgezet in het plan en in de naslag, en het getal is
overgenomen als bewuste keuze met RELAY_MAX_WRITE_BYTES ernaast.

Wat er niet in zit en ook niet gegokt is: data per eigenaar wissen. Het beleid kan
een eigenaar vergeten, maar zijn berichten staan in de SQLite van de relay, en dat
is andermans schema.

Tests: alle vier groen (32, 54, 39 en 60 goed, 0 fout).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Harmen
2026-08-28 11:12:41 +02:00
co-authored by Claude Opus 5
parent edb91c4749
commit 89aa06639b
12 changed files with 819 additions and 72 deletions
+40 -43
View File
@@ -2,72 +2,69 @@
# ═══════════════════════════════════════════════════════════════════════════════
# Bouwt de image voor de app whatsnext-evolu-relay.
#
# Waarom dit bestand bestaat: Trezor publiceert geen image. Hun werkproces duwt
# naar een eigen Amazon ECR en op Docker Hub staat niets, dus er is geen
# `docker pull` die iets oplevert. De broncode is wel publiek, met een Dockerfile
# erin. Dit script is de brug: het haalt de broncode op een vastgezette commit en
# bouwt hún Dockerfile.
# Wat er gebouwd wordt is ONS programma: `src/index.js` roept `createRelay` uit
# `@evolu/nodejs` aan met onze eigen toegangscontrole erin. De relay zelf komt
# gewoon uit npm en wordt niet nagebouwd of aangepast.
#
# Waarom het NIET in de app-map staat: umbreld kopieert de hele app-map naar het
# Dit verving op 28-08-2026 het vorige recept, dat de repo van Trezor kloonde en
# hun Dockerfile bouwde. Dat pakket had een Postgres en een quota-manager nodig en
# kon als zelf-gehoste relay in de kern niet werken; zie het plan Umbrelapp,
# OPEN.md punt 6.
#
# Waarom dit NIET in de app-map staat: umbreld kopieert de hele app-map naar het
# apparaat, en bij een update wordt alleen een whitelist ververst waar een
# Dockerfile niet in zit. Bouwen tijdens het starten van de app zou de installatie
# bovendien minuten laten hangen. Het recept hoort dus in de repo en het resultaat
# in een register of in de lokale Docker-opslag; de app verwijst alleen naar de tag.
#
# Waarom we hun Dockerfile gebruiken en geen eigen: dan hoeven we hun bouwstappen
# niet na te bouwen en niet bij te houden. Wat wij toevoegen is uitsluitend de pin.
# in een register; de app verwijst alleen naar de tag.
#
# Draaien: sh build.sh
# Vereist: docker en git op de machine waar je bouwt.
# Vereist: docker op de machine waar je bouwt. Git is niet meer nodig.
# ═══════════════════════════════════════════════════════════════════════════════
set -eu
# ── De pin ────────────────────────────────────────────────────────────────────
# Dit is het enige wat je aanpast als je een nieuwere versie wil. Verhoog daarna
# ook `version` in whatsnext-evolu-relay/umbrel-app.yml, anders rolt umbrelOS de
# wijziging niet uit.
UPSTREAM_REPO="https://github.com/trezor/trezor-suite-sync.git"
UPSTREAM_COMMIT="c03a2043acec48d4a1bbafca65e94da33dce1edd"
# De tag waar docker-compose.yml van de app naar verwijst. De korte commit zit
# erin, zodat je op het apparaat kunt zien wat er draait.
# De versies van `@evolu/common` en `@evolu/nodejs` staan exact in package.json en
# zijn dáár de pin. Hier staat alleen het etiket op de uitkomst.
#
# Houd VERSION gelijk aan `version` in whatsnext-evolu-relay/umbrel-app.yml. Twee
# redenen: je kunt op het apparaat zien wat er draait, en umbrelOS rolt een
# wijziging niet uit als dat nummer niet omhoog gaat. Dat laatste heeft hier een
# keer een dag gekost.
VERSION="0.2.0"
# Het register staat er expres in en dit is geen smaakkwestie: umbreld haalt élke
# image op via de Docker Engine API, dus een tag die alleen lokaal bestaat is voor
# hem onbereikbaar en de installatie faalt met "pull access denied". Dat is op
# 25-08-2026 op het apparaat vastgesteld. Zie Umbrel-appstore-spec.md.
IMAGE="sc.kamenier-hamer.nl/sysop/evolu-relay:c03a204"
IMAGE="sc.kamenier-hamer.nl/sysop/evolu-relay:${VERSION}"
# ── Bouwen ────────────────────────────────────────────────────────────────────
WORKDIR="$(mktemp -d)"
cleanup() { rm -rf "$WORKDIR"; }
trap cleanup EXIT INT TERM
RECEPT="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
echo "Broncode ophalen op ${UPSTREAM_COMMIT}"
# ── Controles vooraf ──────────────────────────────────────────────────────────
# Beter hier hard falen dan een image bouwen die iets anders bevat dan je denkt.
# Niet `clone --branch`: dat pint op een naam die meebeweegt. Een fetch van één
# commit haalt precies deze toestand op en niets anders. GitHub staat het ophalen
# van een losse commit-sha toe; een Git-server die dat niet doet, geeft hier een
# foutmelding in plaats van stil een andere versie te bouwen.
git init --quiet "$WORKDIR"
git -C "$WORKDIR" remote add origin "$UPSTREAM_REPO"
git -C "$WORKDIR" fetch --quiet --depth 1 origin "$UPSTREAM_COMMIT"
git -C "$WORKDIR" checkout --quiet FETCH_HEAD
# Controle dat we hebben wat we dachten. Zonder deze regel bouwt het script bij
# een gewijzigde afspraak over sha's stil de verkeerde toestand.
GEVONDEN="$(git -C "$WORKDIR" rev-parse HEAD)"
if [ "$GEVONDEN" != "$UPSTREAM_COMMIT" ]; then
echo "FOUT: opgehaald ${GEVONDEN}, verwacht ${UPSTREAM_COMMIT}" >&2
if [ ! -f "${RECEPT}/package.json" ] || [ ! -f "${RECEPT}/src/index.js" ]; then
echo "FOUT: package.json of src/index.js ontbreekt in ${RECEPT}" >&2
exit 1
fi
if [ ! -f "${RECEPT}/package-lock.json" ]; then
echo "LET OP: er is geen package-lock.json, dus npm kiest zelf de onderliggende"
echo " afhankelijkheden. De twee pakketten van Evolu staan exact vast in"
echo " package.json, maar wat daaronder hangt kan meebewegen. Draai eenmalig"
echo " 'npm install' in deze map, commit het lock-bestand, en zet dan in de"
echo " Dockerfile 'npm install' om naar 'npm ci'."
echo
fi
# ── Bouwen ────────────────────────────────────────────────────────────────────
echo "Bouwen als ${IMAGE}"
docker build --tag "$IMAGE" "$WORKDIR"
docker build --tag "$IMAGE" "$RECEPT"
echo
echo "Klaar. De app verwijst naar deze tag:"
echo "Klaar:"
docker image inspect --format '{{.RepoTags}} {{.Id}}' "$IMAGE"
echo
echo "Bouwen is niet genoeg: de app verwijst naar het register, want umbreld kan"
@@ -77,8 +74,8 @@ echo " docker login sc.kamenier-hamer.nl"
echo " docker push ${IMAGE}"
echo
echo "Zet daarna de digest uit de push-uitvoer achter de tag in"
echo "whatsnext-evolu-relay/docker-compose.yml, op beide services, en verhoog"
echo "\`version\` in het manifest. Zonder die verhoging rolt umbrelOS het niet uit."
echo "whatsnext-evolu-relay/docker-compose.yml, en zet \`version\` in het manifest"
echo "op ${VERSION}. Zonder die verhoging rolt umbrelOS het niet uit."
echo
echo "Controleer dat het anoniem te halen is, want umbreld krijgt geen"
echo "inloggegevens mee. Log uit in dezelfde context waarin je inlogde, anders"