diff --git a/essays/agentic-coding-repeated-review-cycles.md b/essays/agentic-coding-repeated-review-cycles.md new file mode 100644 index 0000000..7935420 --- /dev/null +++ b/essays/agentic-coding-repeated-review-cycles.md @@ -0,0 +1,159 @@ +--- +title: "Agentic Coding Requires Repeated Review Cycles to Mitigate Blind Spots" +slug: "agentic-coding-repeated-review-cycles" +originally_published: "2026-02-17" +updated: "2026-05-10" +status: "current" +topics: + - ai-assisted-development + - engineering-governance + - review-discipline +summary: "Coding agents prioritize rather than execute fixed checklists, so a single review pass leaves blind spots. Repeated, focused review cycles — at least three passes with different risk lenses — are a cheap, effective mitigation that turns probabilistic generation into reliable engineering." +lang: "en" +license: "CC-BY-4.0" +--- + +## TL;DR + +- Coding agents make decisions. They don't execute fixed checklists. +- Because they prioritize, they will miss things. +- One review pass is not enough. +- Repeated and focused review prompts dramatically reduce blind spots. +- **"Review at least 3 times"** is a simple but effective mitigation. + +If you skip structured review cycles, you are optimizing for speed over reliability. + +--- + +## The Core Problem + +A static script follows instructions. +A coding agent interprets them. + +That means it: + +- Decides what is important. +- Decides what is "probably not required." +- Compresses reasoning. +- Makes trade-offs. + +Those trade-offs are not always correct. + +Agents don't "forget" steps. They deprioritize them. + +--- + +## Why One Review Is Not Enough + +An agent review is also probabilistic. + +If you ask: + +> "Review the implementation." + +You get one prioritization pass. + +Blind spots remain because: + +- Attention is focused on dominant concerns. +- Secondary risks get compressed away. +- Ambiguities are resolved silently. + +A second and third pass shifts attention. That alone increases issue coverage significantly. + +Repetition reduces blind spots. + +--- + +## Agent Review vs Checklist Review + +**Checklist / static analysis** + +- Deterministic. +- Good for compliance and style. +- Cannot reason about architecture or intent. + +**Agent review** + +- Reinterprets requirements. +- Evaluates trade-offs. +- Identifies missing abstractions. +- But can miss things for the same reason generation did. + +They are complementary. Not interchangeable. + +--- + +## Why Agents Miss Things + +Common patterns: + +- Over-optimization for the main goal ("feature works"). +- Assumptions about context ("validation handled elsewhere"). +- Silent scope narrowing. +- Defaulting to familiar but slightly outdated patterns. + +This is expected behavior in any system that optimizes. + +--- + +## Simple Mitigations That Work + +You don't need complex orchestration. + +### 1. Force multiple passes + +Example: + +``` +Review at least 3 times. +Each pass must identify new issues. +Do not repeat prior findings. +Focus on different risk categories. +``` + +This alone increases depth. + +### 2. Use focused review prompts + +Examples: + +- "Perform a strict security review." +- "Perform a modernization review." +- "Review for architectural consistency." +- "Review for hidden coupling." +- "Review for testability gaps." + +You are guiding attention, not increasing intelligence. + +### 3. Separate generation from review + +Bad pattern: + +- Generate. +- "Looks good?" + +Better pattern: + +- Generate. +- Critical review. +- Refactor. +- Focused review. +- Finalize. + +--- + +## Hard Truth + +If you use agentic coding without repeated review cycles: + +- You are trading reliability for speed. +- You are increasing silent technical debt. +- You are relying on optimistic interpretation. + +The model is not the risk. +The missing review discipline is. + +--- + +*Originally published as an internal Netresearch wiki article in February 2026. Republished here lightly edited for public context.* diff --git a/essays/php-ffi-was-warum-wann.md b/essays/php-ffi-was-warum-wann.md new file mode 100644 index 0000000..f9df87f --- /dev/null +++ b/essays/php-ffi-was-warum-wann.md @@ -0,0 +1,379 @@ +--- +title: "PHP FFI – was, warum, wann?" +slug: "php-ffi-was-warum-wann" +originally_published: "2025-11" +updated: "2026-05-10" +status: "current" +topics: + - php + - rust + - ffi + - performance-engineering + - language-fundamentals +summary: "Wann sich PHP FFI lohnt – am Beispiel eines XLIFF-Imports, der von ORM (~1.400/s) über DBAL Bulk (~5–7k/s) auf eine All-in-Rust-Variante via FFI (~35.320/s) skaliert wird." +lang: "de" +license: "CC-BY-4.0" +--- + +PHP FFI ist das unscheinbare Werkzeug, das den Elefanten aus seinem Gehege lässt. Statt umständlich über Extensions oder unhandliche C-Wrapperschichten zu gehen, öffnet FFI eine direkte Tür zu nativen Bibliotheken. Bedeutet: Performance, wo man sie braucht. Kontrolle, wenn sie zählt. Und Freiheit, ohne jedes Mal einen kompletten Build-Prozess anzuschmeißen. + +Nutzen? Immer dann, wenn: + +- PHP zu langsam ist, +- ein bestehender High-Performance-Code existiert, +- Low-Level-Operationen gefragt sind, +- oder wenn man schlicht Spaß daran hat, sich neue Möglichkeiten im PHP-Ökosystem zu erschließen. + + + +--- + +## Was ist Rust? + +Rust ist die Programmiersprache, die Entwickler zurücklässt mit dem Gefühl: „Warum habe ich das nicht früher benutzt?" Sie kombiniert: + +- **Performance** auf C/C++-Niveau, +- **Speichersicherheit** ohne Garbage Collector, +- **Null-Cost Abstractions**, +- ein Tooling, das einfach funktioniert, +- und eine Community, die Qualität liebt. + +Rust zwingt dich, gute Entscheidungen zu treffen – und belohnt dich mit Geschwindigkeit und Robustheit, die man sonst nur durch jahrelange Feinmechanik erreicht. + + + +--- + +## Ausgangssituation: langsamer Import einer Übersetzungs-Datenbank via ORM + +Importprozesse über ein ORM sind bequem. Lesbar. Stabil. Aber eben auch: langsam. Besonders wenn fünf- oder sechsstellige Datensätze hereinschneien und jede Instanz einzeln über das ORM geschoben wird. + +Das Setup: ein klassischer XLIFF-Import in eine TYPO3-Übersetzungs-Datenbank. Viele Datensätze. Viel Overhead. Viel Geduld. + +Die Herausforderung: nicht warten wollen. + +--- + +## Zwischenstufe: direkter Import via DBAL Bulk Operations + +Bevor eskaliert wird, fair bleiben. DBAL Bulk Operations sind bereits ein ordentlicher Performance-Booster. Weniger Overhead, weniger Magie, mehr Durchsatz. + +Vergleichbar mit: gleiche Strecke, aber statt Familienkombi jetzt ein solider Turbo-Diesel. + +Beispielhafte Umsetzung als Pull Request: + +Gut? Ja. Schnell? Auch. Aber warum hier aufhören? + +--- + +## Ziel/Experiment: Import mittels PHP FFI und Rust + +Jetzt wird's spannend. Die Idee: Die wirklich harte Arbeit – Parsing, Validierung, Strukturierung, Batch-Verarbeitung – wird von Rust erledigt. PHP orchestriert nur noch. + +PHP ruft genau **eine** FFI-Funktion auf: `xliff_import_file_to_db()`. Diese Funktion läuft komplett in Rust: XLIFF einlesen, parsen, validieren, Bulk-Lookups und Bulk-INSERT/UPDATE in der Datenbank. PHP sieht davon nur noch eine kompakte Statistik (Anzahl Inserts/Updates/Fehler, Laufzeit) und kümmert sich um UI, Logging und Fehlerkommunikation. + +Beispielhafte Umsetzung als Pull Request: + +Klingt ungewöhnlich? Ist es. Macht es Spaß? Definitiv. + +--- + +## Ergebnisse: ORM vs. DBAL Bulk vs. PHP FFI + Rust + +### Performance im Vergleich + +``` +Datensätze pro Sekunde + +ORM | ████▌ | ~1.400/s +DBAL Bulk | ██████████████▌ | ~5.000–7.000/s +Rust (FFI) | ██████████████████████████▌ | ~35.320/s +``` + +### Laufzeitvergleich + +``` +Gesamtzeit für 419.428 Einträge + +Rust (FFI) | ██ | 11,88 s +DBAL Bulk | ████████████ | 60–80 s +ORM | ████████████████████████████ | 300+ s +``` + +### Pipeline-Flow (Import-Prozess) + +``` +PHP → FFI → Rust + ↓ + [Parsing] + ↓ + [Existing-Key-Lookup] + ↓ + [Batch Builder] + ↓ + [Bulk INSERT/UPDATE] + ↓ + [Stats zurück an PHP] +``` + +**Datengrundlage** + +- XLIFF-Datei mit 419.428 Übersetzungseinträgen +- identische Umgebung für alle drei Varianten + +**Gemessene Laufzeiten und Durchsatz** + +- **Variante 1 – klassisches ORM** (Stand vor Optimierung) + - ~300+ Sekunden Gesamtzeit + - ~1.400 Datensätze/Sekunde + - sauber, aber massiv überlastet durch Hydration, Events & Kontextverwaltung. +- **Variante 2 – PHP DBAL Bulk** + - ~60–80 Sekunden + - ~5.000–7.000 Datensätze/Sekunde + - je nach Umgebung und Dateigröße 6–33x schneller als das ORM; Architektur bleibt komplett in PHP, aber mit klar getrenntem Bulk-Pfad. +- **Variante 3 – All-in-Rust via PHP FFI** + - 11,88 Sekunden Gesamtzeit + - 35.320 Datensätze/Sekunde + - ca. 25x schneller als die ursprüngliche ORM-Implementierung und typischerweise 5–6x schneller als die DBAL-Bulk-Variante. + +**Zeitanteile in der Rust-Variante (419k Datensätze)** + +- Parsing: ~0,48 s (~4 %) +- Konvertierung/Mapping: ~0,18 s (~1,5 %) +- DB-Import: ~11,2 s (~94 %) + +Die Parse-Phase ist damit praktisch „aus der Gleichung raus" – der Flaschenhals ist ausschließlich noch die Datenbank-I/O. Genau dort will man bei solchen Workloads am Ende ankommen. + +--- + +## Technische Details + +### Timeline der Optimierungsphasen + +``` +─────────────┬────────────────────┬────────────────────────────────────── + │ │ + Phase 1 │ Phase 2 │ Phase 3 + ORM │ DBAL Bulk │ All-in-Rust via FFI + │ │ + langsam │ 6–33x schneller │ >25x schneller vs ORM + │ │ Parsing: <0,5 s statt 45 s +``` + +### Zeitanteile im Rust-Import + +``` +Parsing | █ | 0,48 s (~4 %) +Mapping | █ | 0,18 s (~1,5 %) +DB-Import | ███████████████████ | 11,2 s (~94 %) +``` + +### Batch-Größen und SQL-Reduktion + +``` +419.428 Einträge + ↓ +~700–900 UPDATE-Batches (CASE-WHEN) + ↓ +~400 INSERT-Batches +``` + +--- + +### Architekturvergleich + +| Eigenschaft | ORM | DBAL Bulk | Rust FFI | +| ----------------- | ----------- | -------------- | ----------------------------------- | +| Performance | langsam | mittel | extrem schnell | +| Sicherheit | ok | ok | speichersicher (Rust) | +| Code-Komplexität | niedrig | mittel | höher (zwei Sprachen) | +| Deploy-Aufwand | niedrig | niedrig | einmaliger Build der `.so` | +| Debuggability | hoch | hoch | mittel (Rust-Compiler hilft viel) | +| Skalierung | schlecht | gut | exzellent | +| DB-Last | hoch | mittel | optimal (Batches) | + +### Architektur „All-in-Rust" + +- zentrales Entry-Point in Rust: `xliff_import_file_to_db()` als `extern "C"` exportiert +- PHP erstellt eine FFI-Binding-Signatur und übergibt: + - Pfad zur XLIFF-Datei, + - DB-Konfiguration (Host, Port, Benutzer, Passwort, DB-Name …), + - Environment/Language-Kontext, + - eine Stats-Struktur, die von Rust gefüllt wird (`inserted`, `updated`, `errors`, `duration`). +- Rust übernimmt den kompletten Import: + 1. Datei streamend lesen (1-MB-Puffer statt kleiner Standard-Buffer), + 2. XLIFF parsen und normalisieren, + 3. bestehende Übersetzungen in Batches nachschlagen, + 4. neue Datensätze und Updates in Batches aufbereiten, + 5. Bulk-INSERTs und CASE-WHEN-UPDATEs ausführen. + +Ein Aufruf aus PHP sieht vereinfacht so aus: + +```php +$stats = $ffi->xliff_import_file_to_db( + $filePath, + FFI::addr($config), // DB-Konfiguration + $environment, + $languageUid, + FFI::addr($stats) // wird von Rust gefüllt +); +``` + +PHP selbst fasst die Ergebnisse nur noch zusammen und kümmert sich um UI/Logging. + +### Parser-Optimierungen in Rust + +- größerer `BufReader` (1 MB) reduziert Syscalls drastisch +- Voralloziierung von Vektoren und Strings für IDs und Übersetzungstexte +- Fast-Path für UTF-8-Decoding +- strikt sequentielles, allokationsarmes Parsing + +Der ursprüngliche PHP-SimpleXML-Parse im Hybrid-Ansatz lag bei grob 45 Sekunden; mit der optimierten Rust-Variante liegt das Parsing im Bereich von unter einer halben Sekunde. + +### Bulk-Update-Strategie + +- statt Hunderttausender einzelner UPDATEs werden IDs gebündelt +- pro Batch wird ein Statement der Form `UPDATE … SET value = CASE uid … END WHERE uid IN (…)` generiert +- aus ~419.000 Einzel-Queries werden so unter 1.000 Bulk-Updates + +Damit skaliert der Import nahezu linear mit der Datensatzanzahl, bis die Datenbank selbst zum limitierenden Faktor wird. + +--- + +## Vor- und Nachteile + +### Vorteile + +- **Geschwindigkeit:** Rust erledigt das, was CPU-lastig ist – und das brutal effizient. +- **Sicherheit:** Rust verhindert ganze Klassen von Fehlern. +- **Flexibilität:** FFI macht das Ganze containerfreundlich und infrastrukturell leichtgewichtig. +- **Einmaliger Aufwand:** Bibliothek bauen, FFI anbinden – fertig. + +### Nachteile + +- **Neue Technologie:** Rust ist nicht trivial. Man lernt. +- **Build-Prozess:** einmaliger Aufwand für die `.so`/`.dll`. +- **Debugging-Switch:** man springt zwischen zwei Sprachen. + +Aber: In Containern ist das alles lösbar. Einmal bauen – überall nutzen. + +--- + +## Ergänzende technische Details + +### PHP-Integration: wie FFI tatsächlich verdrahtet wird + +Der FFI-Call ist keine Magie. Das ist schnörkelloser PHP-Code. Entwicklerfreundlich, auditierbar, reproduzierbar. + +#### FFI-Binding (vereinfacht) + +```php +$this->ffi = FFI::cdef( + file_get_contents(__DIR__ . '/ffi/xliff_import.h'), + __DIR__ . '/../../rust/target/release/libnr_textdb_import.so' +); +``` + +#### Datenbank-Config als C-Struktur + +```php +// Hinweis: stark vereinfachtes Beispiel — produktiv unbedingt +// Längen prüfen und Zugangsdaten nicht über stack-allokierte +// char[256]-Buffer übergeben. +$config = $ffi->new('db_config'); +$config->host = FFI::new('char[256]', false); +FFI::memcpy($config->host, $host, strlen($host)); +$config->port = $port; +$config->user = $ffi->new('char[256]', false); +FFI::memcpy($config->user, $user, strlen($user)); +// usw. +``` + +#### Der eigentliche Import-Aufruf + +```php +$stats = $ffi->new('import_stats'); + +$ffi->xliff_import_file_to_db( + $pathToFile, + FFI::addr($config), + $environment, + $languageUid, + FFI::addr($stats) +); +``` + +#### Rückgabe in PHP sichtbar machen + +```php +echo sprintf( + "Inserts: %d, Updates: %d, Errors: %d, Duration: %.2fs", + $stats->inserted, + $stats->updated, + $stats->errors, + $stats->duration +); +``` + +Ohne „Magic", ohne „Hidden Layers". Klar, direkt, nachvollziehbar. + +--- + +### Container- und Runtime-Anpassungen + +Damit das Ganze sauber auf jedem System läuft, müssen im Stack nur wenige Dinge angepasst werden. + +#### 1. Dockerfile + +- Rust-Toolchain nur im **Builder-Stage** (Multi-Stage-Build) +- Ergebnis: schlankes Image, keine Rust-Compilerreste + +```dockerfile +FROM rust:1.91 AS builder +WORKDIR /build +COPY rust/ . +RUN cargo build --release + +FROM php:8.4-fpm +COPY --from=builder /build/target/release/libnr_textdb_import.so /usr/local/lib/ +``` + +#### 2. PHP-FPM + +- `ffi.enable = true` +- Bindung auf die spezifische `.so` + +```ini +php_admin_value[ffi.preload]="/var/www/html/ffi/xliff_import.h" +``` + +#### 3. Backend-Integration + +- neuer „Import"-Button im Backend-Modul +- Fortschrittsanzeige wird mit Rust-Stats gefüllt +- Fehlerlisten werden per Rust-Struct geliefert und im Backend gerendert +- Logging auf zwei Ebenen: + - Rust gibt Maschinenwerte + - PHP generiert daraus lesbare Meldungen für Redakteure + +Dadurch bleibt das Feature für Nicht-Techniker **identisch nutzbar**, während die Engine komplett ersetzt wurde. + +--- + +## Referenzen + +- DBAL-Bulk-Variante: +- All-in-Rust-Variante via PHP FFI: +- PHP-Manual zu FFI: +- Rust: + +--- + +## Diskussion + +Ideen, Kritik, Wünsche? Andere Einsatzszenarien für Rust + PHP FFI? +Immer her damit. + +--- + +*Originally published as an internal Netresearch wiki article in November 2025. Republished here lightly edited for public context.* diff --git a/essays/playwright-mcp-cheat-sheet.md b/essays/playwright-mcp-cheat-sheet.md new file mode 100644 index 0000000..0ba50b1 --- /dev/null +++ b/essays/playwright-mcp-cheat-sheet.md @@ -0,0 +1,151 @@ +--- +title: "Playwright MCP – Cheat Sheet" +slug: "playwright-mcp-cheat-sheet" +originally_published: "2025-08-07" +updated: "2026-05-10" +status: "current" +topics: + - mcp + - browser-testing + - tooling-reference +summary: "Praxisnahes Cheat Sheet zum Playwright MCP Server: Was MCP wirklich bedeutet, wie das offizielle Docker-Image funktioniert, wann manuelles Mounting nötig ist und wie sich der Server in Agenten-Editoren und CI/CD-Pipelines einbinden lässt." +lang: "de" +license: "CC-BY-4.0" +--- + +> Dieses Cheat Sheet richtet sich an Entwickler:innen, DevOps-Teams und Tool-Integratoren, die den **Playwright MCP Server** zur browsergestützten Webautomatisierung über LLMs (Sprachmodelle) einsetzen möchten. *Stand: August 2025 — bei browser-spezifischen Aussagen lohnt sich vor dem Einsatz ein Blick in die aktuellen Release Notes.* + +--- + +## Integration mit Agenten-/Editor-Umgebungen + +> **Hinweis:** Agentenfähige Entwicklungsumgebungen (z. B. LLM-gesteuerte Editoren oder Tools mit integrierter MCP-Unterstützung) mounten das Projektverzeichnis beim Start des MCP-Containers in der Regel **automatisch**. +> ➔ Ein *manuelles Mounting* ist nur erforderlich, wenn du MCP direkt über Docker oder eigene Pipelines betreibst. + +| Verhalten | Erklärung | +| --- | --- | +| Projekt-Mount | Automatisch durch Editor oder Agentenumgebung | +| `playwright.config.ts` | Muss im Projektverzeichnis vorhanden sein | +| Zusatzflags (`-v`, `-w`) | Nicht erforderlich bei automatischer Mount-Logik | +| Eigene Nutzung (Shell, CI, Docker direkt) | Manuelles Mounting notwendig | + +➔ In unterstützten Umgebungen erkennt der Agent das Projektverzeichnis automatisch und stellt es MCP zur Verfügung. + +--- + +## Begriffsklärung: Was bedeutet MCP? + +| Kontext | Bedeutung | +| --- | --- | +| **Playwright MCP** (offiziell) | **Model Context Protocol** | +| Modular Control Plane | *nicht* gemeint im Kontext dieses Projekts | +| Zweck | Verbindung von LLM-Agenten mit browserbasierter Webautomatisierung über ein standardisiertes Protokoll | + +Quelle: [GitHub – microsoft/playwright-mcp](https://github.com/microsoft/playwright-mcp) + +--- + +## Was ist das Model Context Protocol? + +- Standardisiertes **JSON-RPC-Protokoll** +- Ermöglicht Sprachmodellen Zugriff auf Werkzeuge (Browser, Filesystem, Git, Shell etc.) +- Playwright fungiert als **Tool Server**, der über MCP Webautomation ausführt +- Typische Nutzung: *LLM-Agent klickt/scrollt/füllt Formulare aus* via Browser + +--- + +## Docker: `mcr.microsoft.com/playwright/mcp` + +| Komponente | Enthalten? | Hinweis | +| --- | --- | --- | +| `@playwright/mcp` | Ja | MCP-Server | +| Playwright Core | Ja | Playwright CLI & API | +| Browser (Chrome etc.) | Nur *headless Chromium* (Stand August 2025) | siehe Hinweis unten | +| Tests deines Projekts | Nein | müssen *gemountet* werden (siehe oben) | + +### Manuelles Mounting + +```bash +# Führt den MCP-Server aus und bindet das Projektverzeichnis ein +docker run --rm -p 3000:3000 \ + -v $(pwd):/tests \ + -w /tests \ + mcr.microsoft.com/playwright/mcp +``` + +> **Wichtig (Stand August 2025):** Das Docker-Image unterstützt zu diesem Zeitpunkt **nur headless Chromium**. Andere Browser oder headed mode sind nicht verfügbar. Aktueller Stand: [GitHub – Hinweis zur Docker-Einschränkung](https://github.com/microsoft/playwright-mcp#note-the-docker-implementation-only-supports-headless-chromium-at-the-moment). + +--- + +## CI/CD-Pipelines mit MCP verwenden + +Ja – das offizielle Docker-Image ist **CI-tauglich**. + +- Kann in GitHub Actions, GitLab CI, Jenkins etc. verwendet werden +- Du musst: + - das Projektverzeichnis mounten (`-v`) + - oder dein Repo im Container clonen +- Du verwendest dabei **nicht das System-Playwright**, sondern **das im Container vorinstallierte Playwright + Browser** + +Beispiel-Step in der Pipeline (GitHub Actions): + +```yaml +- name: Run MCP server + run: docker run --rm -v ${{ github.workspace }}:/tests -w /tests mcr.microsoft.com/playwright/mcp +``` + +--- + +## Häufige Missverständnisse + +| Aussage | Status | Erklärung | +| --- | --- | --- | +| „MCP = Modular Control Plane" | falsch | Nicht im Kontext dieses Projekts vorhanden | +| „Container sieht meine Tests automatisch" | nur mit Mounting | manuell oder automatisch durch Agenten | +| „MCP = Test Runner" | nein | Fokus liegt auf *Automation via LLM*, nicht auf klassischer Testverteilung | + +--- + +## Manuelles Setup lokal (ohne Agent) + +```bash +npx @playwright/mcp@latest # MCP lokal starten +npx playwright install chrome # Browser manuell installieren +docker run -v $(pwd):/tests -w /tests mcr.microsoft.com/playwright/mcp +``` + +--- + +## Ressourcen + +- GitHub: +- MCP-Protokoll: +- Docker Image: + +--- + +## TL;DR + +- **MCP = Model Context Protocol**, nicht Modular Control Plane +- Container ist vollständig, aber **sieht Tests nur mit Mount** +- Automatisches Mounting bei unterstützten Entwicklungsumgebungen +- Direkt nutzbar in **CI/CD** – verwendet das im Container integrierte Playwright + Browser-Setup +- *Stand August 2025: Nur headless Chromium wird im Docker-Image unterstützt — vor Einsatz in 2026+ aktuelle Release Notes prüfen* + +--- + +## Glossar + +| Begriff | Erklärung | +| --- | --- | +| **MCP** | *Model Context Protocol* – ein JSON-RPC-Standard zur Kommunikation zwischen Sprachmodellen und Tools | +| **Playwright** | Framework zur Automatisierung von Browser-Interaktionen (ähnlich wie Puppeteer) | +| **Headless** | Ausführung eines Browsers ohne sichtbare Benutzeroberfläche (GUI) | +| **Tool Server** | Ein Prozess, der über MCP Kommandos empfängt und in Tools ausführt (z. B. Browseraktionen) | +| **Mounting** | Das Einbinden eines lokalen Verzeichnisses in einen Container per Docker (`-v`) | +| **CI/CD** | *Continuous Integration / Continuous Deployment* – automatisierte Build-, Test- und Deploymentprozesse | +| **LLM-Agent** | Ein KI-Modell (z. B. GPT), das über Protokolle wie MCP externe Aktionen auslöst | + +--- + +*Originally published as an internal Netresearch wiki article in August 2025. Republished here lightly edited for public context.* diff --git a/essays/supply-chain-attacken-shai-hulud.md b/essays/supply-chain-attacken-shai-hulud.md new file mode 100644 index 0000000..3108d79 --- /dev/null +++ b/essays/supply-chain-attacken-shai-hulud.md @@ -0,0 +1,77 @@ +--- +title: "Supply-Chain-Attacken am Beispiel Shai-Hulud" +slug: "supply-chain-attacken-shai-hulud" +originally_published: "2025-09" +updated: "2026-05-10" +status: "current" +topics: + - security + - supply-chain + - incident-analysis +summary: "Analyse des Shai-Hulud-Wurms im npm-Ökosystem – des ersten bekannten sich selbst replizierenden Supply-Chain-Angriffs in JavaScript – und warum kontrollierte Automatisierung, Container-Isolation und gelebte Compliance die richtige Antwort darauf sind, nicht das Bremsen von Updates." +lang: "de" +license: "CC-BY-4.0" +--- + +> Hinweis: Dieser Text entstand ursprünglich als interner Beitrag im Netresearch-Wiki und wurde für die öffentliche Veröffentlichung leicht redigiert. Beispiele aus dem eigenen Stack (AWS, Renovate/Dependabot, Container-Pipelines) sind bewusst stehen geblieben – sie sind kein Geheimnis und machen den Punkt konkreter. + +## Was ist eine Supply-Chain-Attacke? + +Eine **Supply-Chain-Attacke** zielt nicht direkt auf das Endsystem, sondern auf die Werkzeuge, Bibliotheken und Build-Prozesse davor. Angreifer kompromittieren die Lieferkette – also genau den Code, den Teams vertrauensvoll einbinden. Die aktuelle Attacke **Shai-Hulud** auf das npm-Ökosystem ist ein besonders gefährlicher Fall: Ein infiziertes Paket hat sich **selbst repliziert**, Tokens und SSH-Keys exfiltriert und anschließend eigene Repositories oder Workflows in GitHub angelegt. Das ist die erste bekannte **Wurm-Attacke in der JavaScript-Supply-Chain**. + +## Warum das jeden Entwicklungsbetrieb betrifft + +Jede Entwicklerin, jeder Admin, jedes DevOps-Team nutzt Open-Source-Komponenten aus npm, Composer oder PyPI. Die sind mächtig – und ein Risiko. Der Angriff zeigt, dass Angreifer nicht mehr direkt in fremde Infrastruktur einbrechen müssen. Sie warten, bis wir ihren Code *freiwillig installieren*. + +**Kurz gesagt:** Vertrauen in die Supply Chain ist kein Freifahrtschein – es braucht Kontrolle, Automatisierung und saubere Prozesse. + +## Warum **trotzdem** automatische Updates die richtige Antwort sind + +Automatische Updates sind kein Risiko – sie sind **Risikominderung**. Manuelles Patchen führt fast immer zu langen Phasen mit **verwundbaren Versionen**. Tooling wie Renovate oder Dependabot sorgt dafür, dass Updates schnell eingebracht, aber **vor dem Deployment geprüft** werden: + +* **Automatisierte Pull Requests**: Kein Blind-Update, sondern überprüfbare Änderungen mit Review. +* **Security Gates**: Builds stoppen bei `npm audit`- oder `snyk`-Warnungen. +* **Compliance Hooks**: Lizenz- und Sicherheits-Checks verhindern unzulässige Komponenten. + +Der Shai-Hulud-Vorfall zeigt: Wer *spät* patcht, läuft länger mit offenen Türen. Wer *kontrolliert automatisiert*, reagiert schneller. + +## Warum ein **Container-First-Ansatz** zusätzlich schützt + +Ein konsequent container-basierter Ansatz (Docker/Kubernetes) liefert eine zusätzliche Verteidigungsschicht: + +1. **Isolation**: Schadcode bleibt auf Container-Ebene eingeschlossen. +2. **Reproduzierbarkeit**: Images sind deterministisch – kein Platz für versteckte Änderungen. +3. **Ephemerität**: Container leben kurz. Persistenzversuche wie in `/var/lib/docker` werden durch Rebuilds und Pruning eliminiert. +4. **Scanning**: Container-Images werden regelmäßig durch Tools wie *Trivy* oder *AWS Inspector* geprüft. + +Diese Maßnahmen sind keine Kür, sondern Standard-Bausteine eines belastbaren Sicherheitskonzepts – insbesondere zu *Incident Response*, *Schwachstellenmanagement*, *WAF/IDS* und der Anlehnung an *C5/BSI*-Vorgaben. + +## Welche **Compliance-Regeln** zusätzlich absichern + +Belastbare Sicherheitsrichtlinien enthalten mehrere verbindliche Schutzmechanismen, die genau gegen Supply-Chain-Angriffe wirken: + +* **Least Privilege & Secret Management**: Zugriffsschlüssel liegen in einem zentralen Secrets-Store (z. B. AWS Secrets Manager), werden regelmäßig rotiert und nie im Code gespeichert. +* **Code Review & Workflow Protection**: Keine unreviewten Änderungen in produktiven Pipelines. +* **Security Audits & Penetrationstests**: Regelmäßige Prüfungen auf Basis von IT-Grundschutz (APP.3.1, CON.10) und OWASP Top 10. +* **Incident Response & Logging**: Zentrale Überwachung – z. B. über AWS CloudWatch, GuardDuty und CloudTrail oder vergleichbare Stacks. + +## Realität: zwischen Konzept und Alltag klafft eine Lücke + +Ehrlich: Solche Regeln gelten in vielen Unternehmen auf dem Papier – aber sie sind **selten in jedem Projekt vollständig durchgesetzt**. Genau deshalb ist der Shai-Hulud-Vorfall ein willkommener **Weckruf**. Sicherzustellen ist: + +* Secrets und Tokens *überall* zentral verwaltet werden, +* CI/CD-Pipelines keine unreviewten Änderungen erlauben, +* Docker-Images regelmäßig neu gebaut und gescannt werden, +* Entwicklerinnen und Entwickler Sicherheitsrichtlinien *nicht nur kennen*, sondern auch *anwenden*. + +Vorfälle wie dieser sind unangenehm – aber sie sind oft das, was bestehende Regeln endlich **konsequent gelebt** statt nur dokumentiert werden lässt. + +## Fazit + +Die Shai-Hulud-Attacke ist kein Ausnahmefall, sondern ein Vorgeschmack auf künftige Supply-Chain-Bedrohungen. Die richtige Antwort darauf ist nicht Panik – sondern Disziplin: Automatisierung, Compliance und Containerisierung. + +Die Mechanismen sind bekannt. Sie müssen nur überall durchgesetzt werden. + +--- + +*Originally published as an internal Netresearch wiki article in September 2025. Republished here lightly edited for public context.*