Some checks failed
windows-msi / full-msi-unsigned (push) Has been cancelled
windows-msi-sign.yml.example; gofpdf register when EmbedBrandFonts and fonts present.
164 lines
8 KiB
Text
164 lines
8 KiB
Text
# EXAMPLE ONLY — not a live workflow.
|
|
# Copy into .github/workflows/windows-msi-sign.yml (or .forgejo/workflows/) and enable
|
|
# only when org secret store holds the names below. Default product CI remains
|
|
# windows-msi.yml (unsigned full MSI).
|
|
#
|
|
# Secret / var NAMES only — never commit PFX bytes, passwords, thumbprints as values,
|
|
# or Azure client secrets. See platform/windows/wix/CI-SIGN-NOTARY.md.
|
|
#
|
|
# GitHub Actions: secrets.* / vars.* as below.
|
|
# Forgejo Actions: same secret names; map runs-on to your Windows label; keep names identical.
|
|
#
|
|
# After sign + upload: docs/PUBLISH-DIGESTS.md + fill-manifest-sha256.ps1 (hash only; no upload).
|
|
#
|
|
# name: windows-msi-sign
|
|
# on:
|
|
# workflow_dispatch:
|
|
# # push:
|
|
# # tags: ["printstamp-v*"]
|
|
|
|
name: windows-msi-sign-example
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: read
|
|
# id-token: write # uncomment if using Azure OIDC → Trusted Signing (no client secret)
|
|
|
|
jobs:
|
|
# Live default stays unsigned — see windows-msi.yml.
|
|
# This example job is gated off until secrets exist.
|
|
full-msi-sign:
|
|
if: ${{ false }} # flip only after secrets exist; do not claim SmartScreen until clean-VM proof
|
|
runs-on: windows-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Go
|
|
uses: actions/setup-go@v5
|
|
with:
|
|
go-version-file: go.mod
|
|
|
|
- name: Install WiX Toolset v3
|
|
shell: pwsh
|
|
run: |
|
|
choco install wixtoolset --version 3.14.1 -y --no-progress
|
|
$wixBin = "${env:ProgramFiles(x86)}\WiX Toolset v3.14\bin"
|
|
if (-not (Test-Path -LiteralPath (Join-Path $wixBin "candle.exe"))) {
|
|
$found = Get-ChildItem -Path "${env:ProgramFiles(x86)}" -Filter "candle.exe" -Recurse -ErrorAction SilentlyContinue |
|
|
Where-Object { $_.FullName -match 'WiX Toolset' } |
|
|
Select-Object -First 1
|
|
if ($found) { $wixBin = $found.Directory.FullName }
|
|
}
|
|
if (-not (Test-Path -LiteralPath (Join-Path $wixBin "candle.exe"))) {
|
|
Write-Error "WiX candle.exe not found after install."
|
|
}
|
|
"WIX_BIN=$wixBin" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
|
"PATH=$wixBin;$env:PATH" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
|
|
|
- name: Build full MSI (pre-sign)
|
|
shell: pwsh
|
|
run: |
|
|
powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\build-full-msi.ps1 -Arch amd64
|
|
$msi = Get-ChildItem -Path platform\windows\wix\out -Filter "VeraePrintStamp-windows-*.msi" |
|
|
Sort-Object LastWriteTime -Descending | Select-Object -First 1
|
|
if (-not $msi) { Write-Error "No MSI under platform/windows/wix/out" }
|
|
"MSI_PATH=$($msi.FullName)" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
|
"MSI_NAME=$($msi.Name)" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
|
$stage = "platform\windows\wix\StageFull\bin"
|
|
"STAGE_BIN=$stage" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
|
|
|
# --- Path A: PFX via secrets (signtool) ---
|
|
# Secret / var names (placeholders — values never in git):
|
|
# secrets.WINDOWS_CERT_PFX_BASE64
|
|
# secrets.WINDOWS_CERT_PFX_PASSWORD
|
|
# secrets.WINDOWS_CERT_THUMBPRINT # optional if /sha1 preferred after import
|
|
# vars.WINDOWS_SIGN_TIMESTAMP_URL # RFC 3161 TSA
|
|
#
|
|
# - name: Import code-signing PFX
|
|
# shell: pwsh
|
|
# env:
|
|
# WINDOWS_CERT_PFX_BASE64: ${{ secrets.WINDOWS_CERT_PFX_BASE64 }}
|
|
# WINDOWS_CERT_PFX_PASSWORD: ${{ secrets.WINDOWS_CERT_PFX_PASSWORD }}
|
|
# run: |
|
|
# $pfx = Join-Path $env:RUNNER_TEMP "codesign.pfx"
|
|
# [IO.File]::WriteAllBytes($pfx, [Convert]::FromBase64String($env:WINDOWS_CERT_PFX_BASE64))
|
|
# $pwd = ConvertTo-SecureString $env:WINDOWS_CERT_PFX_PASSWORD -AsPlainText -Force
|
|
# Import-PfxCertificate -FilePath $pfx -CertStoreLocation Cert:\CurrentUser\My -Password $pwd | Out-Null
|
|
# Remove-Item -LiteralPath $pfx -Force -ErrorAction SilentlyContinue
|
|
# # Never Upload-Artifact the PFX; never Write-Host password or base64.
|
|
#
|
|
# - name: signtool Authenticode (EXEs + MSI)
|
|
# shell: pwsh
|
|
# env:
|
|
# WINDOWS_SIGN_TIMESTAMP_URL: ${{ vars.WINDOWS_SIGN_TIMESTAMP_URL }}
|
|
# WINDOWS_CERT_THUMBPRINT: ${{ secrets.WINDOWS_CERT_THUMBPRINT }}
|
|
# run: |
|
|
# $tsa = $env:WINDOWS_SIGN_TIMESTAMP_URL
|
|
# if (-not $tsa) { $tsa = "https://timestamp.digicert.com" }
|
|
# $signtool = (Get-Command signtool.exe -ErrorAction Stop).Source
|
|
# $targets = @(
|
|
# (Join-Path $env:STAGE_BIN "verae-print.exe"),
|
|
# (Join-Path $env:STAGE_BIN "verae-printhelper.exe"),
|
|
# $env:MSI_PATH
|
|
# ) | Where-Object { $_ -and (Test-Path -LiteralPath $_) }
|
|
# foreach ($t in $targets) {
|
|
# if ($env:WINDOWS_CERT_THUMBPRINT) {
|
|
# & $signtool sign /fd SHA256 /tr $tsa /td SHA256 /sha1 $env:WINDOWS_CERT_THUMBPRINT $t
|
|
# } else {
|
|
# & $signtool sign /fd SHA256 /tr $tsa /td SHA256 /a $t
|
|
# }
|
|
# if ($LASTEXITCODE -ne 0) { Write-Error "signtool sign failed: $t" }
|
|
# & $signtool verify /pa $t
|
|
# if ($LASTEXITCODE -ne 0) { Write-Error "signtool verify failed: $t" }
|
|
# }
|
|
|
|
# --- Path B: Azure Trusted Signing (prefer over PFX when available) ---
|
|
# Secret / var names (placeholders — values never in git):
|
|
# secrets.WINDOWS_TRUSTED_SIGNING_TENANT_ID # or OIDC; skip client secret
|
|
# secrets.WINDOWS_TRUSTED_SIGNING_CLIENT_ID
|
|
# secrets.WINDOWS_TRUSTED_SIGNING_CLIENT_SECRET # omit when id-token: write + federated creds
|
|
# vars.WINDOWS_TRUSTED_SIGNING_ENDPOINT # e.g. https://cus.codesigning.azure.net
|
|
# vars.WINDOWS_TRUSTED_SIGNING_ACCOUNT
|
|
# vars.WINDOWS_TRUSTED_SIGNING_CERTIFICATE_PROFILE
|
|
# vars.WINDOWS_SIGN_TIMESTAMP_URL # optional; action may default TSA
|
|
#
|
|
# - name: Azure Trusted Signing (EXEs + MSI)
|
|
# # uses: azure/trusted-signing-action@v0 # pin a reviewed tag when enabling
|
|
# # with:
|
|
# # azure-tenant-id: ${{ secrets.WINDOWS_TRUSTED_SIGNING_TENANT_ID }}
|
|
# # azure-client-id: ${{ secrets.WINDOWS_TRUSTED_SIGNING_CLIENT_ID }}
|
|
# # azure-client-secret: ${{ secrets.WINDOWS_TRUSTED_SIGNING_CLIENT_SECRET }}
|
|
# # endpoint: ${{ vars.WINDOWS_TRUSTED_SIGNING_ENDPOINT }}
|
|
# # trusted-signing-account-name: ${{ vars.WINDOWS_TRUSTED_SIGNING_ACCOUNT }}
|
|
# # certificate-profile-name: ${{ vars.WINDOWS_TRUSTED_SIGNING_CERTIFICATE_PROFILE }}
|
|
# # files-folder: ${{ env.STAGE_BIN }}
|
|
# # files-folder-filter: exe
|
|
# # files-folder-recurse: true
|
|
# # file-digest: SHA256
|
|
# # timestamp-rfc3161: ${{ vars.WINDOWS_SIGN_TIMESTAMP_URL }}
|
|
# # timestamp-digest: SHA256
|
|
# shell: pwsh
|
|
# run: |
|
|
# Write-Error "Trusted Signing path not enabled — wire action + secret names above."
|
|
|
|
# - name: Upload signed MSI artifact
|
|
# uses: actions/upload-artifact@v4
|
|
# with:
|
|
# name: VeraePrintStamp-windows-msi-signed
|
|
# path: platform/windows/wix/out/VeraePrintStamp-windows-*.msi
|
|
# if-no-files-found: error
|
|
# retention-days: 14
|
|
|
|
# Operator after download: upload CDN blob → fill-manifest-sha256.ps1 → paste digests.
|
|
# See docs/PUBLISH-DIGESTS.md (does not upload; secret values never land in manifests).
|
|
|
|
- name: Placeholder (example not enabled)
|
|
shell: pwsh
|
|
run: |
|
|
Write-Host "windows-msi-sign.yml.example — sign job gated if: false."
|
|
Write-Host "Live unsigned build: .github/workflows/windows-msi.yml"
|
|
Write-Host "Local dry-run: platform/windows/scripts/sign-dry-run.ps1"
|
|
Write-Host "Digests after sign+upload: docs/PUBLISH-DIGESTS.md"
|