De knop Volgende deed niets. Alpine haalt een boolean-attribuut alleen weg bij
null, undefined of false; het getal 0 zet het juist AAN. Mijn
:disabled="stepMissing().length" gaf bij een ingevuld formulier 0 en zette de
knop dus permanent uit. De logica klopte, de binding niet — met losse logica
niet te vinden, dus er draait nu een test die de echte modal met Alpine in een
DOM rendert en erop klikt.
Tijdzones:
- Nieuwe instelling TIMEZONE, standaard die van de server (TZ, /etc/timezone,
/etc/localtime). In alle 77 sjablonen stond Europe/Amsterdam hard ingevuld.
- Apps zonder tijdzoneveld krijgen TZ er automatisch bij; die draaiden in UTC.
Poorten:
- _bezette_poorten() telt nu ook mee waar de host zelf op luistert, gelezen uit
/proc/net/tcp in een hulpcontainer met --network host. Een nginx buiten
Docker zag Server Up eerder niet.
- GET /api/ports/check geeft vrij/bezet plus een alternatief, en meldt of de
host echt gecontroleerd kon worden.
Netwerken:
- APP_NETWORKS: meerdere gedeelde bridge-netwerken in plaats van één waar élke
app aan hing. Per app kies je welke; aanmaken kan vanuit het invulmenu, met
eigen naam of een voorstel (su-<appnaam>).
- add_shared_network() accepteert een lijst; één naam blijft werken.
- GET /api/networks/<n>/ip-check controleert subnet, bereik, Docker-toewijzing
en de ARP-tabel van de host (vangt een fysiek apparaat met DHCP-adres) en
stelt een vrij adres voor.
Pangolin (nieuw, core/pangolin.py):
- Publieke URL per app via een tunnel, zonder poorten open te zetten.
- De API veranderde in 1.9 (resource hing onder een site, staat nu los); beide
routes worden geprobeerd en bij een fout krijg je beide meldingen.
- API-sleutel is write-only. Getest tegen een nagebouwde API, niet tegen een
echte server.
Nieuw: docs/pangolin.md; docs/netwerken.md uitgebreid. 2369 tests groen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7oLCRYzY5ixJ5Sv8Y8EFb
Server Up beheerde de Docker-daemon als root zonder enige vorm van
authenticatie: elke /api/*-route was gelijk aan root-toegang op de host.
- Authenticatie toegevoegd (core/auth.py): lokale accounts met scrypt-hash,
sessiecookie (HttpOnly, SameSite=Strict) en optionele trusted-proxy-header
SSO die alleen vanaf geconfigureerde proxy-IP's wordt vertrouwd.
- before_request-guard schermt alle API-routes af; loginscherm en
eerste-account-setup in de UI.
- CSRF-token verplicht op elke mutatie; GET-varianten van state-wijzigende
routes verwijderd (o.a. /api/docker/restart was via <img> te triggeren).
- Path traversal in /api/store/install gedicht; gedeelde safe_name()-validatie
voor stack-, instantie- en repo-namen.
- Git-tokens worden niet meer teruggegeven via /api/repos en /api/settings
(has_token-vlag); settings-PUT wist een bestaand token niet meer en kan AUTH
niet overschrijven.
- Git-URL's beperkt tot http(s)/ssh/scp-syntax; ext::-transport (voert een
shell-commando uit) en file:// worden geweigerd.
- Boilerplate-templates renderen in een SandboxedEnvironment (SSTI).
- Automatisch syncen van repo's bij boot standaard uit (AUTO_SYNC_ON_BOOT),
optionele commit-pinning per repo.
- Waitress in plaats van de Flask-ontwikkelserver, MAX_CONTENT_LENGTH,
ProxyFix, en CSP/X-Frame-Options/nosniff/Referrer-Policy headers.
- Front-end libraries (Tailwind, Alpine, htmx) lokaal meegeleverd i.p.v. CDN;
Google Fonts verwijderd. Werkt nu ook offline.
- SSH host-key-verificatie aan (accept-new + /data/known_hosts).
- Lichte /healthz voor de healthcheck i.p.v. `docker info`.
- config.json en secret.key met 0600-rechten.
- Poort standaard op 127.0.0.1 gebonden.
- Audit-log gebruikt één gedeelde SQLite-verbinding (fd-lek per job verholpen);
joblogs afgekapt op 2000 regels.
- VERSION-bestand is de enige bron voor het versienummer.
- pytest-suite toegevoegd (74 tests) en als stap in beide deploy-workflows.
- fix-config.sh verwijderd (hardgecodeerd intern IP, overschreef config).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7oLCRYzY5ixJ5Sv8Y8EFb