Warum Ihre Pipeline Tests und Scans braucht, bevor es zu spät ist

Sie haben gerade Ihre Anwendung fertig gebaut. Der Build war erfolgreich. Das Artefakt existiert. Was nun?

Viele Teams hören hier auf. Sie gehen davon aus, dass das Artefakt produktionsreif ist, wenn der Code kompiliert und der Build durchläuft. Aber ein erfolgreicher Build sagt Ihnen nur, dass der Code assembliert werden kann. Er sagt Ihnen nicht, ob der Code tatsächlich funktioniert, ob er Sicherheitslücken hat oder ob er abstürzt, wenn er mit der Datenbank kommuniziert.

Prüfungen in dieser Phase zu überspringen ist, als würde man ein Paket verschicken, ohne hineinzuschauen. Sie könnten etwas Kaputtes, Gefährliches oder beides versenden.

Beginnen Sie mit dem schnellsten Feedback: Unit-Tests

Die erste Prüfung in jeder Pipeline sollten die Unit-Tests sein. Diese Tests überprüfen das Verhalten Ihres Codes von innen heraus. Sie rufen eine Funktion, einen Anwendungsfall oder einen Endpunkt auf und prüfen, ob das Ergebnis Ihren Erwartungen entspricht.

Das folgende Flussdiagramm zeigt die Reihenfolge der Prüfungen und die kritischen Entscheidungspunkte, an denen ein Fehler die Pipeline stoppt:

flowchart TD A[Unit Tests] --> B{Pass?} B -- No --> C[Stop Pipeline] B -- Yes --> D[Integration Tests] D --> E{Pass?} E -- No --> C E -- Yes --> F[Static Analysis] F --> G{Pass?} G -- No --> C G -- Yes --> H[Vulnerability Scanning] H --> I{Pass?} I -- No --> C I -- Yes --> J[Save Results] J --> K[Proceed to Packaging]

Unit-Tests führen Ihre eigentlichen Logikschichten aus, vom Einstiegspunkt bis zum tiefsten Modul. Sie benötigen keine echte Datenbank, keine externen Dienste und keine Netzwerkaufrufe. Das macht sie schnell. Eine gute Unit-Test-Suite läuft in Sekunden oder höchstens einigen Minuten.

Hier ist ein minimales YAML-Pipeline-Snippet, das Unit-Tests und einen Schwachstellenscan ausführt und die Pipeline stoppt, wenn einer von beiden fehlschlägt:

jobs:
  test-and-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install dependencies
        run: npm ci

      - name: Run unit tests
        run: npm test

      - name: Run vulnerability scan
        run: npm audit --audit-level=high

Wenn ein Unit-Test fehlschlägt, stoppen Sie die Pipeline sofort. Es hat keinen Sinn, fortzufahren, wenn das grundlegende Verhalten Ihres Codes fehlerhaft ist. Alles andere baut auf der Annahme auf, dass der Code das tut, was er tun soll. Wenn diese Annahme falsch ist, ist jede nachfolgende Prüfung verschwendete Mühe.

Prüfen, ob die Teile wirklich zusammenpassen: Integrationstests

Unit-Tests beweisen, dass sinnvolles Verhalten funktioniert, während die Außenwelt kontrolliert wird. Ihre internen Schichten können zwar zusammenlaufen, aber benachbarte Systeme werden simuliert oder unter Testkontrolle gehalten. Software bricht auch dann, wenn sie mit echten Abhängigkeiten kommunizieren muss. Hier kommen Integrationstests ins Spiel.

Integrationstests prüfen, ob Ihre Module korrekt zusammenarbeiten können. Kann das Benutzermodul Daten in der Datenbank speichern? Reagiert die API richtig, wenn der Zahlungsdienst ausfällt? Stimmen die Datenformate zwischen den Diensten überein?

Diese Tests sind langsamer als Unit-Tests, weil sie echte Infrastruktur benötigen: eine Datenbank, eine Message Queue oder eine Testinstanz eines anderen Dienstes. Aber genau hier verstecken sich die meisten realen Fehler. Code, der jeden Unit-Test besteht, kann bei Integrationstests dennoch fehlschlagen, wegen:

  • Falscher Datenbank-Verbindungsstrings
  • Nicht übereinstimmender Datenschemata
  • Falscher Konfigurationswerte
  • Fehlender Umgebungsvariablen

Integrationstests fangen die Art von Problemen, die nur auftreten, wenn Komponenten tatsächlich miteinander interagieren. Wenn Sie sie überspringen, wetten Sie darauf, dass Ihr Code in einer Umgebung, die Sie nicht getestet haben, perfekt funktioniert.

Den Code selbst scannen: Statische Analyse

Funktionale Tests prüfen, was der Code tut. Die statische Analyse prüft, wie der Code geschrieben ist. Sie liest Ihren Quellcode, ohne ihn auszuführen, und sucht nach problematischen Mustern.

Statische Analysetools können erkennen:

  • Variablen, die deklariert, aber nie verwendet werden
  • Code, der zu komplex oder tief verschachtelt ist
  • Potenzielle Nullzeiger-Dereferenzierungen
  • Verstöße gegen Codierungsstandards, auf die sich Ihr Team geeinigt hat
  • Sicherheitsrelevante Muster wie hartcodierte Anmeldeinformationen

