Adopt a8c-secrets in WordPress iOS#25772
Conversation
Wraps `Xcodeproj::Config` with the error handling its raw API lacks: a missing file, a missing key, and a key set to an empty value all raise rather than silently yielding `nil`. Uses `to_hash` rather than `attributes`, since the latter only sees the settings assigned in the file itself, not those it pulls in via `#include`. --- Generated with the help of Claude Code, https://claude.com/claude-code Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`INT_EXPORT_TEAM_ID` duplicated a value the project already declares: enterprise and prototype builds use the `Release-Alpha` configuration, whose `DEVELOPMENT_TEAM` is set in `config/Common.alpha.xcconfig`. Reading it from there removes one secret from the environment the tooling needs to be handed. Note the value also lives in `project.env` in the `mobile-secrets` repository, where it now has no consumer. --- Generated with the help of Claude Code, https://claude.com/claude-code Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Same reasoning as the internal team ID in the previous commit: `EXT_EXPORT_TEAM_ID` duplicated the `DEVELOPMENT_TEAM` that `config/Common.release.xcconfig` already declares for the App Store builds, which use the `Release` configuration. With both gone, `project.env` no longer has to carry either team ID. --- Generated with the help of Claude Code, https://claude.com/claude-code Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Both call sites authenticate with `api_key`, and pilot only ever reads `team_id` on the username/password Spaceship path — see `pilot/lib/pilot/manager.rb:36`, the sole reader of `config[:team_id]` in the whole of `pilot/lib`, which sits in the `else` branch that an API token skips. An App Store Connect API key is issued by a single team, so there is no team left to disambiguate. `woocommerce-ios` has shipped its TestFlight uploads without the parameter for this reason. --- Generated with the help of Claude Code, https://claude.com/claude-code Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Every key it carried is now unused: the two export team IDs come from `xcconfig`, `FASTLANE_ITC_TEAM_ID` was inert alongside an `api_key`, the Sentry slugs are hardcoded constants in `build.rb`, and the two HockeyApp IDs outlived the service. With nothing reading the file, the `before_all` guard demanding it had no purpose either — which is what the three CI scripts were copying the example file to satisfy. `configure_apply` creates its destination directory itself, so nothing else needed that block. The file still exists in `mobile-secrets`, where it can now be deleted. --- Generated with the help of Claude Code, https://claude.com/claude-code Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Centralize the `configure_apply` invocation, duplicated across 12 command scripts and 5 release pipelines, into `install-secrets.sh`. The upcoming move to a8c-secrets then swaps a single call site instead of seventeen. --- Generated with the help of Claude Code, https://claude.com/claude-code Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR deduplicates the Buildkite “install CI secrets” step by extracting the repeated bundle exec fastlane run configure_apply invocation into a shared script, so the upcoming secrets migration can be done by updating a single file.
Changes:
- Introduces
.buildkite/commands/install-secrets.shto centralize secrets installation. - Updates Buildkite command scripts and release pipelines to call the shared script instead of inlining the Fastlane step.
- Unifies pipeline log labeling around “Installing Secrets”.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| .buildkite/release-pipelines/update-app-store-strings.yml | Swaps inline secrets install for shared script call in the pipeline command block. |
| .buildkite/release-pipelines/publish-release.yml | Swaps inline secrets install for shared script call in the pipeline command block. |
| .buildkite/release-pipelines/new-hotfix.yml | Swaps inline secrets install for shared script call in the pipeline command block. |
| .buildkite/release-pipelines/new-beta-release.yml | Swaps inline secrets install for shared script call in the pipeline command block. |
| .buildkite/release-pipelines/code-freeze.yml | Swaps inline secrets install for shared script call in the pipeline command block. |
| .buildkite/commands/release-build-wordpress.sh | Replaces duplicated secrets install lines with shared script invocation. |
| .buildkite/commands/release-build-jetpack.sh | Replaces duplicated secrets install lines with shared script invocation. |
| .buildkite/commands/prototype-build-wordpress.sh | Replaces duplicated secrets install lines with shared script invocation. |
| .buildkite/commands/prototype-build-jetpack.sh | Replaces duplicated secrets install lines with shared script invocation. |
| .buildkite/commands/promote-nightly.sh | Replaces duplicated secrets install lines with shared script invocation. |
| .buildkite/commands/promote-build-to-public.sh | Replaces duplicated secrets install lines with shared script invocation. |
| .buildkite/commands/install-secrets.sh | New shared script that performs the secrets install via Fastlane with a consistent log label. |
| .buildkite/commands/gather-testflight-candidates.sh | Replaces duplicated secrets install lines with shared script invocation. |
| .buildkite/commands/finalize-release.sh | Replaces duplicated secrets install lines with shared script invocation. |
| .buildkite/commands/finalize-hotfix.sh | Replaces duplicated secrets install lines with shared script invocation. |
| .buildkite/commands/complete-code-freeze.sh | Replaces duplicated secrets install lines with shared script invocation. |
| .buildkite/commands/build-for-testing.sh | Replaces duplicated secrets install lines with shared script invocation. |
| .buildkite/commands/build-and-upload-testflight.sh | Replaces duplicated secrets install lines with shared script invocation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
| App Name | Jetpack | |
| Configuration | Release-Alpha | |
| Build Number | 33224 | |
| Version | PR #25772 | |
| Bundle ID | com.jetpack.alpha | |
| Commit | 4346fee | |
| Installation URL | 6ir6hdabtu0mo |
|
| App Name | WordPress | |
| Configuration | Release-Alpha | |
| Build Number | 33224 | |
| Version | PR #25772 | |
| Bundle ID | org.wordpress.alpha | |
| Commit | 4346fee | |
| Installation URL | 22r9n69977s5o |
Swap the secrets store from `.configure`/`.configure-files` to `.a8c-secrets`, tracking the encrypted `*.age` blobs alongside the already-committed repo id and public keys, and updating the `.gitignore` allowlist, `.gitattributes`, and `CODEOWNERS` to match. Part of AINFRA-1538. --- Generated with the help of Claude Code, https://claude.com/claude-code Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Read the three secrets from the a8c-secrets decrypt location (`~/.a8c-secrets/<repo-id>/`) instead of `~/.configure/`, and point the fallback message at the new `configure_secrets` lane. Part of AINFRA-1538. --- Generated with the help of Claude Code, https://claude.com/claude-code Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Decrypt secrets via `a8c-secrets` behind a preflight that points at the installer when the tool is missing, and call it from `before_all` so every lane can rely on the secrets being present. In CI the binary isn't on the lane process's PATH — install-secrets.sh decrypts in its own process — so the preflight detects CI and skips rather than failing the build. Part of AINFRA-1538. --- Generated with the help of Claude Code, https://claude.com/claude-code Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Point the shared `install-secrets.sh` helper and the `credentials:apply` Rake task at `a8c-secrets`: the helper installs the tool and runs `configure_secrets` in one process so the PATH export reaches the decrypt, and the Rake task guards on the tool being installed so open-source builds fall back to templated credentials. The Buildkite command scripts and release pipelines already route through `install-secrets.sh`, so no call sites change here. Part of AINFRA-1538. --- Generated with the help of Claude Code, https://claude.com/claude-code Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
| # dev | ||
| age1srcq3hl92ym9jk3ezj5prwhche3w8szc0cssy8t7afrkjmtkxu2qkjsdfn | ||
| # ci | ||
| age1a7xcr6qzwnzgcxq95sq33p58xdzsmful8w7mp2zktvuy5434yuss9rmv8f |
There was a problem hiding this comment.
CI public key validated by using age-keygen -y on the private key stored in our CI secrets 👍
| curl -fsSL https://raw.githubusercontent.com/Automattic/a8c-secrets/main/install.sh | bash | ||
| # The installer puts the binary in ~/.local/bin, which isn't on the agent's PATH. | ||
| export PATH="$HOME/.local/bin:$PATH" |
There was a problem hiding this comment.
Note that in the future we plan to have a8c-secrets pre-installed and provisionned on all of our CI agents.
We're not there yet so for the iterative migration we might still need this curl and export PATH calls indeed, but that's good to keep in mind and track in some Linear issue to remember to follow-up on this later.
Alternatively, maybe we could start deploying the a8c-secrets (and PATH addition) to our CI agents first, so that PRs that will start to adopt it don't have to do that curl themselves already?
| ${HOME}/.configure/wordpress-ios/secrets/WordPress-Secrets.swift | ||
| ${HOME}/.configure/wordpress-ios/secrets/WordPress-Secrets-Internal.swift | ||
| ${HOME}/.configure/wordpress-ios/secrets/WordPress-Secrets-Alpha.swift | ||
| ${HOME}/.configure/wordpress-ios/secrets/Jetpack-Secrets.swift | ||
| ${HOME}/.configure/wordpress-ios/secrets/Reader-Secrets.swift | ||
| ${HOME}/.a8c-secrets/wordpress-ios@github.com@wordpress-mobile/WordPress-Secrets.swift | ||
| ${HOME}/.a8c-secrets/wordpress-ios@github.com@wordpress-mobile/Jetpack-Secrets.swift | ||
| ${HOME}/.a8c-secrets/wordpress-ios@github.com@wordpress-mobile/Reader-Secrets.swift |
There was a problem hiding this comment.
Is it intentional that the 3 .swift files that were previously split per configuration (Secrets/Secrets-Internal/Secrets-Alpha) for the WordPress target are now unified into a single one, not making the distinction anymore?
I looked at the current 3 files in our ~/.mobile-secrets (the ones used by configure_apply currently) and their content seem to be distinct for all 3:
- Mostly the same between
Secrets.swiftandSecrets-Alpha.swift… except a different SentryDSN - Different SentryDSN but also different ClientID for
Internal
So in practice this migration to have a single WordPress-Secrets.swift file for all 3 Xcode configurations of the WordPress target changes this behavior. Just wanted to check if this was intentional and had been discussed with the team (e.g. we wouldn't want crashes from Internal and Alpha to be reported in the same Sentry project as prod)
There was a problem hiding this comment.
Ok reading the current content of the GenerateCredentials.sh script file I see that maybe the Secrets-Internal and Secrets-Alpha files were in practice never used (never copied by the script in the first place)? Or am I missing something? Or maybe this has been the case for ages and we never cleaned things up?
(I couldn't find a mention of this important gotcha in the PR description, so asking here so we can confirm a common understanding to be sure)
There was a problem hiding this comment.
We no longer need any of the differentiated secrets files – everything can use the same credentials.
Resolve secrets-install conflicts in favor of the `a8c-secrets` migration: `build-for-testing.sh` keeps `install-secrets.sh`, `Fastfile` keeps the `configure_secrets` lane, and `.configure` stays deleted. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>


Description
Migrate the WordPress/Jetpack iOS secrets store off
.configure/mobile-secrets ontoa8c-secrets(AINFRA-1538), part of the fleet-wide rollout. wpios is outside-only, so this is a decrypt-mechanism swap — no app-code changes.The branch opens with a tidy (
Extract secret install into shared script) that centralised the ~17configure_applycall sites into.buildkite/commands/install-secrets.sh, so the mechanism swap here touches that one file instead of every pipeline. The build phase now reads the three Swift secrets from~/.a8c-secrets/<repo-id>/(decrypted from the committed*.ageblobs), and a newconfigure_secretsfastlane lane wrapsa8c-secrets decryptbehind a tool preflight.Follows the woocommerce-ios (AINFRA-1534) and pocket-casts-ios (AINFRA-1541) adoptions, carrying over the pcios refinements:
FastlaneCore::CommandExecutor.which, theis_cigraceful-skip, and abefore_alldecrypt.Validated in CI
Build #33110 is green (26/26). The build-for-testing log confirms the full path on real agents: install
a8c-secrets→a8c-secrets decryptwrites the three secrets to~/.a8c-secrets/wordpress-ios@github.com@wordpress-mobile/→ the build reads them and compiles.A8C_SECRETS_IDENTITYis already provisioned on the agents (the decrypt succeeded), so there is no outstanding provisioning work.Gotchas
ainfra-2643-...— merge that first; this PR targets it, nottrunk.before_alldecrypt must skip in CI:install-secrets.shexportsa8c-secretsonto PATH in its own process, which does not reach the laterfastlane build_*process, so an unguarded decrypt hard-fails every CI build (pcios probe My Profile Network logic #4732). Theis_cibranch handles this — confirmed firing in #33110 with the AINFRA-2681 message, the secrets already on disk frominstall-secrets.sh.How to test
bundle exec fastlane configure_secretslocally (with the dev age identity imported) decrypts the three files into~/.a8c-secrets/wordpress-ios@github.com@wordpress-mobile/. CI exercises the CI path end-to-end (see build #33110).