mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-21 06:00:39 +00:00
feat(ci): sign x64 Windows releases with TrustAsia VSign
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string[]]$Path,
|
||||
|
||||
[string]$ExpectedCertificateSha1 = $env:VSIGN_CERT_HASH
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
Set-StrictMode -Version Latest
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($ExpectedCertificateSha1)) {
|
||||
throw "The expected Authenticode certificate SHA1 is not configured"
|
||||
}
|
||||
|
||||
$expectedSha1 = $ExpectedCertificateSha1.Replace(" ", "").ToUpperInvariant()
|
||||
if ($expectedSha1 -notmatch '^[0-9A-F]{40}$') {
|
||||
throw "The expected Authenticode certificate SHA1 is invalid"
|
||||
}
|
||||
|
||||
foreach ($candidate in $Path) {
|
||||
$resolvedPath = (Resolve-Path -LiteralPath $candidate -ErrorAction Stop).Path
|
||||
if (!(Test-Path -LiteralPath $resolvedPath -PathType Leaf)) {
|
||||
throw "Authenticode target is not a file: $resolvedPath"
|
||||
}
|
||||
|
||||
$signature = Get-AuthenticodeSignature -LiteralPath $resolvedPath
|
||||
if ($null -eq $signature.SignerCertificate) {
|
||||
throw "No Authenticode signature was found on $resolvedPath"
|
||||
}
|
||||
|
||||
$actualSha1 = $signature.SignerCertificate.Thumbprint.Replace(" ", "").ToUpperInvariant()
|
||||
if ($actualSha1 -ne $expectedSha1) {
|
||||
throw "Signing certificate mismatch on $resolvedPath. Expected $expectedSha1, got $actualSha1"
|
||||
}
|
||||
if ($signature.Status -ne "Valid") {
|
||||
throw "Authenticode signature status for $resolvedPath is $($signature.Status): $($signature.StatusMessage)"
|
||||
}
|
||||
if ($null -eq $signature.TimeStamperCertificate) {
|
||||
throw "The Authenticode signature on $resolvedPath does not contain a timestamp certificate"
|
||||
}
|
||||
|
||||
Write-Host "Verified Authenticode signature: $resolvedPath"
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
[CmdletBinding()]
|
||||
param()
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
Set-StrictMode -Version Latest
|
||||
|
||||
$requiredVariables = @(
|
||||
"GITHUB_ENV",
|
||||
"RUNNER_TEMP",
|
||||
"VSIGN_CERT_HASH",
|
||||
"VSIGN_OPERATOR_PFX_B64",
|
||||
"VSIGN_OPERATOR_PWD",
|
||||
"VSIGN_OPERATOR_SHA1",
|
||||
"VSIGN_SERVER",
|
||||
"VSIGN_TOOL_SHA256"
|
||||
)
|
||||
|
||||
foreach ($variableName in $requiredVariables) {
|
||||
$value = [Environment]::GetEnvironmentVariable($variableName)
|
||||
if ([string]::IsNullOrWhiteSpace($value)) {
|
||||
throw "Required VSign configuration is missing: $variableName"
|
||||
}
|
||||
}
|
||||
|
||||
$serverUri = $null
|
||||
if (![Uri]::TryCreate($env:VSIGN_SERVER, [UriKind]::Absolute, [ref]$serverUri) -or $serverUri.Scheme -ne "https") {
|
||||
throw "VSIGN_SERVER must be an absolute HTTPS URL"
|
||||
}
|
||||
|
||||
$expectedToolSha256 = $env:VSIGN_TOOL_SHA256.Replace(" ", "").ToUpperInvariant()
|
||||
$expectedOperatorSha1 = $env:VSIGN_OPERATOR_SHA1.Replace(" ", "").ToUpperInvariant()
|
||||
$expectedCertificateSha1 = $env:VSIGN_CERT_HASH.Replace(" ", "").ToUpperInvariant()
|
||||
if ($expectedToolSha256 -notmatch '^[0-9A-F]{64}$') {
|
||||
throw "VSIGN_TOOL_SHA256 is invalid"
|
||||
}
|
||||
if ($expectedOperatorSha1 -notmatch '^[0-9A-F]{40}$') {
|
||||
throw "VSIGN_OPERATOR_SHA1 is invalid"
|
||||
}
|
||||
if ($expectedCertificateSha1 -notmatch '^[0-9A-F]{40}$') {
|
||||
throw "VSIGN_CERT_HASH is invalid"
|
||||
}
|
||||
|
||||
$runId = if ([string]::IsNullOrWhiteSpace($env:GITHUB_RUN_ID)) { "local" } else { $env:GITHUB_RUN_ID }
|
||||
$runAttempt = if ([string]::IsNullOrWhiteSpace($env:GITHUB_RUN_ATTEMPT)) { "1" } else { $env:GITHUB_RUN_ATTEMPT }
|
||||
$workDir = Join-Path $env:RUNNER_TEMP "vsign-$runId-$runAttempt"
|
||||
$operatorDir = Join-Path $workDir "operator"
|
||||
$operatorFile = Join-Path $operatorDir "dbx-github-ci@ssigncode.pfx"
|
||||
$toolPath = Join-Path $workDir "ssigncode.exe"
|
||||
$toolUrl = "https://github.com/g5wsg/vsign-github-test1/releases/download/vsign-cli-v1/ssigncode.exe"
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $operatorDir | Out-Null
|
||||
Invoke-WebRequest -Uri $toolUrl -OutFile $toolPath
|
||||
|
||||
$actualToolSha256 = (Get-FileHash -LiteralPath $toolPath -Algorithm SHA256).Hash
|
||||
if ($actualToolSha256 -ne $expectedToolSha256) {
|
||||
throw "VSign CLI SHA256 mismatch. Expected $expectedToolSha256, got $actualToolSha256"
|
||||
}
|
||||
|
||||
& $toolPath version
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "VSign CLI version check failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
|
||||
try {
|
||||
$pfxBytes = [Convert]::FromBase64String($env:VSIGN_OPERATOR_PFX_B64.Trim())
|
||||
[IO.File]::WriteAllBytes($operatorFile, $pfxBytes)
|
||||
$flags = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::EphemeralKeySet
|
||||
$operatorCertificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new(
|
||||
$operatorFile,
|
||||
$env:VSIGN_OPERATOR_PWD,
|
||||
$flags
|
||||
)
|
||||
}
|
||||
catch {
|
||||
throw "Cannot restore or decrypt the VSign operator PFX: $($_.Exception.Message)"
|
||||
}
|
||||
|
||||
try {
|
||||
$actualOperatorSha1 = $operatorCertificate.Thumbprint.Replace(" ", "").ToUpperInvariant()
|
||||
if ($actualOperatorSha1 -ne $expectedOperatorSha1) {
|
||||
throw "Operator certificate mismatch. Expected $expectedOperatorSha1, got $actualOperatorSha1"
|
||||
}
|
||||
if (!$operatorCertificate.HasPrivateKey) {
|
||||
throw "The operator PFX does not contain a private key"
|
||||
}
|
||||
if ($operatorCertificate.NotAfter.ToUniversalTime() -le [DateTime]::UtcNow) {
|
||||
throw "The operator certificate has expired"
|
||||
}
|
||||
}
|
||||
finally {
|
||||
$operatorCertificate.Dispose()
|
||||
}
|
||||
|
||||
$githubEnvironment = [ordered]@{
|
||||
VSIGN_WORK_DIR = $workDir
|
||||
VSIGN_CLI = $toolPath
|
||||
SSIGNCODE_OPERATOR_STORE = "file"
|
||||
SSIGNCODE_OPERATOR_DIR = $operatorDir
|
||||
SSIGNCODE_OPERATOR_FILE = $operatorFile
|
||||
}
|
||||
|
||||
foreach ($entry in $githubEnvironment.GetEnumerator()) {
|
||||
"$($entry.Key)=$($entry.Value)" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
}
|
||||
|
||||
Write-Host "VSign CLI and operator certificate are ready."
|
||||
@@ -0,0 +1,72 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true, Position = 0)]
|
||||
[string]$FilePath
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
Set-StrictMode -Version Latest
|
||||
|
||||
$resolvedPath = (Resolve-Path -LiteralPath $FilePath -ErrorAction Stop).Path
|
||||
if (!(Test-Path -LiteralPath $resolvedPath -PathType Leaf)) {
|
||||
throw "VSign target is not a file: $resolvedPath"
|
||||
}
|
||||
|
||||
$extension = [IO.Path]::GetExtension($resolvedPath).ToLowerInvariant()
|
||||
if ($extension -eq ".dll") {
|
||||
Write-Host "Skipping Authenticode signing for DLL: $resolvedPath"
|
||||
return
|
||||
}
|
||||
if ($extension -notin @(".exe", ".msi")) {
|
||||
throw "Unsupported VSign target type: $extension"
|
||||
}
|
||||
|
||||
$requiredVariables = @(
|
||||
"SSIGNCODE_OPERATOR_DIR",
|
||||
"SSIGNCODE_OPERATOR_FILE",
|
||||
"SSIGNCODE_OPERATOR_PWD",
|
||||
"SSIGNCODE_OPERATOR_STORE",
|
||||
"VSIGN_CERT_HASH",
|
||||
"VSIGN_CLI",
|
||||
"VSIGN_KEY_PIN",
|
||||
"VSIGN_SERVER"
|
||||
)
|
||||
|
||||
foreach ($variableName in $requiredVariables) {
|
||||
$value = [Environment]::GetEnvironmentVariable($variableName)
|
||||
if ([string]::IsNullOrWhiteSpace($value)) {
|
||||
throw "Required VSign runtime configuration is missing: $variableName"
|
||||
}
|
||||
}
|
||||
|
||||
$directory = [IO.Path]::GetDirectoryName($resolvedPath)
|
||||
$fileName = [IO.Path]::GetFileNameWithoutExtension($resolvedPath)
|
||||
$signedPath = Join-Path $directory "$fileName.vsign-$([Guid]::NewGuid().ToString('N'))$extension"
|
||||
|
||||
try {
|
||||
& $env:VSIGN_CLI vsign `
|
||||
-s $env:VSIGN_SERVER `
|
||||
--cert_from csign `
|
||||
-u dbx-github-ci `
|
||||
--cert_hash $env:VSIGN_CERT_HASH `
|
||||
-k $env:VSIGN_KEY_PIN `
|
||||
--hash sha256 `
|
||||
-i $resolvedPath `
|
||||
-o $signedPath
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "VSign failed for $resolvedPath with exit code $LASTEXITCODE"
|
||||
}
|
||||
if (!(Test-Path -LiteralPath $signedPath -PathType Leaf)) {
|
||||
throw "VSign did not create the signed output for $resolvedPath"
|
||||
}
|
||||
|
||||
& "$PSScriptRoot/assert-authenticode.ps1" -Path $signedPath
|
||||
Move-Item -LiteralPath $signedPath -Destination $resolvedPath -Force
|
||||
Write-Host "Signed with TrustAsia VSign: $resolvedPath"
|
||||
}
|
||||
finally {
|
||||
if (Test-Path -LiteralPath $signedPath) {
|
||||
Remove-Item -LiteralPath $signedPath -Force
|
||||
}
|
||||
}
|
||||
+250
-41
@@ -130,12 +130,6 @@ jobs:
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- platform: ubuntu-22.04-arm
|
||||
target: aarch64-unknown-linux-gnu
|
||||
- platform: windows-2022
|
||||
target: x86_64-pc-windows-msvc
|
||||
arch: x64
|
||||
- platform: windows-2022
|
||||
target: aarch64-pc-windows-msvc
|
||||
arch: arm64
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
env:
|
||||
@@ -263,12 +257,207 @@ jobs:
|
||||
shell: bash
|
||||
run: ${SCCACHE_PATH} --show-stats
|
||||
|
||||
build-windows:
|
||||
needs: release-ready
|
||||
environment: release-signing
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- target: x86_64-pc-windows-msvc
|
||||
arch: x64
|
||||
sign_windows: true
|
||||
- target: aarch64-pc-windows-msvc
|
||||
arch: arm64
|
||||
sign_windows: false
|
||||
runs-on: windows-2022
|
||||
env:
|
||||
CARGO_INCREMENTAL: "0"
|
||||
RUSTC_WRAPPER: sccache
|
||||
SCCACHE_GHA_ENABLED: ${{ secrets.SCCACHE_S3_BUCKET == '' && 'true' || 'false' }}
|
||||
VSIGN_CERT_HASH: ${{ vars.VSIGN_CERT_HASH }}
|
||||
VSIGN_OPERATOR_SHA1: ${{ vars.VSIGN_OPERATOR_SHA1 }}
|
||||
VSIGN_SERVER: ${{ vars.VSIGN_SERVER }}
|
||||
VSIGN_TOOL_SHA256: ${{ vars.VSIGN_TOOL_SHA256 }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v6
|
||||
|
||||
- name: Install frontend dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Setup Rust
|
||||
uses: dtolnay/rust-toolchain@1.97.1
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
|
||||
- name: Setup sccache
|
||||
uses: mozilla-actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 # v0.0.10
|
||||
with:
|
||||
version: "v0.10.0"
|
||||
|
||||
- name: Configure S3 sccache
|
||||
if: env.SCCACHE_GHA_ENABLED != 'true'
|
||||
shell: bash
|
||||
env:
|
||||
CACHE_BUCKET: ${{ secrets.SCCACHE_S3_BUCKET }}
|
||||
CACHE_ENDPOINT: ${{ secrets.SCCACHE_S3_ENDPOINT }}
|
||||
CACHE_REGION: ${{ secrets.SCCACHE_S3_REGION }}
|
||||
CACHE_KEY_PREFIX: ${{ secrets.SCCACHE_S3_KEY_PREFIX }}
|
||||
CACHE_ACCESS_KEY_ID: ${{ secrets.SCCACHE_S3_ACCESS_KEY_ID }}
|
||||
CACHE_SECRET_ACCESS_KEY: ${{ secrets.SCCACHE_S3_SECRET_ACCESS_KEY }}
|
||||
run: |
|
||||
{
|
||||
echo "SCCACHE_BUCKET=${CACHE_BUCKET}"
|
||||
echo "SCCACHE_ENDPOINT=${CACHE_ENDPOINT}"
|
||||
echo "SCCACHE_REGION=${CACHE_REGION}"
|
||||
echo "SCCACHE_S3_KEY_PREFIX=${CACHE_KEY_PREFIX}"
|
||||
echo "SCCACHE_S3_USE_SSL=true"
|
||||
echo "AWS_ACCESS_KEY_ID=${CACHE_ACCESS_KEY_ID}"
|
||||
echo "AWS_SECRET_ACCESS_KEY=${CACHE_SECRET_ACCESS_KEY}"
|
||||
} >> "$GITHUB_ENV"
|
||||
|
||||
- name: Compute Rust dependency hash
|
||||
id: deps-hash
|
||||
shell: bash
|
||||
run: |
|
||||
{
|
||||
find . -name Cargo.toml -not -path './target/*' -print0 \
|
||||
| sort -z \
|
||||
| xargs -0 sed -E '/^version = /d'
|
||||
grep -v '^version = ' Cargo.lock
|
||||
} | sha256sum | cut -d' ' -f1 | {
|
||||
read -r hash
|
||||
echo "hash=${hash:0:20}" >> "$GITHUB_OUTPUT"
|
||||
}
|
||||
|
||||
- name: Rust cache
|
||||
uses: swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: "./ -> target"
|
||||
shared-key: release-${{ matrix.target }}-${{ steps.deps-hash.outputs.hash }}
|
||||
add-rust-environment-hash-key: false
|
||||
cache-targets: false
|
||||
cache-on-failure: true
|
||||
|
||||
- name: Setup Tauri signing key
|
||||
shell: bash
|
||||
run: |
|
||||
echo "${{ secrets.TAURI_SIGNING_PRIVATE_KEY_BASE64 }}" | base64 --decode > "$RUNNER_TEMP/updater.key"
|
||||
KEY_B64=$(base64 < "$RUNNER_TEMP/updater.key" | tr -d '\r\n')
|
||||
echo "TAURI_SIGNING_PRIVATE_KEY=$KEY_B64" >> "$GITHUB_ENV"
|
||||
if [ -n "${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}" ]; then
|
||||
echo "TAURI_SIGNING_PRIVATE_KEY_PASSWORD=${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}" >> "$GITHUB_ENV"
|
||||
fi
|
||||
|
||||
- name: Setup TrustAsia VSign
|
||||
if: matrix.sign_windows
|
||||
shell: pwsh
|
||||
env:
|
||||
VSIGN_OPERATOR_PFX_B64: ${{ secrets.VSIGN_OPERATOR_PFX_B64 }}
|
||||
VSIGN_OPERATOR_PWD: ${{ secrets.VSIGN_OPERATOR_PWD }}
|
||||
run: ./.github/scripts/setup-vsign.ps1
|
||||
|
||||
- name: Build and sign Tauri app
|
||||
if: matrix.sign_windows
|
||||
uses: tauri-apps/tauri-action@v0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SSIGNCODE_OPERATOR_PWD: ${{ secrets.VSIGN_OPERATOR_PWD }}
|
||||
VSIGN_KEY_PIN: ${{ secrets.VSIGN_KEY_PIN }}
|
||||
with:
|
||||
tagName: ${{ github.ref_name }}
|
||||
releaseDraft: true
|
||||
args: --target ${{ matrix.target }} --config src-tauri/tauri.vsign.conf.json
|
||||
|
||||
- name: Build unsigned Tauri app
|
||||
if: ${{ !matrix.sign_windows }}
|
||||
uses: tauri-apps/tauri-action@v0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tagName: ${{ github.ref_name }}
|
||||
releaseDraft: true
|
||||
args: --target ${{ matrix.target }}
|
||||
|
||||
- name: Verify Windows bundles
|
||||
shell: pwsh
|
||||
run: |
|
||||
$bundleRoot = "target/${{ matrix.target }}/release/bundle"
|
||||
$nsisInstallers = @(
|
||||
Get-ChildItem (Join-Path $bundleRoot "nsis") -Filter "*.exe" -File -ErrorAction SilentlyContinue
|
||||
)
|
||||
$msiInstallers = @(
|
||||
Get-ChildItem (Join-Path $bundleRoot "msi") -Filter "*.msi" -File -ErrorAction SilentlyContinue
|
||||
)
|
||||
if ($nsisInstallers.Count -eq 0) {
|
||||
throw "No NSIS installer was produced for ${{ matrix.target }}"
|
||||
}
|
||||
if ($msiInstallers.Count -eq 0) {
|
||||
throw "No MSI installer was produced for ${{ matrix.target }}"
|
||||
}
|
||||
if ("${{ matrix.sign_windows }}" -eq "true") {
|
||||
./.github/scripts/assert-authenticode.ps1 -Path @(
|
||||
$nsisInstallers.FullName
|
||||
$msiInstallers.FullName
|
||||
)
|
||||
}
|
||||
|
||||
- name: Upload Windows WebView2 offline installer
|
||||
shell: pwsh
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SSIGNCODE_OPERATOR_PWD: ${{ matrix.sign_windows && secrets.VSIGN_OPERATOR_PWD || '' }}
|
||||
VSIGN_KEY_PIN: ${{ matrix.sign_windows && secrets.VSIGN_KEY_PIN || '' }}
|
||||
run: |
|
||||
$version = "${env:GITHUB_REF_NAME}".TrimStart("v")
|
||||
$arch = "${{ matrix.arch }}"
|
||||
$bundleDir = "target/${{ matrix.target }}/release/bundle/nsis"
|
||||
$offlineName = "DBX_${version}_${arch}-webview2-offline-setup.exe"
|
||||
$before = @{}
|
||||
|
||||
if (Test-Path $bundleDir) {
|
||||
Get-ChildItem $bundleDir -Filter "*.exe" | ForEach-Object { $before[$_.FullName] = $_.LastWriteTimeUtc }
|
||||
}
|
||||
|
||||
if ("${{ matrix.sign_windows }}" -eq "true") {
|
||||
pnpm tauri bundle --bundles nsis --target ${{ matrix.target }} `
|
||||
--config src-tauri/tauri.webview2-offline.conf.json `
|
||||
--config src-tauri/tauri.vsign.conf.json
|
||||
} else {
|
||||
pnpm tauri bundle --bundles nsis --target ${{ matrix.target }} `
|
||||
--config src-tauri/tauri.webview2-offline.conf.json
|
||||
}
|
||||
|
||||
$installer = Get-ChildItem $bundleDir -Filter "*.exe" |
|
||||
Where-Object { !$before.ContainsKey($_.FullName) -or $_.LastWriteTimeUtc -gt $before[$_.FullName] } |
|
||||
Sort-Object LastWriteTimeUtc -Descending |
|
||||
Select-Object -First 1
|
||||
|
||||
if (!$installer) {
|
||||
throw "Missing WebView2 offline installer in ${bundleDir}"
|
||||
}
|
||||
|
||||
if ("${{ matrix.sign_windows }}" -eq "true") {
|
||||
./.github/scripts/assert-authenticode.ps1 -Path $installer.FullName
|
||||
}
|
||||
Copy-Item $installer.FullName $offlineName -Force
|
||||
gh release upload "${env:GITHUB_REF_NAME}" $offlineName --repo "${env:GITHUB_REPOSITORY}" --clobber
|
||||
|
||||
- name: Upload Windows portable ZIP
|
||||
if: matrix.arch == 'x64' || matrix.arch == 'arm64'
|
||||
timeout-minutes: 20
|
||||
shell: pwsh
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SSIGNCODE_OPERATOR_PWD: ${{ matrix.sign_windows && secrets.VSIGN_OPERATOR_PWD || '' }}
|
||||
VSIGN_KEY_PIN: ${{ matrix.sign_windows && secrets.VSIGN_KEY_PIN || '' }}
|
||||
run: |
|
||||
$version = "${env:GITHUB_REF_NAME}".TrimStart("v")
|
||||
$arch = "${{ matrix.arch }}"
|
||||
@@ -280,12 +469,15 @@ jobs:
|
||||
$appVersion = ($cargoMetadata.packages | Where-Object { $_.name -eq "dbx" } | Select-Object -First 1).version
|
||||
|
||||
if (!(Test-Path $exePath)) {
|
||||
Write-Error "Missing Windows executable: $exePath"
|
||||
exit 1
|
||||
throw "Missing Windows executable: $exePath"
|
||||
}
|
||||
if (!$appVersion -or $appVersion -ne $version) {
|
||||
Write-Error "Release tag version $version does not match the built DBX package version $appVersion"
|
||||
exit 1
|
||||
throw "Release tag version $version does not match the built DBX package version $appVersion"
|
||||
}
|
||||
|
||||
if ("${{ matrix.sign_windows }}" -eq "true") {
|
||||
./.github/scripts/vsign-sign.ps1 -FilePath $exePath
|
||||
./.github/scripts/assert-authenticode.ps1 -Path $exePath
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $portableDir | Out-Null
|
||||
@@ -315,51 +507,43 @@ jobs:
|
||||
|
||||
$signatureName = "${zipName}.sig"
|
||||
if (!(Test-Path $signatureName)) {
|
||||
Write-Error "Missing portable update signature: $signatureName"
|
||||
exit 1
|
||||
throw "Missing portable update signature: $signatureName"
|
||||
}
|
||||
|
||||
gh release upload "${env:GITHUB_REF_NAME}" $zipName $signatureName --repo "${env:GITHUB_REPOSITORY}" --clobber
|
||||
|
||||
- name: Upload Windows WebView2 offline installer
|
||||
if: matrix.arch == 'x64' || matrix.arch == 'arm64'
|
||||
- name: Show sccache stats
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
shell: bash
|
||||
run: ${SCCACHE_PATH} --show-stats
|
||||
|
||||
- name: Remove temporary VSign files
|
||||
if: ${{ always() && matrix.sign_windows }}
|
||||
shell: pwsh
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
$version = "${env:GITHUB_REF_NAME}".TrimStart("v")
|
||||
$arch = "${{ matrix.arch }}"
|
||||
$bundleDir = "target/${{ matrix.target }}/release/bundle/nsis"
|
||||
$offlineName = "DBX_${version}_${arch}-webview2-offline-setup.exe"
|
||||
$before = @{}
|
||||
|
||||
if (Test-Path $bundleDir) {
|
||||
Get-ChildItem $bundleDir -Filter "*.exe" | ForEach-Object { $before[$_.FullName] = $_.LastWriteTimeUtc }
|
||||
$workDir = if ([string]::IsNullOrWhiteSpace($env:VSIGN_WORK_DIR)) {
|
||||
Join-Path $env:RUNNER_TEMP "vsign-$env:GITHUB_RUN_ID-$env:GITHUB_RUN_ATTEMPT"
|
||||
} else {
|
||||
$env:VSIGN_WORK_DIR
|
||||
}
|
||||
|
||||
pnpm tauri bundle --bundles nsis --target ${{ matrix.target }} --config src-tauri/tauri.webview2-offline.conf.json
|
||||
|
||||
$installer = Get-ChildItem $bundleDir -Filter "*.exe" |
|
||||
Where-Object { !$before.ContainsKey($_.FullName) -or $_.LastWriteTimeUtc -gt $before[$_.FullName] } |
|
||||
Sort-Object LastWriteTimeUtc -Descending |
|
||||
Select-Object -First 1
|
||||
|
||||
if (!$installer) {
|
||||
Write-Error "Missing WebView2 offline installer in ${bundleDir}"
|
||||
exit 1
|
||||
if (Test-Path -LiteralPath $workDir) {
|
||||
Remove-Item -LiteralPath $workDir -Recurse -Force
|
||||
}
|
||||
|
||||
Copy-Item $installer.FullName $offlineName -Force
|
||||
gh release upload "${env:GITHUB_REF_NAME}" $offlineName --repo "${env:GITHUB_REPOSITORY}" --clobber
|
||||
|
||||
build-windows-7-offline:
|
||||
needs: release-ready
|
||||
runs-on: windows-2022
|
||||
environment: release-signing
|
||||
env:
|
||||
CARGO_INCREMENTAL: "0"
|
||||
RUSTC_WRAPPER: sccache
|
||||
SCCACHE_GHA_ENABLED: ${{ secrets.SCCACHE_S3_BUCKET == '' && 'true' || 'false' }}
|
||||
RUSTFLAGS: -C debuginfo=line-tables-only -C target-feature=+crt-static
|
||||
VSIGN_CERT_HASH: ${{ vars.VSIGN_CERT_HASH }}
|
||||
VSIGN_OPERATOR_SHA1: ${{ vars.VSIGN_OPERATOR_SHA1 }}
|
||||
VSIGN_SERVER: ${{ vars.VSIGN_SERVER }}
|
||||
VSIGN_TOOL_SHA256: ${{ vars.VSIGN_TOOL_SHA256 }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
@@ -443,10 +627,19 @@ jobs:
|
||||
shell: pwsh
|
||||
run: ./.github/scripts/assert-win7-pe-compat.ps1 -BinaryPath target/x86_64-win7-windows-msvc/release/dbx.exe
|
||||
|
||||
- name: Setup TrustAsia VSign
|
||||
shell: pwsh
|
||||
env:
|
||||
VSIGN_OPERATOR_PFX_B64: ${{ secrets.VSIGN_OPERATOR_PFX_B64 }}
|
||||
VSIGN_OPERATOR_PWD: ${{ secrets.VSIGN_OPERATOR_PWD }}
|
||||
run: ./.github/scripts/setup-vsign.ps1
|
||||
|
||||
- name: Bundle and upload Windows 7 fixed-runtime installer
|
||||
shell: pwsh
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SSIGNCODE_OPERATOR_PWD: ${{ secrets.VSIGN_OPERATOR_PWD }}
|
||||
VSIGN_KEY_PIN: ${{ secrets.VSIGN_KEY_PIN }}
|
||||
run: |
|
||||
$version = "${env:GITHUB_REF_NAME}".TrimStart("v")
|
||||
$bundleDir = "target/x86_64-win7-windows-msvc/release/bundle/nsis"
|
||||
@@ -459,7 +652,9 @@ jobs:
|
||||
exit 1
|
||||
}
|
||||
|
||||
pnpm tauri bundle --bundles nsis --target x86_64-win7-windows-msvc --config src-tauri/tauri.webview2-win7-fixed.conf.json
|
||||
pnpm tauri bundle --bundles nsis --target x86_64-win7-windows-msvc `
|
||||
--config src-tauri/tauri.webview2-win7-fixed.conf.json `
|
||||
--config src-tauri/tauri.vsign.conf.json
|
||||
|
||||
$installer = Get-ChildItem $bundleDir -Filter "*.exe" |
|
||||
Sort-Object LastWriteTimeUtc -Descending |
|
||||
@@ -470,6 +665,7 @@ jobs:
|
||||
}
|
||||
|
||||
./.github/scripts/assert-win7-installer-content.ps1 -InstallerPath $installer.FullName
|
||||
./.github/scripts/assert-authenticode.ps1 -Path $installer.FullName
|
||||
|
||||
Copy-Item $installer.FullName $offlineName -Force
|
||||
gh release upload "${env:GITHUB_REF_NAME}" $offlineName --repo "${env:GITHUB_REPOSITORY}" --clobber
|
||||
@@ -480,6 +676,19 @@ jobs:
|
||||
shell: bash
|
||||
run: ${SCCACHE_PATH} --show-stats
|
||||
|
||||
- name: Remove temporary VSign files
|
||||
if: always()
|
||||
shell: pwsh
|
||||
run: |
|
||||
$workDir = if ([string]::IsNullOrWhiteSpace($env:VSIGN_WORK_DIR)) {
|
||||
Join-Path $env:RUNNER_TEMP "vsign-$env:GITHUB_RUN_ID-$env:GITHUB_RUN_ATTEMPT"
|
||||
} else {
|
||||
$env:VSIGN_WORK_DIR
|
||||
}
|
||||
if (Test-Path -LiteralPath $workDir) {
|
||||
Remove-Item -LiteralPath $workDir -Recurse -Force
|
||||
}
|
||||
|
||||
static-browser:
|
||||
# Fully static musl builds of the browser (dbx-web) variant. No glibc
|
||||
# dependency, so the tarball runs on any Linux distribution (verified in
|
||||
@@ -583,7 +792,7 @@ jobs:
|
||||
--repo "${GITHUB_REPOSITORY}" --clobber
|
||||
|
||||
cleanup-release-signatures:
|
||||
needs: [build, build-windows-7-offline]
|
||||
needs: [build, build-windows, build-windows-7-offline]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Remove standalone updater signature assets
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"bundle": {
|
||||
"windows": {
|
||||
"signCommand": {
|
||||
"cmd": "pwsh",
|
||||
"args": [
|
||||
"-NoLogo",
|
||||
"-NoProfile",
|
||||
"-NonInteractive",
|
||||
"-ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-File",
|
||||
".github/scripts/vsign-sign.ps1",
|
||||
"%1"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,7 +60,6 @@ ${StrLoc}
|
||||
!define UNINSTKEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCTNAME}"
|
||||
!define MANUKEY "Software\${MANUFACTURER}"
|
||||
!define MANUPRODUCTKEY "${MANUKEY}\${PRODUCTNAME}"
|
||||
!define UNINSTALLERSIGNCOMMAND "{{uninstaller_sign_cmd}}"
|
||||
!define ESTIMATEDSIZE "{{estimated_size}}"
|
||||
!define STARTMENUFOLDER "{{start_menu_folder}}"
|
||||
!searchreplace WEBVIEW2LOADERSRCPATH "${MAINBINARYSRCPATH}" "\${MAINBINARYNAME}.exe" "\WebView2Loader.dll"
|
||||
@@ -114,11 +113,6 @@ VIAddVersionKey "ProductVersion" "${VERSION}"
|
||||
# additional plugins
|
||||
!addplugindir "${ADDITIONALPLUGINSPATH}"
|
||||
|
||||
; Uninstaller signing command
|
||||
!if "${UNINSTALLERSIGNCOMMAND}" != ""
|
||||
!uninstfinalize '${UNINSTALLERSIGNCOMMAND}'
|
||||
!endif
|
||||
|
||||
; Handle install mode, `perUser`, `perMachine` or `both`
|
||||
!if "${INSTALLMODE}" == "perMachine"
|
||||
RequestExecutionLevel admin
|
||||
|
||||
Reference in New Issue
Block a user