name: Release pipeline on: workflow_dispatch: push: tags: - 'v*' permissions: contents: write id-token: write jobs: bootstrap: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup cosign uses: sigstore/cosign-installer@v3.5.0 - name: Validate bootstrap run: | bash -n deploy/ochenstarik-server-monitor-manager.sh bash -n deploy/ochenstarik-smm-policy-apply bash -n deploy/ochenstarik-smm-emergency bash -n tests/bootstrap/run-native-systemd-smoke.sh bash -n tests/bootstrap/run-systemd-container-smoke.sh shellcheck --severity=error deploy/ochenstarik-server-monitor-manager.sh shellcheck --severity=error deploy/ochenstarik-smm-policy-apply shellcheck --severity=error deploy/ochenstarik-smm-emergency shellcheck --severity=error tests/bootstrap/run-native-systemd-smoke.sh shellcheck --severity=error tests/bootstrap/run-systemd-container-smoke.sh bash tests/bootstrap/test-bootstrap-contract.sh bash tests/bootstrap/test-manifest-verification.sh - name: Package bootstrap shell: bash run: | set -Eeuo pipefail install -m 0755 deploy/ochenstarik-server-monitor-manager.sh ochenstarik-server-monitor-manager.sh # Substitute PROGRAM_VERSION from tag if [[ "${GITHUB_REF}" == refs/tags/* ]]; then sed -i "s/^PROGRAM_VERSION=.*$/PROGRAM_VERSION=\"${GITHUB_REF_NAME}\"/" ochenstarik-server-monitor-manager.sh fi sha256sum ochenstarik-server-monitor-manager.sh > ochenstarik-server-monitor-manager.sh.sha256 - name: Upload bootstrap artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: server-monitor-manager-bootstrap path: | ochenstarik-server-monitor-manager.sh ochenstarik-server-monitor-manager.sh.sha256 publish-linux: runs-on: ubuntu-latest strategy: matrix: runtime: [linux-x64, linux-arm64] steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up .NET 10 uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: dotnet-version: 10.0.x - name: Set Version id: version shell: bash run: | if [[ "${GITHUB_REF}" == refs/tags/* ]]; then VERSION="${GITHUB_REF_NAME#v}" else VERSION="0.2.0-dev" fi echo "version=${VERSION}" >> $GITHUB_OUTPUT - name: Publish agent run: dotnet publish src/ServerMonitorManager.Agent/ServerMonitorManager.Agent.csproj --configuration Release --runtime ${{ matrix.runtime }} --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true -p:RestoreLockedMode=true -p:Version=${{ steps.version.outputs.version }} -o out/agent - name: Publish control run: dotnet publish src/ServerMonitorManager.Control/ServerMonitorManager.Control.csproj --configuration Release --runtime ${{ matrix.runtime }} --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true -p:RestoreLockedMode=true -p:Version=${{ steps.version.outputs.version }} -o out/control - name: Publish provisioning helper run: dotnet publish src/ServerMonitorManager.Provisioning.Helper/ServerMonitorManager.Provisioning.Helper.csproj --configuration Release --runtime ${{ matrix.runtime }} --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true -p:RestoreLockedMode=true -p:Version=${{ steps.version.outputs.version }} -o out/provisioning-helper - name: Package shell: bash run: | set -Eeuo pipefail install -d out/deploy out/bootstrap install -m 0644 deploy/ochenstarik-smm-control.service out/deploy/ install -m 0644 deploy/ochenstarik-smm-agent.service out/deploy/ install -m 0644 deploy/ochenstarik-smm-provisioning-helper.service out/deploy/ install -m 0644 deploy/ochenstarik-smm-firewall.service out/deploy/ install -m 0755 deploy/ochenstarik-smm-policy-apply out/deploy/ install -m 0755 deploy/ochenstarik-smm-emergency out/deploy/ install -m 0755 deploy/ochenstarik-server-monitor-manager.sh out/bootstrap/ archive="server-monitor-manager-${{ matrix.runtime }}.tar.gz" tar -C out -czf "$archive" agent control provisioning-helper deploy bootstrap sha256sum "$archive" > "$archive.sha256" - name: Generate SBOM run: | dotnet tool install --global CycloneDX --version 6.2.0 dotnet CycloneDX ServerMonitorManager.slnx \ --output . \ --output-format Json \ --filename "server-monitor-manager-${{ matrix.runtime }}-sbom.json" - name: Upload artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: server-monitor-manager-${{ matrix.runtime }} path: | server-monitor-manager-${{ matrix.runtime }}.tar.gz server-monitor-manager-${{ matrix.runtime }}.tar.gz.sha256 server-monitor-manager-${{ matrix.runtime }}-sbom.json package-windows: runs-on: windows-latest env: SIGNING_CERTIFICATE_BASE64: ${{ secrets.WINDOWS_SIGNING_CERTIFICATE_BASE64 }} SIGNING_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_SIGNING_CERTIFICATE_PASSWORD }} steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up .NET 10 uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: dotnet-version: 10.0.x - name: Prepare signing certificate id: signing shell: pwsh run: | $directory = Join-Path $env:RUNNER_TEMP 'smm-signing' New-Item -ItemType Directory -Path $directory -Force | Out-Null if ($env:SIGNING_CERTIFICATE_BASE64 -and $env:SIGNING_CERTIFICATE_PASSWORD) { Write-Output "::add-mask::$env:SIGNING_CERTIFICATE_PASSWORD" $pfx = Join-Path $directory 'trusted-signing.pfx' [IO.File]::WriteAllBytes($pfx, [Convert]::FromBase64String($env:SIGNING_CERTIFICATE_BASE64)) "certificate=$pfx" >> $env:GITHUB_OUTPUT "password=$env:SIGNING_CERTIFICATE_PASSWORD" >> $env:GITHUB_OUTPUT "test_certificate=false" >> $env:GITHUB_OUTPUT } else { $password = [Convert]::ToBase64String([Security.Cryptography.RandomNumberGenerator]::GetBytes(24)) Write-Output "::add-mask::$password" ./build/windows/New-TestSigningCertificate.ps1 -OutputDirectory $directory -Password $password "certificate=$(Join-Path $directory 'server-monitor-manager-test-signing.pfx')" >> $env:GITHUB_OUTPUT "public_certificate=$(Join-Path $directory 'server-monitor-manager-test-signing.cer')" >> $env:GITHUB_OUTPUT "password=$password" >> $env:GITHUB_OUTPUT "test_certificate=true" >> $env:GITHUB_OUTPUT } - name: Set Version id: version shell: bash run: | if [[ "${GITHUB_REF}" == refs/tags/* ]]; then VERSION="${GITHUB_REF_NAME#v}" else VERSION="0.2.0-dev" fi echo "version=${VERSION}" >> $GITHUB_OUTPUT - name: Build signed MSIX shell: pwsh run: ./build/windows/Build-Installer.ps1 -CertificatePath '${{ steps.signing.outputs.certificate }}' -CertificatePassword '${{ steps.signing.outputs.password }}' -Version '${{ steps.version.outputs.version }}' - name: Include test certificate if: steps.signing.outputs.test_certificate == 'true' shell: pwsh run: Copy-Item -LiteralPath '${{ steps.signing.outputs.public_certificate }}' -Destination artifacts/windows-installer/ServerMonitorManager-test-signing.cer - name: Verify checksum shell: pwsh run: | $line = Get-Content artifacts/windows-installer/SHA256SUMS $expected = ($line -split ' ')[0] $actual = (Get-FileHash artifacts/windows-installer/ServerMonitorManager-win-x64.msix -Algorithm SHA256).Hash.ToLowerInvariant() if ($actual -ne $expected) { throw 'Windows installer checksum mismatch.' } - name: Generate SBOM shell: bash run: | dotnet tool install --global CycloneDX --version 6.2.0 dotnet CycloneDX ServerMonitorManager.slnx \ --output . \ --output-format Json \ --filename server-monitor-manager-win-x64-sbom.json - name: Upload installer artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: server-monitor-manager-win-x64 path: | artifacts/windows-installer/ServerMonitorManager-win-x64.msix artifacts/windows-installer/ServerMonitorManager-test-signing.cer artifacts/windows-installer/SHA256SUMS server-monitor-manager-win-x64-sbom.json if-no-files-found: error manifest: runs-on: ubuntu-latest needs: [bootstrap, publish-linux, package-windows] steps: - name: Setup cosign uses: sigstore/cosign-installer@v3.5.0 - name: Download all artifacts uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: path: artifacts - name: Generate Manifest v2 shell: bash run: | set -Eeuo pipefail # Version fallback for non-tag runs VERSION="${GITHUB_REF_NAME}" if [[ ! "${GITHUB_REF}" == refs/tags/* ]]; then VERSION="0.0.0-dev" fi # Calculate hashes BOOTSTRAP_SHA=$(sha256sum artifacts/server-monitor-manager-bootstrap/ochenstarik-server-monitor-manager.sh | awk '{print $1}') LINUX_X64_SHA=$(sha256sum artifacts/server-monitor-manager-linux-x64/server-monitor-manager-linux-x64.tar.gz | awk '{print $1}') LINUX_ARM64_SHA=$(sha256sum artifacts/server-monitor-manager-linux-arm64/server-monitor-manager-linux-arm64.tar.gz | awk '{print $1}') MSIX_SHA=$(sha256sum artifacts/server-monitor-manager-win-x64/ServerMonitorManager-win-x64.msix | awk '{print $1}') LINUX_X64_SBOM_SHA=$(sha256sum artifacts/server-monitor-manager-linux-x64/server-monitor-manager-linux-x64-sbom.json | awk '{print $1}') LINUX_ARM64_SBOM_SHA=$(sha256sum artifacts/server-monitor-manager-linux-arm64/server-monitor-manager-linux-arm64-sbom.json | awk '{print $1}') WIN_X64_SBOM_SHA=$(sha256sum artifacts/server-monitor-manager-win-x64/server-monitor-manager-win-x64-sbom.json | awk '{print $1}') jq -n \ --arg schema "smm-manifest/v2" \ --arg version "$VERSION" \ --arg bootstrap_sha256 "$BOOTSTRAP_SHA" \ --arg linux_x64_sha256 "$LINUX_X64_SHA" \ --arg linux_arm64_sha256 "$LINUX_ARM64_SHA" \ --arg msix_sha256 "$MSIX_SHA" \ --arg linux_x64_sbom_sha256 "$LINUX_X64_SBOM_SHA" \ --arg linux_arm64_sbom_sha256 "$LINUX_ARM64_SBOM_SHA" \ --arg win_x64_sbom_sha256 "$WIN_X64_SBOM_SHA" \ '{ schema: $schema, version: $version, components: { control: $version, agent: $version, helper: $version, desktop: $version }, protocols: { helper_protocol: "v1" }, hashes: { "ochenstarik-server-monitor-manager.sh": $bootstrap_sha256, "server-monitor-manager-linux-x64.tar.gz": $linux_x64_sha256, "server-monitor-manager-linux-arm64.tar.gz": $linux_arm64_sha256, "ServerMonitorManager-win-x64.msix": $msix_sha256, "server-monitor-manager-linux-x64-sbom.json": $linux_x64_sbom_sha256, "server-monitor-manager-linux-arm64-sbom.json": $linux_arm64_sbom_sha256, "server-monitor-manager-win-x64-sbom.json": $win_x64_sbom_sha256 } }' > server-monitor-manager-manifest.json - name: Sign Manifest shell: bash run: | cosign sign-blob --yes --output-signature server-monitor-manager-manifest.sig server-monitor-manager-manifest.json - name: Attach artifacts to GitHub Release if: startsWith(github.ref, 'refs/tags/') uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2 with: prerelease: ${{ contains(github.ref_name, '-') }} files: | artifacts/server-monitor-manager-bootstrap/* artifacts/server-monitor-manager-linux-x64/* artifacts/server-monitor-manager-linux-arm64/* artifacts/server-monitor-manager-win-x64/* server-monitor-manager-manifest.json server-monitor-manager-manifest.sig