# Linux-Testumgebung (gemeinsam genutzte VM) **Stand: 26.08.2026** · Eingerichtet beim ersten Linux-Lauf von PolyTrader (Roadmap A4a). > **Diese Anleitung gilt projektübergreifend.** Sie richtet sich an alle Agenten und Entwickler, > die auf der VM testen — nicht nur an PolyTrader. Die maßgebliche Fassung liegt auf der Maschine > selbst unter **`~/TESTUMGEBUNG.md`**; dieses Dokument im PolyTrader-Repo ist die versionierte > Kopie. Wer etwas an der Umgebung ändert, zieht **beide** nach. --- ## 1. Was diese Maschine ist Eine Ubuntu-Desktop-VM zum **Testen** — nicht für Produktivbetrieb, nicht für echte Zugangsdaten, nicht für Geld bewegende Läufe. | | | |---|---| | System | Ubuntu 26.04 LTS, Kernel 7.0, x86_64 | | Ausstattung | 31 GB RAM, 5 CPUs, ~33 GB freier Plattenplatz | | Erreichbar | `192.168.40.48` über einen WireGuard-Tunnel | | Benutzer | `richard` | | Besonderheit | **Desktop-Umgebung vorhanden** — grafische Anwendungen sind testbar, nicht nur Dienste | **Warum eine Desktop-VM?** Weil sich damit beides prüfen lässt: der kopflose Serverbetrieb (systemd) *und* die grafische Oberfläche auf der Zielplattform. --- ## 2. Zugang einrichten Der Zugang läuft über **SSH-Schlüssel**. Passwort-Anmeldung wird nicht verwendet — Agenten geben grundsätzlich keine Passwörter ein. ### 2.1 Schlüssel erzeugen (auf dem eigenen Rechner) ```bash ssh-keygen -t ed25519 -f ~/.ssh/testvm_ -N "" -C "@testvm" ``` Ein **eigener Schlüssel je Projekt** — dann lässt sich einzelnen Projekten der Zugang entziehen, ohne alle anderen auszusperren. ### 2.2 Öffentlichen Schlüssel hinterlegen Der Inhalt von `~/.ssh/testvm_.pub` wird auf der VM in `~/.ssh/authorized_keys` eingetragen. **Das muss ein Mensch tun** (einmalig, mit Passwort). Direkt auf der VM: ```bash mkdir -p ~/.ssh && chmod 700 ~/.ssh && echo '' >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys ``` ### 2.3 SSH-Konfiguration (auf dem eigenen Rechner) ``` Host testvm HostName 192.168.40.48 User richard IdentityFile ~/.ssh/testvm_ IdentitiesOnly yes ServerAliveInterval 30 ServerAliveCountMax 4 ``` ⚠️ **Kein `ControlMaster`/`ControlPath` eintragen, wenn der Client unter Windows läuft** — Windows-OpenSSH unterstützt Verbindungs-Multiplexing nicht und scheitert mit „Failed to connect to new control master". Stattdessen mehrere Prüfschritte pro Aufruf bündeln. Test: `ssh testvm "hostname"` --- ## 3. Was installiert ist | Werkzeug | Version | Anmerkung | |---|---|---| | .NET SDK | 10.0.111 (Runtime 10.0.11) | SDK, nicht nur Runtime — auf der VM kann gebaut werden | | MariaDB | 11.8.6 | Dienst `mariadb`, lauscht auf `localhost:3306` | | Git | 2.53.0 | | | Xvfb | vorhanden | Virtueller Framebuffer für GUI-Tests ohne Bildschirm (siehe 4.7) | | xdotool | vorhanden | Klicks und Tastatureingaben skripten | | ImageMagick | vorhanden | `import` für Bildschirmaufnahmen, `convert` zum Zuschneiden | | JetBrains Rider | vorhanden | | | Docker | **nicht** installiert | | | Node.js | **nicht** installiert | | **Nicht vorhandene Werkzeuge dürfen installiert werden** — aber bitte in der Belegungsliste (Abschnitt 6) vermerken, damit andere wissen, was sich geändert hat. --- ## 4. Konventionen für mehrere Projekte Die Maschine wird von mehreren Projekten geteilt. Diese Regeln verhindern, dass sich Tests gegenseitig zerstören: ### 4.1 Datenbanken — je Projekt eine eigene **Niemals** eine fremde Datenbank mitbenutzen und **niemals** eine Produktivdatenbank verbinden. ```bash # Passwort erzeugen und ablegen (nur für den Besitzer lesbar) PW=$(openssl rand -base64 18 | tr -d "/+=" | head -c 20) echo "$PW" > ~/._test_dbpw && chmod 600 ~/._test_dbpw sudo mariadb -e "CREATE DATABASE IF NOT EXISTS _test CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER IF NOT EXISTS '_test'@'localhost' IDENTIFIED BY '$PW'; GRANT ALL PRIVILEGES ON _test.* TO '_test'@'localhost'; FLUSH PRIVILEGES;" ``` | Was | Schema | Beispiel | |---|---|---| | Datenbank | `_test` | `polytrader_test` | | Benutzer | `_test`@`localhost` | `polytrader_test` | | Passwortdatei | `~/._test_dbpw` (Rechte 600) | | Die Rechte enden **an der eigenen Datenbank** — `GRANT ALL ON _test.*`, nie global. ### 4.2 Verzeichnisse | Zweck | Ort | |---|---| | Quellcode | `~/RiderProjects/` | | Publish/Testlauf im Benutzerkontext | `~/-test` | | Installation als Dienst | `/opt/` | ### 4.3 systemd-Dienste Unit-Name = Projektname: `.service`. Eigenes Dienstkonto je Projekt: ```bash sudo useradd --system --home-dir /opt/ --shell /usr/sbin/nologin ``` Nach dem Test **abschalten** (Abschnitt 7) — sonst laufen irgendwann fünf Dienste, die niemand mehr zuordnen kann, und der nächste Test misst gegen fremde Last. ### 4.4 Ports Vor dem Belegen prüfen: `ss -tlnp`. Belegte Ports stehen in Abschnitt 6. Wer einen Port dauerhaft belegt, trägt ihn dort ein. ### 4.5 Erhöhte Rechte `sudo` verlangt normalerweise ein Passwort. Für Testläufe kann es befristet freigeschaltet werden (**ein Mensch, einmalig**): ```bash echo "richard ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/99-testing && sudo chmod 440 /etc/sudoers.d/99-testing ``` **Nach Abschluss wieder entfernen:** ```bash sudo rm /etc/sudoers.d/99-testing ``` Das hebt den Schutz für das Konto vollständig auf — vertretbar auf einer Test-VM hinter VPN, aber nicht dauerhaft und niemals auf einer Produktivmaschine. ### 4.6 GUI-Anwendungen ohne Bildschirm testen Braucht eine Anwendung X11, scheitert sie über SSH mit `XOpenDisplay failed`. Für einen einzelnen Durchlauf genügt: ```bash xvfb-run -a ./MeineAnwendung --irgendein-schalter ``` ### 4.7 Oberflächen selbst begutachten — ohne Bildschirm, ohne fremde Hilfe **Ein Agent kann die Oberfläche eigenständig prüfen.** Kein Mensch muss am Bildschirm sitzen und Bildschirmfotos schicken. Das Verfahren hat sich am 26.08.2026 bewährt und **sieben Befunde zutage gefördert**, darunter einen, der sämtliche Tabellen der Anwendung unsichtbar machte. Drei Werkzeuge, alle installiert: **Xvfb** (virtuelles Display), **xdotool** (Klicken und Tippen), **ImageMagick** (`import` für Aufnahmen, `convert` zum Zuschneiden). Anders als `xvfb-run` wird das Display hier **dauerhaft** gestartet, damit sich zwischen den Aufnahmen navigieren lässt: ```bash #!/bin/bash cd ~/-test export DISPLAY=:99 pkill -f "Xvfb :99" 2>/dev/null; sleep 1 Xvfb :99 -screen 0 1600x1000x24 >/dev/null 2>&1 & sleep 3 nohup ./MeineAnwendung > /tmp/gui.log 2>&1 & APP=$! sleep 25 # Startzeit großzügig bemessen # Fenster-ID ermitteln (bestaetigt, dass die Oberflaeche ueberhaupt erscheint) xdotool search --name "^MeinFenstertitel$" | head -1 # navigieren und aufnehmen shoot() { sleep 5; import -window root /tmp/v_$1.png; } shoot 1_start xdotool mousemove 127 205 click 1; shoot 2_zweite_ansicht xdotool mousemove 127 237 click 1; shoot 3_dritte_ansicht kill $APP 2>/dev/null; sleep 2; pkill -f "Xvfb :99" 2>/dev/null ``` Danach die Bilder abholen und ansehen: ```bash scp testvm:'/tmp/v_*.png' . ``` **Was sich dabei bewährt hat:** - **Großzügige Wartezeiten.** 25 Sekunden nach dem Start, 5 Sekunden nach jedem Klick. Wird zu früh aufgenommen, entsteht ein halb gezeichnetes Fenster, und man sucht Fehler, die keine sind. - **Klickpunkte aus dem ersten Bild ablesen.** Erst eine Aufnahme machen, dort die Koordinaten der Menüpunkte bestimmen, dann das Skript damit bestücken. - **Details vergrößern statt raten.** Bei einem Verdacht den Ausschnitt herausschneiden: ```bash convert v_1_start.png -crop 560x130+265+540 +repage -resize 200% /tmp/detail.png ``` - **Kontraste nachmessen statt schätzen.** Ob Text lesbar ist, lässt sich ausrechnen — Pixelfarben auslesen und das WCAG-Verhältnis bestimmen (4,5:1 für normalen Text). So wird aus „wirkt blass" ein belegter Befund. - **Nur eine Instanz gleichzeitig.** Läuft der systemd-Dienst noch, schreiben zwei Prozesse in dieselbe Datenbank und es entstehen Fehler, die nichts mit der Oberfläche zu tun haben. Vorher `sudo systemctl stop `. - **Auf Zeichen achten, die falsch aussehen.** Fehlt eine Icon-Schriftart, ersetzt Fontconfig sie stillschweigend durch etwas anderes — ein Kalendersymbol wird dann zu einer sinnlosen Zahl. Das fällt nur im Bild auf, nie im Log. Für einen Test **mit echtem Bildschirm** kann trotzdem jemand am Desktop der VM sitzen (oder RDP nutzen, Port 3389 ist offen) — nötig ist es für die Sichtprüfung nicht. --- ## 5. Was hier nicht passieren darf 1. **Keine Produktivdatenbank verbinden.** Hintergrunddienste schreiben oft ungefragt — bei PolyTrader etwa synchronisiert der `MarketSyncService` selbständig Marktdaten. 2. **Keine echten Handels-/Zugangsdaten hinterlegen.** Keine privaten Schlüssel, keine Live-API-Zugänge, keine Lizenzschlüssel für Produktivsysteme. 3. **Keine fremden Projektverzeichnisse oder Datenbanken anfassen.** 4. **Nichts Dauerhaftes hinterlassen**, was nicht in Abschnitt 6 steht. --- ## 6. Belegung (bei Änderungen fortschreiben) **Datenbanken** | Datenbank | Benutzer | Projekt | seit | |---|---|---|---| | `polytrader_test` | `polytrader_test`@localhost | PolyTrader | 26.08.2026 | **Dienste** | Unit | Konto | Verzeichnis | Projekt | seit | |---|---|---|---|---| | `polytrader.service` | `polytrader` | `/opt/polytrader` | PolyTrader | 26.08.2026 | **Ports** (Stand 26.08.2026) | Port | Belegt durch | |---|---| | 22 | SSH | | 3306 | MariaDB (nur localhost) | | 3389 | RDP | | 5000 | vorhandener Dienst (nur IPv6-localhost) | | 631 | CUPS | **Nachträglich installiert:** MariaDB 11.8.6, Xvfb, xdotool, ImageMagick, x11-utils (alle am 26.08.2026 für PolyTrader). --- ## 7. Aufräumen nach dem Test ```bash # Dienst abschalten und entfernen sudo systemctl disable --now sudo rm -f /etc/systemd/system/.service /etc/logrotate.d/ sudo systemctl daemon-reload # Dateien sudo rm -rf /opt/ ~/-test sudo userdel # Datenbank (nur wenn nicht mehr gebraucht) sudo mariadb -e "DROP DATABASE _test; DROP USER '_test'@'localhost';" rm -f ~/._test_dbpw # sudo-Freigabe zurücknehmen sudo rm -f /etc/sudoers.d/99-testing ``` Danach Abschnitt 6 nachziehen. --- ## 8. Bekannte Einschränkungen - **Claude Code lässt sich auf dieser VM nicht betreiben.** Es blockiert die Maschine bis zum Neustart; mehrere Reparaturversuche waren erfolglos, es wird auf ein Update gewartet. Agenten arbeiten deshalb **über SSH von außen**. (Speichermangel ist **nicht** die Ursache — die Maschine hat 31 GB, davon 25 GB frei.) - **Verbindungs-Multiplexing funktioniert nicht mit Windows-OpenSSH** (siehe 2.3). - **Die Systemzeitzone ist Testgegenstand.** Für realistische Servertests wird sie zeitweise auf UTC gestellt (`sudo timedatectl set-timezone UTC`). Wer sie ändert, stellt sie danach zurück — Standard hier ist `Europe/Berlin`.