pipeline { agent { kubernetes { // Definiert den Pod mit dem .NET 8 SDK Image yaml ''' apiVersion: v1 kind: Pod spec: containers: - name: dotnet8 image: mcr.microsoft.com/dotnet/sdk:8.0 command: - cat tty: true - name: trivy image: aquasec/trivy:latest command: - cat tty: true - name: kaniko image: gcr.io/kaniko-project/executor:v1.23.1-debug command: ["sleep"] args: ["99d"] ''' } } options { // Log-Rotation: Bewahre nur die letzten 10 Builds auf // und lösche Berichte/Artefakte von Builds, die älter als 7 Tage sind. buildDiscarder(logRotator(numToKeepStr: '10', artifactNumToKeepStr: '10', daysToKeepStr: '7')) } stages { stage('Checkout Source') { steps { // Ersetze 'dein-user' und 'dein-repo' durch die Namen aus Gitea git url: 'http://130.61.26.230:30080/dev-master/secdevops-csharp-app.git', branch: 'master' } } stage('Build with .NET 8') { steps { // Führt den Build-Befehl im spezialisierten Container aus container('dotnet8') { sh 'dotnet --version' // Zur Bestätigung der Version sh 'dotnet build' } } } stage('Security: Trivy Scan') { steps { container('trivy') { // Wir erstellen ein Verzeichnis für den Report sh 'mkdir -p reports' // Der Befehl erzeugt die HTML-Datei // --format template: Nutzt ein Layout // --template "@/contrib/html.tpl": Das Standard-Trivy-Layout // Scannt das Dateisystem auf Schwachstellen (NuGet) und Secrets // --exit-code 1 lässt die Pipeline bei kritischen Fehlern abbrechen sh 'trivy fs --scanners vuln,misconfig,secret,license --exit-code 1 --severity HIGH,CRITICAL --format template --template "@/contrib/html.tpl" -o reports/trivy-report.html .' } } } stage('Unit Tests') { steps { container('dotnet8') { // Erstellt eine XML-Datei im Format 'junit', die Jenkins lesen kann // sh 'dotnet test --configuration Release' sh 'dotnet test --configuration Release --logger "junit;LogFileName=results.xml"' } } } stage('Set Build Name') { steps { script { // Setzt den Namen des aktuellen Laufs auf die Version + Build-Nummer currentBuild.displayName = "v1.0.0-build-${env.BUILD_NUMBER}" } } } stage('Docker Build & Push') { when { branch 'master' } steps { container('kaniko') { // Nutze die ID, die du in Jenkins für den Token vergeben hast withCredentials([usernamePassword(credentialsId: 'gitea-registry-token', usernameVariable: 'GITEA_USER', passwordVariable: 'GITEA_TOKEN')]) { sh ''' # WORKAROUND: Dem Container beibringen, wer git.example.com ist echo "130.61.26.230 git.example.com" >> /etc/hosts # Erstellt die Docker-Konfiguration für Kaniko # Das $(echo ...) Kommando kombiniert User und Token für den Login echo "{\\"auths\\":{\\"130.61.26.230:30080\\":{\\"auth\\":\\"\$(echo -n \${GITEA_USER}:\${GITEA_TOKEN} | base64)\\"}}}" > /kaniko/.docker/config.json # Der Bau- und Push-Befehl # Wir taggen das Image mit 'latest' UND der Build-Nummer zur Sicherheit /kaniko/executor --context `pwd` \ --dockerfile `pwd`/Dockerfile \ --insecure \ --push-retry 5 \ --skip-tls-verify \ --destination 130.61.26.230:30080/dev-master/secdevops-csharp-app:latest \ --destination 130.61.26.230:30080/dev-master/secdevops-csharp-app:${BUILD_NUMBER} ''' } } } } stage('Security: Trivy Image Scan') { when { branch 'master' } steps { container('trivy') { // Scannt das frisch gepushte Image direkt aus deiner Gitea Registry // Das Flag '--insecure' erlaubt Trivy den Zugriff über die unverschlüsselte IP sh 'trivy image --insecure --exit-code 1 --severity HIGH,CRITICAL 130.61.26.230:30080/dev-master/secdevops-csharp-app:latest' } } } } post { failure { script { currentBuild.description = "Build Fehler. Ev. Sicherheits-Check fehlgeschlagen! Details im Trivy Security Report." } } always { // Sammelt die Testergebnisse ein (die wir im Test-Schritt erzeugen) // Das **/ bedeutet: Suche in allen Unterordnern nach .xml Dateien junit testResults: '**/TestResults/*.xml', allowEmptyResults: true // Dieser Schritt macht den Report im Jenkins-Menü links sichtbar publishHTML([ allowMissing: false, alwaysLinkToLastBuild: true, keepAll: true, reportDir: 'reports', reportFiles: 'trivy-report.html', reportName: 'Trivy Security Report' ]) // Meldet den Status zurück, wenn das Gitea-Plugin korrekt konfiguriert ist echo "Pipeline beendet: ${currentBuild.result}" } } }