Signing the Windows release assets
sign-windows-assets.sh Authenticode-signs the Windows .exe payloads that the
DeepPhe Launcher downloads at install time, then re-uploads them in place on
the DeepPhe/DeepPhe-Dist
releases. Signing uses a YubiKey (PIV slot 9a) through jsign.
You normally trigger it via the full build:
./build-all.sh --sign
…or run it directly once the assets are published:
./sign-windows-assets.sh
Which assets get signed
| Release tag | Asset |
|---|---|
deepphe-visualizer-v2-7.1 | deepphe-visualizer-v2-win-x64.exe |
dphe-data-api-7.1 | dphe-data-api-win-x64.exe |
dphe-db-pipeline-7.1 | DeepPheVizDbCreator-windows-x86_64.exe |
For each one the script: downloads the asset with gh, signs it with jsign
(YubiKey + Sectigo timestamp), verifies the signature and chain with
osslsigncode verify, then re-uploads it with gh release upload --clobber.
Prerequisites
brew install jsign osslsigncode
The YubiKey PIV PIN is read from the macOS keychain at runtime — it is not hard-coded. Store it once:
security add-generic-password -s yubikey-piv-pin -w '<PIN>'
The script retrieves it with security find-generic-password -s yubikey-piv-pin -w.
The script uses the alias X.509 Certificate for PIV Authentication (PIV slot
9a). If that is wrong for your key, run the jsign command without --alias
and it prints the available aliases.
Before you trust the output
These .exe files are single-file bundles (~75–113 MB) that append a payload to
the PE overlay:
- the visualizer / data-api are JS-runtime bundles (pkg / Node SEA / Deno / Bun)
DeepPheVizDbCreatoris a PyInstaller (Python) bundle
Authenticode adds its certificate table to that same overlay. This is usually fine but can occasionally break the embedded payload, so:
- Smoke-test each signed
.exeon Windows — confirm it still launches. Once per tool; if it's clean, it stays clean. - Keep the asset name identical. The installer downloads these by URL/name,
so
--clobberin place is correct — do not rename to…-signed.exe. - Update any checksum the installer verifies. Signing changes the bytes; if a manifest or the install4j installer checks a hash, regenerate it or the download will be rejected.
For final release testing, run the full smoke-test matrix.
Why this is opt-in
Signing the release assets is a remote operation that mutates the public
GitHub releases and needs physical access to the YubiKey. That is why it is
gated behind --sign rather than running on every build.