Reduce background refresh overhead #43
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI DevSecOps | |
| on: | |
| push: | |
| branches: ["main", "master"] | |
| pull_request: | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| actions: read | |
| jobs: | |
| build-test-scan: | |
| runs-on: windows-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: "8.0.x" | |
| - name: Restore | |
| run: dotnet restore "ThreadPilot_1.sln" | |
| - name: Verify formatting | |
| continue-on-error: true | |
| run: dotnet format "ThreadPilot_1.sln" --verify-no-changes --verbosity diagnostic --report dotnet-format-report.json | |
| - name: Build Debug | |
| run: dotnet build "ThreadPilot_1.sln" --configuration Debug --no-restore | |
| - name: Build Release | |
| run: dotnet build "ThreadPilot_1.sln" --configuration Release --no-restore | |
| - name: Run tests | |
| run: dotnet test "Tests/ThreadPilot.Core.Tests/ThreadPilot.Core.Tests.csproj" --configuration Release --no-restore --verbosity normal --collect:"XPlat Code Coverage" --settings "Tests/ThreadPilot.Core.Tests/coverlet.runsettings" --results-directory TestResults | |
| - name: Enforce coverage gate | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| $coveragePath = Get-ChildItem -Path "TestResults" -Recurse -Filter "coverage.cobertura.xml" | | |
| Sort-Object LastWriteTimeUtc -Descending | | |
| Select-Object -First 1 -ExpandProperty FullName | |
| if ([string]::IsNullOrWhiteSpace($coveragePath)) | |
| { | |
| throw "Coverage file not found under TestResults." | |
| } | |
| [xml]$coverage = Get-Content $coveragePath | |
| $lineRate = [double]$coverage.coverage.'line-rate' * 100 | |
| $branchRate = [double]$coverage.coverage.'branch-rate' * 100 | |
| # Temporary floor until the service-hardening coverage tasks land. | |
| $minimumLineRate = 1.5 | |
| $summary = @( | |
| "## Coverage Gate", | |
| "- file: $coveragePath", | |
| "- line coverage: $([math]::Round($lineRate, 2))%", | |
| "- branch coverage: $([math]::Round($branchRate, 2))%", | |
| "- minimum line coverage: $minimumLineRate%" | |
| ) | |
| $summary | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Encoding utf8 -Append | |
| $summary | ForEach-Object { Write-Host $_ } | |
| if ($lineRate -lt $minimumLineRate) | |
| { | |
| throw "Coverage gate failed. Expected >= $minimumLineRate, actual: $([math]::Round($lineRate, 2))" | |
| } | |
| - name: Upload coverage | |
| uses: codecov/codecov-action@v4 | |
| with: | |
| files: '**/coverage.cobertura.xml' | |
| fail_ci_if_error: false | |
| - name: Dependency vulnerability audit | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| $audit = dotnet list "ThreadPilot.csproj" package --vulnerable --include-transitive | |
| $audit | Out-String | Write-Host | |
| if ($LASTEXITCODE -ne 0) { | |
| throw "dotnet list package --vulnerable failed." | |
| } | |
| if ($audit -match "has the following vulnerable packages") { | |
| throw "Vulnerable packages detected." | |
| } | |
| - name: Secret scan (Gitleaks) | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| $version = "8.24.3" | |
| $baseUrl = "https://github.com/gitleaks/gitleaks/releases/download/v$version" | |
| $zipAsset = "gitleaks_${version}_windows_x64.zip" | |
| $tarAsset = "gitleaks_${version}_windows_x64.tar.gz" | |
| $toolDir = Join-Path $env:RUNNER_TEMP "gitleaks-bin" | |
| if (Test-Path $toolDir) { | |
| Remove-Item -Path $toolDir -Recurse -Force | |
| } | |
| try { | |
| Invoke-WebRequest -Uri "$baseUrl/$zipAsset" -OutFile "gitleaks.zip" | |
| Expand-Archive -Path "gitleaks.zip" -DestinationPath $toolDir -Force | |
| } | |
| catch { | |
| Invoke-WebRequest -Uri "$baseUrl/$tarAsset" -OutFile "gitleaks.tar.gz" | |
| New-Item -ItemType Directory -Force -Path $toolDir | Out-Null | |
| tar -xzf "gitleaks.tar.gz" -C $toolDir | |
| } | |
| # Remove vendored tool docs from scan scope to avoid known upstream sample false positives. | |
| if (Test-Path ".\\gitleaks-bin") { | |
| Remove-Item -Path ".\\gitleaks-bin" -Recurse -Force | |
| } | |
| $gitleaksExe = Resolve-Path (Join-Path $toolDir "gitleaks.exe") | |
| & $gitleaksExe detect --source "." --no-git --exit-code 1 --redact --verbose --report-format json --report-path gitleaks-report.json | |
| - name: Upload security artifacts | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: security-reports | |
| path: | | |
| gitleaks-report.json | |
| dotnet-format-report.json |