Skip to content

windows build - #56

Open
guygrigsby wants to merge 5 commits into
mainfrom
windows_build
Open

guygrigsby wants to merge 5 commits into
mainfrom
windows_build

Conversation

@guygrigsby

Copy link
Copy Markdown
Contributor
  • ci: add a Windows build and test gate
  • release: sign Windows binaries with Azure Artifact Signing
  • release: sign Windows with a Cloud HSM key through a store-agnostic Jsign hook

The release now cross-compiles windows/amd64 and windows/arm64 (zip
archives) from the existing macOS GoReleaser run; the signing hook
already passes non-darwin targets through. Windows binaries ship
unsigned: there is no Apple-style notarization gate on Windows, only
SmartScreen reputation, and wiring Authenticode signing (Trusted
Signing or a Key Vault certificate) is a separate decision.

A new Windows CI job runs the same make check gate as Linux and
macOS. GNU make comes from chocolatey; the Makefile's SHELL=/bin/bash
does not resolve on Windows, so the job overrides it with the runner's
Git Bash.

Making the suite green under that gate required real fixes, not just
config: the opencode write-failure test used RLIMIT_FSIZE/SIGXFSZ and
now lives behind the unix build tag, and the test suite isolated state
with HOME/XDG only, which os.UserHomeDir and os.UserConfigDir ignore
on Windows (they read USERPROFILE and APPDATA), so tests would have
leaked into the runner profile and broken each other; every isolation
site now sets both. The binary-discovery tests also assumed
extension-less files are executable; Windows only treats PATHEXT
extensions as executable, so the fakes become .bat and the
common-bin-dirs fallback test skips on Windows because FindBinary
probes those dirs for the bare name, which can never match there.

Verified locally: make check green, GOOS=windows go vet clean for both
arches, and a goreleaser snapshot produces aperture-cli_windows_{amd64,
arm64}.zip containing aperture.exe. The Windows CI job itself can only
be exercised by pushing this branch.
Windows zips shipped unsigned, so SmartScreen warned on every release (the
hash changes each time, resetting reputation) and fleets that block unsigned
executables could not run aperture at all.

A second GoReleaser post-hook signs each aperture.exe with Jsign against
Artifact Signing, before archiving, so zips and checksums describe signed
bytes. Jsign runs on the existing macOS job; signtool would have forced a
second job that re-zips and rewrites checksums after upload. Auth is GitHub
OIDC through azure/login, so no signing secret is stored. Jsign is pinned by
sha256 because it runs with the access token in its environment. A
verify-windows job reads the published zips back on windows-latest and
requires a Valid, timestamped signature from Tailscale Inc.

Not exercised here: a real signature. That needs the Azure account, the Entra
federated credential for the release environment and the repo vars/secrets
listed in the README. See ADR 0009.
…sign hook

The Windows client team does not want signing key material in Actions, and
the HSM route Nick pointed at keeps the key in Google Cloud. The previous
commit hard-wired Azure Artifact Signing into the hook, so moving to the HSM
would have meant rewriting the script, not changing a setting.

sign-windows.sh now reads its key store from WINDOWS_SIGN_* variables and
knows nothing about any provider. The release sets GOOGLECLOUD with a
workload-identity access token; a new ci-windows-signing workflow runs the
same hook with PKCS12 and a throwaway self-signed EC P-256 key, builds both
architectures, trusts the certificate on a windows-latest runner and has
Windows verify the result. That proves the Jsign, timestamp and PE paths,
including ECDSA and arm64, before the HSM key or its CA certificate exist.
verify-windows now shares verify-windows-signature.ps1 with it.

Not exercised: a real HSM signature, workload identity federation, Windows'
verdict on the self-signed build (no runner here), or trust in the CA chain.
The release fails closed until GCP_* variables and
scripts/windows-codesign-chain.pem exist, so do not merge before the key does.
See ADR 0009, rewritten to this decision.
Windows CI failed its first run at make check with exit code 2. The runner
checks out with core.autocrlf=true, so every file lands with CRLF and the
lint step flags all 126 .go files at gofmt -l. Reproduced in a local clone
with core.autocrlf=true, fixed there with this file, and rechecked clean.
The Windows team wants NSIS (Nullsoft) when aperture grows an installer,
which produces an .exe, so the ADR revisit condition should say so instead
of naming an MSI.
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.

1 participant