Skip to content
ReShiki / guide

Configure Windows signing with SignPath

ReShiki has SignPath Open Source Code Signing access. Production Windows signing is not active yet: the Foundation release certificate is pending, the release certificate pin must be configured, and the production signing path must pass a manual run. The two artifact configurations and GitHub environment are configured, including the CI token and test certificate pin. Nightly-version test signing passed on x64 and ARM64, and internal test signing is enabled for daily nightlies. Existing Windows downloads remain unsigned. This record describes the configuration inspected on 2026-10-09 and the remaining setup.

Certificate status rechecked on 2026-10-15

Section titled “Certificate status rechecked on 2026-10-15”

The live portal still shows Release certificate 2026 as CSR PENDING and release-signing as INVALID. The certificate has no validity dates yet. SIGNPATH_ENABLED and SIGNPATH_NIGHTLY_ENABLED remain false; internal nightly test signing remains enabled. Test signatures are not publicly trusted. The Windows security investigation records the current installer detections and the separate proposed inner-executable signing extension, which is not part of the nightly startup fix.

Open SignPath using the maintainer account with MFA. The inspected settings are:

Setting Value
Organization ID c91a089d-e2bc-458e-8453-0d11619e584e
Project slug ReShiki
Repository https://github.com/Ameyanagi/ReShiki.git
Trusted build system GitHub.com, active and linked to ReShiki
Release policy release-signing, currently invalid while its certificate is pending
Release certificate Release certificate 2026, HSM key, CSR pending
Release submitter CI builds
Release approver Project maintainer, one approval required
Release verification Trusted build system and origin verification required
Release allowed branches ** at inspection; review before activation
Test policy test-signing, valid; no approval, trusted-build-system or origin-verification requirement

The valid test policy does not establish production readiness. Its certificate is not publicly trusted. See SignPath’s test and release certificate documentation.

The official SignPath App was installed on 2026-10-09 with Only select repositories → ReShiki. Its installation ID is 169339604. GitHub confirmed read access to Actions, code and metadata, plus read/write access to repository administration. The maintainer approved those permissions and completed GitHub re-authentication. When checking or restoring this integration, inspect Settings → Applications → Installed GitHub Apps and verify that the App is active, limited to ReShiki, and the project remains linked to the active GitHub.com trusted build system. SignPath documents the App and GitHub-hosted runner requirements in its GitHub integration guide.

Review the current ** branch allowance with the Foundation before enabling production. Restrict the policy to the reviewed release origins accepted by SignPath. Check the origin shown for both a main build and a release-tag build; do not assume that a tag pattern is a branch name. The workflow also restricts production signing to main and version tags whose commits belong to main. Keep one manual approval, trusted-build-system verification and origin verification enabled for release-signing.

In the project’s Artifact configurations, create configurations using these exact slugs and copy the corresponding checked-in XML:

Slug XML Required request parameters Signed file inside the uploaded ZIP
windows-app windows-app.xml version reshiki.exe
windows-installer windows-installer.xml version, architecture reshiki-${version}-windows-${architecture}-setup.exe

Both enforce ProductName=ReShiki and exact ProductVersion and FileVersion strings matching the supplied package version. For a nightly, supply the entire VERSION-nightly.DATE.RUN_ID.ATTEMPT string. Numeric VERSIONINFO values remain the three-component base version plus a zero fourth component; they do not contain GitHub’s run ID. The installer request’s architecture is supplied by the workflow and validated as x64 or arm64 before submission. XML parameters themselves do not define an architecture enumeration.

Inno Setup 6.7.3 writes these text fields into fixed placeholders: shorter values retain padding spaces, and a full nightly file version exceeds its 20-character placeholder. The packager writes exact, terminated product-name and version strings into the existing VERSIONINFO allocation before signing, then recomputes the PE checksum. It preserves file offsets, other resources and the installer payload, and rejects a version block that cannot fit. This keeps the strict SignPath identity checks intact and avoids truncating nightly version strings. The pinned compiler’s behavior is defined in its version-resource updater.

Both configurations were registered and reported VALID during setup. Their signing directives specify SHA-256 and preserve the Open Source account’s required signature watermark; custom signature descriptions or description URLs are rejected by this account.

The root is <zip-file> because actions/upload-artifact@v7 creates a ZIP around the single staged executable. Upload that executable directly at the archive root. Do not upload the already-packaged portable ZIP for the windows-app request; that would add another archive level. Keep the normal ZIP behavior and the signing action’s normal decompression behavior. Each configuration signs one explicit PE file and does not sign other files added to an upload. Required parameters, nested paths and match counts follow SignPath’s artifact syntax documentation; metadata restrictions follow its artifact reference.