Die statische Analyse wird keine Logikfehler finden. Aber sie fängt die Art von Fehlern, die Entwickler dutzende Male am Tag machen und die beim Code-Review oft übersehen werden. Sie erzwingt auch Konsistenz im Team. Wenn jeder Commit gegen die gleichen Regeln geprüft wird, bleibt die Codebasis auch bei wachsendem Team wartbar.

Die versteckten Gefahren finden: Schwachstellenscan

Die meisten Sicherheitslücken in modernen Anwendungen stammen nicht aus dem von Ihnen geschriebenen Code. Sie stammen aus den Bibliotheken und Paketen, von denen Sie abhängig sind. Eine einzige veraltete Abhängigkeit mit einem bekannten Exploit kann Ihre gesamte Anwendung gefährden.

Der Schwachstellenscan prüft Ihre Abhängigkeitsliste gegen Datenbanken bekannter Sicherheitsprobleme. Wenn eine Bibliothek eine kritische Schwachstelle aufweist, markiert der Scanner sie und die Pipeline sollte gestoppt werden. Besser, ein Release zu verzögern, als ein bekanntes Sicherheitsloch in die Produktion zu liefern.

Dieser Scan sollte bei jedem Build laufen, nicht nur vor großen Releases. Täglich werden neue Schwachstellen entdeckt. Eine Bibliothek, die letzte Woche noch sicher war, könnte heute eine kritische CVE haben. Regelmäßige Scans stellen sicher, dass Sie diese Probleme erkennen, bevor sie die Benutzer erreichen.

Die Beweise aufbewahren: Warum Ergebnisse gespeichert werden müssen

Jede Prüfung in dieser Phase produziert Ergebnisse. Unit-Tests bestehen oder fallen. Integrationstests berichten, welche Szenarien funktioniert haben. Die statische Analyse listet Warnungen und Fehler auf. Schwachstellenscans markieren Abhängigkeiten.

Diese Ergebnisse sind Beweise. Sie belegen, dass die Pipeline ihre Prüfungen durchgeführt hat, und zeigen, was passiert ist. Speichern Sie sie.

Beweise sind aus drei Gründen wichtig:

  1. Fehlersuche in Produktionsproblemen. Wenn in der Produktion etwas schiefgeht, können Sie prüfen, ob die Pipeline das Problem erkannt hat. Wenn ja, wissen Sie, dass die Prüfung funktioniert hat. Wenn nicht, wissen Sie, dass Sie einen besseren Test brauchen.

  2. Audit und Compliance. Regulierungsbehörden, Kunden und interne Richtlinien verlangen oft den Nachweis, dass jede Änderung vor der Veröffentlichung getestet wurde. Gespeicherte Beweise erfüllen diese Anforderung.

  3. Trendanalyse. Im Laufe der Zeit zeigen die Beweise, ob sich Ihre Codequalität verbessert. Fallen Tests seltener aus? Nehmen Schwachstellen ab? Sind bestimmte Module durchgängig problematisch? Diese Daten helfen Ihnen zu entscheiden, wo Sie Ihre Verbesserungsbemühungen investieren sollten.

Speichern Sie Beweise in einem maschinenlesbaren Format wie JUnit XML oder SARIF und führen Sie auch eine für Menschen lesbare Zusammenfassung. Legen Sie sie an einem Ort ab, der auch nach Abschluss der Pipeline bestehen bleibt, wie einer Artefakt-Registry oder einem dedizierten Storage-Bucket. Verlassen Sie sich nicht auf Pipeline-Logs, die nach ein paar Tagen bereinigt werden.

Praktische Checkliste für diese Phase

Bevor Sie ein Artefakt zur Bereitstellung weitergeben, stellen Sie sicher, dass diese Prüfungen vorhanden sind:

  • Unit-Tests laufen bei jedem Commit und lassen die Pipeline bei Fehlschlag abbrechen
  • Integrationstests decken kritische Komponenteninteraktionen ab
  • Die statische Analyse setzt Codequalitätsstandards durch
  • Der Schwachstellenscan prüft alle Abhängigkeiten
  • Alle Ergebnisse werden als Beweise mit Zeitstempeln und Commit-IDs gespeichert

Was als Nächstes passiert

Nachdem Tests und Scans bestanden sind, wissen Sie, dass das Artefakt behaltenswert ist. Es funktioniert korrekt, der Code ist wartbar und die Abhängigkeiten sind sicher. Jetzt müssen Sie es paketieren und speichern, damit es später bereitgestellt werden kann.

Aber wenn eine Prüfung fehlschlägt, stoppt die Pipeline. Das Team wird benachrichtigt. Das Artefakt erreicht nie die nächste Stufe. Das ist der Punkt: Das Problem hier erkennen, nicht in der Produktion.

Die Kosten, einen Fehler in der Produktion zu finden, sind exponentiell höher als ihn in der Pipeline zu finden. Ein fehlgeschlagener Test kostet ein paar Minuten Entwicklerzeit. Ein Produktionsausfall kostet Benutzervertrauen, Incident Response und nächtliche Debugging-Sessions.

Testen und scannen Sie früh. Testen und scannen Sie automatisch. Und bewahren Sie die Beweise auf. Ihr zukünftiges Ich wird es Ihnen danken, wenn etwas schiefgeht und Sie genau nachweisen können, was und wann geprüft wurde.