diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db09727d..59bdb334 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,39 +1,39 @@ -name: CI - -# Builds the .NET 8 Control Panel (hMailCP) on every push / PR. This catches C# -# regressions cheaply. The C++ server build + the 898-test regression suite need -# the prebuilt native libraries (OpenSSL 4.0.x, Boost 1.91, PostgreSQL 18 libpq — -# see libraries/build-dependencies.ps1) and a database service, so they run in the -# separate, manually-triggered server-build workflow. - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - workflow_dispatch: - -permissions: - contents: read - -jobs: - control-panel: - name: Build Control Panel (.NET 8) - runs-on: windows-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Set up .NET 8 - uses: actions/setup-dotnet@v4 - with: - dotnet-version: '8.0.x' - - - name: Restore - run: dotnet restore hmailserver/source/Tools/ControlPanel/ControlPanel.csproj - - - name: Build (Release, warnings as errors) - run: dotnet build hmailserver/source/Tools/ControlPanel/ControlPanel.csproj -c Release --no-restore -warnaserror - - - name: Publish (smoke check) - run: dotnet publish hmailserver/source/Tools/ControlPanel/ControlPanel.csproj -c Release -o publish --no-build +name: CI + +# Builds the .NET 8 Control Panel (hMailCP) on every push / PR. This catches C# +# regressions cheaply. The C++ server build + the 898-test regression suite need +# the prebuilt native libraries (OpenSSL 4.0.x, Boost 1.91, PostgreSQL 18 libpq — +# see libraries/build-dependencies.ps1) and a database service, so they run in the +# separate, manually-triggered server-build workflow. + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + workflow_dispatch: + +permissions: + contents: read + +jobs: + control-panel: + name: Build Control Panel (.NET 8) + runs-on: windows-latest + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Set up .NET 8 + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '8.0.x' + + - name: Restore + run: dotnet restore hmailserver/source/Tools/ControlPanel/ControlPanel.csproj + + - name: Build (Release, warnings as errors) + run: dotnet build hmailserver/source/Tools/ControlPanel/ControlPanel.csproj -c Release --no-restore -warnaserror + + - name: Publish (smoke check) + run: dotnet publish hmailserver/source/Tools/ControlPanel/ControlPanel.csproj -c Release -o publish --no-build diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 77ada88b..f4aa02b8 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,48 +1,48 @@ -name: CodeQL - -# Static security analysis for the C# code (Control Panel). C++ CodeQL needs the -# native server build (OpenSSL/Boost/libpq) and is deferred to the server-build -# pipeline; this workflow scopes the build to the .NET 8 Control Panel. - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - schedule: - - cron: '32 4 * * 1' # weekly, Monday 04:32 UTC - workflow_dispatch: - -permissions: - contents: read - -jobs: - analyze: - name: Analyze (csharp) - runs-on: windows-latest - permissions: - security-events: write - actions: read - contents: read - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Set up .NET 8 - uses: actions/setup-dotnet@v4 - with: - dotnet-version: '8.0.x' - - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: csharp - build-mode: manual - - - name: Build Control Panel - run: dotnet build hmailserver/source/Tools/ControlPanel/ControlPanel.csproj -c Release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 - with: - category: "/language:csharp" +name: CodeQL + +# Static security analysis for the C# code (Control Panel). C++ CodeQL needs the +# native server build (OpenSSL/Boost/libpq) and is deferred to the server-build +# pipeline; this workflow scopes the build to the .NET 8 Control Panel. + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + schedule: + - cron: '32 4 * * 1' # weekly, Monday 04:32 UTC + workflow_dispatch: + +permissions: + contents: read + +jobs: + analyze: + name: Analyze (csharp) + runs-on: windows-latest + permissions: + security-events: write + actions: read + contents: read + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Set up .NET 8 + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '8.0.x' + + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: csharp + build-mode: manual + + - name: Build Control Panel + run: dotnet build hmailserver/source/Tools/ControlPanel/ControlPanel.csproj -c Release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: "/language:csharp" diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 88bd5204..4b540c4f 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -1,30 +1,30 @@ -name: Dependency review - -# On every pull request, fail if the change introduces a dependency with a known -# high-or-critical CVE (GitHub Advisory Database). This is the merge-time gate -# that complements Dependabot's continuous alerts and the SBOM workflow, giving -# the B8 "dependency/CVE scanning" supply-chain requirement a green-gate. - -on: - pull_request: - branches: [ master ] - -permissions: - contents: read - -jobs: - dependency-review: - name: Dependency review - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: write - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Review dependencies - uses: actions/dependency-review-action@v4 - with: - fail-on-severity: high - comment-summary-in-pr: on-failure +name: Dependency review + +# On every pull request, fail if the change introduces a dependency with a known +# high-or-critical CVE (GitHub Advisory Database). This is the merge-time gate +# that complements Dependabot's continuous alerts and the SBOM workflow, giving +# the B8 "dependency/CVE scanning" supply-chain requirement a green-gate. + +on: + pull_request: + branches: [ master ] + +permissions: + contents: read + +jobs: + dependency-review: + name: Dependency review + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Review dependencies + uses: actions/dependency-review-action@v5 + with: + fail-on-severity: high + comment-summary-in-pr: on-failure diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index ddf2b257..14dbb99f 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -1,44 +1,44 @@ -name: SBOM - -# Generates a Software Bill of Materials for the repository on every push to -# master and attaches it to every published GitHub release, so each shipped -# build has an auditable inventory of its components. Syft (anchore/sbom-action) -# inventories the .NET package references and the files in the tree; the SBOM is -# emitted in both SPDX and CycloneDX JSON. Combined with Dependabot + the -# dependency-review gate, this delivers the B8 "SBOM + dependency/CVE scanning" -# supply-chain requirement. - -on: - push: - branches: [ master ] - release: - types: [ published ] - workflow_dispatch: - -permissions: - contents: read - -jobs: - sbom: - name: Generate SBOM (SPDX + CycloneDX) - runs-on: ubuntu-latest - permissions: - # Required so the SBOM can be attached as an asset on release events. - contents: write - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Generate SPDX SBOM - uses: anchore/sbom-action@v0 - with: - path: . - format: spdx-json - artifact-name: hmailserver.spdx.json - - - name: Generate CycloneDX SBOM - uses: anchore/sbom-action@v0 - with: - path: . - format: cyclonedx-json - artifact-name: hmailserver.cyclonedx.json +name: SBOM + +# Generates a Software Bill of Materials for the repository on every push to +# master and attaches it to every published GitHub release, so each shipped +# build has an auditable inventory of its components. Syft (anchore/sbom-action) +# inventories the .NET package references and the files in the tree; the SBOM is +# emitted in both SPDX and CycloneDX JSON. Combined with Dependabot + the +# dependency-review gate, this delivers the B8 "SBOM + dependency/CVE scanning" +# supply-chain requirement. + +on: + push: + branches: [ master ] + release: + types: [ published ] + workflow_dispatch: + +permissions: + contents: read + +jobs: + sbom: + name: Generate SBOM (SPDX + CycloneDX) + runs-on: ubuntu-latest + permissions: + # Required so the SBOM can be attached as an asset on release events. + contents: write + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Generate SPDX SBOM + uses: anchore/sbom-action@v0 + with: + path: . + format: spdx-json + artifact-name: hmailserver.spdx.json + + - name: Generate CycloneDX SBOM + uses: anchore/sbom-action@v0 + with: + path: . + format: cyclonedx-json + artifact-name: hmailserver.cyclonedx.json diff --git a/.github/workflows/server-build.yml b/.github/workflows/server-build.yml index a814af68..103c5742 100644 --- a/.github/workflows/server-build.yml +++ b/.github/workflows/server-build.yml @@ -1,104 +1,104 @@ -name: Server build & regression tests - -# Builds the native C++ hMailServer service and (optionally) runs the regression -# suite. -# -# This workflow REQUIRES a self-hosted Windows runner. The GitHub-hosted runners -# cannot build the server because it needs: -# * Visual Studio 2026 Build Tools — platform toolset v145 (MSVC 14.51); and -# * the prebuilt native dependencies (boost_1_91_0, openssl-4.0.1, -# postgresql-18.3) pointed to by the machine environment variable -# hMailServerLibs (see libraries/build-dependencies.ps1 and -# IMPLEMENTATION-NOTES.md). -# -# Set up a self-hosted runner with the labels [self-hosted, windows] on a machine -# that has the build prerequisites above. The "Build server" job only needs the -# toolchain + dependencies and is the primary compile gate. -# -# Running the regression suite (run_tests = true) additionally needs: -# * the runner process to be elevated (post-build.ps1 registers the COM server -# and the steps control the Windows service); -# * the hMailServer Windows service installed on the runner, with its image path -# pointing at this checkout's build output; and -# * a reachable database plus the test-environment integrations (see AGENTS.md / -# IMPLEMENTATION-NOTES.md for the recipe behind the full 898/898 result). - -on: - workflow_dispatch: - inputs: - configuration: - description: 'Build configuration' - type: choice - options: [Release, Debug] - default: Release - run_tests: - description: 'Also build and run the regression suite (needs DB + deployed service on the runner)' - type: boolean - default: false - -permissions: - contents: read - -jobs: - server-build: - name: Build server (VS 2026 / v145) - runs-on: [self-hosted, windows] - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Verify native dependencies - shell: powershell - run: | - if (-not $env:hMailServerLibs) { throw "hMailServerLibs is not set on this runner." } - if (-not (Test-Path $env:hMailServerLibs)) { throw "hMailServerLibs path '$($env:hMailServerLibs)' does not exist." } - foreach ($d in 'boost_1_91_0', 'openssl-4.0.1', 'postgresql-18.3') { - if (-not (Test-Path (Join-Path $env:hMailServerLibs $d))) { - Write-Warning "Expected dependency folder not found under hMailServerLibs: $d (the build may fail to link)." - } - } - Write-Host "hMailServerLibs = $($env:hMailServerLibs)" - - - name: Stop hMailServer service (free the executable) - shell: powershell - run: Stop-Service hMailServer -ErrorAction SilentlyContinue - - - name: Build server (warnings = errors via /WX in the project) - shell: powershell - run: ./build/build.ps1 -Configuration ${{ github.event.inputs.configuration }} - - - name: Build regression tests - if: ${{ github.event.inputs.run_tests == 'true' }} - shell: powershell - run: ./build/build-tests.ps1 - - - name: Deploy & register COM (post-build) - if: ${{ github.event.inputs.run_tests == 'true' }} - shell: powershell - run: ./build/post-build.ps1 -Configuration ${{ github.event.inputs.configuration }} - - - name: Start hMailServer service - if: ${{ github.event.inputs.run_tests == 'true' }} - shell: powershell - run: | - Remove-Item 'C:\HM\Logs\ERROR_hmailserver_*.log' -ErrorAction SilentlyContinue - Start-Service hMailServer - Start-Sleep -Seconds 5 - - - name: Run regression suite - if: ${{ github.event.inputs.run_tests == 'true' }} - shell: powershell - run: ./build/run-tests.ps1 - - - name: Upload test results - if: ${{ always() && github.event.inputs.run_tests == 'true' }} - uses: actions/upload-artifact@v4 - with: - name: regression-test-results - path: TestResult.xml - if-no-files-found: ignore - - - name: Restart hMailServer service - if: ${{ always() }} - shell: powershell - run: Start-Service hMailServer -ErrorAction SilentlyContinue +name: Server build & regression tests + +# Builds the native C++ hMailServer service and (optionally) runs the regression +# suite. +# +# This workflow REQUIRES a self-hosted Windows runner. The GitHub-hosted runners +# cannot build the server because it needs: +# * Visual Studio 2026 Build Tools — platform toolset v145 (MSVC 14.51); and +# * the prebuilt native dependencies (boost_1_91_0, openssl-4.0.1, +# postgresql-18.3) pointed to by the machine environment variable +# hMailServerLibs (see libraries/build-dependencies.ps1 and +# IMPLEMENTATION-NOTES.md). +# +# Set up a self-hosted runner with the labels [self-hosted, windows] on a machine +# that has the build prerequisites above. The "Build server" job only needs the +# toolchain + dependencies and is the primary compile gate. +# +# Running the regression suite (run_tests = true) additionally needs: +# * the runner process to be elevated (post-build.ps1 registers the COM server +# and the steps control the Windows service); +# * the hMailServer Windows service installed on the runner, with its image path +# pointing at this checkout's build output; and +# * a reachable database plus the test-environment integrations (see AGENTS.md / +# IMPLEMENTATION-NOTES.md for the recipe behind the full 898/898 result). + +on: + workflow_dispatch: + inputs: + configuration: + description: 'Build configuration' + type: choice + options: [Release, Debug] + default: Release + run_tests: + description: 'Also build and run the regression suite (needs DB + deployed service on the runner)' + type: boolean + default: false + +permissions: + contents: read + +jobs: + server-build: + name: Build server (VS 2026 / v145) + runs-on: [self-hosted, windows] + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Verify native dependencies + shell: powershell + run: | + if (-not $env:hMailServerLibs) { throw "hMailServerLibs is not set on this runner." } + if (-not (Test-Path $env:hMailServerLibs)) { throw "hMailServerLibs path '$($env:hMailServerLibs)' does not exist." } + foreach ($d in 'boost_1_91_0', 'openssl-4.0.1', 'postgresql-18.3') { + if (-not (Test-Path (Join-Path $env:hMailServerLibs $d))) { + Write-Warning "Expected dependency folder not found under hMailServerLibs: $d (the build may fail to link)." + } + } + Write-Host "hMailServerLibs = $($env:hMailServerLibs)" + + - name: Stop hMailServer service (free the executable) + shell: powershell + run: Stop-Service hMailServer -ErrorAction SilentlyContinue + + - name: Build server (warnings = errors via /WX in the project) + shell: powershell + run: ./build/build.ps1 -Configuration ${{ github.event.inputs.configuration }} + + - name: Build regression tests + if: ${{ github.event.inputs.run_tests == 'true' }} + shell: powershell + run: ./build/build-tests.ps1 + + - name: Deploy & register COM (post-build) + if: ${{ github.event.inputs.run_tests == 'true' }} + shell: powershell + run: ./build/post-build.ps1 -Configuration ${{ github.event.inputs.configuration }} + + - name: Start hMailServer service + if: ${{ github.event.inputs.run_tests == 'true' }} + shell: powershell + run: | + Remove-Item 'C:\HM\Logs\ERROR_hmailserver_*.log' -ErrorAction SilentlyContinue + Start-Service hMailServer + Start-Sleep -Seconds 5 + + - name: Run regression suite + if: ${{ github.event.inputs.run_tests == 'true' }} + shell: powershell + run: ./build/run-tests.ps1 + + - name: Upload test results + if: ${{ always() && github.event.inputs.run_tests == 'true' }} + uses: actions/upload-artifact@v7 + with: + name: regression-test-results + path: TestResult.xml + if-no-files-found: ignore + + - name: Restart hMailServer service + if: ${{ always() }} + shell: powershell + run: Start-Service hMailServer -ErrorAction SilentlyContinue