diff --git a/Jenkinsfile b/Jenkinsfile index 6664312..4749a74 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,14 +1,12 @@ pipeline { agent none + options { ansiColor('xterm'); timestamps() } environment { - // Optional: tweak for speed DOTNET_CLI_TELEMETRY_OPTOUT = '1' DOTNET_SKIP_FIRST_TIME_EXPERIENCE = '1' - - // Sonar: set host via withSonarQubeEnv; token via credentials below - SONAR_PROJECT_KEY = 'AS400-API' - SONAR_PROJECT_NAME = 'AS/400 API (.NET9)' + SONAR_PROJECT_KEY = 'as400api-dotnet' // <-- change if you like + SONAR_PROJECT_NAME = 'AS400_API_DOTNET (.NET 9)' } stages { @@ -17,56 +15,57 @@ pipeline { steps { checkout scm } } - stage('SCA (Dependency Audit)') { - // Run inside official .NET 9 SDK image - agent { - docker { image 'mcr.microsoft.com/dotnet/sdk:9.0'; reuseNode true } - } + stage('SCA (NuGet vulnerabilities + OWASP)') { + agent { docker { image 'mcr.microsoft.com/dotnet/sdk:9.0'; reuseNode true } } steps { sh ''' + set -e dotnet --info - # 1) Built-in vulnerability audit (NuGet advisory DB) dotnet restore - # dotnet list package --vulnerable exits 0 even when vulnerabilities found; use Jenkins Warnings NG to surface, or grep to fail on high + + echo "=== NuGet vulnerability audit ===" + # Prints known vulnerable packages (won't fail the build by default) dotnet list package --vulnerable || true - # 2) (Optional) OWASP Dependency-Check via Docker - # Scans csproj/packages.lock.json for known CVEs + echo "=== OWASP Dependency-Check (try Docker first) ===" mkdir -p depcheck - docker run --rm \ - -v "$PWD":/src \ - -v "$PWD/depcheck":/report \ - owasp/dependency-check:latest \ - --scan /src \ - --format "HTML" \ - --out /report || true - echo "Dependency-Check report at depcheck/dependency-check-report.html" + if command -v docker >/dev/null 2>&1; then + docker run --rm \ + -v "$PWD":/src \ + -v "$PWD/depcheck":/report \ + owasp/dependency-check:latest \ + --scan /src --format "HTML" --out /report || true + else + echo "Docker not found; falling back to CLI zip…" + curl -sSL -o depcheck.zip https://github.com/jeremylong/DependencyCheck/releases/latest/download/dependency-check.zip || true + if [ -f depcheck.zip ]; then + unzip -q depcheck.zip -d depcheckcli || true + java -jar depcheckcli/dependency-check/bin/dependency-check.jar \ + --scan . --format HTML --out depcheck || true + fi + fi + + echo "SCA reports generated in depcheck/" ''' - // You can archive the HTML report for viewing in Jenkins - archiveArtifacts artifacts: 'depcheck/**', allowEmptyArchive: true + } + post { + always { + archiveArtifacts artifacts: 'depcheck/**', allowEmptyArchive: true + } } } stage('SAST + Coverage (SonarQube + Tests)') { - agent { - docker { - // Use SDK image; we’ll install scanner + reportgenerator inside - image 'mcr.microsoft.com/dotnet/sdk:9.0' - reuseNode true - } - } - environment { - SONAR_TOKEN = credentials('sonar-token') - } + agent { docker { image 'mcr.microsoft.com/dotnet/sdk:9.0'; reuseNode true } } + environment { SONAR_TOKEN = credentials('sonar-token') } steps { withSonarQubeEnv('SonarQubeServer') { sh ''' - # Install dotnet tools we need + set -e dotnet tool install --global dotnet-sonarscanner --version 7.* dotnet tool install --global dotnet-reportgenerator-globaltool export PATH="$PATH:/root/.dotnet/tools" - # Begin Sonar analysis (SAST + quality gates) dotnet sonarscanner begin \ /k:"$SONAR_PROJECT_KEY" \ /n:"$SONAR_PROJECT_NAME" \ @@ -75,22 +74,17 @@ pipeline { /d:sonar.cs.opencover.reportsPaths="**/TestResults/**/coverage.opencover.xml" \ /d:sonar.coverage.exclusions="**/*.cshtml,**/Migrations/**" - # Build (needed for Sonar to analyze) - dotnet restore - dotnet build -c Release --no-restore - - # Test + Coverage (OpenCover format for Sonar) - # This uses coverlet.msbuild (works without editing csproj) - # Generates: .//TestResults//coverage.opencover.xml - dotnet test -c Release --no-build \ + dotnet build -c Release + # run tests; produce OpenCover coverage for Sonar + # If your test project path differs, specify it explicitly or run at solution level: + dotnet test -c Release \ /p:CollectCoverage=true \ /p:CoverletOutputFormat=opencover \ /p:CoverletOutput=./TestResults/coverage - # End Sonar (uploads results to server) dotnet sonarscanner end /d:sonar.login="$SONAR_TOKEN" - # Optional: create a single Cobertura report for Jenkins UI + # Generate a Cobertura report for Jenkins Coverage UI reportgenerator \ -reports:**/TestResults/**/coverage.opencover.xml \ -targetdir:coverage-report \ @@ -100,7 +94,6 @@ pipeline { } post { always { - // Publish coverage into Jenkins (Cobertura) publishCoverage adapters: [coberturaAdapter('coverage-report/Cobertura.xml')], sourceFileResolver: sourceFiles('STORE_LAST_BUILD') junit '**/TestResults/**/*.trx' @@ -110,11 +103,10 @@ pipeline { } stage('Build Artifact') { - agent { - docker { image 'mcr.microsoft.com/dotnet/sdk:9.0'; reuseNode true } - } + agent { docker { image 'mcr.microsoft.com/dotnet/sdk:9.0'; reuseNode true } } steps { sh ''' + set -e dotnet publish -c Release -o out ls -la out ''' @@ -122,9 +114,4 @@ pipeline { } } } - - options { - ansiColor('xterm') - timestamps() - } } \ No newline at end of file