feat(build): Authenticode code signing via Azure Trusted Signing (all 7 installers) - #1363
Merged
Merged
Conversation
… Azure Trusted Signing Add Windows code signing for QUILL and all six companion apps using Azure Trusted Signing (no PFX on disk; auth is the ambient az login / workload credential). Distinct from the Ed25519 provenance signing in quill/tools/signing.py. - scripts/code_signing.py: one reusable signer + CLI (doctor, ensure-dlib, sign, sign-tree, sign-build, verify). Locates signtool, downloads and SHA-256-verifies the pinned Microsoft.Trusted.Signing.Client dlib into gitignored build/deps/trusted-signing/, and invokes signtool via an argv list (never an MSYS shell, which mangles /fd switches). Opt-in via QUILL_SIGN=1; fail-open unless QUILL_SIGN_REQUIRED=1; QUILL_SIGN_PATTERNS tunes the fileset. - Wired into all seven installers. Payload .exe/.dll are signed before packaging; each Setup.exe and its embedded uninstaller are signed by Inno's native SignTool + SignedUninstaller during compile, gated behind an "#ifdef Sign" block (ISCC gets /DSign + a /Squilltrusted mapping). A plain build passes neither, so unsigned builds compile unchanged. - Main app: build_inno_setup_script emits the block; compile_inno_setup_installer adds the sign args when QUILL_SIGN is set; installer/quill.iss regenerated. - Standalones: block added to each .iss; each build_release.ps1 gains a -Sign switch and passes the sign args to ISCC. - Docs: docs/code-signing.md, with cross-refs from docs/signing.md, the PRD, and CLAUDE.md. Tests: tests/unit/scripts/test_code_signing.py (10, cert-free). - metadata.json: Trusted Signing account/profile config (endpoint + names only, no secret) so CI and other machines can sign. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds Windows Authenticode code signing for QUILL and all six companion apps via Azure Trusted Signing (no PFX/private key on disk; auth is the ambient
az login/ workload-identity credential). This is distinct from the existing Ed25519 provenance signing inquill/tools/signing.pyand the update-feed key — see the comparison table indocs/code-signing.md.Signs three things per app: each shipped
.exe/.dll, theSetup.exe, and the Inno-generated uninstaller.What's included
scripts/code_signing.py— one reusable signer + CLI (doctor,ensure-dlib,sign,sign-tree,sign-build,verify). Locatessigntool, downloads + SHA-256-verifies the pinnedMicrosoft.Trusted.Signing.Clientdlib into gitignoredbuild/deps/trusted-signing/, and invokessigntoolvia an argv list (never an MSYS shell, which mangles/fdswitches into paths).QUILL_SIGN=1; aborts only underQUILL_SIGN_REQUIRED=1;QUILL_SIGN_PATTERNStunes the fileset (default*.exe,*.dll). Plain builds — CI, offline, contributor clones — are byte-for-byte unchanged.Setup.exe+ the embedded uninstaller signed by Inno's nativeSignTool+SignedUninstallerduring compile, gated behind an#ifdef Signblock (ISCC gets/DSign+ a/Squilltrustedmapping). The embedded uninstaller can only be signed this way.build_inno_setup_scriptemits the block;compile_inno_setup_installeradds the sign args;installer/quill.issregenerated..iss; eachbuild_release.ps1gains a-Signswitch.docs/code-signing.md(runbook), cross-refs fromdocs/signing.md, PRD §10.6, andCLAUDE.md.metadata.json: Trusted Signing account/profile config (endpoint + names only, no secret) so CI and other machines can sign.Verification
CN=Jeffrey Bishop, timestamped).uninst.e32.tmp(uninstaller) andMiniSetup.exe(setup), both "Verification successful".tests/unit/scripts/test_code_signing.py(10, cert-free) + installer sync/compile tests pass;ruffclean; docs parity gate passes; all sixbuild_release.ps1parse.Follow-ups (not in this PR)
-lite/-shared.issvariants aren't compiled by the current build scripts, so they're not wired.🤖 Generated with Claude Code