diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1e9ab8b --- /dev/null +++ b/.gitattributes @@ -0,0 +1,22 @@ +# Zeilenenden +# +# Entwickelt wird auf Windows (core.autocrlf=true), ausgeführt wird auf Linux. Für die +# meisten Dateien ist das folgenlos - für die unten aufgeführten nicht: ein Shell-Skript +# oder eine systemd-Unit mit CRLF scheitert auf Linux mit irreführenden Meldungen +# ("command not found" für einen Befehl, der sichtbar dasteht - das \r gehört noch dazu). +# Deshalb wird für diese Dateien LF erzwungen, unabhängig von der lokalen Git-Konfiguration. + +# Standard: Git entscheidet, im Repo immer LF +* text=auto + +# Muss im Arbeitsverzeichnis LF bleiben - wird auf Linux ausgeführt +*.yml text eol=lf +*.yaml text eol=lf +*.sh text eol=lf +*.service text eol=lf + +# Binärdateien nicht anfassen +*.png binary +*.ico binary +*.nupkg binary +*.pdf binary diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..770e54f --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,159 @@ +name: CI + +# Wozu diese CI da ist: +# PolyTrader läuft künftig auf einem Linux-Server. Der plattformneutrale Zustand ist am +# 22.08.2026 mühsam hergestellt worden (WinForms-Ausbau) und driftet ohne Wächter wieder weg — +# eine einzige `net10.0-windows`-Zeile oder ein `using System.Drawing` genügt, und der +# Linux-Build ist still kaputt. Genau das fängt der "guard"-Job ab, und zwar auf Linux, +# nicht auf einer Windows-Entwicklermaschine, auf der es zufällig weiter baut. + +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + +env: + DOTNET_NOLOGO: "true" + DOTNET_CLI_TELEMETRY_OPTOUT: "true" + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: "true" + +jobs: + + build-test: + name: Build & Tests (Linux) + runs-on: ubuntu-latest + steps: + - name: Quellcode holen + uses: actions/checkout@v4 + + - name: .NET SDK einrichten + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.0.x' + + - name: Pakete wiederherstellen + # Der lokale Feed lib/nuget (Deploymentcenter.Client) ist in NuGet.Config relativ + # eingebunden und liegt im Repo - hier ist also nichts zusätzlich einzurichten. + run: dotnet restore PolyTraderSharp.sln + + - name: Bauen + run: dotnet build PolyTraderSharp.sln --configuration Release --no-restore + + - name: Tests + run: dotnet test tests/PolyTrader.Tests/PolyTrader.Tests.csproj --configuration Release --no-build --verbosity normal + + - name: Linux-Publish (Nachweis der Lauffähigkeit) + # Kein Selbstzweck: hier fällt auf, wenn ein Paket doch windows-only ist. + run: dotnet publish src/PolyTrader.App.Avalonia/PolyTrader.App.Avalonia.csproj --configuration Release --runtime linux-x64 --self-contained false --output ./artifacts/linux-x64 + + - name: Publish-Ergebnis prüfen + run: | + set -e + cd ./artifacts/linux-x64 + for f in PolyTrader.App.Avalonia PolyTrader.App.Avalonia.dll appsettings.json setup.json; do + if [ ! -f "$f" ]; then + echo "FEHLER: '$f' fehlt im Linux-Publish." + exit 1 + fi + done + # Die nativen Skia-/HarfBuzz-Bibliotheken müssen die Linux-Fassung sein. + if ! ls libSkiaSharp.so >/dev/null 2>&1; then + echo "FEHLER: libSkiaSharp.so fehlt - Avalonia wäre auf Linux nicht lauffähig." + exit 1 + fi + echo "Linux-Publish vollständig ($(ls | wc -l) Dateien)." + + guard: + name: Plattformneutralität & Hygiene + runs-on: ubuntu-latest + steps: + - name: Quellcode holen + uses: actions/checkout@v4 + + - name: .NET SDK einrichten + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.0.x' + + - name: Keine windows-spezifischen Zielframeworks + run: | + set -e + treffer=$(grep -rn -E "[^<]*-windows" --include="*.csproj" . || true) + if [ -n "$treffer" ]; then + echo "FEHLER: windows-spezifisches Zielframework gefunden:" + echo "$treffer" + echo "" + echo "PolyTrader ist seit dem 22.08.2026 plattformneutral. Siehe docs/PROJEKTSTAND.md." + exit 1 + fi + echo "OK - alle Projekte sind plattformneutral." + + - name: Kein WinForms/WPF + run: | + set -e + treffer=$(grep -rn -E "<(UseWindowsForms|UseWPF)>\s*true" --include="*.csproj" . || true) + if [ -n "$treffer" ]; then + echo "FEHLER: WinForms/WPF wurde wieder eingeschaltet:" + echo "$treffer" + exit 1 + fi + echo "OK - kein WinForms/WPF." + + - name: Keine windows-only Namespaces im Code + run: | + set -e + # Nur echte using-Direktiven, keine Kommentare - die erklären im Bestand + # bewusst, WARUM etwas nicht verwendet wird. + treffer=$(grep -rn -E "^\s*using\s+System\.(Windows\.Forms|Drawing)\s*;" --include="*.cs" src/ tests/ || true) + if [ -n "$treffer" ]; then + echo "FEHLER: windows-only Namespace eingebunden:" + echo "$treffer" + echo "" + echo "System.Drawing.Common ist seit .NET 7 Windows-only und wirft auf Linux." + exit 1 + fi + echo "OK - keine windows-only Namespaces." + + - name: Keine Secret-Dateien versioniert + run: | + set -e + # Diese Dateien enthalten echte Zugangsdaten und gehören nie ins Repo. + # packager.config.json trägt FTP-Passwort und updateservice:publish-Token. + verboten="deploy/packager.config.json appsettings.Local.json master.key openrouter.key .gitea-token server_settings.xml" + fehler=0 + for f in $verboten; do + if git ls-files --error-unmatch "$f" >/dev/null 2>&1; then + echo "FEHLER: '$f' ist versioniert - enthält Zugangsdaten." + fehler=1 + fi + done + # Zusätzlich: Deploymentcenter-Tokens im Klartext irgendwo in versionierten Dateien. + # Die Plandokumente kürzen Tokens bewusst mit "…" ab, echte sind 40+ Zeichen. + if git grep -nE "dc_(sub|master)_[0-9a-f]{40,}" -- . >/dev/null 2>&1; then + echo "FEHLER: Deploymentcenter-Token im Klartext gefunden:" + git grep -nE "dc_(sub|master)_[0-9a-f]{40,}" -- . + fehler=1 + fi + if [ "$fehler" -ne 0 ]; then + echo "" + echo "Diese Dateien gehören in .gitignore, nicht ins Repo." + exit 1 + fi + echo "OK - keine Secret-Dateien versioniert." + + - name: Pakete auf bekannte Schwachstellen prüfen + # Punkt 1 der wiederkehrenden Audit-Checkliste aus docs/sicherheit/SICHERHEITSKONZEPT.md. + # Läuft ab jetzt bei jedem Push statt nur quartalsweise von Hand. + run: | + set -e + dotnet restore PolyTraderSharp.sln + ausgabe=$(dotnet list PolyTraderSharp.sln package --vulnerable --include-transitive) + echo "$ausgabe" + if echo "$ausgabe" | grep -qE "^\s+>\s"; then + echo "" + echo "FEHLER: anfällige Pakete gefunden (siehe oben)." + exit 1 + fi + echo "OK - keine anfälligen Pakete." diff --git a/docs/LEITFADEN-CI.md b/docs/LEITFADEN-CI.md new file mode 100644 index 0000000..79769be --- /dev/null +++ b/docs/LEITFADEN-CI.md @@ -0,0 +1,133 @@ +# Leitfaden: Continuous Integration + +**Stand: 22.08.2026** · Workflow: [`.gitea/workflows/ci.yml`](../.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 `…-windows` in einer `.csproj` | +| WinForms/WPF | `true` oder `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`](./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. `-warnaserror` +> wä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 + +```bash +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= \ + -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 + +```bash +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: + +1. **Container-Image mit SDK** statt `setup-dotnet` — im Workflow je Job ergänzen: + ```yaml + container: + image: mcr.microsoft.com/dotnet/sdk:10.0 + ``` + Dann muss das `setup-dotnet`-Steps-Paar entfallen. **Achtung:** Dieses Image bringt kein + Node mit; `actions/checkout` braucht es. Entweder ein eigenes Image bauen + (`dotnet/sdk:10.0` + `nodejs`) oder auschecken per `git clone` statt per Action. +2. **SDK im Runner-Image vorinstallieren** und `setup-dotnet` weglassen. + +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. diff --git a/docs/PROJEKTSTAND.md b/docs/PROJEKTSTAND.md index dbd1697..4adbd53 100644 --- a/docs/PROJEKTSTAND.md +++ b/docs/PROJEKTSTAND.md @@ -114,7 +114,7 @@ etwas anderes: | Punkt | Details | |---|---| -| **Keine CI** | Weder `.github/workflows` noch `.gitea/workflows` — es existiert keinerlei Automatisierung. Build und Tests laufen ausschließlich von Hand. **Der größte strukturelle Mangel** | +| **CI: Workflow da, Runner fehlt** | [`.gitea/workflows/ci.yml`](../.gitea/workflows/ci.yml) ist angelegt (Build + 476 Tests + Linux-Publish auf Linux, dazu Wächter gegen windows-spezifische Rückfälle, versionierte Secrets und anfällige Pakete). **Auf der Gitea-Instanz ist aber kein Runner registriert** — geprüft auf Repo-, Benutzer- und Instanzebene. Bis der Runner steht, läuft der Workflow nicht. Einrichtung: [LEITFADEN-CI.md](./LEITFADEN-CI.md) §3 | | **15 Build-Warnungen** | Alle im Avalonia-Projekt: 13 × `CS8618` (Felder in Fenster-Konstruktoren), 1 × `CS8848` (Vorrang bei `switch`), 1 × `CS8602` (möglicher Nullverweis in `PdfExporter.cs:40`). Die letzten beiden sind einen Blick wert | | **TerminalLogger** | Stempelt mit `DateTime.Now` statt der konfigurierten `AppTimeZone`. Auf einem UTC-Linuxserver passen Logdatei-Grenzen nicht zur angezeigten Uhrzeit. Umstellung auf `Microsoft.Extensions.Logging` steht ohnehin aus | | **God-Methoden** | `PollLiveAccountsAsync`, `ProcessAccountOrderAsync`; duplizierte Closed-Trade-Erzeugung (Phase 7) | @@ -173,6 +173,7 @@ gekennzeichnet, `ANALYSE-Linux-Portierung.md` steht auf Revision 6. | `PROJEKTSTAND.md` | **Dieses Dokument** — Einstieg und Gesamtüberblick | | `ANALYSE-Linux-Portierung.md` | Rahmen der Linux-Fähigkeit, Fahrplan P1–P11 / L1–L5 | | `LEITFADEN-Avalonia-Portierung.md` | Arbeitsregeln für die Oberfläche. **Vor jeder UI-Arbeit lesen** | +| `LEITFADEN-CI.md` | Was die CI prüft und wie der Gitea-Runner eingerichtet wird | | `UI-SPEZIFIKATION-WinForms.md` | Beschreibung der alten Oberfläche — Vergleichsvorlage für A5 | | `umsetzungsplaene/` | Detailpläne je Vorhaben | | `konzepte/` | Vorhaben ohne Umsetzungsplan | @@ -188,8 +189,9 @@ gekennzeichnet, `ANALYSE-Linux-Portierung.md` steht auf Revision 6. 1. **A5 durchklicken** — die Oberfläche mit echten Daten abnehmen. Blockiert nichts technisch, ist aber die letzte offene Zusage der UI-Portierung. -2. **CI aufsetzen** — der größte strukturelle Mangel. Ein Workflow, der `dotnet build` und - `dotnet test` auf Linux fährt, hätte den plattformneutralen Zustand von allein gehalten. +2. **CI scharf schalten** — der Workflow liegt, es fehlt nur der Runner (etwa 10 Minuten, + siehe [LEITFADEN-CI.md](./LEITFADEN-CI.md) §3). Erst dann hält der plattformneutrale + Zustand von allein; bis dahin ist er nur eine Momentaufnahme. 3. **Deploymentcenter live abnehmen** — danach können die Altdienste abgeschaltet werden, womit zwei Sicherheits-Auflagen von selbst entfallen. 4. **Erst dann neue Module.** MarketMaking und BundleArbitrage sind fertig geplant und diff --git a/docs/README.md b/docs/README.md index 4a7240a..1e4c4bf 100644 --- a/docs/README.md +++ b/docs/README.md @@ -12,7 +12,8 @@ durch die Detailpläne zu lesen. Daneben liegen im Wurzelverzeichnis dieses Ordners drei querschnittliche Dokumente: `ANALYSE-Linux-Portierung.md` (Rahmen und Fahrplan der Plattformneutralität), -`LEITFADEN-Avalonia-Portierung.md` (**Arbeitsregeln — vor jeder UI-Arbeit lesen**) und +`LEITFADEN-Avalonia-Portierung.md` (**Arbeitsregeln — vor jeder UI-Arbeit lesen**), +`LEITFADEN-CI.md` (was die CI prüft und wie der Gitea-Runner eingerichtet wird) und `UI-SPEZIFIKATION-WinForms.md` (Beschreibung der abgelösten Oberfläche, Vergleichsvorlage für die Abnahme A5).