mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-02 07:42:14 +00:00
ci(windows): wire SignPath test-signing for portable bundle
Add SignPath artifact configuration (windows-portable-v1) signing only the first-party binaries orca-slicer.exe and OrcaSlicer.dll, plus verification and inventory scripts. The Windows build job uploads the unsigned portable bundle, submits it to SignPath (test-signing), verifies the returned signatures, and rebuilds the installer/zip from the signed binaries. project-slug matches the SignPath project (OrcaSlicer).
This commit is contained in:
4
.github/workflows/build_all.yml
vendored
4
.github/workflows/build_all.yml
vendored
@@ -13,6 +13,8 @@ on:
|
|||||||
- 'localization/**'
|
- 'localization/**'
|
||||||
- 'resources/**'
|
- 'resources/**'
|
||||||
- ".github/workflows/build_*.yml"
|
- ".github/workflows/build_*.yml"
|
||||||
|
- 'signpath/**'
|
||||||
|
- 'scripts/*.ps1'
|
||||||
- 'scripts/flatpak/**'
|
- 'scripts/flatpak/**'
|
||||||
|
|
||||||
pull_request:
|
pull_request:
|
||||||
@@ -26,9 +28,11 @@ on:
|
|||||||
- '**/CMakeLists.txt'
|
- '**/CMakeLists.txt'
|
||||||
- 'version.inc'
|
- 'version.inc'
|
||||||
- ".github/workflows/build_*.yml"
|
- ".github/workflows/build_*.yml"
|
||||||
|
- 'signpath/**'
|
||||||
- 'build_linux.sh'
|
- 'build_linux.sh'
|
||||||
- 'build_release_vs2022.bat'
|
- 'build_release_vs2022.bat'
|
||||||
- 'build_release_macos.sh'
|
- 'build_release_macos.sh'
|
||||||
|
- 'scripts/*.ps1'
|
||||||
- 'scripts/flatpak/**'
|
- 'scripts/flatpak/**'
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
61
.github/workflows/build_orca.yml
vendored
61
.github/workflows/build_orca.yml
vendored
@@ -292,6 +292,50 @@ jobs:
|
|||||||
# WindowsSDKVersion: '10.0.26100.0\'
|
# WindowsSDKVersion: '10.0.26100.0\'
|
||||||
run: .\build_release_vs.bat slicer
|
run: .\build_release_vs.bat slicer
|
||||||
|
|
||||||
|
- name: Pack PDB
|
||||||
|
if: runner.os == 'Windows' && !vars.SELF_HOSTED
|
||||||
|
working-directory: ${{ github.workspace }}/build/src/Release
|
||||||
|
shell: cmd
|
||||||
|
run: '"C:/Program Files/7-Zip/7z.exe" a -m0=lzma2 -mx9 Debug_PDB_${{ env.ver }}_for_developers_only.7z *.pdb'
|
||||||
|
|
||||||
|
- name: Upload unsigned Windows portable artifact for SignPath
|
||||||
|
id: upload-windows-portable
|
||||||
|
if: github.repository == 'OrcaSlicer/OrcaSlicer' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) && runner.os == 'Windows' && !vars.SELF_HOSTED
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: OrcaSlicer_Windows_${{ env.ver }}_portable_unsigned
|
||||||
|
path: ${{ github.workspace }}/build/OrcaSlicer
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
- name: Submit Windows portable artifact to SignPath
|
||||||
|
if: github.repository == 'OrcaSlicer/OrcaSlicer' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) && runner.os == 'Windows' && !vars.SELF_HOSTED
|
||||||
|
uses: signpath/github-action-submit-signing-request@v2
|
||||||
|
with:
|
||||||
|
api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
|
||||||
|
organization-id: ${{ secrets.SIGNPATH_ORGANIZATION_ID }}
|
||||||
|
project-slug: OrcaSlicer
|
||||||
|
signing-policy-slug: test-signing
|
||||||
|
artifact-configuration-slug: windows-portable-v1
|
||||||
|
github-artifact-id: ${{ steps.upload-windows-portable.outputs.artifact-id }}
|
||||||
|
wait-for-completion: true
|
||||||
|
output-artifact-directory: ${{ github.workspace }}/build/signpath/windows-portable
|
||||||
|
|
||||||
|
- name: Verify SignPath Windows portable signatures
|
||||||
|
if: github.repository == 'OrcaSlicer/OrcaSlicer' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) && runner.os == 'Windows' && !vars.SELF_HOSTED
|
||||||
|
shell: pwsh
|
||||||
|
run: ./scripts/verify-authenticode.ps1 -ArtifactDirectory '${{ github.workspace }}/build/signpath/windows-portable'
|
||||||
|
|
||||||
|
- name: Replace Windows portable bundle with signed output
|
||||||
|
if: github.repository == 'OrcaSlicer/OrcaSlicer' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) && runner.os == 'Windows' && !vars.SELF_HOSTED
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
$source = Join-Path "${{ github.workspace }}" "build/signpath/windows-portable"
|
||||||
|
$destination = Join-Path "${{ github.workspace }}" "build/OrcaSlicer"
|
||||||
|
if (-not (Test-Path -LiteralPath $source -PathType Container)) {
|
||||||
|
throw "SignPath output directory not found: $source"
|
||||||
|
}
|
||||||
|
Get-ChildItem -LiteralPath $source -Force | Copy-Item -Destination $destination -Recurse -Force
|
||||||
|
|
||||||
- name: Create installer Win
|
- name: Create installer Win
|
||||||
if: runner.os == 'Windows' && !vars.SELF_HOSTED
|
if: runner.os == 'Windows' && !vars.SELF_HOSTED
|
||||||
working-directory: ${{ github.workspace }}/build
|
working-directory: ${{ github.workspace }}/build
|
||||||
@@ -301,14 +345,14 @@ jobs:
|
|||||||
- name: Pack app
|
- name: Pack app
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
working-directory: ${{ github.workspace }}/build
|
working-directory: ${{ github.workspace }}/build
|
||||||
shell: cmd
|
shell: pwsh
|
||||||
run: '"C:/Program Files/7-Zip/7z.exe" a -tzip OrcaSlicer_Windows_${{ env.ver }}_portable.zip ${{ github.workspace }}/build/OrcaSlicer'
|
run: |
|
||||||
|
$zipPath = "OrcaSlicer_Windows_${{ env.ver }}_portable.zip"
|
||||||
- name: Pack PDB
|
Remove-Item -LiteralPath $zipPath -Force -ErrorAction SilentlyContinue
|
||||||
if: runner.os == 'Windows' && !vars.SELF_HOSTED
|
& "C:/Program Files/7-Zip/7z.exe" a -tzip $zipPath "${{ github.workspace }}/build/OrcaSlicer"
|
||||||
working-directory: ${{ github.workspace }}/build/src/Release
|
if ($LASTEXITCODE -ne 0) {
|
||||||
shell: cmd
|
exit $LASTEXITCODE
|
||||||
run: '"C:/Program Files/7-Zip/7z.exe" a -m0=lzma2 -mx9 Debug_PDB_${{ env.ver }}_for_developers_only.7z *.pdb'
|
}
|
||||||
|
|
||||||
- name: Upload artifacts Win zip
|
- name: Upload artifacts Win zip
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
@@ -316,6 +360,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: OrcaSlicer_Windows_${{ env.ver }}_portable
|
name: OrcaSlicer_Windows_${{ env.ver }}_portable
|
||||||
path: ${{ github.workspace }}/build/OrcaSlicer
|
path: ${{ github.workspace }}/build/OrcaSlicer
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Upload artifacts Win installer
|
- name: Upload artifacts Win installer
|
||||||
if: runner.os == 'Windows' && !vars.SELF_HOSTED
|
if: runner.os == 'Windows' && !vars.SELF_HOSTED
|
||||||
|
|||||||
48
scripts/inventory-authenticode.ps1
Normal file
48
scripts/inventory-authenticode.ps1
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[ValidateScript({ Test-Path -LiteralPath $_ -PathType Container })]
|
||||||
|
[string]$ArtifactDirectory
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
function Get-RelativePath {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$Root,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$Path
|
||||||
|
)
|
||||||
|
|
||||||
|
$rootWithSeparator = $Root.TrimEnd([IO.Path]::DirectorySeparatorChar, [IO.Path]::AltDirectorySeparatorChar) + [IO.Path]::DirectorySeparatorChar
|
||||||
|
$rootUri = [Uri]$rootWithSeparator
|
||||||
|
$pathUri = [Uri]$Path
|
||||||
|
|
||||||
|
[Uri]::UnescapeDataString($rootUri.MakeRelativeUri($pathUri).ToString()).Replace("/", [IO.Path]::DirectorySeparatorChar)
|
||||||
|
}
|
||||||
|
|
||||||
|
$artifactRoot = (Resolve-Path -LiteralPath $ArtifactDirectory).Path
|
||||||
|
$binaries = Get-ChildItem -LiteralPath $artifactRoot -Recurse -File |
|
||||||
|
Where-Object { $_.Extension -in @(".exe", ".dll") } |
|
||||||
|
Sort-Object -Property FullName
|
||||||
|
|
||||||
|
if (-not $binaries) {
|
||||||
|
Write-Warning "No .exe or .dll files found under '$artifactRoot'."
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
$binaries | ForEach-Object {
|
||||||
|
$signature = Get-AuthenticodeSignature -LiteralPath $_.FullName
|
||||||
|
|
||||||
|
[pscustomobject]@{
|
||||||
|
RelativePath = Get-RelativePath -Root $artifactRoot -Path $_.FullName
|
||||||
|
Status = $signature.Status
|
||||||
|
SignatureType = $signature.SignatureType
|
||||||
|
Signer = if ($signature.SignerCertificate) { $signature.SignerCertificate.Subject } else { "" }
|
||||||
|
SignerThumbprint = if ($signature.SignerCertificate) { $signature.SignerCertificate.Thumbprint } else { "" }
|
||||||
|
Timestamped = [bool]$signature.TimeStamperCertificate
|
||||||
|
TimeStamper = if ($signature.TimeStamperCertificate) { $signature.TimeStamperCertificate.Subject } else { "" }
|
||||||
|
}
|
||||||
|
} | Format-Table -AutoSize
|
||||||
73
scripts/verify-authenticode.ps1
Normal file
73
scripts/verify-authenticode.ps1
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[ValidateScript({ Test-Path -LiteralPath $_ -PathType Container })]
|
||||||
|
[string]$ArtifactDirectory,
|
||||||
|
|
||||||
|
[string[]]$Files = @(
|
||||||
|
"orca-slicer.exe",
|
||||||
|
"OrcaSlicer.dll"
|
||||||
|
),
|
||||||
|
|
||||||
|
[string]$SignToolPath
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
function Resolve-SignToolPath {
|
||||||
|
param(
|
||||||
|
[string]$ExplicitPath
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($ExplicitPath) {
|
||||||
|
if (Test-Path -LiteralPath $ExplicitPath -PathType Leaf) {
|
||||||
|
return (Resolve-Path -LiteralPath $ExplicitPath).Path
|
||||||
|
}
|
||||||
|
|
||||||
|
throw "SignTool was not found at '$ExplicitPath'."
|
||||||
|
}
|
||||||
|
|
||||||
|
$fromPath = Get-Command -Name "signtool.exe" -ErrorAction SilentlyContinue
|
||||||
|
if ($fromPath) {
|
||||||
|
return $fromPath.Source
|
||||||
|
}
|
||||||
|
|
||||||
|
$candidateRoots = @(
|
||||||
|
"${env:ProgramFiles(x86)}\Windows Kits\10\bin",
|
||||||
|
"${env:ProgramFiles}\Windows Kits\10\bin"
|
||||||
|
) | Where-Object { $_ -and (Test-Path -LiteralPath $_ -PathType Container) }
|
||||||
|
|
||||||
|
foreach ($root in $candidateRoots) {
|
||||||
|
$candidate = Get-ChildItem -LiteralPath $root -Recurse -Filter "signtool.exe" -File -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object { $_.FullName -match "\\(x64|arm64)\\signtool\.exe$" } |
|
||||||
|
Sort-Object -Property FullName -Descending |
|
||||||
|
Select-Object -First 1
|
||||||
|
|
||||||
|
if ($candidate) {
|
||||||
|
return $candidate.FullName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw "signtool.exe was not found. Install the Windows SDK or pass -SignToolPath."
|
||||||
|
}
|
||||||
|
|
||||||
|
$artifactRoot = (Resolve-Path -LiteralPath $ArtifactDirectory).Path
|
||||||
|
$signtool = Resolve-SignToolPath -ExplicitPath $SignToolPath
|
||||||
|
|
||||||
|
Write-Host "Using SignTool: $signtool"
|
||||||
|
Write-Host "Verifying Authenticode signatures in: $artifactRoot"
|
||||||
|
|
||||||
|
foreach ($relativePath in $Files) {
|
||||||
|
$filePath = Join-Path $artifactRoot $relativePath
|
||||||
|
if (-not (Test-Path -LiteralPath $filePath -PathType Leaf)) {
|
||||||
|
throw "Expected signed file was not found: $filePath"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Verifying $relativePath"
|
||||||
|
& $signtool verify /pa /all /tw /v $filePath
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
throw "SignTool verification failed for '$relativePath' with exit code $LASTEXITCODE."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Authenticode verification passed."
|
||||||
16
signpath/README.md
Normal file
16
signpath/README.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# SignPath configurations
|
||||||
|
|
||||||
|
This directory contains SignPath artifact configurations used by GitHub Actions.
|
||||||
|
|
||||||
|
## `windows-portable-v1`
|
||||||
|
|
||||||
|
`windows-portable-v1.xml` is the initial conservative Windows portable-bundle signing configuration. It signs only the two first-party binaries:
|
||||||
|
|
||||||
|
- `orca-slicer.exe`
|
||||||
|
- `OrcaSlicer.dll`
|
||||||
|
|
||||||
|
Do not broaden this to all DLLs without first confirming ownership, provenance, and whether upstream vendor signatures should be verified instead.
|
||||||
|
|
||||||
|
The Windows workflow uploads `${{ github.workspace }}/build/OrcaSlicer` with `actions/upload-artifact`. GitHub stores that artifact as a ZIP, and the uploaded directory contents are rooted at the ZIP root. Because of that, the SignPath configuration uses `<zip-file>` with `orca-slicer.exe` and `OrcaSlicer.dll` directly beneath it.
|
||||||
|
|
||||||
|
The release portable ZIP is a separate archive created with 7-Zip from `${{ github.workspace }}/build/OrcaSlicer`; that archive keeps the top-level `OrcaSlicer/` folder. After SignPath returns the signed artifact, the workflow copies the signed files back into `build/OrcaSlicer` and recreates the portable release ZIP so the public ZIP layout stays unchanged.
|
||||||
12
signpath/windows-portable-v1.xml
Normal file
12
signpath/windows-portable-v1.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<artifact-configuration xmlns="http://signpath.io/artifact-configuration/v1">
|
||||||
|
<zip-file>
|
||||||
|
<pe-file path="orca-slicer.exe">
|
||||||
|
<authenticode-sign />
|
||||||
|
</pe-file>
|
||||||
|
|
||||||
|
<pe-file path="OrcaSlicer.dll">
|
||||||
|
<authenticode-sign />
|
||||||
|
</pe-file>
|
||||||
|
</zip-file>
|
||||||
|
</artifact-configuration>
|
||||||
Reference in New Issue
Block a user