The project’s initial default configuration signs an unrestricted PE file. Retire or replace it with the same restrictions after registering and validating the new configurations. Release requests must explicitly select windows-app or windows-installer; do not leave an unrestricted configuration available for production signing. Compare the portal XML with the repository when changing either configuration. Use a new slug for an incompatible artifact layout, as recommended by SignPath’s project configuration guide.

Create the windows-signing GitHub environment in ReShiki’s repository settings. Add the following secret and environment variables. The signing switches are repository variables, so publication and the reusable release workflow can read them outside the signing environment.

Location Name Value
Environment secret SIGNPATH_API_TOKEN API token for the CI builds submitter
Environment variable SIGNPATH_ORGANIZATION_ID c91a089d-e2bc-458e-8453-0d11619e584e
Environment variable SIGNPATH_PROJECT_SLUG ReShiki
Environment variable SIGNPATH_TEST_CERTIFICATE_SHA256 SHA-256 of the test policy’s DER-encoded public certificate
Environment variable SIGNPATH_RELEASE_CERTIFICATE_SHA256 SHA-256 of the issued release policy’s DER-encoded public certificate
Repository variable SIGNPATH_ENABLED false until production validation completes
Repository variable SIGNPATH_NIGHTLY_ENABLED false; enable separately to require signed nightlies
Repository variable SIGNPATH_NIGHTLY_TEST_ENABLED true; the manual nightly-version test-signing run passed, enabling internal CI artifacts only

In SignPath’s Users and Groups, open the existing CI builds CI user and reuse its previously saved API token, or regenerate it if it was not saved. Verify that this user is a submitter for the two intended ReShiki policies and has no unnecessary administrator permissions. Store the token directly in GitHub’s environment-secret field; do not place it in source files, commands, logs or chat. SignPath displays a token only when generated; regenerating it can invalidate an existing integration. See its CI user documentation.

Download each policy’s public X.509 certificate from SignPath to calculate its pin. Do not use a CSR, a private-key export, or the portal’s SHA-1 thumbprint. In PowerShell 7, for a downloaded .cer file:

Terminal window
$certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new((Resolve-Path '.\signpath-test.cer').Path)
$certificate.GetCertHashString([System.Security.Cryptography.HashAlgorithmName]::SHA256)

The method hashes the certificate’s DER bytes, even when the downloaded file uses another supported encoding. Store the resulting 64 hexadecimal characters in the matching variable. Repeat for the issued release certificate when it becomes available. Pin the certificate used by the policy, and update the pin deliberately when that certificate is rotated. CI checks returned signatures against these pins; it does not trust a publisher name alone.

The active windows-signing environment permits main only. The temporary signing/signpath-windows validation-branch allowance was removed after merging the integration. Add a v* release-tag policy when activating production signing; retain the main branch policy. The workflow has its own origin gates as well. The nightly reusable call must retain secrets: inherit, and signing jobs need actions: read and contents: read permissions. The integration uses signpath/github-action-submit-signing-request@v3, explicitly passes each artifact configuration slug and downloads the completed signed artifact. See the SignPath action inputs.

Keep both publication switches false. On main, dispatch Release builds with Sign Windows test packages enabled and windows_signing_policy set to test-signing:

Terminal window
gh workflow run release.yml --ref main -f sign_windows=true -f windows_signing_policy=test-signing

This manual run does not publish a release. Repeat with -f nightly=true to exercise the full nightly version string. The workflow also permits internal test-policy dispatches on a feature branch; the signing environment must allow that branch before such a run can access its credentials. Both x64 and ARM64 must complete the following sequence:

  1. Check the qualified unsigned archive’s checksum, source commit, version, architecture and expected contents, then stage its reshiki.exe.
  2. Upload and sign the application using windows-app; verify the returned executable’s version metadata, timestamped Authenticode signature and test-certificate pin.
  3. Put that signed executable in the portable package and build Inno Setup from the same package contents.
  4. Upload and sign the final setup executable using windows-installer; verify its metadata, signature and pin.
  5. Retest the final portable package and installed application, including upgrades and uninstallation, and generate package checksum sidecars from the final bytes.

