Skip to content

Publish Signed Builds #62

Publish Signed Builds

Publish Signed Builds #62

# Credits to @Scighost from Starward for his contributions!
name: Publish Signed Builds
#run-name: Canary Build for ${{ github.ref }}
on:
workflow_dispatch:
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
SIGNPATH_ARTIFACT_SLUG: 'aot-release' # change this to 'aot-release' when releasing with AOT or 'initial' for normal release
BUILD_PROFILE_PREVIEW: 'Publish-PreviewReleaseAOT'
BUILD_PROFILE_STABLE: 'Publish-StableReleaseAOT'
BUILD_PROFILE_DEBUG: 'Publish-DebugCIReleaseAOT'
# schedule:
# - cron: '0 0 * * 0' # At 00:00 on Sunday
jobs:
build:
runs-on: windows-2025-vs2026
strategy:
matrix:
platform: [x64]
# Required for build attestation
permissions:
id-token: write
attestations: write
env:
CONFIGURATION_STRATEGY: ""
PUBLISH_PROFILE: ""
SIGNING_POLICY_SLUG: ""
VERSION: ""
PRODUCT_VERSION: ""
Platform: ${{ matrix.platform }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
steps:
- name: Set Configuration and Environment Variables
id: set_env
run: |
$branch = $env:GITHUB_REF_NAME
echo "ADDITIONAL_COMPPARAM=-p:PublishAotSelf=true" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
if ($branch -eq "preview") {
echo "CONFIGURATION_STRATEGY=Release" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
echo "PUBLISH_PROFILE=${{ env.BUILD_PROFILE_PREVIEW }}" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
echo "SIGNING_POLICY_SLUG=release-signing" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
} elseif ($branch -eq "stable") {
echo "CONFIGURATION_STRATEGY=Publish" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
echo "PUBLISH_PROFILE=${{ env.BUILD_PROFILE_STABLE }}" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
echo "SIGNING_POLICY_SLUG=release-signing" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
} elseif ($branch -eq "github-signpath-test") {
echo "CONFIGURATION_STRATEGY=Release" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
echo "PUBLISH_PROFILE=${{ env.BUILD_PROFILE_PREVIEW }}" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
echo "SIGNING_POLICY_SLUG=test-signing-ci" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
} else {
Write-Error "Unknown branch or input: $branch"
exit 1
}
- name: Print env
run: |
echo "::notice::Configuration Strategy: $env:CONFIGURATION_STRATEGY"
echo "::notice::Publish Profile: $env:PUBLISH_PROFILE"
echo "::notice::Signing Policy: $env:SIGNING_POLICY_SLUG"
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: 'Preparing Environment Variables'
if: ${{ github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name }}
run: |
$env = Get-Content env.json | ConvertFrom-Json
foreach ($prop in $env.PSObject.Properties) {
echo "$($prop.Name)=$($prop.Value)" >> $env:GITHUB_ENV
}
- name: Install .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
dotnet-quality: ${{ env.DOTNET_QUALITY }}
cache: true
cache-dependency-path: CollapseLauncher/packages.lock.json
- name: Build
run: |
dotnet workload update
dotnet publish CollapseLauncher -c ${{ env.CONFIGURATION_STRATEGY }} -p:PublishProfile=${{ env.PUBLISH_PROFILE }} -p:PublishDir=".\build\" ${{ env.ADDITIONAL_COMPPARAM }}
- name: Prepare publish artifacts
run: |
cd CollapseLauncher
.\build\CollapseLauncher.exe generatevelopackmetadata
$version = ((Get-Item .\build\CollapseLauncher.exe).VersionInfo.FileVersion)
if ($version.EndsWith(".0")) {
$version = $version.Substring(0, $version.Length - 2)
}
echo "::notice::Build version: $version"
echo "VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
mkdir SignArtifact
mkdir SignArtifact\BuildArtifact-$version
xcopy .\build\ "SignArtifact\BuildArtifact-$version\" /E /K /Y /I
- name: Upload Artifact (unsigned)
id: upload-unsigned-artifact
uses: actions/upload-artifact@v4
with:
name: collapse-v${{ env.VERSION }}_${{ env.SIGNING_POLICY_SLUG }}-${{ env.CONFIGURATION_STRATEGY }}_${{ env.PUBLISH_PROFILE }}
path: ./CollapseLauncher/SignArtifact
compression-level: 9
- name: Notify Discord for pending build
uses: sarisia/actions-status-discord@v1.15.3
if: always()
continue-on-error: true
with:
webhook: ${{ secrets.DISCORD_WEBHOOK_CIRELEASENOTIFIER }}
title: Collapse Launcher Release CI build is PENDING!
nofail: true
color: 0xFF0000
url: https://github.com/CollapseLauncher/Collapse/actions/runs/${{ github.run_id }}
description: |
Commit `${{ github.sha }}` by ${{ github.actor }} in branch `${{ github.ref_name }}`
Version: ${{ env.VERSION }}
[Click here to view the run](https://github.com/CollapseLauncher/Collapse/actions/runs/${{ github.run_id }})
For core maintainers, go to SignPath to sign the build!
- name: Sign Build Artifact with SignPath
uses: signpath/github-action-submit-signing-request@v1.3
with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
organization-id: ${{ secrets.SIGNPATH_ORG_ID }}
project-slug: 'Collapse'
signing-policy-slug: ${{ env.SIGNING_POLICY_SLUG }}
github-artifact-id: '${{ steps.upload-unsigned-artifact.outputs.artifact-id }}'
wait-for-completion: true
wait-for-completion-timeout-in-seconds: 1200
output-artifact-directory: '${{ runner.temp }}/SignedArtifact/'
artifact-configuration-slug: ${{ env.SIGNPATH_ARTIFACT_SLUG}}
- name: Process Signed Build
run: |
$buildDir = '${{ runner.temp }}\SignedArtifact\BuildArtifact-${{ env.VERSION }}'
echo "Re-checking build version"
$versionFinal = ((Get-Item $buildDir\CollapseLauncher.exe).VersionInfo.FileVersion)
if ($versionFinal.EndsWith(".0")) {
$versionFinal = $versionFinal.Substring(0, $versionFinal.Length - 2)
}
echo "::notice::Final build version: $versionFinal"
echo "VERSION=$versionFinal" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
- name: Verify Signed Artifacts
run: |
$buildDir = '${{ runner.temp }}\SignedArtifact\BuildArtifact-${{ env.VERSION }}'
$files = Get-ChildItem -Path "$buildDir" -Recurse -Include "*.exe","*.dll"
foreach ($file in $files) {
$signature = Get-AuthenticodeSignature $file.FullName
if ($signature.Status -ne "Valid") {
echo "::error::Invalid signature on $($file.Name): $($signature.Status)"
}
else {
echo "::notice::✓ $($file.Name): $($signature.SignerCertificate.Subject)"
}
}
- name: Re-upload Signed Artifact to GitHub
uses: actions/upload-artifact@v4
with:
name: SIGNED_collapse-v${{ env.VERSION }}_${{ env.SIGNING_POLICY_SLUG }}-${{ env.CONFIGURATION_STRATEGY }}_${{ env.PUBLISH_PROFILE }}
path: ${{ runner.temp }}/SignedArtifact
compression-level: 9
- name: Final Notify Discord
uses: sarisia/actions-status-discord@v1.15.3
if: always()
continue-on-error: true
with:
webhook: ${{ secrets.DISCORD_WEBHOOK_CIRELEASENOTIFIER }}
title: Collapse Launcher Release CI build is complete!
status: ${{ job.status }}
nofail: true
url: https://github.com/CollapseLauncher/Collapse/actions/runs/${{ github.run_id }}
description: |
Commit `${{ github.sha }}` by ${{ github.actor }} in branch `${{ github.ref_name }}`
Click [here](https://nightly.link/CollapseLauncher/Collapse/actions/runs/${{ github.run_id }}) to download!
- name: Install Sentry CLI
uses: MinoruSekine/setup-scoop@v4.0.1
with:
buckets: extras
apps: sentry-cli
- name: Upload Debug artifact to Sentry
continue-on-error: true
shell: pwsh
run: |
sentry-cli debug-files upload --org collapse --project collapse-launcher --include-sources '${{ runner.temp }}\SignedArtifact\BuildArtifact-${{ env.VERSION }}'
- name: Set release version in Sentry
shell: pwsh
continue-on-error: true
run: |
$exePath = "${{ runner.temp }}\SignedArtifact\BuildArtifact-${{ env.VERSION }}\CollapseLauncher.exe"
if (Test-Path $exePath) {
$prefix = "CollapseLauncher@"
$version = ((Get-Item $exePath).VersionInfo.ProductVersion)
$version = $prefix + $version
if ($version) {
sentry-cli releases new --org collapse --project collapse-launcher $version
sentry-cli releases set-commits --auto $version
sentry-cli releases finalize $version
}
else {
Write-Warning "No product version found in $exePath"
}
}
else {
Write-Error "File not found: $exePath"
}
- name: Attest Build Provenance
uses: actions/attest-build-provenance@v3
with:
subject-path: "${{ runner.temp }}/SignedArtifact/BuildArtifact-${{ env.VERSION }}/**"