Make the Buildkite signing scripts runnable - #3019
Draft
mokagio wants to merge 24 commits into
Draft
Conversation
5.3.1 was a placeholder carried over from the reference pipeline, marked `← infra: confirm current version` because nobody had checked. 6.3.0 is the current release; `buildkite-ci`'s own pipeline upload template is already on 5.6.0, so 5.3.1 was behind even the shared default. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
No agent image provisions a Go toolchain — nothing under `src/agents/` in `Automattic/buildkite-ci` installs one, and there is no `mise` or `asdf` either — so `command -v go || exit 1` failed every build before it started. Each platform installs it the way that platform already does: the `mac` queue has Homebrew provisioned, the `windows` queue has Chocolatey, and the `default` queue runs Amazon Linux 2023, whose `golang` package is 1.25.12. None of those give us 1.27, and they do not have to. `GOTOOLCHAIN` defaults to `auto`, so any Go >= 1.21 downloads and uses the version the module asks for. The new `toolchain go1.27.0` directive is what pins it: the compiler is then identical on all three platforms no matter what brew, choco or dnf shipped, and the version lives in `go.mod` alone rather than being restated in `GO_VERSION`. `beeper/bridge-manager` reaches the same conclusion for the same reason — see `.buildkite/commands/sign-macos-binaries.sh` there. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`local goarch="$1" out="…-${goarch}"` expands `$goarch` before the same
`local` has assigned it, so every artifact was written to `…-linux-` and
`…-darwin-` with no arch (verified under both bash and dash).
Both arches therefore wrote to one path, the second clobbering the first,
and the smoke test then looked for a `-amd64`/`-arm64` file that had never
existed — so both scripts died on their first run regardless of signing.
Nothing had caught it because these scripts have never executed: no pipeline
was registered, and no workflow lints `.buildkite/`.
---
Generated with the help of Claude Code, https://claude.ai/code
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The arch-suffix bug fixed in the previous commit was a plain ShellCheck warning that sat in trunk because nothing reads these files: no Buildkite pipeline is registered, and `ci-go.yml`'s `paths:` filter excludes `.buildkite/`. Deliberately no `paths:` filter here — a paths filter is what let the directory go unlinted in the first place, and the repo's other small workflows run on every PR anyway. `-S warning` suppresses the `info` level, which is otherwise all SC1091 for the runtime-sourced `shared-pipeline-vars`. Every tracked script passes at that level today, so this starts green with nothing grandfathered. `build-windows.ps1` stays uncovered; PSScriptAnalyzer is a separate job. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
15.0.0 is the current release, and its `EnvManager` is what replaces the vendored copy in the next commit. Neither of its breaking changes affects us: `ios_build_preflight` and `android_build_preflight` are not used here, and `EnvManager` now layering the `.env` into the process `ENV` is what our vendored copy already did via `Dotenv.load`. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`fastlane/lib/env_manager.rb` was a copy of the one in `Automattic/download`, carrying a note to replace it with the canonical version if one existed. It does — and the plugin providing it was already a dependency, so the copy sat unused next to the real thing. The class-level API (`set_up`, `require_env_vars!`) is unchanged in 15.0.0, so this is a drop-in: `configure_code_signing` still stops at the same guard with the same message. `beeper/bridge-manager` resolves it the same way. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`configure_code_signing` demanded the App Store Connect key on every run and never checked the `match` credentials at all — exactly backwards for its default path. A readonly fetch only reads and decrypts the S3 bucket, so it needs `MATCH_S3_*` and `MATCH_PASSWORD` and nothing from App Store Connect. The ASC key is only needed to create or renew a certificate, which is what `readonly: false` means. Missing match credentials used to surface as a failure from inside `match`; they now fail at the guard, naming the variable. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Passing an app identifier made `match` look for a provisioning profile for `com.automattic.vip-cli`, and fail with "No matching provisioning profiles found and cannot create a new one because you enabled `readonly`". Nothing here needs a profile. `codesign` needs the Developer ID Application certificate, and Developer ID certs are not app-scoped — which also settles the open question of whether to reuse the team cert or make a new match entry for this app: there is no per-app entry to make. With this, `configure_code_signing` completes: it decrypts the bucket and installs the certificate. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Running any lane writes `fastlane/README.md` and `fastlane/report.xml` into the working tree, so both were one `git add .` away from being committed and then churning on every subsequent run. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
It is a convention carried over from the mobile Fastfiles, which use it to build paths. Nothing here does: no reference in this repo, the release toolkit, or any installed gem. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Without it every agent resolved fastlane, the release toolkit and their transitive dependencies afresh, so the gems that signed a release were neither pinned nor reviewable — and a bad upstream release would have landed straight in a signing run. Checked against the macOS agents before committing, since `install_gems` derives the Bundler version from this file: it will install Bundler 4.0.19, which needs Ruby >= 3.2.0, and the agents' rbenv default is 3.2.2. No gem in the lock requires a newer Ruby. That is no headroom, though — the release toolkit's floor is exactly 3.2.2, so a future bump to it needs the agent image moved first. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The macOS step could never have started: the `mac` queue's command hook exits with "You must specify an IMAGE_ID to use" when the variable is unset, and it was unset on the assumption that a Go build needs no Xcode image. It does — `codesign`, `pkgbuild`, `productsign` and `xcrun notarytool` all come from Xcode, whatever compiled the binary. `.xcode-version` rather than a literal, matching wpios, wcios, pcios and `beeper/bridge-manager`, so the pin is visible where people look for it. 26.6 is the newest image. `bridge-manager` pins 26.3 instead because it forces the Ruby platform and nokogiri will not build from source on 26.5's clang; that does not apply here — `Gemfile.lock` resolves the precompiled `nokogiri-1.19.4-arm64-darwin` and there is no `.bundle/config` overriding it. This also corrects 1165b41, which said the agents default to Ruby 3.2.2 with no headroom. That was read off the 26.5 manifest. 26.6 defaults to 3.4.9 and also carries 3.3.11 and 4.0.5, so the locked gems have room above the release toolkit's 3.2.2 floor. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Contributor
Dependency ReviewThe following issues were found:
|
The CI toolkit's `install_gems` ends with `save_cache vendor/bundle`, so without `BUNDLE_PATH` that directory never existed: gems went to the system gem dir and every build silently cached nothing, then reinstalled 127 gems from scratch. Ported from Simperium/simperium-ios@3452bee3, minus its `BUNDLE_FORCE_RUBY_PLATFORM`. That setting makes nokogiri build from source, which fails on current clang — `gumbo.c: fatal error: 'nokogiri_gumbo.h' file not found`, reproduced locally. It is why `beeper/bridge-manager` is pinned back to the Xcode 26.3 image; adopting it here would mean giving up 26.6 and its Ruby 3.4.9 default for 26.3's 3.2.2. Nothing needs it: `Gemfile.lock` resolves `nokogiri-1.19.4-arm64-darwin` precompiled, so there is no build to force a platform for. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`Automattic/studio` is the closest precedent — an a8c app with the same fastlane setup that also builds on Linux — and it sets these alongside `BUNDLE_PATH`. Retries matter more on CI than locally, where a single flaky gem fetch fails the whole build. It notably does not set `BUNDLE_FORCE_RUBY_PLATFORM`, which is the other half of the simperium-ios config and the reason that repo cannot use a current Xcode image. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
AINFRA-2927 made ~> 2.238 the floor after `bundle_id` was removed from `notarize`. The lock already resolved 2.238.0; this only raises the constraint. --- Generated with the help of Grok, https://grok.x.ai Co-Authored-By: Grok 4.6 <grok@x.ai>
Matches the Xcode 26.6 image default and the wpios/pcios/Day One CLI pin, so `install_gems` cache keys off an explicit version rather than whichever rbenv default the agent happens to have. --- Generated with the help of Grok, https://grok.x.ai Co-Authored-By: Grok 4.6 <grok@x.ai>
Day One CLI signs without the toolkit: a 10-line helper, not a gem whose nokogiri forces the Ruby-platform / Xcode-image dance. The plugin was only here for `EnvManager`. --- Generated with the help of Grok, https://grok.x.ai Co-Authored-By: Grok 4.6 <grok@x.ai>
Day One CLI is the reference: certs, codesign with `--identifier`, verify, and notarize live in lanes, not Bash. The `.pkg` path needed an Installer cert `match` never fetched, so it is gone. `GOFLAGS=-mod=mod` keeps Go from treating Bundler's `vendor/bundle` as a Go vendor tree. --- Generated with the help of Grok, https://grok.x.ai Co-Authored-By: Grok 4.6 <grok@x.ai>
Tag-gating is what left the 3013 path untested. Day One CLI signs every build and only gates GitHub upload; this matches that. --- Generated with the help of Grok, https://grok.x.ai Co-Authored-By: Grok 4.6 <grok@x.ai>
PFX is dead for EV certs since 2023. Studio and Simplenote Electron call `setup_azure_trusted_signing.ps1` from the CI toolkit on `queue: windows`; the six Azure vars are already on that queue. The plugin was missing from this step, so even the old PFX secrets would not have injected. --- Generated with the help of Grok, https://grok.x.ai Co-Authored-By: Grok 4.6 <grok@x.ai>
AINFRA-3030 is done when none remain in shipped files. The queue names were already correct; the rest were unfinished decisions that this branch has now made. Docs catch up so they no longer describe the tag-gated `.pkg`/PFX path. --- Generated with the help of Grok, https://grok.x.ai Co-Authored-By: Grok 4.6 <grok@x.ai>
The `default` queue has no passwordless sudo, so `dnf` cannot work. Unpack under `$HOME/.local` (not `$HOME/go`, which is GOPATH) using the `toolchain` version from `go.mod`. --- Generated with the help of Grok, https://grok.x.ai Co-Authored-By: Grok 4.6 <grok@x.ai>
--- Generated with the help of Grok, https://grok.x.ai Co-Authored-By: Grok 4.6 <grok@x.ai>
A 5.* tag is a Go release and is used verbatim. PRs and 4.x npm tags must not advertise a Node version, so they get 5.0.0-dev.<shortsha>. --- Generated with the help of Grok, https://grok.x.ai Co-Authored-By: Grok 4.6 <grok@x.ai>
|
3 tasks
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.



