mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-10 06:53:48 +00:00
Signed AI Studio for macOS and Windows (#1029)
This commit is contained in:
1 parent
f7451d0e38
commit
5308027003
6 files changed
+353
-33
No files matched your search
@@ -0,0 +1,105 @@
|
||||
#
|
||||
# Signs one Windows binary with our Certum code signing certificate. Tauri calls this script as its
|
||||
# custom sign command for every file it signs: the main binary, the sidecar, PDFium, the NSIS
|
||||
# plugins, the uninstaller, and the installer.
|
||||
#
|
||||
# Usage:
|
||||
# sign-windows.ps1 <path of the file to sign>
|
||||
#
|
||||
# Environment:
|
||||
# CERTUM_EMAIL e-mail address of the Certum SimplySign account
|
||||
# CERTUM_OTP TOTP seed of that account, from which ssign computes each one-time code
|
||||
#
|
||||
# The script needs ssign (https://github.com/Le-Syl21/ssign) in the PATH. ssign adds the
|
||||
# certificate chain and a timestamp, and keeps its cloud session for a while, so a build logs in
|
||||
# only once.
|
||||
#
|
||||
# ssign does not sign in place here: it would replace the file by renaming its signed copy over it,
|
||||
# and Windows refuses that while another process keeps the file open. Tauri does exactly that with
|
||||
# the main binary while signing it. So ssign writes its copy elsewhere, and this script writes the
|
||||
# copy back into the very same file, which an open handle with write sharing allows.
|
||||
#
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string] $Path
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Tauri passes some paths relative to its working directory. .NET would resolve them against the
|
||||
# working directory of the process instead, so every call below gets the full path:
|
||||
$Path = (Resolve-Path -LiteralPath $Path).ProviderPath
|
||||
|
||||
# Tauri hands over some files without checking whether they are signed already, the NSIS plugins
|
||||
# among them. ssign never replaces an existing signature, so a valid one stays as it is, and an
|
||||
# invalid one stops the build with a clear message instead of three failed attempts:
|
||||
$signature = Get-AuthenticodeSignature -FilePath $Path
|
||||
if ($signature.Status -eq 'Valid') {
|
||||
Write-Output "Already signed, skipping: $Path"
|
||||
exit 0
|
||||
}
|
||||
|
||||
if ($signature.Status -ne 'NotSigned') {
|
||||
Write-Error "'$Path' carries a signature which is not valid ($($signature.Status)), and ssign cannot replace it."
|
||||
}
|
||||
|
||||
# Tauri shows the output of its sign command only when signing succeeds. Everything ssign says
|
||||
# therefore goes into a log, which the workflow prints when the build fails:
|
||||
$logDirectory = if ($env:RUNNER_TEMP) { $env:RUNNER_TEMP } else { [System.IO.Path]::GetTempPath() }
|
||||
$logFile = Join-Path $logDirectory 'sign-windows.log'
|
||||
|
||||
$outputDirectory = Join-Path ([System.IO.Path]::GetTempPath()) "sign-windows-$([guid]::NewGuid())"
|
||||
New-Item -ItemType Directory -Path $outputDirectory | Out-Null
|
||||
|
||||
try {
|
||||
# Certum accepts every one-time code only once. When both Windows builds log in within the same
|
||||
# 30 seconds, one of them is rejected and succeeds with the next code:
|
||||
$maxAttempts = 3
|
||||
for ($attempt = 1; $attempt -le $maxAttempts; $attempt++) {
|
||||
$stdout = New-TemporaryFile
|
||||
$stderr = New-TemporaryFile
|
||||
$process = Start-Process -FilePath 'ssign' -ArgumentList @('--verbose', '--output-dir', "`"$outputDirectory`"", "`"$Path`"") -NoNewWindow -Wait -PassThru -RedirectStandardOutput $stdout.FullName -RedirectStandardError $stderr.FullName
|
||||
$exitCode = $process.ExitCode
|
||||
|
||||
Add-Content -Path $logFile -Value "--- $(Get-Date -Format o) | attempt $attempt of $maxAttempts | exit code $exitCode | $Path"
|
||||
Get-Content -Path $stdout.FullName, $stderr.FullName | Add-Content -Path $logFile
|
||||
Get-Content -Path $stdout.FullName, $stderr.FullName
|
||||
Remove-Item -Path $stdout.FullName, $stderr.FullName
|
||||
|
||||
if ($exitCode -eq 0) {
|
||||
break
|
||||
}
|
||||
|
||||
if ($attempt -eq $maxAttempts) {
|
||||
Write-Error "ssign could not sign '$Path' in $maxAttempts attempts, see $logFile."
|
||||
}
|
||||
|
||||
Write-Output "ssign failed in attempt $attempt of $maxAttempts, retrying in 35 seconds ..."
|
||||
Start-Sleep -Seconds 35
|
||||
}
|
||||
|
||||
$signedCopy = Join-Path $outputDirectory (Split-Path -Path $Path -Leaf)
|
||||
$source = [System.IO.File]::OpenRead($signedCopy)
|
||||
try {
|
||||
$target = [System.IO.File]::Open($Path, [System.IO.FileMode]::Truncate, [System.IO.FileAccess]::Write, [System.IO.FileShare]::ReadWrite)
|
||||
try {
|
||||
$source.CopyTo($target)
|
||||
}
|
||||
finally {
|
||||
$target.Dispose()
|
||||
}
|
||||
}
|
||||
finally {
|
||||
$source.Dispose()
|
||||
}
|
||||
}
|
||||
finally {
|
||||
Remove-Item -Path $outputDirectory -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
$signature = Get-AuthenticodeSignature -FilePath $Path
|
||||
if ($signature.Status -ne 'Valid') {
|
||||
Write-Error "The signature of '$Path' is not valid: $($signature.Status), $($signature.StatusMessage)"
|
||||
}
|
||||
|
||||
Write-Output "Signed by '$($signature.SignerCertificate.Subject)': $Path"
|
||||
Reference in new issue
Block a user