Review both architectures’ SignPath request records and workflow logs. Test signatures lack public trust. After matching the DER SHA-256 pin, the verification helper temporarily trusts that test certificate on the disposable GitHub-hosted Windows runner to validate Authenticode and its timestamp, and removes that trust in its cleanup path. Do not install the test certificate on users’ computers. Do not publish test-signed packages or describe them as trusted Windows releases. Passing this run also does not exercise the release policy’s approval and origin requirements.

Only the application and final setup executable are signed. Inno Setup’s generated uninstaller remains unsigned; signing the outer setup program does not sign it. The installer privacy disclosure and update-check opt-out requirements must also be reviewed with SignPath Foundation before production activation.

The manual nightly-version validation completed successfully on 2026-10-09, at commit 29bd9cfc65befe4f46b8a985bdbe33e5f3d9f00f, using package version 0.11.0-nightly.20261008.37822934801.1. All six platform builds passed, and SignPath completed the application and installer requests for both Windows architectures. Both native signing jobs passed certificate-pin, timestamp, metadata, content-integrity, final installation/upgrade/uninstallation, chemistry and packaged MCP checks. One initial ARM64 PowerShell startup timeout passed on an unchanged failed-job retry; the other five qualified builds were reused.

PR #270 is merged, and repository variable SIGNPATH_NIGHTLY_TEST_ENABLED is now true. Daily nightlies are scheduled for 03:37 Japan time; GitHub may start scheduled runs later. Both production switches remain false, and the release certificate remains CSR pending.

After the manual test-policy run passes for both architectures, repeat it with -f nightly=true and verify the full nightly version in the signed packages. Then set repository variable SIGNPATH_NIGHTLY_TEST_ENABLED=true to add test signing to scheduled and manually dispatched Nightly builds on main. Keep SIGNPATH_ENABLED=false and SIGNPATH_NIGHTLY_ENABLED=false while the release certificate is pending. The updated workflows must be merged to main before the scheduled run can use this path.

Each nightly reuses the qualified Windows artifacts from its existing six-target build; it does not start a second full build. It submits four test-signing requests: one application and one setup program for each of x64 and ARM64. These requests use the configured test-certificate pin and require no manual SignPath approval. The completed packages remain workflow artifacts named test-signed-windows-x64 and test-signed-windows-arm64 for internal validation. They are untrusted on ordinary Windows installations.

The public nightly release still downloads the original unsigned Windows artifacts, labels Windows downloads as unsigned, and calculates SHA256SUMS from those published bytes. It never downloads the test-signed artifacts. A failing internal signing job prevents that nightly run from publishing; review the failure before starting another run.

The reusable release workflow accepts and validates windows_signing_policy and exports the selected policy alongside windows_signing_enabled. The nightly publisher treats Windows packages as release-signed only when signing is enabled and the selected policy is release-signing. If SIGNPATH_NIGHTLY_ENABLED=true, production signing takes precedence over the internal test switch and requires the issued release certificate and manual approvals described below.

The inspected Release certificate 2026 entry is still a pending CSR and has no validity dates. A CSR is not an issued certificate and cannot supply the release certificate pin. Wait for the Foundation’s certificate-issuance process. If the entry remains pending, contact the Foundation through the existing approval correspondence with the organization ID, project slug and pending certificate name; ask what remains to complete issuance. Do not generate a replacement key or buy/upload an unrelated certificate as a workaround. SignPath explains its HSM CSR flow in Managing certificates.

After the certificate is issued, confirm that release-signing is valid, download its public certificate and set SIGNPATH_RELEASE_CERTIFICATE_SHA256. Dispatch the same manual workflow using -f windows_signing_policy=release-signing. For each architecture, the approver must review and approve the application request before the installer request can be built and submitted, then review and approve that installer request. Check the commit, version, artifact configuration and verified origin for every request. Keep the workflow running while completing its approvals.

Before activation, both architectures must pass public-trust verification with a timestamp, the release-certificate pin, final package tests, install/upgrade and uninstall checks. Record the run and request URLs in the release validation record. Only then set repository variable SIGNPATH_ENABLED=true. Stable tag publication now requires the signed Windows artifacts and fails if signing or verification fails; it does not substitute unsigned packages.

Nightly signing remains a separate choice. Set SIGNPATH_NIGHTLY_ENABLED=true only after validating a nightly-version release-signing run and arranging manual approvals for each daily build. Leave it false to continue clearly labelled unsigned Windows nightlies. Test signing is never used for public nightlies.

The final Windows ZIP and setup checksums are generated after signing and package verification. Publication generates SHA256SUMS from those final packages. An unsigned build’s checksums cannot be reused because signing changes file bytes. See the code signing policy, release process and Foundation conditions.