Selvhostet Forgejo Actions-runner for backend-testene

Empirisk push viste at repoet ikke hadde noen aktiv runner (jobb ble
stående som "Waiting"). Satt opp act_runner lokalt på serveren
(Docker-utenfor-Docker, docker.sock automount) siden
run_backend_tests.sh er avhengig av teeoff_db/teeoff_default som kun
finnes her. Kjører nå som egen tjeneste i docker-compose.yml. Se
ADR-059 og CHANGELOG punkt 68.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Erol Haagenrud 2026-08-10 22:41:48 +02:00
parent c5eed728e1
commit b65491afc8
4 changed files with 150 additions and 13 deletions

1
.gitignore vendored
View file

@ -4,3 +4,4 @@ __pycache__/
Temp-uploads/
.venv/
.pytest_cache/
.forgejo-runner/

View file

@ -5616,13 +5616,83 @@ grønne. Ekte `teecup_db` sitt rolleoppsett (`teecup_app`:
uendret etter kjøring. Ingen deploy denne runden — dette er ren
testinfrastruktur, ingen produksjonskode endret.
**Bevisst utenfor omfang, egne fremtidige runder:** CI-workflow-fil
(venter på bekreftet runner), frontend-tester, og dekning av flere
router-funksjoner enn de tre høyest-risiko-områdene over (f.eks.
øvrige `rounds.py`-endepunkter, `individual_tournaments.py`,
org-turnering-match-scoring sin `scoring.py` — sistnevnte spesielt
interessant siden ADR-057 dokumenterte AT den mangler samtidighetsvern,
men det er foreløpig udekket av en test som beviser det empirisk).
**Bevisst utenfor omfang, egne fremtidige runder:** frontend-tester, og
dekning av flere router-funksjoner enn de tre høyest-risiko-områdene
over (f.eks. øvrige `rounds.py`-endepunkter,
`individual_tournaments.py`, org-turnering-match-scoring sin
`scoring.py` — sistnevnte spesielt interessant siden ADR-057
dokumenterte AT den mangler samtidighetsvern, men det er foreløpig
udekket av en test som beviser det empirisk). CI-workflow-filen ble
løst SAMME dag — se ADR-059.
---
## ADR-059: Selvhostet Forgejo Actions-runner — 2026-08-10
Direkte oppfølging av ADR-058: `.forgejo/workflows/backend-tests.yml`
ble lagt til og pushet som en EMPIRISK test av om
forgejo.jegvil.no faktisk hadde en aktiv runner for dette repoet
(instansen svarte `has_actions: true` på et anonymt API-kall, men det
beviste ikke at noe faktisk plukker opp jobber). Resultat: jobben la
seg i kø som "Waiting" og ble stående uendret i over et minutt — ingen
runner fantes. Bruker ba om at det rettes.
**Beslutning A — selvhostet `act_runner` PÅ DENNE serveren, ikke en
ekstern/skyhostet runner.** `run_backend_tests.sh` er avhengig av
`docker exec teeoff_db` og `teeoff_default`-nettverket, som kun
eksisterer på denne verten. En runner et annet sted ville uansett
ikke kunnet kjøre testene slik de er skrevet i dag.
**Beslutning B — Docker-utenfor-Docker (DooD) via
`docker_host: automount` i runner-konfigen, ikke Docker-i-Docker.**
Jobb-containeren får HOST-ens `docker.sock` bind-montert inn (samme
mønster som runneren selv bruker for å starte jobb-containere i
utgangspunktet), slik at `scripts/run_backend_tests.sh` sine egne
`docker build`/`docker run`/`docker exec`-kall oppretter ekte
søsken-containere på host-nivå — ikke en nøstet, isolert
docker-daemon som ikke ville sett `teeoff_db` i det hele tatt.
Jobb-image: `catthehacker/ubuntu:act-latest` (de facto standardimage
for act/act_runner — har docker-CLI, git, bash forhåndsinstallert,
unngår `apt-get install` i hvert eneste kjør).
**Beslutning C — registrerings-tokenet ble ALDRI limt inn i chatten.**
Bruker hentet det selv fra Forgejo sitt UI (repo → Settings → Actions
→ Runners) og la det i en midlertidig fil med `chmod 600` på serveren;
Claude leste filen direkte via shell, registrerte runneren
(`forgejo-runner register --no-interactive`), og makulerte
tokenfilen umiddelbart etterpå (`shred -u`). Selve
runner-legitimasjonen som oppsto (`.forgejo-runner/.runner` — en ekte,
langlevd hemmelighet, ikke det korte engangs-registreringstokenet) er
gitignored, `chmod 600`, aldri committet — samme disiplin som
`.env`.
**Beslutning D — kjøres via `docker-compose.yml`, ikke en løs
`docker run`.** Startet først manuelt for å bevise at det fungerte
(ekte push → "Waiting" → runner registrert → jobb plukket opp →
"Success", verifisert i Forgejo sitt UI), deretter flyttet inn som en
egen `teecup-forgejo-runner`-tjeneste i `docker-compose.yml` for
samme drift-disiplin som resten av stacken (`restart: unless-stopped`,
dokumentert, ikke en engangs-kommando ingen husker senere).
`group_add: "112"` (docker-gruppens GID på DENNE verten) er
nødvendig fordi runner-imagets prosess kjører som ikke-root — uten
den kan den ikke lese den mountede sokkelen selv om den er tilgjengelig.
Vertsspesifikk verdi, sjekk på nytt om dette noensinne flyttes.
**Sikkerhetsnotat, bevisst akseptert:** tilgang til `docker.sock`
tilsvarer root-ekvivalent kontroll over VERTEN (enhver som kan
opprette en container kan mounte hva som helst fra filsystemet).
Dette er en reell heving av angrepsflaten sammenlignet med resten av
stacken, som ingen andre containere her har. Akseptert fordi (a) det
er en direkte konsekvens av arkitekturen `run_backend_tests.sh` allerede
hadde (samme prinsipp, bare automatisert fremfor kjørt manuelt fra en
already-priviligert shell), og (b) runneren kjører KUN denne ene
repoens CI, på en enkeltpersons egen server — ikke en delt/flerbruker-
instans.
**Verifisert:** ekte push → `.forgejo/workflows/backend-tests.yml`
kjørte, viste "Success" i Forgejo sitt UI (grønn hake, samme run som
sto "Waiting" rett før runneren startet). `teecup_db`s rolleoppsett og
fravær av gjenglemte scratch-databaser bekreftet uendret etter kjøring.
Disse må avklares før eller under de relevante fasene:

View file

@ -10278,9 +10278,49 @@ Neste steg:
grønne. Ingen produksjonskode endret denne runden — ren
testinfrastruktur, ingen deploy.
**Bevisst utenfor omfang:** CI-workflow-fil (Forgejo Actions har
`has_actions: true` for repoet, men ingen bekreftet aktiv runner —
egen runde), frontend-tester, og dekning av org-turneringenes
match-scoring (`scoring.py`) — som ADR-057 allerede har dokumentert
mangler samtidighetsvern, men som fortsatt ikke har en test som
beviser det empirisk.
**Bevisst utenfor omfang:** frontend-tester, og dekning av
org-turneringenes match-scoring (`scoring.py`) — som ADR-057
allerede har dokumentert mangler samtidighetsvern, men som
fortsatt ikke har en test som beviser det empirisk.
CI-workflow-filen ble løst SAMME dag, se punkt 68.
68. **Selvhostet Forgejo Actions-runner — 2026-08-10, se ADR-059.**
Direkte oppfølging av punkt 67: en `.forgejo/workflows/
backend-tests.yml` ble lagt til og pushet som en empirisk test —
Forgejo-instansen svarte `has_actions: true`, men det beviste ikke
at noe faktisk plukket opp jobber. Jobben la seg som "Waiting" og
sto uendret i over et minutt. Ingen runner fantes. Bruker ba om
at det rettes ("start med ci").
Satt opp en selvhostet `act_runner` PÅ DENNE serveren (må være her
`run_backend_tests.sh` er avhengig av `docker exec teeoff_db` og
`teeoff_default`-nettverket, som kun finnes lokalt). Docker-
utenfor-Docker (`docker_host: automount`): jobb-containeren får
host-ens `docker.sock` bind-montert inn, slik at testskriptets
egne `docker build`/`run`/`exec`-kall lager ekte søsken-containere
på host-nivå. Jobb-image `catthehacker/ubuntu:act-latest` (docker-
CLI/git/bash forhåndsinstallert).
Registrerings-tokenet ble ALDRI limt inn i chatten — bruker hentet
det selv fra Forgejo sitt UI, la det i en `chmod 600`-fil på
serveren, Claude leste filen direkte og makulerte den (`shred -u`)
rett etter registrering. Den ekte, langlevde runner-legitimasjonen
som oppsto (`.forgejo-runner/.runner`) er gitignored og `chmod 600`
— samme disiplin som `.env`.
Startet først manuelt for å bevise at det virket, deretter flyttet
inn som en egen `teecup-forgejo-runner`-tjeneste i
`docker-compose.yml` (`restart: unless-stopped`) for samme
driftsdisiplin som resten av stacken.
**Sikkerhetsnotat, bevisst akseptert:** `docker.sock`-tilgang er
root-ekvivalent kontroll over verten — en reell heving av
angrepsflaten. Akseptert fordi det er samme prinsipp
`run_backend_tests.sh` allerede krevde (nå automatisert fremfor
kjørt fra en allerede-priviligert shell), og runneren betjener kun
denne ene repoens CI på en enkeltpersons egen server.
**Verifisert:** ekte push → workflowen kjørte → "Success" i
Forgejo sitt UI (grønn hake, samme kø-oppføring som nettopp sto
"Waiting"). `teecup_db`s rolleoppsett og fravær av gjenglemte
scratch-databaser bekreftet uendret etter kjøring.

View file

@ -57,6 +57,32 @@ services:
depends_on:
- teecup_api
# Selvhostet Forgejo Actions-runner (ADR-059, 2026-08-10) -- kjører
# backend-testsuiten (.forgejo/workflows/backend-tests.yml) automatisk
# ved push. Docker-utenfor-Docker (docker_host: automount i
# .forgejo-runner/config.yaml): jobb-containeren får docker.sock
# bind-mountet inn, slik at scripts/run_backend_tests.sh kan opprette
# SINE EGNE scratch-db-/testcontainere via HOST-ens docker-daemon --
# ikke en nøstet docker-daemon inni runneren. `.runner`-fila i
# .forgejo-runner/ er en ekte, langlevd registreringshemmelighet
# (gitignored, ALDRI committet).
#
# group_add: 112 er docker-gruppens GID på DENNE verten (`stat -c %g
# /var/run/docker.sock`) -- uten den kan ikke runner-prosessen (som
# kjører som en ikke-root-bruker i imaget) lese sokkelen, selv når den
# er mountet inn. Sjekk/juster GID-en om dette flyttes til en annen vert.
teecup-forgejo-runner:
image: code.forgejo.org/forgejo/runner:6
container_name: teecup-forgejo-runner
command: forgejo-runner daemon --config config.yaml
working_dir: /data
group_add:
- "112"
volumes:
- ./.forgejo-runner:/data
- /var/run/docker.sock:/var/run/docker.sock
restart: unless-stopped
volumes:
teecup_minio_data: