Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PICARD-3002: Use Azure Trusted Signing for code signing #2557

Merged
merged 1 commit into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 59 additions & 68 deletions .github/workflows/package-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ jobs:
runs-on: windows-2019
strategy:
matrix:
type:
- store-app
- signed-app
- installer
- portable
setup:
- type: installer
- type: portable
build-portable: 1
- type: store-app
disable-autoupdate: 1
fail-fast: false
env:
CODESIGN: 0
CODESIGN: ${{ !!secrets.AZURE_CERT_PROFILE_NAME }}
steps:
- uses: actions/checkout@v4
with:
Expand All @@ -32,9 +33,6 @@ jobs:
-DiscidVersion $Env:DISCID_VERSION -DiscidSha256Sum $Env:DISCID_SHA256SUM `
-FpcalcVersion $Env:FPCALC_VERSION -FpcalcSha256Sum $Env:FPCALC_SHA256SUM
Add-Content $env:GITHUB_PATH "C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x64"
$ReleaseTag = $(git describe --match "release-*" --abbrev=0 --always HEAD)
$BuildNumber = $(git rev-list --count "$ReleaseTag..HEAD")
Add-Content $env:GITHUB_ENV "BUILD_NUMBER=$BuildNumber"
New-Item -Name .\artifacts -ItemType Directory
env:
DISCID_VERSION: 0.6.4
Expand All @@ -57,80 +55,73 @@ jobs:
- name: Patch build version
if: startsWith(github.ref, 'refs/tags/') != true
run: |
$ReleaseTag = $(git describe --match "release-*" --abbrev=0 --always HEAD)
$BuildNumber = $(git rev-list --count "$ReleaseTag..HEAD")
python setup.py patch_version --platform=$Env:BUILD_NUMBER.$(git rev-parse --short HEAD)
- name: Run tests
timeout-minutes: 30
run: pytest --verbose
- name: Prepare code signing certificate
if: matrix.type != 'store-app'
- name: Prepare clean build environment
run: |
If ($Env:CODESIGN_P12_URL -And $Env:AWS_ACCESS_KEY_ID) {
pip install awscli
aws s3 cp "$Env:CODESIGN_P12_URL" .\codesign.pfx
Add-Content $env:GITHUB_ENV "CODESIGN=1"
} Else {
Write-Output "::warning::No code signing certificate available, skipping code signing."
}
env:
AWS_DEFAULT_REGION: eu-central-1
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
CODESIGN_P12_URL: ${{ secrets.CODESIGN_P12_URL }}
- name: Build Windows 10 store app package
if: matrix.type == 'store-app'
Remove-Item -Path build,dist/picard,locale -Recurse -ErrorAction Ignore
python setup.py clean
- name: Build
run: |
& .\scripts\package\win-package-appx.ps1 -BuildNumber $Env:BUILD_NUMBER
Move-Item .\dist\*.msix .\artifacts
python setup.py build --build-number=$BuildNumber
python setup.py build_ext
pyinstaller --noconfirm --clean picard.spec
If ($env:PICARD_BUILD_PORTABLE -ne "1") {
dist\picard\_internal\fpcalc -version
}
env:
PICARD_APPX_PUBLISHER: CN=0A9169B7-05A3-4ED9-8876-830F17846709
- name: Build Windows 10 signed app package
if: matrix.type == 'signed-app' && env.CODESIGN == '1'
run: |
$CertificateFile = ".\codesign.pfx"
$CertificatePassword = ConvertTo-SecureString -String $Env:CODESIGN_P12_PASSWORD -Force -AsPlainText
& .\scripts\package\win-package-appx.ps1 -BuildNumber $Env:BUILD_NUMBER `
-CertificateFile $CertificateFile -CertificatePassword $CertificatePassword
Move-Item .\dist\*.msix .\artifacts
env:
CODESIGN_P12_PASSWORD: ${{ secrets.CODESIGN_P12_PASSWORD }}
PICARD_BUILD_PORTABLE: ${{ matrix.setup.build-portable }}
PICARD_DISABLE_AUTOUPDATE: ${{ matrix.setup.disable-autoupdate }}
- name: Sign picard.exe
uses: azure/[email protected]
if: matrix.setup.type != 'portable' && env.CODESIGN == 'true'
with:
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
endpoint: ${{ secrets.AZURE_ENDPOINT }}
trusted-signing-account-name: ${{ secrets.AZURE_CODE_SIGNING_NAME }}
certificate-profile-name: ${{ secrets.AZURE_CERT_PROFILE_NAME }}
files-folder: dist\picard
files-folder-filter: exe
files-folder-recurse: true
timestamp-rfc3161: http://timestamp.acs.microsoft.com
timestamp-digest: SHA256
- name: Build Windows installer
if: matrix.type == 'installer'
if: matrix.setup.type == 'installer'
run: |
# choco install nsis
If ($Env:CODESIGN -eq "1") {
$CertificateFile = ".\codesign.pfx"
$CertificatePassword = ConvertTo-SecureString -String $Env:CODESIGN_P12_PASSWORD -Force -AsPlainText
} Else {
$CertificateFile = $null
$CertificatePassword = $null
}
& .\scripts\package\win-package-installer.ps1 -BuildNumber $Env:BUILD_NUMBER `
-CertificateFile $CertificateFile -CertificatePassword $CertificatePassword
makensis.exe /INPUTCHARSET UTF8 installer\picard-setup.nsi
Move-Item .\installer\*.exe .\artifacts
dist\picard\_internal\fpcalc -version
env:
CODESIGN_P12_PASSWORD: ${{ secrets.CODESIGN_P12_PASSWORD }}
- name: Build Windows portable app
if: matrix.type == 'portable'
if: matrix.setup.type == 'portable'
run: |
If ($Env:CODESIGN -eq "1") {
$CertificateFile = ".\codesign.pfx"
$CertificatePassword = ConvertTo-SecureString -String $Env:CODESIGN_P12_PASSWORD -Force -AsPlainText
} Else {
$CertificateFile = $null
$CertificatePassword = $null
}
& .\scripts\package\win-package-portable.ps1 -BuildNumber $Env:BUILD_NUMBER `
-CertificateFile $CertificateFile -CertificatePassword $CertificatePassword
Move-Item .\dist\*.exe .\artifacts
env:
CODESIGN_P12_PASSWORD: ${{ secrets.CODESIGN_P12_PASSWORD }}
- name: Cleanup
if: env.CODESIGN == '1'
run: Remove-Item .\codesign.pfx
- name: Build Windows 10 store app package
if: matrix.setup.type == 'store-app'
run: |
& .\scripts\package\win-package-appx.ps1 dist\picard
Move-Item .\dist\*.msix .\artifacts
- name: Sign final executable
uses: azure/[email protected]
if: matrix.setup.type != 'store-app' && env.CODESIGN == 'true'
with:
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
endpoint: ${{ secrets.AZURE_ENDPOINT }}
trusted-signing-account-name: ${{ secrets.AZURE_CODE_SIGNING_NAME }}
certificate-profile-name: ${{ secrets.AZURE_CERT_PROFILE_NAME }}
files-folder: artifacts
files-folder-filter: exe
timestamp-rfc3161: http://timestamp.acs.microsoft.com
timestamp-digest: SHA256
- name: Archive production artifacts
uses: actions/upload-artifact@v4
if: matrix.type != 'signed-app' || env.CODESIGN == '1'
with:
name: windows-${{ matrix.type }}
name: windows-${{ matrix.setup.type }}
path: artifacts/
19 changes: 19 additions & 0 deletions scripts/package/win-build-fixes.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Apply fixes to the build result

Param(
[ValidateScript({Test-Path $_ -PathType Container})]
[String]
$Path
)

$ErrorActionPreference = 'Stop'

$InternalPath = (Join-Path -Path $Path -ChildPath _internal)
# Move all Qt6 DLLs into the main folder to avoid conflicts with system wide
# versions of those dependencies. Since some version PyInstaller tries to
# maintain the file hierarchy of imported modules, but this easily breaks
# DLL loading on Windows.
# Workaround for https://tickets.metabrainz.org/browse/PICARD-2736
$Qt6Dir = (Join-Path -Path $InternalPath -ChildPath PyQt6\Qt6)
Move-Item -Path (Join-Path -Path $Qt6Dir -ChildPath bin\*.dll) -Destination $Path -Force
Remove-Item -Path (Join-Path -Path $Qt6Dir -ChildPath bin)
49 changes: 0 additions & 49 deletions scripts/package/win-common.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -8,55 +8,6 @@ Param(
$CertificatePassword
)

# RFC 3161 timestamp server for code signing
$TimeStampServer = 'http://ts.ssl.com'

Function CodeSignBinary {
Param(
[ValidateScript({Test-Path $_ -PathType Leaf})]
[String]
$BinaryPath
)
If ($CertificateFile) {
SignTool sign /v /fd SHA256 /tr "$TimeStampServer" /td sha256 `
/f "$CertificateFile" /p (ConvertFrom-SecureString -AsPlainText $CertificatePassword) `
$BinaryPath
ThrowOnExeError "SignTool failed"
} Else {
Write-Output "Skip signing $BinaryPath"
}
}

Function ThrowOnExeError {
Param( [String]$Message )
If ($LastExitCode -ne 0) {
Throw $Message
}
}

Function FinalizePackage {
Param(
[ValidateScript({Test-Path $_ -PathType Container})]
[String]
$Path
)

$InternalPath = (Join-Path -Path $Path -ChildPath _internal)

CodeSignBinary -BinaryPath (Join-Path -Path $Path -ChildPath picard.exe) -ErrorAction Stop
CodeSignBinary -BinaryPath (Join-Path -Path $InternalPath -ChildPath fpcalc.exe) -ErrorAction Stop
CodeSignBinary -BinaryPath (Join-Path -Path $InternalPath -ChildPath discid.dll) -ErrorAction Stop

# Move all Qt6 DLLs into the main folder to avoid conflicts with system wide
# versions of those dependencies. Since some version PyInstaller tries to
# maintain the file hierarchy of imported modules, but this easily breaks
# DLL loading on Windows.
# Workaround for https://tickets.metabrainz.org/browse/PICARD-2736
$Qt6Dir = (Join-Path -Path $InternalPath -ChildPath PyQt6\Qt6)
Move-Item -Path (Join-Path -Path $Qt6Dir -ChildPath bin\*.dll) -Destination $Path -Force
Remove-Item -Path (Join-Path -Path $Qt6Dir -ChildPath bin)
}

Function DownloadFile {
Param(
[Parameter(Mandatory = $true)]
Expand Down
60 changes: 6 additions & 54 deletions scripts/package/win-package-appx.ps1
Original file line number Diff line number Diff line change
@@ -1,72 +1,24 @@
# Build a MSIX app package for Windows 10

Param(
[ValidateScript({ (Test-Path $_ -PathType Leaf) -or (-not $_) })]
[ValidateScript({ Test-Path $_ -PathType Container })]
[String]
$CertificateFile,
[SecureString]
$CertificatePassword,
[Int]
$BuildNumber
$PackageDir
)

# Errors are handled explicitly. Otherwise any output to stderr when
# calling classic Windows exes causes a script error.
# TODO: For PowerShell >= 7.3 use $PSNativeCommandUseErrorActionPreference = $true
$ErrorActionPreference = 'Continue'
$ErrorActionPreference = 'Stop'
$PSNativeCommandUseErrorActionPreference = $true

If (-Not $BuildNumber) {
$BuildNumber = 0
}

If (-Not $Certificate -And $CertificateFile) {
$Certificate = Get-PfxCertificate -FilePath $CertificateFile -Password $CertificatePassword
}

$ScriptDirectory = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
. $ScriptDirectory\win-common.ps1 -CertificateFile $CertificateFile -CertificatePassword $CertificatePassword

Write-Output "Building Windows 10 app package..."

# Set the publisher based on the certificate subject
if ($Certificate) {
$env:PICARD_APPX_PUBLISHER = $Certificate.Subject
Write-Output "Publisher: $env:PICARD_APPX_PUBLISHER"
}

# Build
Remove-Item -Path build,dist/picard,locale -Recurse -ErrorAction Ignore
python setup.py clean 2>&1 | %{ "$_" }
ThrowOnExeError "setup.py clean failed"
python setup.py build --build-number=$BuildNumber --disable-autoupdate 2>&1 | %{ "$_" }
ThrowOnExeError "setup.py build failed"
python setup.py build_ext -i 2>&1 | %{ "$_" }
ThrowOnExeError "setup.py build_ext -i failed"

# Package application
pyinstaller --noconfirm --clean picard.spec 2>&1 | %{ "$_" }
ThrowOnExeError "PyInstaller failed"
$PackageDir = (Resolve-Path dist\picard)
FinalizePackage $PackageDir
$PackageDir = (Resolve-Path $PackageDir)

# Generate resource files
Copy-Item appxmanifest.xml $PackageDir
$PriConfigFile = (Join-Path (Resolve-Path .\build) priconfig.xml)
Push-Location $PackageDir
MakePri createconfig /ConfigXml $PriConfigFile /Default en-US /Overwrite
ThrowOnExeError "MakePri createconfig failed"
MakePri new /ProjectRoot $PackageDir /ConfigXml $PriConfigFile
ThrowOnExeError "MakePri new failed"
Pop-Location

# Generate msix package
$PicardVersion = (python -c "import picard; print(picard.__version__)")
If ($CertificateFile -or $Certificate) {
$PackageFile = "dist\MusicBrainz-Picard-$PicardVersion.msix"
} Else {
$PackageFile = "dist\MusicBrainz-Picard-$PicardVersion-unsigned.msix"
}
$PackageFile = "dist\MusicBrainz-Picard-${PicardVersion}_unsigned.msix"
MakeAppx pack /o /h SHA256 /d $PackageDir /p $PackageFile
ThrowOnExeError "MakeAppx failed"

CodeSignBinary -BinaryPath $PackageFile -ErrorAction Stop
43 changes: 0 additions & 43 deletions scripts/package/win-package-installer.ps1

This file was deleted.

Loading
Loading