Gate 0.1.0: eigen image, het command-blok is een script, de app-map is leeg

Plan Eigenimage, fase 1 tot en met 3. De vier templates verhuizen naar
tools/electrum-gate/ zonder extensie; daarnaast Dockerfile (nginx:1.30-alpine
plus python3), entrypoint.sh (het command-blok van de compose, zonder $$) en
build.sh naar het voorbeeld van Evolu Relay. Een image voor beide containers,
gebouwd op de Umbrel; open punt 2 en 3 daarmee beslist.

Inhoudelijk anders dan alleen verplaatst: het log_format staat in stream.conf
zelf, het backend-adres komt via twee plaatshouders zonder dollarteken uit de
omgeving (ook in de server-service), en de pagina haalt versie en adres uit
status.json via GATE_APP_VERSION.

Tests mee verhuisd en uitgebreid: entrypoint.sh en Dockerfile in plaats van het
command-blok, en de tag in de compose gelijk aan VERSION in build.sh voor elke
eigen image. Mutatie-getest met drie ingrepen.

Nog niet gebouwd: er is hier geen Docker. De tag staat ongepind tot de eerste
push; dat is fase 4 en die is van de gebruiker.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Harmen
2026-09-07 20:20:42 +02:00
co-authored by Claude Fable 5.1
parent 7b3804df89
commit 973b24a23f
25 changed files with 981 additions and 410 deletions
+42 -21
View File
@@ -9,7 +9,7 @@ gelden, dan per app wat alleen daar geldt.
| App | Map | Toestand |
|-|-|-|
| **Electrum Gate** | `whatsnext-electrum-gate/` | draait op de Umbrel, wordt gebruikt |
| **Electrum Gate** | `whatsnext-electrum-gate/` | draait op de Umbrel, wordt gebruikt. Sinds 0.1.0 met een eigen image en dus een bouwstap: zie **Electrum Gate** hieronder |
| **Evolu Relay** | `whatsnext-evolu-relay/` | draait op de Umbrel sinds 28-08-2026 en wordt gebruikt. Let op de bouwstap: zie **Evolu Relay** hieronder |
**Zet geen CLAUDE.md of andere werkbestanden in een app-map.** umbreld kopieert bij installatie de héle
@@ -25,12 +25,14 @@ Deze gelden voor élke app hier, want het zijn eigenschappen van umbrelOS. Met b
`${...}` in zo'n bestand door `envsubst`, ook een variabele die niet bestaat, en die wordt dan leeg. Dat
sloopt Python-code, en in een nginx-config betekent het geen `$host`, geen `log_format` en geen
`access_log` met variabelen. Moet er tóch een dollarteken in een nginx-directive, dan hoort die directive
in een bestand dat het `command`-blok van de compose wegschrijft, want daar is `$$` te ontsnappen.
in een bestand dat het `command`-blok van de compose wegschrijft (daar is `$$` te ontsnappen), of in een
eigen image, waar geen envsubst aan te pas komt. Electrum Gate doet sinds 0.1.0 het tweede; Evolu Relay
heeft zijn agent en pagina nog als `*.template`.
**Wat bij een update meekomt is een whitelist**: `docker-compose.yml`, `*.template`, `exports.sh`, `torrc`,
`hooks` en `umbrel-app.yml`. Al het andere bereikt een bestaande installatie nooit, zonder foutmelding.
Zet logica die later nog moet kunnen wijzigen dus in de compose of in een `*.template`, en nooit in een
los bestand of in een submap.
Zet logica die later nog moet kunnen wijzigen dus in de compose, in een `*.template` of in een eigen
image, en nooit in een los bestand of in een submap van de app-map.
**Een wijziging zonder verhoging van `version` in `umbrel-app.yml` wordt niet uitgerold.** Geen melding,
geen fout; umbrelOS ziet hetzelfde nummer en doet niets. Dat heeft hier een keer een dag gekost. De
@@ -57,7 +59,8 @@ python tests/test_agent_certificates.py
python tests/test_server_start_zonder_certificaat.py
```
Deze twee gaan over Electrum Gate en noemen die app-map bij naam. Er is een derde die over de **store**
Deze twee gaan over Electrum Gate en noemen `tools/electrum-gate/` en die app-map bij naam. Er is een
derde die over de **store**
gaat en zijn apps zelf vindt, dus over beide:
```
@@ -75,18 +78,22 @@ Er is ook een test over de **pagina's** van beide apps, en die is geen Python:
node tests/test_paginas_parsen.mjs
```
Hij toetst dat de JavaScript in elke `index.html.template` parseert, en dat hij dat ook nog doet ná de
invulling door umbreld. Dat is de enige klasse paginafouten die niet op het apparaat gevonden hoeft te
worden; alles wat de pagina *toont* blijft handwerk in een browser.
Hij toetst dat de JavaScript in elke statuspagina parseert. Een pagina staat op een van twee plekken: als
`index.html.template` in de app-map (Evolu Relay; dan toetst hij ook dat het script heel blijft ná de
invulling door umbreld) of als `index.html` in `tools/<app>/` (Electrum Gate sinds 0.1.0; dan toetst hij
dat er geen accolade-variabele meer in staat). Dat is de enige klasse paginafouten die niet op het
apparaat gevonden hoeft te worden; alles wat de pagina *toont* blijft handwerk in een browser.
**Wil je een pagina bekijken, gebruik `tools/voorbeeldpagina.mjs`.** Een `*.template` is niet te openen: er
staan accolade-variabelen in en de gegevens komen van een agent die alleen in de app bestaat. Dat script
vult beide in en zet het resultaat in `voorbeeld/` (gitignored). Geen bewijs, wel het gereedschap dat op
**Wil je een pagina bekijken, gebruik `tools/voorbeeldpagina.mjs`.** Een statuspagina is niet zomaar te
openen: de gegevens komen van een agent die alleen in de app bestaat, en in een `*.template` staan
bovendien accolade-variabelen. Dat script vindt de pagina op een van de twee plekken, vult in wat er in te
vullen is en zet het resultaat in `voorbeeld/` (gitignored). Geen bewijs, wel het gereedschap dat op
30-08-2026 twee echte opmaakfouten vond voordat ze uitgerold waren.
`test_appstore_vorm.py` toetst **expres niet** dat images op een digest gepind zijn. Dat is wél de regel,
maar geen van de twee apps haalt hem vandaag, en een suite die altijd rood staat wordt niet gelezen. Hij
drukt de pinstatus wel af.
maar geen van de twee apps haalt hem volledig, en een suite die altijd rood staat wordt niet gelezen. Hij
drukt de pinstatus wel af. Wat hij wél toetst: dat de tag van een eigen image gelijk is aan `VERSION` in
het bijbehorende `tools/<app>/build.sh`.
Twee dingen om te weten voordat je een groene uitslag vertrouwt:
@@ -94,20 +101,34 @@ Twee dingen om te weten voordat je een groene uitslag vertrouwt:
certificaatwinkel van het besturingssysteem nodig, en de subjectAltName-toets heeft netwerk nodig. Staat
er `OVERGESLAGEN` in de uitvoer, dan is dat deel níet bewezen. Lees de uitvoer dus, tel niet alleen de
exitcode;
- **de suite dekt de agent, niet de pagina.** Alles in `index.html.template` is handwerk in een browser.
- **de suite dekt de agent, niet de pagina.** Alles in `index.html` is handwerk in een browser.
### Architectuurregels
**De app-code zit in een eigen image, gebouwd uit `tools/electrum-gate/`** (sinds 0.1.0, 07-09-2026). De
agent, de nginx-configuratie, het stream-blok, de pagina en het startscript staan daar; in de app-map
staan alleen nog de compose, het manifest, het icoon en `data/`. Eén image voor beide containers: de
compose start hem als `server` met het standaardcommando en als `agent` met `python3 /app/agent.py`.
Gevolg dat je moet kennen voordat je iets belooft: **een wijziging in `tools/electrum-gate/` is pas
uitgerold als de image gebouwd, geduwd en met zijn digest in de compose gezet is**, en dat kan alleen de
gebruiker, op de Umbrel. Verhoog je `VERSION` in `build.sh`, dan verhoog je ook `version` in het manifest
en de tag in de compose (twee keer); `test_appstore_vorm.py` houdt tag en `VERSION` gelijk.
**Geen Docker-socket.** De agent kan nginx daarom niet zelf herladen; hij zet een vlagbestand neer en de
nginx-container herlaadt zichzelf. Als je denkt de socket nodig te hebben, is er bijna zeker een
vlagbestand-oplossing.
**De pagina start altijd, ook zonder certificaat.** Het TLS-blok staat daarom niet in
`nginx.conf.template` maar in `stream.conf.template`, en het `command`-blok van de compose zet dat pas in
`/var/lib/gate/tls/` als de agent een `cert.conf` geschreven heeft; `nginx.conf` haalt die map met een
jokerteken op. Zet het blok niet terug in `nginx.conf`, hoe netjes dat ook staat: nginx weigert te starten
als een `listen ssl` geen certificaat heeft, en dan komt de pagina waarop je dat certificaat kiest ook niet
omhoog. Dat was de fout in 0.0.3. `tests/test_server_start_zonder_certificaat.py` houdt het dicht.
**De pagina start altijd, ook zonder certificaat.** Het TLS-blok staat daarom niet in `nginx.conf` maar
in `stream.conf`, en `entrypoint.sh` zet dat pas in `/var/lib/gate/tls/` als de agent een `cert.conf`
geschreven heeft; `nginx.conf` haalt die map met een jokerteken op. Zet het blok niet terug in
`nginx.conf`, hoe netjes dat ook staat: nginx weigert te starten als een `listen ssl` geen certificaat
heeft, en dan komt de pagina waarop je dat certificaat kiest ook niet omhoog. Dat was de fout in 0.0.3.
`tests/test_server_start_zonder_certificaat.py` houdt het dicht.
**Het backend-adres komt uit de omgeving, in beide containers.** nginx kan in een `proxy_pass` van het
stream-blok geen omgevingsvariabele lezen, dus `stream.conf` heeft twee plaatshouders zonder dollarteken
die `entrypoint.sh` bij het starten invult. De pagina haalt de versie en het adres uit `status.json`; tot
0.0.29 vulde umbreld die rechtstreeks in de pagina in.
**Bij twijfel over een certificaat weigert de app.** Meerdere kandidaten zonder keuze van de gebruiker
levert géén automatische keuze op, ook niet "de nieuwste". Een verkeerd certificaat geeft een verbinding
@@ -116,7 +137,7 @@ dan een app die weigert en zegt waarom.
### Feiten
- App-id en mapnaam `whatsnext-electrum-gate`.
- App-id en mapnaam `whatsnext-electrum-gate`; image `sc.kamenier-hamer.nl/sysop/electrum-gate`.
- De TLS-poort is **50022**, niet de conventionele 50002: die bezet Fulcrum op de host.
- De app leest de certificaatmap van Zoraxy alleen-lezen. Dat is het meest ongebruikelijke aan dit
pakket; zie het masterplan **Publicatie-Gate** §4.