Die Plattformneutralitaet war nach dem WinForms-Ausbau eine Momentaufnahme: eine einzige net10.0-windows-Zeile oder ein "using System.Drawing" genuegt, und der Linux-Build ist kaputt, ohne dass es auf einer Windows-Maschine auffaellt - dort baut es weiter. Genau das faengt die CI ab, und zwar auf Linux. .gitea/workflows/ci.yml, zwei Jobs auf ubuntu-latest: - build-test: restore, build, die 476 Tests (brauchen keine DB, laufen gegen EF-InMemory), Linux-Publish. Der Publish ist kein Selbstzweck - dort faellt auf, wenn ein Paket doch windows-only ist. Anschliessend wird geprueft, dass die Executable, appsettings.json, setup.json und libSkiaSharp.so wirklich im Ergebnis liegen. - guard: keine windows-TFMs, kein UseWindowsForms/UseWPF, keine windows-only using-Direktiven, keine versionierten Secret-Dateien, keine anfaelligen Pakete. Alle Waechter sind in beide Richtungen gegengeprueft: sie schlagen bei simulierten Regressionen an (windows-TFM, UseWindowsForms, using System.Drawing, getrackte packager.config.json samt dc_sub_-Token, Newtonsoft 11.0.2) und schweigen beim Ist-Zustand. Die Namespace-Pruefung trifft bewusst nur echte using-Direktiven: im Bestand steht an vielen Stellen erklaert, WARUM System.Drawing nicht verwendet wird, und das darf keinen Fehlalarm ausloesen. Der Schwachstellen-Check ist Punkt 1 der wiederkehrenden Audit-Checkliste aus dem Sicherheitskonzept - laeuft ab jetzt bei jedem Push statt quartalsweise von Hand. Er wuerde zum Beispiel anschlagen, wenn der Newtonsoft-Pin im Core faellt. Bewusst kein -warnaserror: die 15 vorhandenen Warnungen muessten erst weg, sonst ist die CI ab dem ersten Tag rot und wird ignoriert. WICHTIG - die CI laeuft noch nicht: auf der Gitea-Instanz ist kein Actions-Runner registriert (auf Repo-, Benutzer- und Instanzebene geprueft, ueberall 0). has_actions ist true, es fehlt nur der Runner. Einrichtung Schritt fuer Schritt in docs/LEITFADEN-CI.md Abschnitt 3. .gitattributes neu: erzwingt LF fuer .yml/.sh/.service. Entwickelt wird mit autocrlf=true auf Windows, ausgefuehrt auf Linux - ein Shell-Skript mit CRLF scheitert dort mit irrefuehrenden Meldungen. Bisher gab es keine .gitattributes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
6.5 KiB
Leitfaden: Continuous Integration
Stand: 22.08.2026 · Workflow: .gitea/workflows/ci.yml
Status: Der Workflow liegt, der Runner fehlt noch. Gitea 1.26.2 hat Actions aktiviert (
has_actions: true), aber auf der Instanz ist kein einziger Runner registriert — geprüft auf Repo-, Benutzer- und Instanzebene. Bis Abschnitt 3 erledigt ist, passiert bei einem Push nichts. Der Workflow ist dann sofort lauffähig, ohne weitere Änderung.
1. Warum überhaupt
PolyTrader soll auf einem Linux-Server laufen. Der plattformneutrale Zustand wurde am
22.08.2026 mit dem WinForms-Ausbau hergestellt — und er driftet ohne Wächter wieder weg.
Eine einzige net10.0-windows-Zeile oder ein using System.Drawing genügt, und der
Linux-Build ist kaputt, ohne dass es auf einer Windows-Entwicklermaschine auffällt: dort baut
es weiter.
Genau deshalb läuft die CI auf Linux. Sie ist kein Selbstzweck, sondern die einzige Instanz, die den mühsam hergestellten Zustand verteidigt.
2. Was geprüft wird
Zwei Jobs, beide auf ubuntu-latest:
build-test — Build & Tests
| Schritt | Zweck |
|---|---|
dotnet restore |
Der lokale Feed lib/nuget (Deploymentcenter-SDK) ist relativ eingebunden und liegt im Repo — nichts einzurichten |
dotnet build -c Release |
Baut alle 7 Projekte |
dotnet test |
Die 476 Tests. Brauchen keine Datenbank — sie laufen gegen EF-InMemory |
dotnet publish -r linux-x64 |
Kein Selbstzweck: hier fällt auf, wenn ein Paket doch windows-only ist |
| Publish-Prüfung | Erwartet PolyTrader.App.Avalonia, appsettings.json, setup.json und libSkiaSharp.so — ohne die native Skia-Bibliothek wäre Avalonia auf Linux nicht lauffähig |
guard — Plattformneutralität & Hygiene
| Prüfung | Schlägt fehl bei |
|---|---|
| Zielframeworks | irgendeinem <TargetFramework>…-windows in einer .csproj |
| WinForms/WPF | <UseWindowsForms>true oder <UseWPF>true |
| Namespaces | echten using System.Windows.Forms; / using System.Drawing;-Direktiven in src/ oder tests/ |
| Secret-Dateien | deploy/packager.config.json, appsettings.Local.json, master.key, openrouter.key, .gitea-token oder server_settings.xml versioniert; oder einem Deploymentcenter-Token im Klartext |
| Schwachstellen | dotnet list package --vulnerable --include-transitive findet etwas |
Zur Namespace-Prüfung: Sie trifft bewusst nur echte using-Direktiven, keine Kommentare.
Im Bestand steht an vielen Stellen erklärt, warum System.Drawing nicht verwendet wird —
das darf keinen Fehlalarm auslösen. Beide Richtungen sind gegengeprüft.
Zum Schwachstellen-Check: Das ist Punkt 1 der wiederkehrenden Audit-Checkliste aus
sicherheit/SICHERHEITSKONZEPT.md — läuft ab jetzt bei
jedem Push statt quartalsweise von Hand. Er würde zum Beispiel anschlagen, wenn der
Newtonsoft.Json-Pin im Core entfernt wird: Nethereum 6.1.0 löst dann transitiv auf 11.0.2
auf (GHSA-5crp-9r3c-p9vr, Schweregrad hoch).
Die Warnungen des Builds (aktuell 15) lassen die CI nicht fehlschlagen.
-warnaserrorwäre hier verfrüht: die vorhandenen Warnungen müssten erst abgearbeitet werden, sonst ist die CI ab dem ersten Tag rot und wird ignoriert.
3. Runner einrichten (einmalig)
Ohne Runner führt Gitea den Workflow nicht aus. Der Runner ist ein eigenes Programm
(act_runner), das sich beim Gitea-Server meldet und Jobs abholt. Er läuft sinnvollerweise
auf dem Gitea-Host (192.168.178.10) oder jeder anderen Maschine im selben Netz, die
Docker hat.
3.1 Registrierungstoken holen
In der Weboberfläche: Repo → Einstellungen → Actions → Runner → „Runner erstellen".
Dort steht ein Token der Form …. Alternativ instanzweit unter
Website-Verwaltung → Actions → Runner, wenn der Runner mehreren Repos dienen soll —
für den Anfang genügt der Repo-Runner.
3.2 Runner per Docker starten
docker run -d --restart always \
--name gitea-runner \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /opt/gitea-runner:/data \
-e GITEA_INSTANCE_URL=http://192.168.178.10:8418 \
-e GITEA_RUNNER_REGISTRATION_TOKEN=<TOKEN_AUS_3.1> \
-e GITEA_RUNNER_NAME=polytrader-runner \
-e GITEA_RUNNER_LABELS=ubuntu-latest:docker://catthehacker/ubuntu:act-latest \
gitea/act_runner:latest
Das GITEA_RUNNER_LABELS-Feld ist der kritische Teil. Es bildet runs-on: ubuntu-latest
aus dem Workflow auf ein Container-Image ab. Fehlt das Label, bleibt der Job auf
„warten auf Runner" stehen, ohne Fehlermeldung. Das Image catthehacker/ubuntu:act-latest
bringt Node mit, das actions/checkout und actions/setup-dotnet benötigen.
Der Mount von docker.sock ist nötig, weil der Runner die Job-Container selbst startet.
3.3 Prüfen
curl -s -H "Authorization: token $(cat ~/.gitea-token)" http://192.168.178.10:8418/api/v1/repos/Richard/PolyTraderSharp/actions/runners
Steht dort "total_count": 0, hat sich der Runner nicht registriert — dann in die Logs sehen:
docker logs gitea-runner.
Danach den Workflow von Hand anstoßen: Repo → Actions → CI → „Run workflow"
(workflow_dispatch ist im Workflow vorgesehen). Der erste Lauf dauert länger, weil das
.NET-SDK heruntergeladen wird.
4. Wenn kein Internetzugang besteht
actions/setup-dotnet lädt das SDK von Microsoft. Ist der Runner offline, gibt es zwei Wege:
- Container-Image mit SDK statt
setup-dotnet— im Workflow je Job ergänzen:Dann muss dascontainer: image: mcr.microsoft.com/dotnet/sdk:10.0setup-dotnet-Steps-Paar entfallen. Achtung: Dieses Image bringt kein Node mit;actions/checkoutbraucht es. Entweder ein eigenes Image bauen (dotnet/sdk:10.0+nodejs) oder auschecken pergit clonestatt per Action. - SDK im Runner-Image vorinstallieren und
setup-dotnetweglassen.
Weg 1 mit eigenem Image ist der sauberere, sobald das Netz wirklich zu ist.
5. Was die CI (noch) nicht tut
- Kein Deployment. Die Auslieferung läuft über den Deploymentcenter-Packager
(
deploy/packager.config.json, siehe Schnitt D-4). Das bewusst nicht automatisiert, solange die Live-Abnahme aussteht. - Keine Integrationstests gegen eine echte MySQL. Die Testsuite läuft gegen EF-InMemory. Ein MySQL-Service-Container wäre der nächste sinnvolle Ausbauschritt, wenn die Repository-Schicht einmal gegen echtes SQL geprüft werden soll.
- Kein
-warnaserror. Siehe Kasten in Abschnitt 2.