Opus blabber. It's been aweful in this PR...
Description
The Buildkite signing setup added alongside the Go CLI had never run — no pipeline was registered, and
ci-go.yml'spaths:filter excludes.buildkite/, so nothing read those files. The pipeline now exists, and this makes the scripts it runs capable of actually starting.Four things would each have failed the macOS step before it reached signing:
IMAGE_ID. Themacqueue's command hook aborts when it is unset. It was omitted on the assumption that a Go build needs no Xcode image — butcodesign,pkgbuild,productsignandxcrun notarytoolall come from Xcode regardless of what compiled the binary. Now pinned via.xcode-version, as in the iOS repos.GOTOOLCHAINdefaults toauto, so the newtoolchain go1.27.0directive ingo.modis what fixes the compiler, and it is now stated in one place instead of two.local goarch="$1" out="…-${goarch}"expands$goarchbefore the samelocalassigns it, so both arches wrote to one path and the smoke test then looked for a file that never existed. Also adds a ShellCheck workflow, since a plain warning sitting in trunk is the actual failure here.matchasked for a provisioning profile. Passing an app identifier made it hunt a profile forcom.automattic.vip-clithat has never existed, instead of the Developer ID certificatecodesignneeds. Developer ID certs are not app-scoped.Also: the credential guards were backwards (the App Store Connect key was demanded on every run while the
matchcredentials went unchecked), the vendoredEnvManagercopy is replaced by the release toolkit's, andGemfile.lockis now tracked.Intentional tradeoffs
Pinning Xcode 26.6, not 26.3. A sibling repo pins back because it forces the Ruby platform and nokogiri will not build from source on 26.5's clang. That does not apply here:
Gemfile.lockresolves the precompilednokogiri-1.19.4-arm64-darwinand there is no.bundle/configoverriding it.No
paths:filter on the ShellCheck workflow. A paths filter is what let.buildkite/go unlinted in the first place.Gotchas
Signing still cannot succeed on a tag build.
build-macos.shrunsproductsignwith a Developer ID Installer certificate that the fastlane lane never fetches — the provisioning for it is commented out. Whether to fix that or drop the.pkgand ship signed, notarized bare binaries is an open decision, tracked separately along with thego-search-replacebundling gap and Windows secret injection.docs/BUILD-SIGNING.mdstill describes the previous arrangement and needs a follow-up pass; left out here to keep this reviewable.No customer-facing change, so no changelog entry — nothing here ships in the published CLI.
Pull request checklist
Steps to Test
Everything below was run locally on macOS before opening this.
bundle install && bundle exec fastlane configure_code_signing— decrypts thematchbucket and installs the Developer ID Application certificate. Ontrunkthis fails with "No matching provisioning profiles found".env -u MATCH_PASSWORD bundle exec fastlane configure_code_signing— fails at the guard namingMATCH_PASSWORD, rather than deep insidematch.git ls-files '*.sh' | xargs shellcheck -S warning— clean; run it againsttrunk's.buildkite/build-linux.shand it fails../.buildkite/build-linux.sh— producesvip-next-linux-amd64andvip-next-linux-arm64with matching.sha256files. Ontrunkthis yields a singlevip-next-linux-and then dies. It exits non-zero at the smoke step on a non-Linux host, which is expected.. .buildkite/shared-pipeline-vars && echo "$IMAGE_ID"— printsxcode-26.6.go build ./cmd/vip-next— confirms thetoolchaindirective resolves.The macOS and Windows steps cannot be exercised locally; the Buildkite build on this PR is the first real run.