Skip to content

Sign msix packages, and fail the build when signing does not happen - #22

Merged
JoshuaPeddle merged 2 commits into
mainfrom
fix/15101-msix-codesigning
Aug 25, 2026
Merged

JoshuaPeddle merged 2 commits into
mainfrom
fix/15101-msix-codesigning

Conversation

@JoshuaPeddle

@JoshuaPeddle JoshuaPeddle commented Aug 25, 2026 •

Copy link
Copy Markdown
Contributor

Description

TL/DR: Fixed silent publishing of unsigned msix files. Uploads now keep their extension (via X-FileExtension header or zip-content detection), and batch signing errors/timeouts are surfaced as failures instead of the client timing out and shipping unsigned artifacts.

Uploads were stored under a generated id with no file extension. signtool picks the handler for container formats such as msix by file name, so it refused the package and exited non-zero for the whole batch, leaving the msi and exe unsigned as well.

Two further defects hid that failure. A batch level signing error was written under the batch id but polled for under the per-file id, so every poll returned 425 until the client gave up 1200 seconds later. The client then reported no failures and exited 0, so the pipeline generated checksums over unsigned artifacts and published them to Box.

The service now keeps the extension on the working file, taking it from the X-FileExtension header when the client sends one and otherwise detecting an appx package from its content, so the currently deployed client signs an msix correctly with no client-side change. Batch errors are surfaced to pollers, and an expired batch timeout is reported as a failure instead of success.

Covered end to end by packing a real msix with makeappx and signing it through the batch endpoint with no header at all, asserting the returned package carries an AppxSignature.p7x.

Example logs:

[2026-08-21T19:33:31.737Z] Attached signing enabled.
[2026-08-21T19:33:32.333Z] Pre-installed client at C:\Program Files\TownSuite.CodeSigning.Client has mismatched hash. Expected: 1499c6d62bd62f9cdfc1c450f11077662e61edc343ced99ded239d2055ce1a91, Got: 878ee006325725e1516da51e16a306a2eb073cdbce29ba668afc15948f6748df. Will attempt to download.
[2026-08-21T19:33:32.333Z] Downloading TownSuite.CodeSigning.Client from https://github.com/TownSuite/TownSuite.CodeSigning.Service/releases/download/v26.10.4/TownSuite.CodeSigning.Client.exe to C:\Windows\system32\config\systemprofile\Tools\TownSuite.CodeSigning\TownSuite.CodeSigning.Client.exe
[2026-08-21T19:33:35.668Z] Successfully downloaded and verified TownSuite.CodeSigning.Client at C:\Windows\system32\config\systemprofile\Tools\TownSuite.CodeSigning\TownSuite.CodeSigning.Client.exe
[2026-08-21T19:33:35.668Z] Signing *.msi;*.exe;*.msix
[2026-08-21T19:33:35.668Z] in C:\Jenkins\workspace\TownSuite-Native-Installers/dist/windows_x64
[2026-08-21T19:33:35.668Z] Signing *.msi;*.exe;*.msix
[2026-08-21T19:33:41.005Z] Uploading file: C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:33:41.598Z] Uploading file: C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:33:42.571Z] Uploading file: C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix
[2026-08-21T19:33:43.543Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:33:43.543Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:33:43.544Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix
[2026-08-21T19:34:51.370Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:34:51.370Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:34:51.370Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix
[2026-08-21T19:35:47.747Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:35:47.747Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:35:47.747Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix
[2026-08-21T19:36:55.590Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:36:55.590Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:36:55.590Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix
[2026-08-21T19:37:51.963Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:37:51.963Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:37:51.963Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix
[2026-08-21T19:38:48.343Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:38:48.343Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:38:48.343Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix
[2026-08-21T19:39:56.162Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:39:56.162Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:39:56.162Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix
[2026-08-21T19:40:52.547Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:40:52.547Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:40:52.547Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix
[2026-08-21T19:41:48.927Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:41:48.927Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:41:48.927Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix
[2026-08-21T19:42:56.829Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:42:56.830Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:42:56.830Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix
[2026-08-21T19:43:53.195Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:43:53.195Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:43:53.195Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix
[2026-08-21T19:45:01.079Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:45:01.079Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:45:01.079Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix
[2026-08-21T19:45:57.617Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:45:57.617Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:45:57.617Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix
[2026-08-21T19:46:54.185Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:46:54.186Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:46:54.186Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix
[2026-08-21T19:48:02.415Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:48:02.415Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:48:02.415Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix
[2026-08-21T19:48:58.751Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:48:58.751Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:48:58.751Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix
[2026-08-21T19:49:55.099Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:49:55.099Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:49:55.099Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix
[2026-08-21T19:51:02.952Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:51:02.952Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:51:02.952Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix
[2026-08-21T19:51:59.325Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:51:59.325Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:51:59.325Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix
[2026-08-21T19:52:55.708Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msi
[2026-08-21T19:52:55.708Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.exe
[2026-08-21T19:52:55.708Z] Polling download for file C:\Jenkins\workspace\TownSuite-Native-Installers\dist\windows_x64\TownSuiteIntelligence_1.0.177_windows_x64.msix

Motivation and Context

https://github.com/TownSuite/TownSuite.IssueTracker/issues/15101

Types of changes

  • Bug fix (non-breaking change which fixes an issue)

Checklist:

  • All new and existing tests passed.

… does not happen

TownSuite/TownSuite.IssueTracker#15101

Uploads were stored under a generated id with no extension, so signtool did not recognize an msix and failed the whole batch, leaving the msi and exe unsigned as well. The failure was then invisible: batch errors were written under the batch id but polled for under the file id, and the client treated its own timeout as success, so builds published unsigned installers.

- Client sends the original extension as X-FileExtension on upload and poll, and the service keeps it on the working file so signtool recognizes msix and appx. An absent header keeps the previous behaviour.
- Validate that extension against a short alphanumeric pattern before it reaches a signtool command line.
- GET /sign/batch checks the batch level error file as well as the per-file one, so a batch failure returns 500 instead of 425 until the client gives up.
- DownloadSignedFiles reports files still outstanding when the batch timeout expires, so a timeout exits non-zero.
- Add coverage, including an end to end msix sign through the batch endpoint using real makeappx and signtool.
…an msix

TownSuite/TownSuite.IssueTracker#15101

Recovering the extension from the X-FileExtension header alone meant nothing improved until a new client was released, pinned in codesigning.ps1 and rolled out to the build agents. An msix is a zip carrying an AppxManifest, so the service can identify one on its own and the client needs no change at all.

- Fall back to content detection when no extension header is sent. The header still wins when present.
- Locate the finished file by id prefix instead of rebuilding its name from the header, so the download no longer depends on the caller sending anything. ISigner.GetFileName is replaced by FindResultFile.
- Drop the extension header from the poll request, which no longer needs it.
- Cover appx packages and bundles, plain zips that must not be mistaken for one, and non-zip and truncated input.
@JoshuaPeddle
JoshuaPeddle merged commit 02f49ba into main Aug 25, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants