Skip to content

Sign Windows forkpress binaries with Azure Trusted Signing in BK#386

Open
mokagio wants to merge 2 commits into
mokagio/buildkite-ci-skeletonfrom
mokagio/buildkite-windows-codesign
Open

Sign Windows forkpress binaries with Azure Trusted Signing in BK#386
mokagio wants to merge 2 commits into
mokagio/buildkite-ci-skeletonfrom
mokagio/buildkite-windows-codesign

Conversation

@mokagio
Copy link
Copy Markdown

@mokagio mokagio commented May 19, 2026

Stacked on #385.

Rationale

forkpress is a new app, so it adopts Azure Trusted Signing for Windows from day one — no PFX cert to rotate, no fallback path to keep alive. Replaces the PFX placeholder scripts/windows/sign.ps1 and wires signing into the BK windows-build step so the smoke artifact gets the same treatment a release will.

Tradeoffs

  • Missing Azure env vars throw; no PFX fallback.
  • signtool /debug always on — verbose, but the only way Azure auth/quota errors surface (Studio #3290 lesson).

Gotchas

  • GHA gates flip from WINDOWS_CODESIGN_CERT_BASE64 to AZURE_TENANT_ID. GHA secrets aren't wired, so those steps stay no-op until they are; BK is where signing actually runs.
  • Windows PowerShell 5.1 reads .ps1 as ANSI, not UTF-8 — keep these scripts ASCII-only (fix landed in 7f5534a after build [codex] Extend merge revalidation and WordPress semantic guards #313 broke on an em dash).

How to test

  • BK build #315: Windows build + Windows tests green; Get-AuthenticodeSignature returned Valid.

Copilot AI review requested due to automatic review settings May 19, 2026 07:41
@mokagio mokagio self-assigned this May 19, 2026
@mokagio mokagio force-pushed the mokagio/buildkite-macos-codesign branch from 9c0626a to ee7027f Compare May 19, 2026 07:43
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR replaces the Windows signing placeholder with Azure Trusted Signing and wires signing into the Buildkite Windows build, while also expanding ForkPress’ COW/merge, remote-site cloning, and plugin-compatibility tooling/documentation.

Changes:

  • Implement Azure Trusted Signing for Windows artifacts and exercise signing in BK Windows CI.
  • Add macOS codesigning + notarization helper scripts and integrate signing/notarization in BK mac builds.
  • Expand COW merge capabilities and test coverage (stale-audit/revalidation, router/admin UX paths, MySQL export/import to SQLite, plugin compatibility manifest + docs updates).

Reviewed changes

Copilot reviewed 68 out of 74 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
vendor/wordpress-php-toolkit/components/Git/Protocol/Parser/class-protocoldemultiplexer.php Adjust Git protocol demuxing to handle unmultiplexed PACK streams across chunks.
tests/cow/stale_audit.php Extend stale-audit fixtures (runs-only audit, restored reviews, bulk apply + revalidation scenarios).
tests/cow/schema_review.php Add merge CLI helper + new schema drift/revalidation fixtures and filters.
tests/cow/router_paths.php Add coverage for wp-admin plugin install/update routing and legacy redirects.
tests/cow/router_branch_actions.php Add coverage for non-async/admin-page merge action and CLI argv auditing.
tests/cow/mysql_import.php New focused test for MySQL JSONL → SQLite import behavior.
tests/cow/merge.php Extend merge suite with scoped crash recovery + after-revalidate resolution expectations.
tests/cow/media_validator.php Expand media validator fixtures (invalid shapes, WordPress semantic upload conflicts, MIME/filesize drift).
tests/cow/id_bands.php Add fixtures for plain INTEGER PRIMARY KEY parent/child collision guarding + reset-band import guard.
tests/cow/git_server.php Add tests for PACK demux tail handling + missing branch DB invariant enforcement.
tests/cow/filesystem.php Add after-revalidate coverage for binary file conflict source drift.
tests/cow/explicit_ids.php Add explicit-ID graph fixtures (post_parent, logical identity unique collision, exhausted band refresh).
tests/cow/branch_ui.php Extend wp-admin branch UI test harness for history/tree/admin page rendering + menu registration.
scripts/windows/sign.ps1 Replace PFX signing with Azure Trusted Signing via signtool /dlib + strict env validation.
scripts/popular-plugin-install-smoke.php New smoke script to download/unpack popular plugin zips and validate package shape + headers.
scripts/popular-plugin-compat.test.mjs Add Node test to validate the popular-plugin compatibility manifest.
scripts/popular-plugin-compat.mjs Add manifest refresh/validate CLI for WordPress.org top-100 popular plugins.
scripts/macos/sign-and-notarize.sh New helper to codesign then notarize a macOS binary (optional skip).
scripts/macos/notarize.sh New helper to submit a zipped binary to notarytool and fetch logs on failure.
scripts/macos/entitlements.plist Add (currently empty) hardened-runtime entitlements file.
scripts/macos/codesign.sh New helper to codesign with hardened runtime + timestamp and verify signature.
scripts/dev/cow-changed-test-plan.sh Add --jobs parallelism for local changed-test-plan execution + log capture.
scripts/cow/mysql_import_sqlite.php New MySQL JSONL import tool to create/populate SQLite + indexes.
scripts/cow/mysql_export.php New remote MySQL exporter producing JSONL (tables/indexes/rows) without booting WP.
scripts/cow/git_server.php Make missing branch DB on existing-branch update a hard error (enforced invariant).
runtime/cow/router.php Redirect legacy plugin install/update routes to wp-admin equivalents when appropriate.
runtime/cow/bootstrap_wp.php Preserve existing $table_prefix and enable wp-admin plugin install/update prerequisites.
README.md Add installation quick-start improvements + remote-site overview and links.
package.json Add mermaid support + manifest validation test; bump Astro; add packageManager.
Makefile Add MySQL import test target and new e2e selector target; include mysql import in fast set.
installer/windows/ForkPress.iss Bump Windows installer version macro.
experiments/branchfs/runtime/managed_wp_files.php Align branchfs wp-config defaults with COW bootstrap (FS_METHOD, mods/http flags).
experiments/branchfs/runtime/bootstrap_wp.php Align branchfs bootstrap wp-config defaults with COW bootstrap (FS_METHOD, mods/http flags).
docs/top-plugin-support.md Document top-100 plugin compatibility target + refresh/validate + smoke testing.
docs/stale-audit-workflow.md Update stale-audit workflow doc for expanded after-revalidate support and bulk apply behavior.
docs/remote-sites.md New guide for remote-site cloning, thin/full sync, MySQL import, and plugin installs.
docs/plugin-validator-recipes.md New practical plugin validator recipe guide (graphs, identities, driver rules, tests).
docs/plugin-merge-validators.md Cross-link to recipes/top-plugin support and expand semantic fixture descriptions.
docs/merging.md Add branch history/tree UX docs and update conflict-queue command references.
docs/merge-test-speed.md Document --jobs parallel changed-test-plan and CI/release-matrix rationale.
docs/merge-crash-consistency.md Document scoped crash recovery + expand crash/rollback coverage notes.
docs/documentation-site.md Document Mermaid diagram support and integration ordering requirement.
docs/conflict-review.md New end-to-end conflict review workflow guide (history/tree/queues/revalidate/after-revalidate).
docs/commands.md Add references to conflict-review and remote-sites docs; add history/tree/conflicts commands.
docs/branching.md Add remote-site branching entry point and link to remote-site guide.
crates/forkpress-storage/src/remote.rs Add --force replace-existing branch behavior for remote branching + cleanup flow.
crates/forkpress-storage/src/lib.rs Add external-tree branch creation helper, branch existence check, recreate cleanup, merge --root-host, and test failpoint guard.
crates/forkpress-storage/Cargo.toml Version bump to 0.1.48.
crates/forkpress-server/Cargo.toml Version bump to 0.1.48.
crates/forkpress-runtime/Cargo.toml Version bump to 0.1.48.
crates/forkpress-git/Cargo.toml Version bump to 0.1.48.
crates/forkpress-core/Cargo.toml Version bump to 0.1.48.
crates/forkpress-cli/Cargo.toml Version bump to 0.1.48.
crates/forkpress-cli/build.rs Include MySQL export/import scripts in bundled runtime assets.
Cargo.lock Lockfile updates for crate version bumps.
astro.config.mjs Add astro-mermaid integration and extend docs sidebar navigation.
AGENTS.md Clarify Codex sandbox .git permission failure diagnosis/remediation guidance.
.github/workflows/release-verify.yml Update action versions/caches and switch Windows signing gate to Azure tenant env var.
.github/workflows/release-publish.yml Update action versions/caches and switch Windows signing gate/warnings to Azure tenant env var.
.github/workflows/release-prepare.yml Update checkout action version.
.github/workflows/ci.yml Update checkout/cache action versions across CI jobs.
.buildkite/commands/windows-build.ps1 Build and now sign Windows smoke artifact in BK.
.buildkite/commands/mac-x86_64-build.sh Add sign+notarize step for mac x86_64 BK build.
.buildkite/commands/mac-aarch64-build.sh Codesign before e2e; notarize after e2e for mac aarch64 BK build.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/dev/cow-changed-test-plan.sh Outdated
Comment on lines 259 to 283
wait_one_command() {
local wait_index="${running_indices[0]}"
local pid="${pids[$wait_index]}"
local status=0
if wait "$pid"; then
status=0
else
status=$?
fi
statuses[$wait_index]=$status
if [ "$status" -ne 0 ]; then
failed=1
fi
running_indices=("${running_indices[@]:1}")
}

while [ "$next_command" -lt "${#commands[@]}" ] || [ "${#running_indices[@]}" -gt 0 ]; do
while [ "$next_command" -lt "${#commands[@]}" ] && [ "${#running_indices[@]}" -lt "$JOBS" ]; do
start_command "$next_command"
next_command=$((next_command + 1))
done
if [ "${#running_indices[@]}" -gt 0 ]; then
wait_one_command
fi
done
Comment on lines +142 to +151
function download_zip(array $plugin, string $cache_dir): string {
$slug = (string)$plugin['slug'];
$url = (string)($plugin['download_link'] ?? '');
if ($url === '') {
fail("$slug has no download_link");
}
mkdir_p($cache_dir);
$zip_path = rtrim($cache_dir, '/\\') . '/' . $slug . '.zip';
if (is_file($zip_path) && filesize($zip_path) > 0) {
return $zip_path;
Comment thread scripts/windows/sign.ps1
Comment on lines +55 to +57
$timestampServer = if ($env:AZURE_TIMESTAMP_SERVER) { $env:AZURE_TIMESTAMP_SERVER } else { 'http://timestamp.acs.microsoft.com' }
$fileDigest = if ($env:AZURE_FILE_DIGEST) { $env:AZURE_FILE_DIGEST } else { 'SHA256' }
$timestampDigest = if ($env:AZURE_TIMESTAMP_DIGEST) { $env:AZURE_TIMESTAMP_DIGEST } else { 'SHA256' }
Comment thread scripts/windows/sign.ps1
Comment on lines 1 to +18
<#
.SYNOPSIS
Signs Windows release artifacts when a code-signing certificate is available.
Signs Windows artifacts with Azure Trusted Signing.

.DESCRIPTION
SHA256-only Authenticode signing via `signtool.exe /dlib /dmdf`. No PFX
fallback — forkpress is a new app with a single signing identity, so the
script throws loudly when Azure Trusted Signing is not configured rather
than silently producing unsigned binaries.

The CI Toolkit plugin's `setup_azure_trusted_signing.ps1` materializes
`signtool.exe` + the Azure DLib and exports `SIGNTOOL_PATH`,
`AZURE_CODE_SIGNING_DLIB`, `AZURE_METADATA_JSON`. This script invokes
the setup once (per process) when those vars aren't already set, then
signs each `-Files` entry.

The `/debug` flag is always on: without it, remote auth/quota/network
failures from Azure collapse to a generic `SignTool Error`.
mokagio and others added 2 commits May 19, 2026 20:08
Replaces the previous PFX-based `scripts/windows/sign.ps1` with an
Azure Trusted Signing implementation and wires it into the BK
`windows-build` step so smoke-artifact builds exercise the same
signing path the release-publish workflow will use.

forkpress is a new app with a single Windows signing identity, so
the script intentionally has no PFX fallback: missing Azure env
vars throw with a message naming every absent var. `signtool` is
always invoked with `/debug` so Azure auth/quota/network failures
surface diagnostics instead of collapsing to the generic
`SignTool Error` we have been bitten by on Studio and pcd.

The CI Toolkit plugin's `setup_azure_trusted_signing.ps1` is what
materializes `signtool.exe` + the Azure DLib and exports
`SIGNTOOL_PATH`, `AZURE_CODE_SIGNING_DLIB`, `AZURE_METADATA_JSON`.
`sign.ps1` resolves it via `Get-Command` and runs it once per
process when those vars aren't already set.

GHA `release-publish.yml` and `release-verify.yml` switch their
conditional gates from `WINDOWS_CODESIGN_CERT_BASE64` /
`WINDOWS_CODESIGN_PASSWORD` to `AZURE_TENANT_ID`. The forkpress
GHA environment does not currently expose the Azure secrets, so
those steps remain no-ops there until the secrets are wired —
the warning message is updated accordingly.

Smoke-validated locally on macOS: `pwsh` parse-check passes for
both scripts, the throw fires with every missing var named, and
the `Get-Command setup_azure_trusted_signing.ps1` lookup fails
cleanly when the CI Toolkit plugin isn't on PATH. Actual signtool
round-trip is Tier 3 — proven only on a BK `windows` agent.

---

Generated with the help of Claude Code, https://claude.com/claude-code

Co-Authored-By: Claude Code Opus 4.7 (1M context) <noreply@anthropic.com>
Windows PowerShell 5.1 (BK `windows` queue) reads `.ps1` files as
ANSI/Windows-1252 unless a UTF-8 BOM is present, so the em dashes
in `sign.ps1`'s `throw` message and the comment in
`windows-build.ps1` got decoded as garbage and broke the parser
mid-string with cascading "Unexpected token" / "missing terminator"
errors during the `windows-tests` `[scriptblock]::Create(...)`
syntax check on build #313.

Local `pwsh` on macOS (PowerShell Core 7+, UTF-8 native) parsed
the same file cleanly, which is why the Tier 2 parse-check missed
this. Going forward, scan with
`grep -nP "[^\x00-\x7F]" path/to/script.ps1` before pushing
PowerShell intended for the Windows queue.

---

Generated with the help of Claude Code, https://claude.com/claude-code

Co-Authored-By: Claude Code Opus 4.7 (1M context) <noreply@anthropic.com>
@mokagio mokagio force-pushed the mokagio/buildkite-windows-codesign branch from 7f5534a to e5526d3 Compare May 19, 2026 10:09
@mokagio mokagio changed the base branch from mokagio/buildkite-macos-codesign to mokagio/buildkite-ci-skeleton May 19, 2026 10:09
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