De pagina van Evolu Relay op de lijst van de gebruiker
Negen punten uit echt gebruik met 0.4.0, alle negen gedaan. Twee ervan waren onderzoeksvragen en die staan onderaan. Evolu Relay 0.5.0 - Een tijdvenster van twee minuten voor nieuwe eigenaars, met een stopknop. De teller zit in het relay-proces en niet in de pagina: een teller in een tabblad dat je sluit, sluit de deur niet. policy.js kreeg learningUntil, isLearningOpen en expireLearning. - decideOwner kijkt naar isLearningOpen en niet naar het veld learning. De lus die een verlopen venster opruimt loopt elke twee seconden, en in dat gat zou een onbekende alsnog binnenkomen. - Zonder STATE_VERSION te verhogen, met een toets die dat verdedigt: een verhoging zou de allowlist van de draaiende installatie laten afwijzen en de deur sluiten voor eigenaars die er al in stonden. - Labels op een eigenaar-id, in een eigen labels.json met de agent als enige schrijver. Een label zegt niets over toegang, dus de relay hoeft het niet te weten; het is daardoor meteen opgeslagen en werkt ook als de relay omligt. - Geblokkeerde en geweigerde eigenaars in een kader, met een badge die zegt welke van de twee het is. De badge staat buiten het hover-blok, anders is dat onderscheid onzichtbaar tenzij je over de regel gaat. - Maatvoering gelijk aan Electrum Gate: 1760px, hetzelfde raster, icoon van 64 pixels, dezelfde kop, versienummer erachter. Uitleg uit de kaders, knoppen pas bij hover, geen voetregel. Electrum Gate 0.0.24 - Menu-item "About this app", in beide apps. - De statuswidget zei "Answering" met "answered in 7 ms, from inside the app" en zegt nu "Running" met de meting eronder. De nuance dat de controle van container naar container loopt is verplaatst naar een eigen kopje in die dialoog, waar er ruimte voor is; vier woorden waren te weinig. Toetsen en gereedschap - tests/test_relay_agent.py (nieuw, 65 toetsen) en tests/test_paginas_parsen.mjs (nieuw). Muteertests gedraaid op de beslissende regels. - Een dollarteken-toets in test_appstore_vorm.py. Het commentaar in drie bestanden beweerde al dat die test bestond; nu is dat waar. - Een toets dat er geen werkbestanden in een app-map staan. umbreld kopieert de hele map naar het apparaat en in de back-up. - tools/voorbeeldpagina.mjs maakt van een *.template een pagina die je in een browser kunt openen. Dat vond meteen twee echte opmaakfouten. De twee onderzoeksvragen - Een geweigerde eigenaar komt niet in de database: isOwnerAllowed zit in de WebSocket-upgrade, dus het is een 401 en een gesloten socket. Het gewenste gevolg treedt wel op, via de client: die is local-first en levert bij toelating de hele geschiedenis. Blokkeren werkt daarentegen pas bij de volgende verbinding, en dat staat als open punt. - De blobs zijn niet met een xpub te ontcijferen; een OwnerId komt daar niet uit. Met de SLIP-21-node van het apparaat kan het wel, maar die geeft volledige zeggenschap, dus dat hoort niet in een relay. Als plan-punt opgenomen bij de tool in HomeGit/Trezor. Nog niet uitgerold: de image 0.5.0 moet gebouwd en geduwd worden. De digest staat daarom niet in de compose, want een oude digest onder een nieuwe tag levert stil de oude relay. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -316,6 +316,126 @@ def test_containernamen_zijn_volledig(u, app):
|
||||
not fout, "korte namen: %r" % fout)
|
||||
|
||||
|
||||
def test_geen_werkbestanden_in_de_app_map(u, app):
|
||||
"""In een app-map staat alleen wat umbreld nodig heeft.
|
||||
|
||||
umbreld kopieert bij een installatie de héle app-map naar
|
||||
`~/umbrel/app-data/<app-id>/` met `rsync --archive`. Alles wat daar staat
|
||||
belandt dus op het apparaat en in de back-up: een CLAUDE.md, een gelaagd
|
||||
bewerkbestand van een icoon, een testscript, een aantekening.
|
||||
|
||||
Dat is geen theorie. Op 30-08-2026 stond er een `icon.pdn` van 175 kB in de map
|
||||
van Evolu Relay, een Paint.NET-bestand van een icoon dat nog niet af was. Het
|
||||
apparaat kan er niets mee en het maakt elke back-up groter. Verplaatst naar
|
||||
`tools/icons/`; deze toets is wat voorkomt dat de volgende terugkomt.
|
||||
|
||||
De lijst hieronder is een whitelist en geen blacklist, en dat is met opzet: bij
|
||||
een nieuw soort bestand hoort iemand na te denken of het daar hoort, en een
|
||||
blacklist stelt die vraag nooit.
|
||||
"""
|
||||
TOEGESTAAN_EXACT = {
|
||||
"umbrel-app.yml", "docker-compose.yml", "exports.sh", "torrc",
|
||||
"icon.png", "icon.svg", ".gitkeep",
|
||||
}
|
||||
TOEGESTAANE_MAPPEN = {"data", "hooks"}
|
||||
|
||||
fout = []
|
||||
for naam in sorted(os.listdir(os.path.join(REPO, app))):
|
||||
pad = os.path.join(REPO, app, naam)
|
||||
|
||||
if os.path.isdir(pad):
|
||||
# __pycache__ is niet gecommit (het staat in .gitignore) en komt dus
|
||||
# nooit in de kloon die umbreld ophaalt. Het staat er in een werkboom
|
||||
# zodra een test de agent-template importeert, en daarover klagen zou
|
||||
# de toets rood zetten op iets dat het apparaat niet bereikt.
|
||||
if naam == "__pycache__":
|
||||
continue
|
||||
if naam not in TOEGESTAANE_MAPPEN:
|
||||
fout.append(naam + "/")
|
||||
continue
|
||||
|
||||
if naam in TOEGESTAAN_EXACT:
|
||||
continue
|
||||
# Alles wat umbreld bij een update ververst is een template, en die horen
|
||||
# er dus per definitie.
|
||||
if naam.endswith(".template"):
|
||||
continue
|
||||
fout.append(naam)
|
||||
|
||||
u.check("%s: er staan geen werkbestanden in de app-map" % app,
|
||||
not fout,
|
||||
"deze horen buiten de app-map: %r" % fout)
|
||||
|
||||
|
||||
# De variabelen die umbrelOS werkelijk invult. Alleen deze mogen in een template
|
||||
# staan; zie test_templates_hebben_geen_losse_dollars. Overgenomen uit de tabel in
|
||||
# Docs/Referenties/Umbrel-appstore-spec.md §3.
|
||||
UMBREL_VARIABELEN = {
|
||||
"APP_ID", "APP_VERSION", "APP_DATA_DIR", "APP_MANIFEST_FILE", "UMBREL_ROOT",
|
||||
"DEVICE_HOSTNAME", "DEVICE_DOMAIN_NAME", "APP_DOMAIN",
|
||||
"APP_PROXY_HOSTNAME", "APP_PROXY_PORT", "NETWORK_IP",
|
||||
"TOR_PROXY_IP", "TOR_PROXY_PORT", "TOR_DATA_DIR",
|
||||
"APP_HIDDEN_SERVICE", "APP_SEED", "APP_PASSWORD",
|
||||
}
|
||||
|
||||
# Een app krijgt daarnaast de exports van zijn afhankelijkheden, en die heten
|
||||
# APP_<AFHANKELIJKHEID>_<IETS>. Electrum Gate gebruikt APP_ELECTRS_NODE_IP en
|
||||
# APP_ELECTRS_NODE_PORT. Die kunnen niet in een vaste lijst staan, want welke er
|
||||
# zijn hangt af van de afhankelijkheid; vandaar een vorm in plaats van een naam.
|
||||
EXPORT_VORM = r"^APP_[A-Z0-9]+_[A-Z0-9_]+$"
|
||||
|
||||
|
||||
def test_templates_hebben_geen_losse_dollars(u, app):
|
||||
"""In een *.template staat geen dollarteken dat umbrelOS niet invult.
|
||||
|
||||
Dit is de valstrik van dit hele project, en tot 30-08-2026 beweerde het
|
||||
commentaar in drie bestanden dat déze test hem dichthield terwijl dat niet zo
|
||||
was.
|
||||
|
||||
Wat er gebeurt: umbreld haalt elke `*.template` bij het starten door envsubst.
|
||||
Dat vervangt élke accolade-vorm, ook een variabele die niet bestaat, en die
|
||||
wordt dan leeg. Gevolgen per bestandstype:
|
||||
|
||||
- in een pagina sloopt het een JavaScript-template-literal, want die gebruikt
|
||||
accolades achter een dollarteken. Vandaar dat de pagina's overal strings met
|
||||
een plus aan elkaar plakken;
|
||||
- in een nginx-config verdwijnen `host`, `log_format` en elke variabele in een
|
||||
access_log;
|
||||
- in Python-code verdwijnt stilzwijgend een stuk code.
|
||||
|
||||
Er komt geen foutmelding. Het bestand wordt gewoon anders dan je schreef.
|
||||
|
||||
Beide vormen die envsubst kent worden gevlagd: `${NAAM}` en het kale `$NAAM`.
|
||||
Dat tweede is de vorm waarin een nginx-variabele als `$host` geschreven wordt,
|
||||
en die is hier dus net zo fout als de eerste.
|
||||
|
||||
Wat NIET gevlagd wordt is een los dollarteken zonder naam erachter. Dat laat
|
||||
envsubst staan, en het staat in dit project in de commentaarregels die deze
|
||||
regel juist uitleggen: een toets die zijn eigen uitleg rood zet, wordt
|
||||
uitgezet.
|
||||
"""
|
||||
import re
|
||||
|
||||
for bestandsnaam in sorted(os.listdir(os.path.join(REPO, app))):
|
||||
if not bestandsnaam.endswith(".template"):
|
||||
continue
|
||||
|
||||
tekst = lees(os.path.join(REPO, app, bestandsnaam))
|
||||
onbekend = []
|
||||
for regelnummer, regel in enumerate(tekst.splitlines(), start=1):
|
||||
for treffer in re.finditer(r"\$\{?([A-Za-z_][A-Za-z0-9_]*)\}?", regel):
|
||||
naam = treffer.group(1)
|
||||
if naam in UMBREL_VARIABELEN:
|
||||
continue
|
||||
if re.match(EXPORT_VORM, naam):
|
||||
continue
|
||||
onbekend.append("regel %d: %r" % (regelnummer, treffer.group(0)))
|
||||
|
||||
u.check("%s/%s: geen dollartekens die umbrelOS leegmaakt" % (app, bestandsnaam),
|
||||
not onbekend,
|
||||
"gevonden: %r" % onbekend[:4])
|
||||
|
||||
|
||||
def rapporteer_pinstatus(apps):
|
||||
"""Afdrukken, niet toetsen. Zie de uitleg bovenaan dit bestand."""
|
||||
print()
|
||||
@@ -346,6 +466,8 @@ def main():
|
||||
test_compose_bestaat_en_hangt_samen(u, app)
|
||||
test_data_onder_data(u, app)
|
||||
test_containernamen_zijn_volledig(u, app)
|
||||
test_geen_werkbestanden_in_de_app_map(u, app)
|
||||
test_templates_hebben_geen_losse_dollars(u, app)
|
||||
|
||||
rapporteer_pinstatus(apps)
|
||||
return u.rapport()
|
||||
|
||||
Reference in New Issue
Block a user