This commit is contained in:
Jordy Hoogeveen
2026-09-10 14:03:34 +02:00
parent 09cc6ae488
commit 1b14553417
12 changed files with 299 additions and 58 deletions
+70 -28
View File
@@ -32,6 +32,25 @@ Vite proxyt `/api` naar `localhost:3001` binnen dezelfde container.
> ⚠️ Alleen `.\dev.ps1 down` wist de development-database (`docker compose down -v`).
> `.\dev.ps1 up` doet een gewone `down` en laat het volume staan.
### Welke versie de dev-app toont
De versie in "Over VibeFinance" komt uit `VITE_APP_VERSION`. `dev.ps1` leest die
uit de **root** `package.json`, zet hem in de omgeving en synct hem naar
`frontend/package.json`. In de dev-container is het een *runtime*-variabele
(`docker-compose.dev.yml`, sectie `environment`) en geen build-arg: Vite bakt
`__APP_VERSION__` in bij het **starten** van de dev-server, niet bij het bouwen
van het image. Is hij leeg, dan valt `vite.config.js` terug op
`frontend/package.json`.
Ziet de app een oude versie, dan draait de dev-server nog van vóór de bump —
`.\dev.ps1 up` hercreëert de container en start Vite opnieuw. Start je de stack
handmatig met `docker compose -f docker-compose.dev.yml up`, dan staat
`VITE_APP_VERSION` niet in je shell en zie je de versie uit
`frontend/package.json`.
> Een versie met een suffix (`1.0.1-dev`) onderdrukt de update-melding
> permanent — zie [Update-notificaties](#update-notificaties).
---
## Testen
@@ -77,27 +96,35 @@ docker compose -f docker-compose.dev.yml exec -w /app/frontend app npm run lint
## Tokens
> **De `Vibe`-organisatie staat op public.** Alles wat alleen *leest* heeft
> daardoor geen token meer nodig: `git clone`, `docker compose pull` en de
> update-check van de app werken anoniem. Het host-token hieronder is dus
> optioneel geworden. *Schrijven* blijft geauthenticeerd — een publieke
> organisatie verandert daar niets aan.
Twee tokens, gesplitst op machine en op read/write. De grens die iets betekent
ligt tussen werkstation en server, niet tussen push en release: op één machine
kan wie het ene token kan lezen, het andere ook.
| Token | Machine | Scopes | Gebruikt voor |
|---|---|---|---|
| `vibefinance-workstation` | dit werkstation | `write:package`, `write:repository` | `docker push` (`release.ps1`, `dev.ps1 push`) en het aanmaken van de Gitea-release |
| `vibefinance-host` | de Docker-host | `read:package`, `read:repository` | `docker compose pull` en de update-check van de app |
| Token | Machine | Scopes | Gebruikt voor | Nog nodig? |
|---|---|---|---|---|
| `vibefinance-workstation` | dit werkstation | `write:package`, `write:repository` | `docker push` (`release.ps1`, `dev.ps1 push`) en het aanmaken van de Gitea-release | **Ja** |
| `vibefinance-host` | de Docker-host | `read:package`, `read:repository` | `docker compose pull` en de update-check van de app | Nee, zolang de organisatie public is |
Aanmaken: Gitea → Settings → Applications → Generate New Token. Doe dat onder een
account dat lid is van de `Vibe`-organisatie — die is privé, dus een token van
een buitenstaander ziet de repo niet.
account dat lid is van de `Vibe`-organisatie: voor schrijven volstaat
organisatie-lidmaatschap niet automatisch, het account moet ook push-rechten op de
repo hebben.
**Waar ze terechtkomen**
| | Werkstation | Docker-host |
|---|---|---|
| Registry | `docker login` (credential store), of `REGISTRY_USER` + `REGISTRY_TOKEN` in `.env.release` | `docker login` als de gebruiker die deployt |
| Gitea-API | `GITEA_TOKEN` in `.env.release` | `UPDATE_CHECK_TOKEN` in `.env` |
| Registry | `docker login` (credential store), of `REGISTRY_USER` + `REGISTRY_TOKEN` in `.env.release` | niets nodig voor een pull; anders `docker login` als de gebruiker die deployt |
| Gitea-API | `GITEA_TOKEN` in `.env.release` | niets nodig; optioneel `UPDATE_CHECK_TOKEN` in `.env` |
**Waarom het host-token read-only blijft.** Dat staat in platte tekst in `.env` op
**Waarom een host-token read-only blijft** — voor het geval de organisatie weer
privé gaat en je er alsnog één neerzet. Dat staat in platte tekst in `.env` op
een server die de app op poort 3400 publiceert. Met schrijfrechten kan wie bij dat
bestand komt — via de container, een shell op die host, of een backup — een eigen
image als `latest` naar de registry pushen, en die host pullt `latest` zelf.
@@ -109,7 +136,7 @@ Read-only houdt je eigen deploy-pad uit de aanvalsketen.
|---|---|
| 401 | Token ongeldig of verlopen. Op de registry: helemaal niet ingelogd. |
| 403 | Het token mag de repo wél zien, maar mist de **scope** voor dit endpoint. Gitea noemt de vereiste scope in de response-body. |
| 404 | Het token mag de repo niet zien. Gitea geeft geen 403, om niet te verklappen dat iets bestaat: verkeerd account, of geen toegang tot de organisatie. |
| 404 | Het token mag de repo niet zien. Gitea geeft geen 403, om niet te verklappen dat iets bestaat: verkeerd account, of geen toegang tot de organisatie. Nu de organisatie public is, wijst een 404 op een leesactie eerder op een verkeerde URL dan op rechten. |
Scopes van een bestaand token zijn in Gitea niet aan te passen. Bij een 403 maak
je dus een nieuw token aan; bijwerken kan niet.
@@ -126,9 +153,21 @@ Vanuit de app-container op de host valt de body van een fout anders weg —
busybox-`wget` gooit die bij een foutstatus weg, en Node zit in het image:
```bash
docker exec vibefinance_app node -e 'fetch(process.env.UPDATE_CHECK_URL,{headers:{Accept:"application/json",Authorization:`token ${process.env.UPDATE_CHECK_TOKEN}`}}).then(async r=>console.log(r.status, (await r.text()).slice(0,300)))'
# Anoniem, zoals de app het doet zonder UPDATE_CHECK_TOKEN
docker exec vibefinance_app node -e 'fetch(process.env.UPDATE_CHECK_URL,{headers:{Accept:"application/json"}}).then(async r=>console.log(r.status, (await r.text()).slice(0,300)))'
# Mét token, precies zoals routes/update.js de header opbouwt
docker exec vibefinance_app node -e 'const t=process.env.UPDATE_CHECK_TOKEN; fetch(process.env.UPDATE_CHECK_URL,{headers:{Accept:"application/json",...(t&&{Authorization:`token ${t}`})}}).then(async r=>console.log(r.status, (await r.text()).slice(0,300)))'
```
> Let op: een **ongeldig** token geeft `401`, ook op deze publieke repo — Gitea
> valt bij een verkeerd token niet terug op anonieme toegang. Krijg je 401
> terwijl anoniem `200` geeft, haal `UPDATE_CHECK_TOKEN` dan uit `.env` in plaats
> van hem te vervangen. Een *leeg* token is onschuldig: `Authorization: token `
> negeert Gitea (`200`), en `config/index.js` zet met `|| null` bij een lege
> waarde helemaal geen header. Nagemeten op 2026-09-10:
> geen header `200`, `token ongeldig123` `401`, leeg `200`.
### Tokens opruimen
De lijst onder Settings → Applications heeft een kolom **Last used**. Zet eerst
@@ -406,20 +445,8 @@ docker-credential-desktop list
### Pullen op een deploy-machine
Het package is privé, dus ook een **pull** vereist een login — anoniem geeft
`401 Unauthorized` (`docker compose pull` meldt dan "no basic auth credentials"
of "pull access denied"). Eenmalig op de Docker-host:
```bash
docker login vibehoogie.duckdns.org
# gebruikersnaam: je Gitea-account
# wachtwoord: het token van deze host (vibefinance-host, read:package)
```
Daarna werkt `docker compose pull && docker compose up -d`. De login komt in
`~/.docker/config.json` van de gebruiker die het commando uitvoert — doe het dus
als dezelfde gebruiker (bij `sudo docker` is dat root). Log in op
`vibehoogie.duckdns.org` **zonder** `:3000`.
De organisatie is public, dus een **pull** werkt anoniem — `docker compose pull &&
docker compose up -d` en klaar, zonder `docker login`.
Controleren zonder te pullen:
@@ -427,8 +454,23 @@ Controleren zonder te pullen:
docker manifest inspect vibehoogie.duckdns.org/vibe/vibefinance-app:latest
```
Ditzelfde token gaat als `UPDATE_CHECK_TOKEN` in de `.env` op deze host, voor de
update-check van de app — één token voor beide, zie [Tokens](#tokens).
Krijg je `401 Unauthorized`, "no basic auth credentials" of "pull access denied",
dan is het package niet publiek leesbaar (organisatie weer op privé, of de
package-eigenaar wijkt af van de organisatie). Dan alsnog eenmalig op de host:
```bash
docker login vibehoogie.duckdns.org
# gebruikersnaam: je Gitea-account
# wachtwoord: een token met read:package
```
De login komt in `~/.docker/config.json` van de gebruiker die het commando
uitvoert — doe het dus als dezelfde gebruiker (bij `sudo docker` is dat root).
Log in op `vibehoogie.duckdns.org` **zonder** `:3000`.
Moet je terug naar een token, dan kan datzelfde token ook als
`UPDATE_CHECK_TOKEN` in de `.env` op deze host — één token voor beide, zie
[Tokens](#tokens).
---
@@ -464,7 +506,7 @@ uit `.env` (of de default in `docker-compose.yml`). Beschikbare backend-variabel
| Variabele | Betekenis |
|---|---|
| `UPDATE_CHECK_URL` | Release-API die gepolld wordt. Leeg = melding uit. |
| `UPDATE_CHECK_TOKEN` | Nodig zolang de `Vibe`-organisatie in Gitea privé is: het token van de host (`read:repository`, zie [Tokens](#tokens)). Zonder token geeft `releases/latest` 404, met een verkeerde scope 403 — in beide gevallen blijft de melding leeg, met alleen een `WARN` in het containerlog. |
| `UPDATE_CHECK_TOKEN` | Optioneel. De `Vibe`-organisatie is public, dus `releases/latest` antwoordt anoniem met `200` en de check heeft geen token nodig. Gaat de organisatie weer privé, dan is het host-token nodig (`read:repository`, zie [Tokens](#tokens)): zonder geeft `releases/latest` dan 404, met een verkeerde scope 403 — in beide gevallen blijft de melding leeg, met alleen een `WARN` in het containerlog. |
**Een release publiceren**