pipeline {
    agent {
        kubernetes {
            // Definieren des Pod mit 3 Containern als Build Agent, Trivy und Kaniko
            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 {
        // Aktivieren von Log Rotation: 
        // *) Letzten 10 Builds werden aufbewahrt
        // ** Builds, die älter als 7 Tage sind, werden gelöscht
        buildDiscarder(logRotator(numToKeepStr: '10', artifactNumToKeepStr: '10', daysToKeepStr: '7'))
    }

	stages {
        // Auschecken der Sourcen zum App Projekt
		stage('Checkout Source') {
			steps {
				git url: 'http://130.61.26.230:30080/dev-master/secdevops-csharp-app.git',
					branch: 'master'
			}
		}

        stage('Security: Trivy Scan') {
            steps {
                // Ausführen des 'dotnet restore' für den nachfolgenden Trivy Scan, der diese wiederhergestellte Dateien/NuGet Pakete und Abhängigkeiten scanned
                // Generiert automatisch das obj/ mit der project.assets.json
                // Alle Container eines Pods teilen sich das Jenkins Arbeitsverzeichnis
                container('dotnet8') {
                    sh 'dotnet restore' 
                }

                // Ausführen des Trivy Scans 
                //
                // Wichtig: trivy ersetzt -> dotnet list package --vulnerable --include-transitive
                container('trivy') {
                    // Erzeugen des Directory zum Speichern des Reports
                    sh 'mkdir -p reports'

                    // Ausführen des Scans hinsichtlich Vulnerabilities, Miskonfigurationen, Secrets und Licences im Jenkins Arbeitsverzeichnis
                    // Abbruch bei bei kritischen Fehlern (--exit-code 1 --severity HIGH,CRITICAL)
                    sh 'trivy fs --scanners vuln,misconfig,secret,license --exit-code 1 --severity HIGH,CRITICAL --format template --template "@/contrib/html.tpl" -o reports/trivy-fs-report.html .'
                }
            }
        }
 
        // Kompilieren der Anwendung (DLLs werden erzeugt)
        // Schritt muss gar nicht durchgeführt werden, da kaniko das Image erzeugt
		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 --configuration Release'   // optimierter Build Prozess ohne Debug und ungenutzt Pfade
				}
			}	
		}
		
		//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 {
					// Setzen des 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') {
                    // Stellt die Informationen aus dem Token in Form von Umgebungsvariablen der Jenkins Pipeline zur Verfügung
                    // Nachfolgend werden diese Credentials im JSON Format in config.json geschrieben
                    // Vorgehen ist zwar nicht extrem sicher, aber die Lebenszeit im Container ist kurz, dass diese base64 kodierten Daten zurückverwandelt werden könnten

                     // Erzeugen des Directory zum Speichern des Reports, falls das bei einem vorigen Schritt nicht durchgeführt wurde
                    sh 'mkdir -p reports'

                    withCredentials([usernamePassword(credentialsId: 'gitea-registry-token', 
                                                    usernameVariable: 'GITEA_USER', 
                                                    passwordVariable: 'GITEA_TOKEN')]) {
                        sh '''
                        # WORKAROUND: Dem Container beibringen, wer git.example.com ist, ansonsten funktioniert das Übertragen des Images an Git nicht!!!
                        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 \
                            --skip-tls-verify \
                            --build-arg JENKINS_BUILD=${BUILD_NUMBER} \
                            --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 {

                // Trivy Scan wird auf das Image im Git Repository angewendet. Das Image wird heruntergeladen.
                container('trivy') {
                    // 1. Scan ausführen und als HTML-Report speichern (Achte auf den neuen Dateinamen)
                    sh '''
                        trivy image --insecure \
                            --severity HIGH,CRITICAL \
                            --format template \
                            --template "@/contrib/html.tpl" \
                            --exit-code 1 \
                            -o reports/trivy-image-report.html \
                            130.61.26.230:30080/dev-master/secdevops-csharp-app:latest
                    '''
                    
                    // Den Scan ein zweites Mal kurz ohne Report ausführen, damit die Pipeline bei Lücken blockiert
                    // 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 {
            // Suchen und Einelen von etwaigen Testreports von JUnit. Keine Vorhanden? -auch ok
            junit testResults: '**/*.xml', allowEmptyResults: true

             // Verwenden des HTML Publisher Modules zum Schreiben der gefundenen Testreports in das Build Menu und speichert den HTML Bericht dann historisch ab (keepAll)
            publishHTML([
                allowMissing: false,
                alwaysLinkToLastBuild: true,
                keepAll: true,
                reportDir: 'reports',
                reportFiles: 'trivy-fs-report.html,trivy-image-report.html',
                reportName: 'Trivy Security Report'
            ])

            // Schreiben des Build Status in das Build Log
            echo "Pipeline beendet: ${currentBuild.result}"
        }
    }
}