docs(ci): correct guard rationale and unverified claims in ADR-0003
Refs #43 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
501310f43b
commit
25610c1ec9
3 changed files with 48 additions and 21 deletions
|
|
@ -153,8 +153,7 @@ jobs:
|
|||
# (erreichbar über das Default-Gateway des Job-Netzes). Supabase-Ports liegen dann im dind;
|
||||
# die Supabase-CLI nimmt den Host aus DOCKER_HOST automatisch.
|
||||
# Nutzt die eingecheckte supabase/config.toml. Ohne passenden Runner Job bei Bedarf deaktivieren.
|
||||
# SICHERHEIT: siehe Kommentar am Job e2e und docs/adr/0003-ci-runner-sicherheit.md. Der `if:` ist nur Komfort
|
||||
# (keine hängenden Läufe für Fork-PRs), kein Schutz.
|
||||
# SICHERHEIT: siehe Kommentar am Job e2e und docs/adr/0003-ci-runner-sicherheit.md. Der `if:` ist kein Schutz.
|
||||
supabase-tests:
|
||||
runs-on: docker-host
|
||||
concurrency:
|
||||
|
|
@ -194,9 +193,10 @@ jobs:
|
|||
# TCP-Relay (e2e/support/tcp-forward.mjs) macht ihn im Job unter 127.0.0.1 erreichbar.
|
||||
# SICHERHEIT (ADR-0003, Issue #43): Der Job führt PR-Code mit Zugriff auf den dind-Daemon des Runners aus
|
||||
# (Daemon = Root-Äquivalent). Der `if:` unten ist KEIN Schutz vor böswilligen Forks: Bei pull_request kommt die
|
||||
# Workflow-Datei aus dem PR-Head, ein Fork kann die Bedingung entfernen. Er verhindert nur, dass ehrliche Fork-PRs
|
||||
# auf einen Lauf warten, den niemand freigibt. Die tatsächliche Absicherung liegt außerhalb dieser Datei:
|
||||
# Freigabe-Pflicht für Fork-PRs (Maintainer prüft die Workflow-Änderungen vor „Freigeben“) und ein isolierter
|
||||
# Workflow-Datei aus dem PR-Head, ein Fork kann die Bedingung entfernen. Er hält nur einen unveränderten, bereits
|
||||
# freigegebenen Fork-PR von docker-host fern; er verhindert weder das Warten auf die Freigabe (gilt für den ganzen Lauf,
|
||||
# das Job-`if` wird erst danach ausgewertet) noch einen manipulierten Lauf. Die tatsächliche Absicherung liegt außerhalb
|
||||
# dieser Datei: Freigabe-Pflicht (eine Freigabe vertraut dem Nutzer dauerhaft, also Fork-PRs hier nicht freigeben) und ein isolierter
|
||||
# Runner/Daemon. Schritt-für-Schritt-Anleitung und Restrisiken: docs/adr/0003-ci-runner-sicherheit.md.
|
||||
# Gleiches gilt für supabase-tests.
|
||||
# needs + concurrency: Beide Jobs belegen dieselben festen Container-Namen/Ports (project_id shuffle, 54321 ...) im dind.
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ das Verhalten des Runners und die Aussagen zu Runner-Konfiguration stammen aus D
|
|||
## Was Forgejo 8.0.3 bietet
|
||||
| Mechanismus | Verfügbarkeit | Bewertung |
|
||||
|---|---|---|
|
||||
| Freigabe für Fork-PR-Workflows (`need approval`) | Eingebaut, **keine Repo-Einstellung zum Ein-/Ausschalten**. Laut Quelltext v8.0.3: Fork-PR (Event `pull_request`) braucht Freigabe, außer der Nutzer hat Schreibrecht, **oder es gibt im Repo schon einen freigegebenen Lauf dieses Nutzers**. Eingeschränkte Nutzer (`restricted`) brauchen immer Freigabe. | Hauptschutz, aber mit Lücke: **Eine einzige Freigabe vertraut dem Nutzer dauerhaft.** Spätere Pushes mit manipulierten Workflows laufen ohne weitere Freigabe. Die Freigabe ist also faktisch eine Entscheidung „diesem Nutzer vertraue ich den Runner an“. |
|
||||
| Nutzer `restricted` (Admin-Bereich -> Benutzerkonten, bzw. `app.ini` `[service] DEFAULT_USER_IS_RESTRICTED = true` für neue Konten) | Eingebaut | Erzwingt die Freigabe bei **jedem** Lauf (Quelltext). Sinnvoll, wenn Registrierung offen ist. |
|
||||
| Freigabe für Fork-PR-Workflows (`need approval`) | Eingebaut, **keine Repo-Einstellung zum Ein-/Ausschalten**. Entscheidet über den ganzen Lauf. Laut Quelltext v8.0.3 braucht ein Fork-PR (Event `pull_request`) Freigabe, außer der Nutzer hat Schreibrecht oder es gibt im Repo schon einen freigegebenen Lauf dieses Nutzers. | Hauptschutz mit Lücke, siehe Absatz unter der Tabelle. |
|
||||
| Nutzer `restricted` (Administration -> Benutzerkonten; `app.ini` `[service] DEFAULT_USER_IS_RESTRICTED` für neue Konten, **unverifiziert**) | Eingebaut | Erzwingt die Freigabe bei jedem Lauf (Quelltext). Nebenwirkung vermutlich: keine Sicht auf öffentliche Repos ohne Zuordnung (**unverifiziert**), siehe C.2. |
|
||||
| `pull_request_target` | Läuft mit Workflow aus dem Base-Branch | Nicht verwenden, um PR-Code auf `docker-host` zu bauen (klassische Pwn-Request-Lücke). |
|
||||
| Runner-Scoping (Instanz/Organisation/Nutzer/Repo) | Eingebaut | Begrenzt, *welche Repos* den Runner nutzen, nicht *welche Events*. Hilft hier nicht gegen Fork-PRs im selben Repo. |
|
||||
| Runner-Labels | Eingebaut | Jeder Workflow darf jedes Label anfordern. Kein Schutz. |
|
||||
|
|
@ -28,14 +28,19 @@ das Verhalten des Runners und die Aussagen zu Runner-Konfiguration stammen aus D
|
|||
| Repo privat stellen | Eingebaut | Beseitigt das Problem (Fremde können keine PRs öffnen), kostet Öffentlichkeit. |
|
||||
| Forks instanzweit verbieten (`app.ini`, Forgejo-Doku prüfen: `[repository] DISABLE_FORKS`/ähnlich) | In 8.0.3 nicht verifiziert | Nur als Prüfpunkt. |
|
||||
|
||||
**Vertrauenslücke der Freigabe:** Eine einzige Freigabe vertraut dem Nutzer dauerhaft. Für alle künftigen PRs dieses Nutzers im
|
||||
Repo (nicht nur für diesen PR) laufen Fork-PR-Workflows ohne weitere Freigabe, auch nach einem Push mit manipuliertem Workflow.
|
||||
Eine Freigabe ist also faktisch die Entscheidung „diesem Nutzer vertraue ich den Runner an“.
|
||||
|
||||
## Entscheidung (Vorschlag)
|
||||
Verteidigung in drei Schichten; nur die erste lässt sich im Repo ausdrücken, der Rest braucht Chris:
|
||||
|
||||
1. **Repo (umgesetzt):** `if:`-Guard an `supabase-tests` und `e2e` bleibt als Komfort (ehrliche Fork-PRs hängen nicht in
|
||||
„wartet auf Freigabe“); Kommentare in `ci.yml` benennen ihn ausdrücklich als keinen Schutz.
|
||||
1. **Repo (umgesetzt):** Der `if:`-Guard an `supabase-tests` und `e2e` hält nur einen unveränderten, bereits freigegebenen
|
||||
Fork-PR von `docker-host` fern. Er verhindert weder das Warten auf Freigabe (die gilt für den ganzen Lauf, das Job-`if`
|
||||
wird erst danach ausgewertet) noch einen manipulierten Lauf. Die Kommentare in `ci.yml` sagen das.
|
||||
2. **Forgejo (Chris):** Fork-PR-Läufe auf diesem Runner **nicht freigeben**, solange er nicht isoliert ist (3.) oder das Repo
|
||||
nicht privat ist. Grund: Eine Freigabe gilt für alle späteren Läufe des Nutzers. Fremde Beiträge lokal prüfen oder als Branch
|
||||
ins Haupt-Repo übernehmen. Neue/fremde Konten als `restricted` führen, damit jeder Lauf einzeln freigegeben werden muss.
|
||||
nicht privat ist. Grund: Eine Freigabe gilt für alle künftigen PRs des Nutzers im Repo. Fremde Beiträge lokal prüfen oder als
|
||||
Branch ins Haupt-Repo übernehmen.
|
||||
3. **Runner/Mac (Chris):** Blast Radius des dind begrenzen (siehe Anleitung).
|
||||
|
||||
Solange 2. und 3. nicht erledigt sind, gilt `docker-host` als **nicht für externe Beiträge geeignet**. Empfehlung: vor dem
|
||||
|
|
@ -49,7 +54,12 @@ ersten externen Beitrag, spätestens vor Release, entweder 3. umsetzen oder das
|
|||
2. Erwartung: Lauf steht auf „Wartet auf Freigabe“ und startet erst nach Klick auf **Freigeben** (PR-Seite bzw. Actions-Lauf).
|
||||
Falls er ohne Freigabe startet (Quelltext sagt anderes): Das Repo sofort privat stellen (Einstellungen -> Repository -> Sichtbarkeit) und
|
||||
Runner pausieren (B.3), dann Forgejo-Version/Doku prüfen.
|
||||
3. Zweiten Push im selben PR machen: Läuft er jetzt ohne erneute Freigabe? Dann ist „einmal freigegeben, immer freigegeben“ bestätigt. Danach das Testkonto als `restricted` markieren und wiederholen: Jetzt muss jeder Lauf freigegeben werden.
|
||||
3. Zweiten Push im selben PR machen: Läuft er jetzt ohne erneute Freigabe? Dann ist „einmal freigegeben, immer freigegeben“ bestätigt.
|
||||
4. Aufräumen: Testkonto und Fork **löschen** (dauerhaft vertrautes Konto!). Falls das nicht geht: mindestens `restricted` setzen und
|
||||
Anmeldung verbieten (Administration -> Benutzerkonten).
|
||||
|
||||
Hinweis: Der Test mit `restricted` (jeder Lauf einzeln freigegeben) ist eventuell nicht durchführbar, weil eingeschränkte Nutzer
|
||||
vermutlich keine öffentlichen Repos ohne Zuordnung sehen (**unverifiziert**, siehe C.2). Dann entfällt er; die Quelltext-Aussage bleibt.
|
||||
|
||||
### B. Auf dem Mac (Runner/dind)
|
||||
1. Labels sind keine Grenze: Ein Fork-PR kann `runs-on: docker-host` selbst setzen. Eine Trennung `docker` / `docker-host` im
|
||||
|
|
@ -62,18 +72,28 @@ ersten externen Beitrag, spätestens vor Release, entweder 3. umsetzen oder das
|
|||
2. Wirksam: Runner in eine Wegwerf-VM (z. B. Lima/Colima/UTM) oder auf einen separaten Rechner/Hetzner-Server verlagern, ohne
|
||||
Host-Mounts, ohne Zugriff aufs LAN, ohne Zugangsdaten und ohne persönliche Daten auf dem Mac. Ziel: Ein Ausbruch aus dem dind
|
||||
trifft nichts Wertvolles. Eigenes Registrierungs-Token verwenden; `.runner` und Token nicht ins Repo und nicht in Logs.
|
||||
3. Notbremse: Runner stoppen (`launchctl`/Prozess beenden oder in Forgejo unter Einstellungen -> Actions -> Runner deaktivieren).
|
||||
3. Notbremse: Runner-Prozess auf dem Mac beenden (z. B. `launchctl unload` des Dienstes oder Prozess/Container stoppen; der genaue Weg hängt von der Einrichtung ab, **unverifiziert**). In Forgejo (Einstellungen -> Actions -> Runner) gibt es in 8.0.3 evtl. nur Bearbeiten/Löschen statt Deaktivieren (**unverifiziert**); Löschen macht den Runner unbrauchbar, bis er neu registriert wird.
|
||||
4. Runner nur für dieses Repo registrieren (Repo-Scope statt Instanz-/Nutzer-Scope), damit andere Repos ihn nicht ansprechen können.
|
||||
|
||||
### C. In Forgejo
|
||||
1. Fork-PR-Läufe nicht freigeben (siehe Entscheidung 2.); fremde Konten unter Administration -> Benutzerkonten als eingeschränkt markieren.
|
||||
2. Optional: Branch-Schutz für `main` mit **Geschützte Dateimuster** `.forgejo/**;e2e/**;supabase/config.toml`, damit
|
||||
Änderungen daran nie ohne Review in `main` landen (wirkt auf Pushes nach `main`, nicht auf PR-Läufe).
|
||||
3. Repo privat stellen, wenn externe Beiträge nicht gewollt sind (löst das Problem vollständig).
|
||||
4. Runner-Token regelmäßig erneuern.
|
||||
1. Fork-PR-Läufe nicht freigeben (siehe Entscheidung 2.).
|
||||
2. Fremde Konten als `restricted` zu führen ist mit Vorsicht zu genießen: Eingeschränkte Nutzer sehen vermutlich keine öffentlichen
|
||||
Repos ohne explizite Zuordnung (**unverifiziert**). Dann könnten sie keinen Fork/PR anlegen, d. h. `restricted` sperrt externe
|
||||
Beiträge faktisch aus. Das ist eine Alternative zum Repo-privat-Stellen, kein Mittel für „jeder Lauf einzeln freigeben“.
|
||||
Erst mit dem Testkonto aus A prüfen.
|
||||
3. Optional: Branch-Schutz für `main` mit geschützten Dateimustern (UI-Bezeichnung in 8.0.3 **unverifiziert**, bei
|
||||
Gitea „Protected file patterns“) `.forgejo/**;e2e/**;supabase/config.toml`. Achtung, vermutlich blockiert das auch das
|
||||
Mergen von PRs, die solche Dateien ändern, also auch deine eigenen CI-PRs (**unverifiziert**); nur nutzen, wenn du dafür eine
|
||||
Ausnahme (Admin-Merge/Whitelist) hast, sonst weglassen. Es schützt nur `main`, nicht die PR-Läufe.
|
||||
4. Repo privat stellen, wenn externe Beiträge nicht gewollt sind (löst das Problem vollständig).
|
||||
5. Runner-Token rotieren (Registrierungs-Token ist kein Dauer-Geheimnis, das `.runner` auf dem Mac enthält das Laufzeit-Token):
|
||||
Runner in Forgejo (Einstellungen -> Actions -> Runner) löschen, im selben Dialog ein neues Registrierungs-Token erzeugen, den
|
||||
Runner auf dem Mac mit `forgejo-runner register` neu registrieren und die alte `.runner` löschen. Vorschlag: alle 3 Monate
|
||||
sowie sofort bei Verdacht. Token nie in Chats, Logs oder ins Repo kopieren.
|
||||
|
||||
## Konsequenzen
|
||||
- Externe Beiträge laufen nicht auf `docker-host`, bis der Runner isoliert ist.
|
||||
- Fork-PRs bekommen für `supabase-tests`/`e2e` keine Prüfung, solange der `if:`-Guard steht; sie laufen dann nur auf `docker`
|
||||
(Format, Analyse, Tests, Web-Build). Ein Maintainer kann den Branch bei Bedarf ins Haupt-Repo übernehmen, um die Docker-Jobs zu starten.
|
||||
- Fork-PRs bekommen ohne Freigabe kein CI (der ganze Lauf wartet, mit allen Jobs). Eine Freigabe vertraut dem Nutzer den ganzen
|
||||
Runner dauerhaft an. Fremde Beiträge daher als Branch ins Haupt-Repo übernehmen (dort läuft CI ohne Freigabe, weil Schreibrecht).
|
||||
- Externe Beiträge laufen nicht auf `docker-host`, bis der Runner isoliert ist oder das Repo privat ist.
|
||||
- Der `if:`-Guard ändert daran nichts (siehe Entscheidung 1).
|
||||
- Offen: Ergebnis der Prüfung A und Umsetzung B. Bis dahin Issue #43 nicht schließen.
|
||||
|
|
|
|||
7
docs/adr/README.md
Normal file
7
docs/adr/README.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# Architecture Decision Records
|
||||
|
||||
| Nr. | Titel | Status |
|
||||
|---|---|---|
|
||||
| [0001](0001-tech-stack.md) | Tech-Stack | Angenommen |
|
||||
| [0002](0002-hosting.md) | Hosting: Supabase selbst gehostet auf Hetzner | Angenommen |
|
||||
| [0003](0003-ci-runner-sicherheit.md) | CI-Sicherheit: Fork-PRs und Runner `docker-host` | Vorgeschlagen |
|
||||
Loading…
Reference in a new issue