diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 99829bc..99ed8c1 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -9,14 +9,15 @@ on: version: description: 'Version number (e.g. v1.2.3)' required: true - default: 'v1.2.3' permissions: contents: write + # Necessary for GCP authentication (https://github.com/google-github-actions/setup-gcloud#usage) + id-token: write jobs: release: - runs-on: windows-latest + runs-on: ${{ github.repository_owner == 'coder' && 'windows-latest-16-cores' || 'windows-latest' }} steps: - uses: actions/checkout@v4 @@ -64,8 +65,16 @@ jobs: service_account: ${{ secrets.GCP_CODE_SIGNING_SERVICE_ACCOUNT }} token_format: "access_token" - - name: Setup GCloud SDK - uses: google-github-actions/setup-gcloud@77e7a554d41e2ee56fc945c52dfd3f33d12def9a # v2.1.4 + - name: Install wix + shell: pwsh + run: | + $ErrorActionPreference = "Stop" + & dotnet.exe tool install --global wix --version 5.0.2 + if ($LASTEXITCODE -ne 0) { throw "Failed to install wix" } + foreach ($ext in @("WixToolset.Bal.wixext/5.0.2", "WixToolset.Netfx.wixext/5.0.2", "WixToolset.UI.wixext/5.0.2", "WixToolset.Util.wixext/5.0.2")) { + & wix.exe extension add -g $ext + if ($LASTEXITCODE -ne 0) { throw "Failed to add wix extension $ext" } + } - name: scripts/Release.ps1 id: release @@ -74,6 +83,7 @@ jobs: $ErrorActionPreference = "Stop" $env:EV_CERTIFICATE_PATH = Join-Path $env:TEMP "ev_cert.pem" + Set-Content -Path $env:EV_CERTIFICATE_PATH -Value $env:EV_SIGNING_CERT $env:JSIGN_PATH = Join-Path $env:TEMP "jsign-6.0.jar" Invoke-WebRequest -Uri "https://github.com/ebourg/jsign/releases/download/6.0/jsign-6.0.jar" -OutFile $env:JSIGN_PATH diff --git a/.gitignore b/.gitignore index 54c47a0..0ebfb2c 100644 --- a/.gitignore +++ b/.gitignore @@ -403,7 +403,11 @@ FodyWeavers.xsd .idea/**/shelf publish -WindowsAppRuntimeInstall-*.exe -windowsdesktop-runtime-*.exe -wintun.dll -wintun-*.dll + +*.wxs +*.wixobj +*.wixpdb +*.wixlib +*.wixmdb +*.wixprj +*.wixproj diff --git a/scripts/Publish.ps1 b/scripts/Publish.ps1 index 2bdc7d6..08b30bd 100644 --- a/scripts/Publish.ps1 +++ b/scripts/Publish.ps1 @@ -1,4 +1,4 @@ -# Usage: Publish.ps1 -arch -version [-buildPath ] [-outputPath ] +# Usage: Publish.ps1 -arch -version [-msiOutputPath ] [-outputPath ] [-sign] param ( [ValidateSet("x64", "arm64")] [Parameter(Mandatory = $true)] @@ -50,6 +50,8 @@ function Find-EnvironmentVariables([string[]] $variables) { } } +Find-Dependencies @("dotnet.exe", "wix.exe") + if ($sign) { Write-Host "Signing is enabled" Find-Dependencies java @@ -73,6 +75,12 @@ function Add-CoderSignature([string] $path) { --tsaurl $env:EV_TSA_URL ` $path if ($LASTEXITCODE -ne 0) { throw "Failed to sign $path" } + + # Verify that the output exe is authenticode signed + $sig = Get-AuthenticodeSignature $path + if ($sig.Status -ne "Valid") { + throw "File $path is not authenticode signed" + } } # CD to the root of the repo @@ -97,13 +105,16 @@ if (Test-Path $outputPath.Replace(".exe", ".wixpdb")) { } # Create a publish directory -$buildPath = Join-Path $repoRoot "publish\buildtemp-$($version)-$($arch)" +$publishDir = Join-Path $repoRoot "publish" +$buildPath = Join-Path $publishDir "buildtemp-$($version)-$($arch)" if (Test-Path $buildPath) { Remove-Item -Recurse -Force $buildPath } New-Item -ItemType Directory -Path $buildPath -Force # Build in release mode +& dotnet.exe restore +if ($LASTEXITCODE -ne 0) { throw "Failed to dotnet restore" } $servicePublishDir = Join-Path $buildPath "service" & dotnet.exe publish .\Vpn.Service\Vpn.Service.csproj -c Release -a $arch -o $servicePublishDir if ($LASTEXITCODE -ne 0) { throw "Failed to build Vpn.Service" } @@ -126,8 +137,12 @@ Copy-Item "scripts\files\License.txt" $buildPath $vpnFilesPath = Join-Path $buildPath "vpn" New-Item -ItemType Directory -Path $vpnFilesPath -Force Copy-Item "scripts\files\LICENSE.WINTUN.txt" $vpnFilesPath -$wintunDllPath = Join-Path $vpnFilesPath "wintun.dll" -Copy-Item "scripts\files\wintun-*-$($arch).dll" $wintunDllPath +$wintunDllSrc = Get-Item "scripts\files\wintun-*-$($arch).dll" +if ($null -eq $wintunDllSrc) { + throw "Failed to find wintun DLL" +} +$wintunDllDest = Join-Path $vpnFilesPath "wintun.dll" +Copy-Item $wintunDllSrc $wintunDllDest # Build the MSI installer & dotnet.exe run --project .\Installer\Installer.csproj -c Release -- ` @@ -158,7 +173,39 @@ Add-CoderSignature $msiOutputPath --msi-path $msiOutputPath ` --logo-png "scripts\files\logo.png" if ($LASTEXITCODE -ne 0) { throw "Failed to build bootstrapper" } -Add-CoderSignature $outputPath + +# Sign the bootstrapper, which is not as simple as just signing the exe. +if ($sign) { + $burnIntermediate = Join-Path $publishDir "burn-intermediate-$($version)-$($arch)" + New-Item -ItemType Directory -Path $burnIntermediate -Force + $burnEngine = Join-Path $publishDir "burn-engine-$($version)-$($arch).exe" + + # Move the current output path + $unsignedOutputPath = Join-Path (Split-Path $outputPath -Parent) ("UNSIGNED-" + (Split-Path $outputPath -Leaf)) + Move-Item $outputPath $unsignedOutputPath + + # Extract the engine from the bootstrapper + & wix.exe burn detach $unsignedOutputPath -intermediateFolder $burnIntermediate -engine $burnEngine + if ($LASTEXITCODE -ne 0) { throw "Failed to extract engine from bootstrapper" } + + # Sign the engine + Add-CoderSignature $burnEngine + + # Re-attach the signed engine to the bootstrapper + & wix.exe burn reattach $unsignedOutputPath -intermediateFolder $burnIntermediate -engine $burnEngine -out $outputPath + if ($LASTEXITCODE -ne 0) { throw "Failed to re-attach signed engine to bootstrapper" } + if (!(Test-Path $outputPath)) { throw "Failed to create reattached bootstrapper at $outputPath" } + + # Now sign the output path + Add-CoderSignature $outputPath + + # Clean up the intermediate files + if (!$keepBuildTemp) { + Remove-Item -Force $unsignedOutputPath + Remove-Item -Recurse -Force $burnIntermediate + Remove-Item -Force $burnEngine + } +} if (!$keepBuildTemp) { Remove-Item -Recurse -Force $buildPath diff --git a/scripts/Release.ps1 b/scripts/Release.ps1 index 40bb0fa..1654f9a 100644 --- a/scripts/Release.ps1 +++ b/scripts/Release.ps1 @@ -1,48 +1,48 @@ # Usage: Release.ps1 -version param ( - [Parameter(Mandatory = $true)] - [ValidatePattern("^\d+\.\d+\.\d+\.\d+$")] - [string] $version, + [Parameter(Mandatory = $true)] + [ValidatePattern("^\d+\.\d+\.\d+$")] + [string] $version, - [Parameter(Mandatory = $true)] - [ValidatePattern("^\d+\.\d+\.\d+\.\d+$")] - [string] $assemblyVersion + [Parameter(Mandatory = $true)] + [ValidatePattern("^\d+\.\d+\.\d+\.\d+$")] + [string] $assemblyVersion ) $ErrorActionPreference = "Stop" foreach ($arch in @("x64", "arm64")) { - Write-Host "::group::Publishing $arch" - try { - $archUpper = $arch.ToUpper() + Write-Host "::group::Publishing $arch" + try { + $archUpper = $arch.ToUpper() - $msiOutputPath = "publish/CoderDesktopCore-$version-$arch.msi" - Add-Content -Path $env:GITHUB_OUTPUT -Value "$($archUpper)_MSI_OUTPUT_PATH=$msiOutputPath" - Write-Host "MSI_OUTPUT_PATH=$msiOutputPath" + $msiOutputPath = "publish/CoderDesktopCore-$version-$arch.msi" + Add-Content -Path $env:GITHUB_OUTPUT -Value "$($archUpper)_MSI_OUTPUT_PATH=$msiOutputPath" + Write-Host "MSI_OUTPUT_PATH=$msiOutputPath" - $outputPath = "publish/CoderDesktop-$version-$arch.exe" - Add-Content -Path $env:GITHUB_OUTPUT -Value "$($archUpper)_OUTPUT_PATH=$outputPath" - Write-Host "OUTPUT_PATH=$outputPath" + $outputPath = "publish/CoderDesktop-$version-$arch.exe" + Add-Content -Path $env:GITHUB_OUTPUT -Value "$($archUpper)_OUTPUT_PATH=$outputPath" + Write-Host "OUTPUT_PATH=$outputPath" - $publishScript = Join-Path $PSScriptRoot "Publish.ps1" - & $publishScript ` - -version $assemblyVersion ` - -arch $arch ` - -msiOutputPath $msiOutputPath ` - -outputPath $outputPath ` - -sign - if ($LASTEXITCODE -ne 0) { throw "Failed to publish" } + $publishScript = Join-Path $PSScriptRoot "Publish.ps1" + & $publishScript ` + -version $assemblyVersion ` + -arch $arch ` + -msiOutputPath $msiOutputPath ` + -outputPath $outputPath ` + -sign + if ($LASTEXITCODE -ne 0) { throw "Failed to publish" } - # Verify that the output exe is authenticode signed - $sig = Get-AuthenticodeSignature $outputPath - if ($sig.Status -ne "Valid") { - throw "Output file is not authenticode signed" + # Verify that the output exe is authenticode signed + $sig = Get-AuthenticodeSignature $outputPath + if ($sig.Status -ne "Valid") { + throw "Output file is not authenticode signed" + } + else { + Write-Host "Output file is authenticode signed" + } } - else { - Write-Host "Output file is authenticode signed" + finally { + Write-Host "::endgroup::" } - } - finally { - Write-Host "::endgroup::" - } } diff --git a/scripts/files/wintun-0.14.1-arm64.dll b/scripts/files/wintun-0.14.1-arm64.dll new file mode 100644 index 0000000..dc4e4ae Binary files /dev/null and b/scripts/files/wintun-0.14.1-arm64.dll differ diff --git a/scripts/files/wintun-0.14.1-x64.dll b/scripts/files/wintun-0.14.1-x64.dll new file mode 100644 index 0000000..aee04e7 Binary files /dev/null and b/scripts/files/wintun-0.14.1-x64.dll differ