From a01b057349b812a2ede09a2203206f71fa770aaf Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Sun, 12 Jul 2026 15:47:40 +1000 Subject: [PATCH 01/18] Extract secret install into shared script 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) --- .buildkite/commands/build-and-upload-testflight.sh | 3 +-- .buildkite/commands/build-for-testing.sh | 3 +-- .buildkite/commands/complete-code-freeze.sh | 3 +-- .buildkite/commands/finalize-hotfix.sh | 3 +-- .buildkite/commands/finalize-release.sh | 3 +-- .buildkite/commands/gather-testflight-candidates.sh | 3 +-- .buildkite/commands/install-secrets.sh | 6 ++++++ .buildkite/commands/promote-build-to-public.sh | 3 +-- .buildkite/commands/promote-nightly.sh | 3 +-- .buildkite/commands/prototype-build-jetpack.sh | 3 +-- .buildkite/commands/prototype-build-wordpress.sh | 3 +-- .buildkite/commands/release-build-jetpack.sh | 3 +-- .buildkite/commands/release-build-wordpress.sh | 3 +-- .buildkite/release-pipelines/code-freeze.yml | 3 +-- .buildkite/release-pipelines/new-beta-release.yml | 3 +-- .buildkite/release-pipelines/new-hotfix.yml | 3 +-- .buildkite/release-pipelines/publish-release.yml | 3 +-- .buildkite/release-pipelines/update-app-store-strings.yml | 3 +-- 18 files changed, 23 insertions(+), 34 deletions(-) create mode 100755 .buildkite/commands/install-secrets.sh diff --git a/.buildkite/commands/build-and-upload-testflight.sh b/.buildkite/commands/build-and-upload-testflight.sh index d8d6ee04a81b..7a65810c4917 100755 --- a/.buildkite/commands/build-and-upload-testflight.sh +++ b/.buildkite/commands/build-and-upload-testflight.sh @@ -7,8 +7,7 @@ APP="${1:?Usage: build-and-upload-testflight.sh }" "$(dirname "${BASH_SOURCE[0]}")/shared-set-up.sh" "$(dirname "${BASH_SOURCE[0]}")/shared-set-up-distribution.sh" -echo "--- :closed_lock_with_key: Installing Secrets" -bundle exec fastlane run configure_apply +"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" echo "--- :testflight: Building and uploading ${APP} to TestFlight" bundle exec fastlane build_and_upload_app_for_testflight app:"${APP}" diff --git a/.buildkite/commands/build-for-testing.sh b/.buildkite/commands/build-for-testing.sh index 80fd7fae1e68..4350e855fed2 100755 --- a/.buildkite/commands/build-for-testing.sh +++ b/.buildkite/commands/build-for-testing.sh @@ -16,8 +16,7 @@ fi "$(dirname "${BASH_SOURCE[0]}")/shared-set-up.sh" -echo "--- :closed_lock_with_key: Installing Secrets" -bundle exec fastlane run configure_apply +"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" echo "--- :hammer_and_wrench: Building" bundle exec fastlane "build_${APP}_for_testing" diff --git a/.buildkite/commands/complete-code-freeze.sh b/.buildkite/commands/complete-code-freeze.sh index 9297d9e4d298..bde99028ed0c 100755 --- a/.buildkite/commands/complete-code-freeze.sh +++ b/.buildkite/commands/complete-code-freeze.sh @@ -14,8 +14,7 @@ source use-bot-for-git "$(dirname "${BASH_SOURCE[0]}")/shared-set-up.sh" -echo '--- :closed_lock_with_key: Access secrets' -bundle exec fastlane run configure_apply +"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" echo '--- :shipit: Complete code freeze' bundle exec fastlane complete_code_freeze skip_confirm:true diff --git a/.buildkite/commands/finalize-hotfix.sh b/.buildkite/commands/finalize-hotfix.sh index cb3be53d1d66..d42699302d2d 100755 --- a/.buildkite/commands/finalize-hotfix.sh +++ b/.buildkite/commands/finalize-hotfix.sh @@ -15,8 +15,7 @@ source use-bot-for-git echo '--- :ruby: Setup Ruby tools' install_gems -echo '--- :closed_lock_with_key: Access secrets' -bundle exec fastlane run configure_apply +"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" echo '--- :shipit: Finalize hotfix' bundle exec fastlane finalize_hotfix_release skip_confirm:true diff --git a/.buildkite/commands/finalize-release.sh b/.buildkite/commands/finalize-release.sh index bbba37e01b8d..e553e49b3e53 100755 --- a/.buildkite/commands/finalize-release.sh +++ b/.buildkite/commands/finalize-release.sh @@ -15,8 +15,7 @@ source use-bot-for-git echo '--- :ruby: Setup Ruby tools' install_gems -echo '--- :closed_lock_with_key: Access secrets' -bundle exec fastlane run configure_apply +"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" echo '--- :shipit: Finalize release' bundle exec fastlane finalize_release skip_confirm:true diff --git a/.buildkite/commands/gather-testflight-candidates.sh b/.buildkite/commands/gather-testflight-candidates.sh index c7c2052b62c6..9100c091e958 100755 --- a/.buildkite/commands/gather-testflight-candidates.sh +++ b/.buildkite/commands/gather-testflight-candidates.sh @@ -6,8 +6,7 @@ echo "--- :rubygems: Setting up Gems" install_gems -echo "--- :closed_lock_with_key: Installing Secrets" -bundle exec fastlane run configure_apply +"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" echo "--- :testflight: Gathering candidates and opening the block step" bundle exec fastlane gather_testflight_candidates diff --git a/.buildkite/commands/install-secrets.sh b/.buildkite/commands/install-secrets.sh new file mode 100755 index 000000000000..181f3e3267da --- /dev/null +++ b/.buildkite/commands/install-secrets.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -euo pipefail + +echo "--- :closed_lock_with_key: Installing Secrets" +bundle exec fastlane run configure_apply diff --git a/.buildkite/commands/promote-build-to-public.sh b/.buildkite/commands/promote-build-to-public.sh index d7d510d10196..935e316a2df8 100755 --- a/.buildkite/commands/promote-build-to-public.sh +++ b/.buildkite/commands/promote-build-to-public.sh @@ -14,8 +14,7 @@ fi echo "--- :rubygems: Setting up Gems" install_gems -echo "--- :closed_lock_with_key: Installing Secrets" -bundle exec fastlane run configure_apply +"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" echo "--- :rocket: Promoting ${BUILD_CODE} to public beta" bundle exec fastlane promote_build build_code:"${BUILD_CODE}" diff --git a/.buildkite/commands/promote-nightly.sh b/.buildkite/commands/promote-nightly.sh index 76e15e7aa168..e313e561f2e1 100755 --- a/.buildkite/commands/promote-nightly.sh +++ b/.buildkite/commands/promote-nightly.sh @@ -5,8 +5,7 @@ echo "--- :rubygems: Setting up Gems" install_gems -echo "--- :closed_lock_with_key: Installing Secrets" -bundle exec fastlane run configure_apply +"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" echo "--- :new_moon: Promoting last build of the day to nightly beta" # The lane refuses to run anywhere but trunk. diff --git a/.buildkite/commands/prototype-build-jetpack.sh b/.buildkite/commands/prototype-build-jetpack.sh index 8e91a0bdbfe8..621edef8bd75 100644 --- a/.buildkite/commands/prototype-build-jetpack.sh +++ b/.buildkite/commands/prototype-build-jetpack.sh @@ -7,8 +7,7 @@ fi "$(dirname "${BASH_SOURCE[0]}")/shared-set-up.sh" "$(dirname "${BASH_SOURCE[0]}")/shared-set-up-distribution.sh" -echo "--- :closed_lock_with_key: Installing Secrets" -bundle exec fastlane run configure_apply +"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" echo "--- :hammer_and_wrench: Building" bundle exec fastlane build_and_upload_jetpack_prototype_build diff --git a/.buildkite/commands/prototype-build-wordpress.sh b/.buildkite/commands/prototype-build-wordpress.sh index 1798ddb780b8..9b649f5b636a 100644 --- a/.buildkite/commands/prototype-build-wordpress.sh +++ b/.buildkite/commands/prototype-build-wordpress.sh @@ -7,8 +7,7 @@ fi "$(dirname "${BASH_SOURCE[0]}")/shared-set-up.sh" "$(dirname "${BASH_SOURCE[0]}")/shared-set-up-distribution.sh" -echo "--- :closed_lock_with_key: Installing Secrets" -bundle exec fastlane run configure_apply +"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" echo "--- :hammer_and_wrench: Building" bundle exec fastlane build_and_upload_wordpress_prototype_build diff --git a/.buildkite/commands/release-build-jetpack.sh b/.buildkite/commands/release-build-jetpack.sh index 0c8b3ad9f3e0..7de02454d910 100755 --- a/.buildkite/commands/release-build-jetpack.sh +++ b/.buildkite/commands/release-build-jetpack.sh @@ -3,8 +3,7 @@ "$(dirname "${BASH_SOURCE[0]}")/shared-set-up.sh" "$(dirname "${BASH_SOURCE[0]}")/shared-set-up-distribution.sh" -echo "--- :closed_lock_with_key: Installing Secrets" -bundle exec fastlane run configure_apply +"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" echo "--- :hammer_and_wrench: Building" bundle exec fastlane build_and_upload_jetpack_for_app_store diff --git a/.buildkite/commands/release-build-wordpress.sh b/.buildkite/commands/release-build-wordpress.sh index 86326de30ba7..d8e92522c4d9 100755 --- a/.buildkite/commands/release-build-wordpress.sh +++ b/.buildkite/commands/release-build-wordpress.sh @@ -3,8 +3,7 @@ "$(dirname "${BASH_SOURCE[0]}")/shared-set-up.sh" "$(dirname "${BASH_SOURCE[0]}")/shared-set-up-distribution.sh" -echo "--- :closed_lock_with_key: Installing Secrets" -bundle exec fastlane run configure_apply +"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" echo "--- :hammer_and_wrench: Building" bundle exec fastlane build_and_upload_app_store_connect \ diff --git a/.buildkite/release-pipelines/code-freeze.yml b/.buildkite/release-pipelines/code-freeze.yml index e03a83cfbe41..aebbd91bf1f5 100644 --- a/.buildkite/release-pipelines/code-freeze.yml +++ b/.buildkite/release-pipelines/code-freeze.yml @@ -18,8 +18,7 @@ steps: echo '--- :ruby: Setup Ruby tools' install_gems - echo '--- :closed_lock_with_key: Access secrets' - bundle exec fastlane run configure_apply + .buildkite/commands/install-secrets.sh echo '--- :shipit: Run code freeze' bundle exec fastlane code_freeze version:"${RELEASE_VERSION}" skip_confirm:true diff --git a/.buildkite/release-pipelines/new-beta-release.yml b/.buildkite/release-pipelines/new-beta-release.yml index 4835caaf293e..e0040a418816 100644 --- a/.buildkite/release-pipelines/new-beta-release.yml +++ b/.buildkite/release-pipelines/new-beta-release.yml @@ -19,8 +19,7 @@ steps: echo '--- :ruby: Setup Ruby tools' install_gems - echo '--- :closed_lock_with_key: Access secrets' - bundle exec fastlane run configure_apply + .buildkite/commands/install-secrets.sh echo '--- :shipit: Deploy new beta' bundle exec fastlane new_beta_release skip_confirm:true diff --git a/.buildkite/release-pipelines/new-hotfix.yml b/.buildkite/release-pipelines/new-hotfix.yml index ec8deef72852..b9b499a5fed0 100644 --- a/.buildkite/release-pipelines/new-hotfix.yml +++ b/.buildkite/release-pipelines/new-hotfix.yml @@ -19,8 +19,7 @@ steps: echo '--- :ruby: Setup Ruby tools' install_gems - echo '--- :closed_lock_with_key: Access secrets' - bundle exec fastlane run configure_apply + .buildkite/commands/install-secrets.sh echo '--- :shipit: Start new hotfix' bundle exec fastlane new_hotfix_release skip_confirm:true version:"$VERSION" diff --git a/.buildkite/release-pipelines/publish-release.yml b/.buildkite/release-pipelines/publish-release.yml index 024c3f616f90..abb9518ce335 100644 --- a/.buildkite/release-pipelines/publish-release.yml +++ b/.buildkite/release-pipelines/publish-release.yml @@ -19,8 +19,7 @@ steps: echo '--- :ruby: Setup Ruby tools' install_gems - echo '--- :closed_lock_with_key: Access secrets' - bundle exec fastlane run configure_apply + .buildkite/commands/install-secrets.sh echo '--- :package: Publish Release' bundle exec fastlane publish_release skip_confirm:true diff --git a/.buildkite/release-pipelines/update-app-store-strings.yml b/.buildkite/release-pipelines/update-app-store-strings.yml index 83dc1a1bd6b5..7fc327ed43ba 100644 --- a/.buildkite/release-pipelines/update-app-store-strings.yml +++ b/.buildkite/release-pipelines/update-app-store-strings.yml @@ -18,8 +18,7 @@ steps: echo '--- :ruby: Setup Ruby tools' install_gems - echo '--- :closed_lock_with_key: Access secrets' - bundle exec fastlane run configure_apply + .buildkite/commands/install-secrets.sh echo '--- :shipit: Update relaese notes and other App Store metadata' bundle exec fastlane update_appstore_strings skip_confirm:true From 13d16f9aecd88855e3af91fe389e73b27c91c0aa Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Sun, 12 Jul 2026 15:51:12 +1000 Subject: [PATCH 02/18] Set up `a8c-secrets` (identities only) --- .a8c-secrets/keys.pub | 4 ++++ .a8c-secrets/repo-id | 1 + 2 files changed, 5 insertions(+) create mode 100644 .a8c-secrets/keys.pub create mode 100644 .a8c-secrets/repo-id diff --git a/.a8c-secrets/keys.pub b/.a8c-secrets/keys.pub new file mode 100644 index 000000000000..af1dfa3e9cfc --- /dev/null +++ b/.a8c-secrets/keys.pub @@ -0,0 +1,4 @@ +# dev +age1srcq3hl92ym9jk3ezj5prwhche3w8szc0cssy8t7afrkjmtkxu2qkjsdfn +# ci +age1a7xcr6qzwnzgcxq95sq33p58xdzsmful8w7mp2zktvuy5434yuss9rmv8f diff --git a/.a8c-secrets/repo-id b/.a8c-secrets/repo-id new file mode 100644 index 000000000000..b60ad318d574 --- /dev/null +++ b/.a8c-secrets/repo-id @@ -0,0 +1 @@ +wordpress-ios@github.com@wordpress-mobile From 5811889174a2811f10b139ddc344878a1a8411a4 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 22 Jul 2026 15:24:45 +1000 Subject: [PATCH 03/18] Replace .configure secrets store with a8c-secrets 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) --- .a8c-secrets/Secrets.swift.age | Bin 0 -> 1038 bytes .configure | 13 ------------- .configure-files/Secrets.swift.enc | Bin 1152 -> 0 bytes .gitattributes | 2 +- .gitignore | 10 ++++++---- CODEOWNERS | 2 +- Scripts/BuildPhases/GenerateCredentials.sh | 4 ++-- .../BuildPhases/GenerateCredentials.xcfilelist | 2 +- 8 files changed, 11 insertions(+), 22 deletions(-) create mode 100644 .a8c-secrets/Secrets.swift.age delete mode 100644 .configure delete mode 100644 .configure-files/Secrets.swift.enc diff --git a/.a8c-secrets/Secrets.swift.age b/.a8c-secrets/Secrets.swift.age new file mode 100644 index 0000000000000000000000000000000000000000..fe8fcccc268640095cd9229eaceb0047ae1ab9f4 GIT binary patch literal 1038 zcmV+p1o8V}XJsvAZewzJaCB*JZZ2F-I$5Y*7kkNKkf0PDMv6a#3SSXKY$YY&bD$ zHez*HQ$s>aI8SpgRX9XUMru|_WHbsbJ|I{!H8n9gAW2JcFGgriL{4orcx^dWYf4XP zQ8PkHZ**!_H+e&IS1U1ZGh$IfK|xnV3NTVsP;pvKdTc90VsltTFjp{EaWrOgQetjM zD?w^zVPsiHPB3aVdRAF53N1b$QZ;Q^C@p7lWnpt=3OQO?OmcEXLqSMFPcv6JS2ay) zM@D9La%xLKG*@~uMKNMwOJy%GMoDrtbW$rwWp*}IMnP0bQ*2soGgW3)QwmW?N_J*# zQBitlO$se7Eg*MjG(&S|Ra8?mQ#WH#Nls>TWMOzOZ$fHjW;SSQN^&wdRct{pd1-7+ zMGDeXqhx`8Ybe^>RM!a$>lh}Kl2CX@;k#Q6;|L0jb4T|Hy!rvFvx7ElmYohA4DjYLR^XRL zUYjjrai_QOX=UvUwiTWdP8-(Sq(4Y8T1~CvbNgyz-bMnd((5du!zb z;N*Z(&&6nJvs=R>g z+~&MC7X@g5UAazYQ^L1KZBZ7AF3F>6Xu()2sR1*&6( zq7+JIisMa(x5c2o{(hy`QzimO8iEQE4CdF-?!!%cfaPL4&2 zw-n6h|D$Q&DbNnmao<&dB+&MWSjB{FK4T^%IoMbyiQnC+z|2)pXJLikyK@8YHlfn^ IG6hsr6$}5uTmS$7 literal 0 HcmV?d00001 diff --git a/.configure b/.configure deleted file mode 100644 index b7892ab8149c..000000000000 --- a/.configure +++ /dev/null @@ -1,13 +0,0 @@ -{ - "project_name": "WordPress-iOS", - "branch": "trunk", - "pinned_hash": "6baf4e086398ddf8141d7132e557703a715fafd2", - "files_to_copy": [ - { - "file": "iOS/WPiOS/Secrets.swift", - "destination": "~/.configure/wordpress-ios/secrets/Secrets.swift", - "encrypt": true - } - ], - "file_dependencies": [] -} diff --git a/.configure-files/Secrets.swift.enc b/.configure-files/Secrets.swift.enc deleted file mode 100644 index 500132fd96da05c30bd388e46a952e78597fd96d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1152 zcmV-`1b_SQ#81BYE8wZir~1r;eZ9xI!DK;Y=}%{P&2fa|1j~$?<89t;V~^{tm=Byy zU)jvpe3*JI(*uZlh!$=|@Suhs@LH^zBq*&U21muS6EW|=P@c9j;g-YPr_3bjSpEvo ziz=W}u65u?k~go*-Z-Bk^qyIxl7}q>XjNdS1T;Ey?Fv{}*@;-#i0qMzy{HF*VlFB} zmdutX^#Qv#AJV}=LV@8teJkcSu&zMqtn6zN>nJCT+0|bko(Vn05>Sk|C%;mydBa?l zF`Tvm*lF?WmJ90pnN=PqP3}CsJR_h6-nlL36M(dHLo5bKaQ}w;gBJb5h_s!j!8bQ4 ziD1PDy-W<7w>S;adY+vujhGX)`nmiVE-P5151>CJ+#Rzat6p%O)lgyXe4z z7avFtOIg&{GL36D>SRP?@#H@pfB*PUCbt!7_WRe?c-dwcx@f9X+P4&<)}+(=I9PVq z=sz3loB|o&E)7!{@%!|+?qL%;w`D&f_rbp&q*r9c5$PHh_g*Xu4@}a%D!bTo^SJ72 z4G0qlgpNDRl6WiU*%YwZTLBiy)mtX{5W=(DTXOvpgBa!tUp@yIw;BH$X|$EH9kE%%PrCaT zylD(+{145%jXrw5Pe0nilodLe743)8=U8 z1X-;sER?{RWuyS|vr!iVzTtzWG^U?yARz=r3BE3$OF@eN!joy2ZuOQfoX|}MJpxInI+Co+ z3gkS*;;-x-?>mBRS5|$OsQV!KFaZ&4U$68!aXA+O{~=x< zby*T#kN$`R_5v$-mbe+5X1qynYZRnVlKN1v@)(JZddq9eVPvXI4hN^BPxW$JRa5#> zf9@5)$J3@J*DWJc`o=6zT#<+$kugGpj*L6OI7e5O7b%p|4u>jjlEj+|Tc)#aJ^x;) zx6b3t?2!*Sh=qx2`p2IG1jRr;lB@ceP6CJ{g^E5}y1wlcb-Om$+mHZ~KQV)whJ{6z zgs$BjycJ8Hq(i4$Ml&huv)7ev( zCY3zBmy{6^N}6Htm6ODTUE*M<4C(aihpxm diff --git a/.gitattributes b/.gitattributes index 648ab329c02f..3b002f08fa65 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,4 @@ RELEASE-NOTES.txt merge=union *.strings diff=localizablestrings -.configure-files/*.enc binary +.a8c-secrets/*.age binary diff --git a/.gitignore b/.gitignore index 12c9beff70d0..de1564ba1a58 100644 --- a/.gitignore +++ b/.gitignore @@ -85,10 +85,12 @@ Scripts/fastlane/ # CI Artifacts Location Artifacts -# All encrypted secrets should be stored under .configure-files -# Everything without a .enc extension is ignored -.configure-files/* -!.configure-files/*.enc +# a8c-secrets decrypts into ~/.a8c-secrets//, outside the checkout. +# In-repo, track only the repo id, the public keys, and the encrypted *.age blobs. +.a8c-secrets/* +!.a8c-secrets/repo-id +!.a8c-secrets/keys.pub +!.a8c-secrets/*.age # A file external contributors can have locally to provide their own credentials. # This file is created during the `rake init:oss` task, based on the Secrets-example.swift file. diff --git a/CODEOWNERS b/CODEOWNERS index c29db1d94519..220249b7e6e5 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -24,4 +24,4 @@ Dangerfile* @wordpress-mobile/apps-infra-tooling .xcode-version @wordpress-mobile/apps-infra-tooling # Secrets -.configure-files/ @wordpress-mobile/apps-infra-tooling +.a8c-secrets/ @wordpress-mobile/apps-infra-tooling diff --git a/Scripts/BuildPhases/GenerateCredentials.sh b/Scripts/BuildPhases/GenerateCredentials.sh index 8afb065ffdd8..37e3baa3d05f 100755 --- a/Scripts/BuildPhases/GenerateCredentials.sh +++ b/Scripts/BuildPhases/GenerateCredentials.sh @@ -3,7 +3,7 @@ set -euo pipefail # The Secrets File Sources -SECRETS_ROOT="${HOME}/.configure/wordpress-ios/secrets" +SECRETS_ROOT="${HOME}/.a8c-secrets/wordpress-ios@github.com@wordpress-mobile" # To help the Xcode build system optimize the build, we want to ensure each of # the secrets we want to copy is defined as an input file for the run script @@ -86,7 +86,7 @@ fi # resort, unless building for Release. COULD_NOT_FIND_SECRET_MSG="Could not find secrets file at ${SECRETS_DESTINATION_FILE}. This is likely due to the source secrets being missing from ${SECRETS_ROOT}" -INTERNAL_CONTRIBUTOR_MSG="If you are an internal contributor, run \`bundle exec fastlane run configure_apply\` to update your secrets and try again" +INTERNAL_CONTRIBUTOR_MSG="If you are an internal contributor, run \`bundle exec fastlane configure_secrets\` to update your secrets and try again" EXTERNAL_CONTRIBUTOR_MSG="If you are an external contributor, run \`bundle exec rake init:oss\` to set up and use your own credentials" case $CONFIGURATION in diff --git a/Scripts/BuildPhases/GenerateCredentials.xcfilelist b/Scripts/BuildPhases/GenerateCredentials.xcfilelist index 2d99cf0ff613..d687b72f6a56 100644 --- a/Scripts/BuildPhases/GenerateCredentials.xcfilelist +++ b/Scripts/BuildPhases/GenerateCredentials.xcfilelist @@ -1,6 +1,6 @@ # Lists of input files for the script that populates the app's secrets with the # correct values for the current scheme and build configuration. -${HOME}/.configure/wordpress-ios/secrets/Secrets.swift +${HOME}/.a8c-secrets/wordpress-ios@github.com@wordpress-mobile/Secrets.swift # Local Secrets file that external contributors can use to specify their own # ClientID and Secrets. This file is created by the Rakefile when external From 9146eb200dd7e22343601990e927538463e43872 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 22 Jul 2026 15:32:52 +1000 Subject: [PATCH 04/18] Point the credentials build phase at a8c-secrets The hint named a `configure_secrets` fastlane lane this repo never gained. Name the tool's own command and link its repo, so the message stays correct as the setup steps evolve. 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) --- Scripts/BuildPhases/GenerateCredentials.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/BuildPhases/GenerateCredentials.sh b/Scripts/BuildPhases/GenerateCredentials.sh index 37e3baa3d05f..e18155e411f0 100755 --- a/Scripts/BuildPhases/GenerateCredentials.sh +++ b/Scripts/BuildPhases/GenerateCredentials.sh @@ -86,7 +86,7 @@ fi # resort, unless building for Release. COULD_NOT_FIND_SECRET_MSG="Could not find secrets file at ${SECRETS_DESTINATION_FILE}. This is likely due to the source secrets being missing from ${SECRETS_ROOT}" -INTERNAL_CONTRIBUTOR_MSG="If you are an internal contributor, run \`bundle exec fastlane configure_secrets\` to update your secrets and try again" +INTERNAL_CONTRIBUTOR_MSG="If you are an internal contributor, run \`a8c-secrets decrypt\` to update your secrets and try again (see https://github.com/Automattic/a8c-secrets for setup)" EXTERNAL_CONTRIBUTOR_MSG="If you are an external contributor, run \`bundle exec rake init:oss\` to set up and use your own credentials" case $CONFIGURATION in From 97c105237746675510a62aeaef1871df7d906480 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 22 Jul 2026 15:32:58 +1000 Subject: [PATCH 05/18] Decrypt secrets with a8c-secrets, not fastlane CI installs the tool through the toolkit's `install_a8c-secrets_binary`, added in plugin 6.2.0, which pins the version and checksums the download. `rake dependencies` now decrypts only when the tool is present, so external contributors bootstrap unchanged, and treats a failed decrypt as a warning: the build phase already falls back to the example secrets and errors on its own for Release builds. 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) --- .buildkite/commands/install-secrets.sh | 8 +++++++- .buildkite/shared-pipeline-vars | 2 +- Rakefile | 26 ++++++++++++-------------- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/.buildkite/commands/install-secrets.sh b/.buildkite/commands/install-secrets.sh index 181f3e3267da..90489ad5846d 100755 --- a/.buildkite/commands/install-secrets.sh +++ b/.buildkite/commands/install-secrets.sh @@ -2,5 +2,11 @@ set -euo pipefail +# `install_a8c-secrets_binary` comes from the a8c-ci-toolkit plugin. It pins the +# a8c-secrets version and checks the download against a checksum vendored there. +install_dir="$HOME/.local/bin" +install_a8c-secrets_binary --install-dir "$install_dir" +export PATH="$install_dir:$PATH" + echo "--- :closed_lock_with_key: Installing Secrets" -bundle exec fastlane run configure_apply +a8c-secrets decrypt diff --git a/.buildkite/shared-pipeline-vars b/.buildkite/shared-pipeline-vars index ef632b72f9df..01b4e25703c9 100755 --- a/.buildkite/shared-pipeline-vars +++ b/.buildkite/shared-pipeline-vars @@ -5,7 +5,7 @@ # The ~> modifier is not currently used, but we check for it just in case XCODE_VERSION=$(sed -E 's/^~> ?//' .xcode-version) -CI_TOOLKIT_PLUGIN_VERSION="6.1.1" +CI_TOOLKIT_PLUGIN_VERSION="6.2.0" TEST_COLLECTOR_PLUGIN_VERSION="1.11.0" export IMAGE_ID="xcode-$XCODE_VERSION" diff --git a/Rakefile b/Rakefile index 5c03a487e2d9..5e715c36afee 100644 --- a/Rakefile +++ b/Rakefile @@ -77,20 +77,18 @@ namespace :dependencies do namespace :credentials do task :apply do - next unless Dir.exist?(File.join(Dir.home, '.mobile-secrets/.git')) || ENV.key?('CONFIGURE_ENCRYPTION_KEY') - - # The string is indented all the way to the left to avoid padding when printed in the terminal - command = %( -FASTLANE_SKIP_UPDATE_CHECK=1 \ -FASTLANE_HIDE_CHANGELOG=1 \ -FASTLANE_HIDE_PLUGINS_TABLE=1 \ -FASTLANE_ENV_PRINTER=1 \ -FASTLANE_SKIP_ACTION_SUMMARY=1 \ -FASTLANE_HIDE_TIMESTAMP=1 \ -bundle exec fastlane run configure_apply force:true - ) - - sh(command) + # External contributors build with their own credentials and never install the tool. + unless command?('a8c-secrets') + puts 'Skipping secrets decryption: `a8c-secrets` is not installed. Internal contributors, see https://github.com/Automattic/a8c-secrets.' + next + end + + sh('a8c-secrets', 'decrypt') do |ok, _res| + next if ok + + # Not fatal: the build phase falls back to the example secrets and errors on its own for Release builds. + puts 'Failed to decrypt secrets. See https://github.com/Automattic/a8c-secrets for setup and troubleshooting.' + end end end From 0cdf4839541edfa65aee6eda54d32d2d51ae7e43 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 22 Jul 2026 15:37:50 +1000 Subject: [PATCH 06/18] Drop the GPG key onboarding tasks The flow existed to get developers a key for the `mobile-secrets` repo. a8c-secrets authenticates with age identities instead, so nothing in this repo reads a GPG key any more. 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) --- Rakefile | 95 -------------------------------------------------------- 1 file changed, 95 deletions(-) diff --git a/Rakefile b/Rakefile index 5e715c36afee..ecb6f01fe5b6 100644 --- a/Rakefile +++ b/Rakefile @@ -198,7 +198,6 @@ namespace :init do dependencies install:tools:check_developer credentials:setup - gpg_key:setup ] end @@ -328,7 +327,6 @@ namespace :install do developer_tools = { 'convert' => 'imagemagick', 'gs' => 'ghostscript', 'sentry-cli' => 'getsentry/tools/sentry-cli', - 'gpg' => 'gpg', 'git-crypt' => 'git-crypt' } # Check for tool, install if not installed @@ -424,99 +422,6 @@ namespace :credentials do end end -namespace :gpg_key do - # automate the process of creatong a GPG key - task setup: %w[gpg_key:check gpg_key:prompt gpg_key:finish] - - # confirm that GPG tools is installed - task :check do - puts 'Checking system for GPG Tools' - if command?('gpg') - puts 'GPG Tools found' - else - Rake::Task['gpg_key:install'].invoke - end - end - - # install GPG Tools - task :install do - puts 'GPG Tools not found. Installing GPG Tools' - sh 'brew install gpg' - end - - # Ask developer if they need to create a new key. - # If yes, begin process of creating key, if no move on - task :prompt do - next unless create_gpg_key? - - if create_default_key? - display_default_config_helpers - Rake::Task['gpg_key:generate_default'].invoke - else - Rake::Task['gpg_key:generate_custom'].invoke - end - end - - # Generate new GPG key - task :generate_custom do - puts '' - puts 'Begin Generating Custom GPG Keys' - puts '=====================================================================================' - - sh 'gpg --full-generate-key', verbose: false - end - - # Generate new default GPG key - task :generate_default do - puts '' - puts 'Begin Generating Default GPG Keys' - puts '=====================================================================================' - - sh 'gpg --generate-key', verbose: false - end - - # prompt developer to send GPG key to Platform - task :finish do - puts '=====================================================================================' - puts 'Key Generation Complete!' - puts 'Please send your GPG public key to Platform 9-3/4' - puts 'You can contact them in the Slack channel #platform9' - puts '=====================================================================================' - end - - # ask user if they want to create a key, loop till given a valid answer - def create_gpg_key? - puts '=====================================================================================' - puts 'To access production credentials for the WordPress app you will need to a GPG Key' - puts 'Do you need to generate a new GPG Key?' - puts "Press 'Y' to create a new key. Press 'N' to skip" - - display_prompt_response? - end - - # ask user if they want to create a key, loop till given a valid answer - def create_default_key? - puts '=====================================================================================' - puts 'You can choose to setup with a default or custom key pair setup' - puts 'Default setup - Type: RSA to RSA, RSA length: 2048, Valid for: does not expire' - puts 'Would you like to continue with the default setup?' - puts '=====================================================================================' - puts "Press 'Y' for Yes. Press 'N' for custom configuration" - - display_prompt_response? - end - - # display prompt for developer to aid in setting up default key - def display_default_config_helpers - puts '' - puts '' - puts '=====================================================================================' - puts 'You will need to enter the following info to create your key' - puts 'Please enter your real name, email address, and a password for your key when prompted' - puts '=====================================================================================' - end -end - # prompt for a Y or N response, continue asking if other character # return true for Y and false for N def display_prompt_response? From d46cde5b9e910c76c652b7b3b7e5f587d3f72218 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 22 Jul 2026 20:53:47 +1000 Subject: [PATCH 07/18] Ask a8c-secrets where the secrets are Neither file now names the tool's storage layout: the input list declares the committed `.age` blob it can actually see, and the script asks `a8c-secrets which` for the plaintext. A repo id or decrypt root spelled out here would silently rot the day either changes. `copy_if_changed` keeps a checkout that only bumps an input's mtime from forcing a recompile of `Secrets.swift`. Mirrors Gravatar-SDK-iOS `2fc29684`. 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) --- Scripts/BuildPhases/GenerateCredentials.sh | 27 ++++++++++++------- .../GenerateCredentials.xcfilelist | 6 ++++- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/Scripts/BuildPhases/GenerateCredentials.sh b/Scripts/BuildPhases/GenerateCredentials.sh index e18155e411f0..ab4a098c4e45 100755 --- a/Scripts/BuildPhases/GenerateCredentials.sh +++ b/Scripts/BuildPhases/GenerateCredentials.sh @@ -2,8 +2,10 @@ set -euo pipefail -# The Secrets File Sources -SECRETS_ROOT="${HOME}/.a8c-secrets/wordpress-ios@github.com@wordpress-mobile" +# The committed .age blob is the versioned source of the decrypted secrets file. +# Where a8c-secrets puts the plaintext is the tool's business, so ask it rather +# than spelling out its layout here. +ENCRYPTED_SECRETS_FILE="${SRCROOT}/../.a8c-secrets/Secrets.swift.age" # To help the Xcode build system optimize the build, we want to ensure each of # the secrets we want to copy is defined as an input file for the run script @@ -49,8 +51,7 @@ function ensure_is_in_input_files_list() { fi } -SECRETS_FILE="${SECRETS_ROOT}/Secrets.swift" -ensure_is_in_input_files_list $SECRETS_FILE +ensure_is_in_input_files_list $ENCRYPTED_SECRETS_FILE LOCAL_SECRETS_FILE="${SRCROOT}/Credentials/Secrets.swift" EXAMPLE_SECRETS_FILE="${SRCROOT}/Credentials/Secrets-example.swift" @@ -60,10 +61,18 @@ ensure_is_in_input_files_list $EXAMPLE_SECRETS_FILE SECRETS_DESTINATION_FILE="${SCRIPT_OUTPUT_FILE_0}" mkdir -p "$(dirname "$SECRETS_DESTINATION_FILE")" +# Only rewrite the destination when the content changed: a checkout can bump an +# input's mtime without the secrets themselves changing, and an unconditional +# copy would then force a recompile of Secrets.swift. +function copy_if_changed() { + cmp -s "$1" "$SECRETS_DESTINATION_FILE" || cp -v "$1" "$SECRETS_DESTINATION_FILE" +} + +# `a8c-secrets which` exits non-zero when the file has not been decrypted yet. # WordPress, Jetpack, and Reader use all the same secrets at this time. -if [ -f "$SECRETS_FILE" ]; then +if command -v a8c-secrets > /dev/null 2>&1 && SECRETS_FILE=$(a8c-secrets which Secrets.swift 2>/dev/null); then echo "Applying Production Secrets" - cp -v "$SECRETS_FILE" "${SECRETS_DESTINATION_FILE}" + copy_if_changed "$SECRETS_FILE" exit 0 fi @@ -78,14 +87,14 @@ if [ -f "$LOCAL_SECRETS_FILE" ]; then echo "warning: Using local Secrets from $LOCAL_SECRETS_FILE. If you are an external contributor, this is expected and you can ignore this warning. If you are an internal contributor, make sure to use our shared credentials instead." echo "Applying Local Secrets" - cp -v "$LOCAL_SECRETS_FILE" "${SECRETS_DESTINATION_FILE}" + copy_if_changed "$LOCAL_SECRETS_FILE" exit 0 fi # None of the above secrets was found. Use the example secrets file as a last # resort, unless building for Release. -COULD_NOT_FIND_SECRET_MSG="Could not find secrets file at ${SECRETS_DESTINATION_FILE}. This is likely due to the source secrets being missing from ${SECRETS_ROOT}" +COULD_NOT_FIND_SECRET_MSG="Could not find secrets file at ${SECRETS_DESTINATION_FILE}. This is likely due to the secrets not having been decrypted" INTERNAL_CONTRIBUTOR_MSG="If you are an internal contributor, run \`a8c-secrets decrypt\` to update your secrets and try again (see https://github.com/Automattic/a8c-secrets for setup)" EXTERNAL_CONTRIBUTOR_MSG="If you are an external contributor, run \`bundle exec rake init:oss\` to set up and use your own credentials" @@ -100,6 +109,6 @@ case $CONFIGURATION in *) echo "warning: $COULD_NOT_FIND_SECRET_MSG. Falling back to $EXAMPLE_SECRETS_FILE. In a Release build, this would be an error. $INTERNAL_CONTRIBUTOR_MSG. $EXTERNAL_CONTRIBUTOR_MSG." echo "Applying Example Secrets" - cp -v "$EXAMPLE_SECRETS_FILE" "${SECRETS_DESTINATION_FILE}" + copy_if_changed "$EXAMPLE_SECRETS_FILE" ;; esac diff --git a/Scripts/BuildPhases/GenerateCredentials.xcfilelist b/Scripts/BuildPhases/GenerateCredentials.xcfilelist index d687b72f6a56..3556dff3b751 100644 --- a/Scripts/BuildPhases/GenerateCredentials.xcfilelist +++ b/Scripts/BuildPhases/GenerateCredentials.xcfilelist @@ -1,6 +1,10 @@ # Lists of input files for the script that populates the app's secrets with the # correct values for the current scheme and build configuration. -${HOME}/.a8c-secrets/wordpress-ios@github.com@wordpress-mobile/Secrets.swift + +# The committed .age is the versioned source of the decrypted secrets file the +# phase actually reads (via `a8c-secrets which`), so tracking it re-runs the +# phase after a pull that rotates the secret. +${SRCROOT}/../.a8c-secrets/Secrets.swift.age # Local Secrets file that external contributors can use to specify their own # ClientID and Secrets. This file is created by the Rakefile when external From 51e40a79f4c8d33d94c3b14c0735b04a3b8ff3da Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Tue, 4 Aug 2026 21:06:57 +1000 Subject: [PATCH 08/18] Install secrets only in jobs that build the app `a8c-secrets decrypt` produces a single file, `Secrets.swift`, and its only consumer is the `GenerateCredentials.sh` Xcode build phase. The release-management and TestFlight-promotion jobs never invoke a compile, and take their App Store Connect, GitHub, and Slack credentials from Buildkite environment variables, so the decryption was dead weight in those jobs. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Code Opus 5 --- .buildkite/commands/complete-code-freeze.sh | 2 -- .buildkite/commands/finalize-hotfix.sh | 2 -- .buildkite/commands/finalize-release.sh | 2 -- .buildkite/commands/gather-testflight-candidates.sh | 4 +--- .buildkite/commands/promote-build-to-public.sh | 4 +--- .buildkite/commands/promote-nightly.sh | 4 +--- .buildkite/release-pipelines/code-freeze.yml | 2 -- .buildkite/release-pipelines/new-beta-release.yml | 2 -- .buildkite/release-pipelines/new-hotfix.yml | 2 -- .buildkite/release-pipelines/publish-release.yml | 2 -- .buildkite/release-pipelines/update-app-store-strings.yml | 2 -- 11 files changed, 3 insertions(+), 25 deletions(-) diff --git a/.buildkite/commands/complete-code-freeze.sh b/.buildkite/commands/complete-code-freeze.sh index bde99028ed0c..dccabcf320fa 100755 --- a/.buildkite/commands/complete-code-freeze.sh +++ b/.buildkite/commands/complete-code-freeze.sh @@ -14,7 +14,5 @@ source use-bot-for-git "$(dirname "${BASH_SOURCE[0]}")/shared-set-up.sh" -"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" - echo '--- :shipit: Complete code freeze' bundle exec fastlane complete_code_freeze skip_confirm:true diff --git a/.buildkite/commands/finalize-hotfix.sh b/.buildkite/commands/finalize-hotfix.sh index d42699302d2d..942410578b73 100755 --- a/.buildkite/commands/finalize-hotfix.sh +++ b/.buildkite/commands/finalize-hotfix.sh @@ -15,7 +15,5 @@ source use-bot-for-git echo '--- :ruby: Setup Ruby tools' install_gems -"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" - echo '--- :shipit: Finalize hotfix' bundle exec fastlane finalize_hotfix_release skip_confirm:true diff --git a/.buildkite/commands/finalize-release.sh b/.buildkite/commands/finalize-release.sh index e553e49b3e53..18ff3a002112 100755 --- a/.buildkite/commands/finalize-release.sh +++ b/.buildkite/commands/finalize-release.sh @@ -15,7 +15,5 @@ source use-bot-for-git echo '--- :ruby: Setup Ruby tools' install_gems -"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" - echo '--- :shipit: Finalize release' bundle exec fastlane finalize_release skip_confirm:true diff --git a/.buildkite/commands/gather-testflight-candidates.sh b/.buildkite/commands/gather-testflight-candidates.sh index 9100c091e958..a8bd5eb696ab 100755 --- a/.buildkite/commands/gather-testflight-candidates.sh +++ b/.buildkite/commands/gather-testflight-candidates.sh @@ -1,12 +1,10 @@ #!/bin/bash -eu # Lists the nightly builds, opens the "choose a build" block step, and posts the -# candidate list to Slack. No build — just gems + secrets. +# candidate list to Slack. No build — just gems. echo "--- :rubygems: Setting up Gems" install_gems -"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" - echo "--- :testflight: Gathering candidates and opening the block step" bundle exec fastlane gather_testflight_candidates diff --git a/.buildkite/commands/promote-build-to-public.sh b/.buildkite/commands/promote-build-to-public.sh index 935e316a2df8..2fcea9d166d4 100755 --- a/.buildkite/commands/promote-build-to-public.sh +++ b/.buildkite/commands/promote-build-to-public.sh @@ -1,6 +1,6 @@ #!/bin/bash -eu -# Promotes the build chosen in the preceding block step to public beta. No build — just gems + secrets. +# Promotes the build chosen in the preceding block step to public beta. No build — just gems. # `build_to_promote` must stay in sync with PROMOTION_META_DATA_KEY in fastlane/lanes/promote.rb, # which is the key the gather lane writes the block-step select field under. @@ -14,7 +14,5 @@ fi echo "--- :rubygems: Setting up Gems" install_gems -"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" - echo "--- :rocket: Promoting ${BUILD_CODE} to public beta" bundle exec fastlane promote_build build_code:"${BUILD_CODE}" diff --git a/.buildkite/commands/promote-nightly.sh b/.buildkite/commands/promote-nightly.sh index e313e561f2e1..28c0586251f4 100755 --- a/.buildkite/commands/promote-nightly.sh +++ b/.buildkite/commands/promote-nightly.sh @@ -1,12 +1,10 @@ #!/bin/bash -eu -# Promotes the last build of the day to the nightly group. No build — just gems + secrets. +# Promotes the last build of the day to the nightly group. No build — just gems. echo "--- :rubygems: Setting up Gems" install_gems -"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" - echo "--- :new_moon: Promoting last build of the day to nightly beta" # The lane refuses to run anywhere but trunk. bundle exec fastlane promote_nightly_build diff --git a/.buildkite/release-pipelines/code-freeze.yml b/.buildkite/release-pipelines/code-freeze.yml index aebbd91bf1f5..43a93eb80064 100644 --- a/.buildkite/release-pipelines/code-freeze.yml +++ b/.buildkite/release-pipelines/code-freeze.yml @@ -18,8 +18,6 @@ steps: echo '--- :ruby: Setup Ruby tools' install_gems - .buildkite/commands/install-secrets.sh - echo '--- :shipit: Run code freeze' bundle exec fastlane code_freeze version:"${RELEASE_VERSION}" skip_confirm:true retry: diff --git a/.buildkite/release-pipelines/new-beta-release.yml b/.buildkite/release-pipelines/new-beta-release.yml index e0040a418816..db065dbce699 100644 --- a/.buildkite/release-pipelines/new-beta-release.yml +++ b/.buildkite/release-pipelines/new-beta-release.yml @@ -19,8 +19,6 @@ steps: echo '--- :ruby: Setup Ruby tools' install_gems - .buildkite/commands/install-secrets.sh - echo '--- :shipit: Deploy new beta' bundle exec fastlane new_beta_release skip_confirm:true retry: diff --git a/.buildkite/release-pipelines/new-hotfix.yml b/.buildkite/release-pipelines/new-hotfix.yml index b9b499a5fed0..d4a48fae2dc0 100644 --- a/.buildkite/release-pipelines/new-hotfix.yml +++ b/.buildkite/release-pipelines/new-hotfix.yml @@ -19,8 +19,6 @@ steps: echo '--- :ruby: Setup Ruby tools' install_gems - .buildkite/commands/install-secrets.sh - echo '--- :shipit: Start new hotfix' bundle exec fastlane new_hotfix_release skip_confirm:true version:"$VERSION" retry: diff --git a/.buildkite/release-pipelines/publish-release.yml b/.buildkite/release-pipelines/publish-release.yml index abb9518ce335..f25dfffbfeee 100644 --- a/.buildkite/release-pipelines/publish-release.yml +++ b/.buildkite/release-pipelines/publish-release.yml @@ -19,8 +19,6 @@ steps: echo '--- :ruby: Setup Ruby tools' install_gems - .buildkite/commands/install-secrets.sh - echo '--- :package: Publish Release' bundle exec fastlane publish_release skip_confirm:true retry: diff --git a/.buildkite/release-pipelines/update-app-store-strings.yml b/.buildkite/release-pipelines/update-app-store-strings.yml index 7fc327ed43ba..1edfa69d0cb8 100644 --- a/.buildkite/release-pipelines/update-app-store-strings.yml +++ b/.buildkite/release-pipelines/update-app-store-strings.yml @@ -18,8 +18,6 @@ steps: echo '--- :ruby: Setup Ruby tools' install_gems - .buildkite/commands/install-secrets.sh - echo '--- :shipit: Update relaese notes and other App Store metadata' bundle exec fastlane update_appstore_strings skip_confirm:true retry: From 442a53fc07e9654f36995750c86816a384d28325 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Tue, 4 Aug 2026 21:14:35 +1000 Subject: [PATCH 09/18] Normalize the secrets path like Xcode does Xcode collapses `..` when it resolves an `.xcfilelist`, so the entry landed in the processed list rooted at the repo while the script still held the `WordPress/..` form of the same path. `ensure_is_in_input_files_list` compares the two as strings, so every target running `Generate Credentials` failed the phase. The paths this replaced were rooted at `${HOME}` and had no `..` to collapse, which is why the check held up until now. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Code Opus 5 --- Scripts/BuildPhases/GenerateCredentials.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Scripts/BuildPhases/GenerateCredentials.sh b/Scripts/BuildPhases/GenerateCredentials.sh index ab4a098c4e45..460ce2c459a4 100755 --- a/Scripts/BuildPhases/GenerateCredentials.sh +++ b/Scripts/BuildPhases/GenerateCredentials.sh @@ -5,7 +5,11 @@ set -euo pipefail # The committed .age blob is the versioned source of the decrypted secrets file. # Where a8c-secrets puts the plaintext is the tool's business, so ask it rather # than spelling out its layout here. -ENCRYPTED_SECRETS_FILE="${SRCROOT}/../.a8c-secrets/Secrets.swift.age" +# +# Reach the repo root by trimming SRCROOT's last component rather than appending +# `/..`: the input file list this path is matched against is the one Xcode +# resolved, and Xcode collapses `..` when it writes it. +ENCRYPTED_SECRETS_FILE="${SRCROOT%/*}/.a8c-secrets/Secrets.swift.age" # To help the Xcode build system optimize the build, we want to ensure each of # the secrets we want to copy is defined as an input file for the run script From 05dff651acee9e47b386ae8563328cf491c77886 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Tue, 4 Aug 2026 21:14:47 +1000 Subject: [PATCH 10/18] Source the secrets install so PATH reaches Xcode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `Generate Credentials` build phase resolves `a8c-secrets` off PATH, and the CI agents don't carry `~/.local/bin` — the installer says so itself on the way past. Running the script as a child process left the export behind with it, so the phase would have fallen through to the example secrets and failed every Release build. Gravatar-SDK-iOS keeps the install and the export inline in the job script for the same reason; sourcing gets there without copying them into six callers. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Code Opus 5 --- .buildkite/commands/build-and-upload-testflight.sh | 2 +- .buildkite/commands/build-for-testing.sh | 2 +- .buildkite/commands/install-secrets.sh | 3 +++ .buildkite/commands/prototype-build-jetpack.sh | 2 +- .buildkite/commands/prototype-build-wordpress.sh | 2 +- .buildkite/commands/release-build-jetpack.sh | 2 +- .buildkite/commands/release-build-wordpress.sh | 2 +- 7 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.buildkite/commands/build-and-upload-testflight.sh b/.buildkite/commands/build-and-upload-testflight.sh index 7a65810c4917..c69ad7af7c1e 100755 --- a/.buildkite/commands/build-and-upload-testflight.sh +++ b/.buildkite/commands/build-and-upload-testflight.sh @@ -7,7 +7,7 @@ APP="${1:?Usage: build-and-upload-testflight.sh }" "$(dirname "${BASH_SOURCE[0]}")/shared-set-up.sh" "$(dirname "${BASH_SOURCE[0]}")/shared-set-up-distribution.sh" -"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" +source "$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" echo "--- :testflight: Building and uploading ${APP} to TestFlight" bundle exec fastlane build_and_upload_app_for_testflight app:"${APP}" diff --git a/.buildkite/commands/build-for-testing.sh b/.buildkite/commands/build-for-testing.sh index 4350e855fed2..90c93afaafac 100755 --- a/.buildkite/commands/build-for-testing.sh +++ b/.buildkite/commands/build-for-testing.sh @@ -16,7 +16,7 @@ fi "$(dirname "${BASH_SOURCE[0]}")/shared-set-up.sh" -"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" +source "$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" echo "--- :hammer_and_wrench: Building" bundle exec fastlane "build_${APP}_for_testing" diff --git a/.buildkite/commands/install-secrets.sh b/.buildkite/commands/install-secrets.sh index 90489ad5846d..7aa45333ed55 100755 --- a/.buildkite/commands/install-secrets.sh +++ b/.buildkite/commands/install-secrets.sh @@ -1,5 +1,8 @@ #!/usr/bin/env bash +# Source this, don't execute it: the `Generate Credentials` build phase resolves +# `a8c-secrets` off PATH, and a child process would take the export below with it. + set -euo pipefail # `install_a8c-secrets_binary` comes from the a8c-ci-toolkit plugin. It pins the diff --git a/.buildkite/commands/prototype-build-jetpack.sh b/.buildkite/commands/prototype-build-jetpack.sh index 621edef8bd75..e08e4eb6b5ee 100644 --- a/.buildkite/commands/prototype-build-jetpack.sh +++ b/.buildkite/commands/prototype-build-jetpack.sh @@ -7,7 +7,7 @@ fi "$(dirname "${BASH_SOURCE[0]}")/shared-set-up.sh" "$(dirname "${BASH_SOURCE[0]}")/shared-set-up-distribution.sh" -"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" +source "$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" echo "--- :hammer_and_wrench: Building" bundle exec fastlane build_and_upload_jetpack_prototype_build diff --git a/.buildkite/commands/prototype-build-wordpress.sh b/.buildkite/commands/prototype-build-wordpress.sh index 9b649f5b636a..2f02c85dc648 100644 --- a/.buildkite/commands/prototype-build-wordpress.sh +++ b/.buildkite/commands/prototype-build-wordpress.sh @@ -7,7 +7,7 @@ fi "$(dirname "${BASH_SOURCE[0]}")/shared-set-up.sh" "$(dirname "${BASH_SOURCE[0]}")/shared-set-up-distribution.sh" -"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" +source "$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" echo "--- :hammer_and_wrench: Building" bundle exec fastlane build_and_upload_wordpress_prototype_build diff --git a/.buildkite/commands/release-build-jetpack.sh b/.buildkite/commands/release-build-jetpack.sh index 7de02454d910..67be73947e03 100755 --- a/.buildkite/commands/release-build-jetpack.sh +++ b/.buildkite/commands/release-build-jetpack.sh @@ -3,7 +3,7 @@ "$(dirname "${BASH_SOURCE[0]}")/shared-set-up.sh" "$(dirname "${BASH_SOURCE[0]}")/shared-set-up-distribution.sh" -"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" +source "$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" echo "--- :hammer_and_wrench: Building" bundle exec fastlane build_and_upload_jetpack_for_app_store diff --git a/.buildkite/commands/release-build-wordpress.sh b/.buildkite/commands/release-build-wordpress.sh index d8e92522c4d9..e4ce9e4f893b 100755 --- a/.buildkite/commands/release-build-wordpress.sh +++ b/.buildkite/commands/release-build-wordpress.sh @@ -3,7 +3,7 @@ "$(dirname "${BASH_SOURCE[0]}")/shared-set-up.sh" "$(dirname "${BASH_SOURCE[0]}")/shared-set-up-distribution.sh" -"$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" +source "$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" echo "--- :hammer_and_wrench: Building" bundle exec fastlane build_and_upload_app_store_connect \ From 448b9a2fd436ee912a2676320dc6e4f91868ac97 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 5 Aug 2026 11:02:08 +1000 Subject: [PATCH 11/18] Fail loudly when install-secrets.sh is executed A comment asking callers to source the script is easy to miss, and the failure mode is silent: the build phase falls through to the example secrets and only breaks later, in a Release build. The guard matches the one in `set-up-git-to-fetch-private-packages.sh` in `dayone-apple` and `use-bot-for-git.sh` in the CI agent images. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Code Opus 5 --- .buildkite/commands/install-secrets.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.buildkite/commands/install-secrets.sh b/.buildkite/commands/install-secrets.sh index 7aa45333ed55..267732b50bcf 100755 --- a/.buildkite/commands/install-secrets.sh +++ b/.buildkite/commands/install-secrets.sh @@ -1,7 +1,11 @@ #!/usr/bin/env bash -# Source this, don't execute it: the `Generate Credentials` build phase resolves -# `a8c-secrets` off PATH, and a child process would take the export below with it. +# The `Generate Credentials` build phase resolves `a8c-secrets` off PATH, so the +# export below has to survive in the caller's shell. +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + echo "This script must be sourced, not executed, because it exports PATH." >&2 + exit 1 +fi set -euo pipefail From f19eeebad738ec424f680500882392aebecda748 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 5 Aug 2026 11:09:15 +1000 Subject: [PATCH 12/18] Copy the secrets unconditionally Matches the shape agreed in Gravatar-SDK-iOS, whose build phase copies without comparing first: https://github.com/Automattic/Gravatar-SDK-iOS/pull/824 The phase declares its inputs and output, so Xcode already skips it when nothing changed. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Code Opus 5 --- Scripts/BuildPhases/GenerateCredentials.sh | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/Scripts/BuildPhases/GenerateCredentials.sh b/Scripts/BuildPhases/GenerateCredentials.sh index 460ce2c459a4..9b729c09ef62 100755 --- a/Scripts/BuildPhases/GenerateCredentials.sh +++ b/Scripts/BuildPhases/GenerateCredentials.sh @@ -65,18 +65,11 @@ ensure_is_in_input_files_list $EXAMPLE_SECRETS_FILE SECRETS_DESTINATION_FILE="${SCRIPT_OUTPUT_FILE_0}" mkdir -p "$(dirname "$SECRETS_DESTINATION_FILE")" -# Only rewrite the destination when the content changed: a checkout can bump an -# input's mtime without the secrets themselves changing, and an unconditional -# copy would then force a recompile of Secrets.swift. -function copy_if_changed() { - cmp -s "$1" "$SECRETS_DESTINATION_FILE" || cp -v "$1" "$SECRETS_DESTINATION_FILE" -} - # `a8c-secrets which` exits non-zero when the file has not been decrypted yet. # WordPress, Jetpack, and Reader use all the same secrets at this time. if command -v a8c-secrets > /dev/null 2>&1 && SECRETS_FILE=$(a8c-secrets which Secrets.swift 2>/dev/null); then echo "Applying Production Secrets" - copy_if_changed "$SECRETS_FILE" + cp -v "$SECRETS_FILE" "$SECRETS_DESTINATION_FILE" exit 0 fi @@ -91,7 +84,7 @@ if [ -f "$LOCAL_SECRETS_FILE" ]; then echo "warning: Using local Secrets from $LOCAL_SECRETS_FILE. If you are an external contributor, this is expected and you can ignore this warning. If you are an internal contributor, make sure to use our shared credentials instead." echo "Applying Local Secrets" - copy_if_changed "$LOCAL_SECRETS_FILE" + cp -v "$LOCAL_SECRETS_FILE" "$SECRETS_DESTINATION_FILE" exit 0 fi @@ -113,6 +106,6 @@ case $CONFIGURATION in *) echo "warning: $COULD_NOT_FIND_SECRET_MSG. Falling back to $EXAMPLE_SECRETS_FILE. In a Release build, this would be an error. $INTERNAL_CONTRIBUTOR_MSG. $EXTERNAL_CONTRIBUTOR_MSG." echo "Applying Example Secrets" - copy_if_changed "$EXAMPLE_SECRETS_FILE" + cp -v "$EXAMPLE_SECRETS_FILE" "$SECRETS_DESTINATION_FILE" ;; esac From 0601dfe74f6d2ba16d543c276a32887d7611b70a Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 5 Aug 2026 11:11:25 +1000 Subject: [PATCH 13/18] Drop cp's verbose flag Each call site already echoes which secrets it is applying. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Code Opus 5 --- Scripts/BuildPhases/GenerateCredentials.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Scripts/BuildPhases/GenerateCredentials.sh b/Scripts/BuildPhases/GenerateCredentials.sh index 9b729c09ef62..8b1e640ad273 100755 --- a/Scripts/BuildPhases/GenerateCredentials.sh +++ b/Scripts/BuildPhases/GenerateCredentials.sh @@ -69,7 +69,7 @@ mkdir -p "$(dirname "$SECRETS_DESTINATION_FILE")" # WordPress, Jetpack, and Reader use all the same secrets at this time. if command -v a8c-secrets > /dev/null 2>&1 && SECRETS_FILE=$(a8c-secrets which Secrets.swift 2>/dev/null); then echo "Applying Production Secrets" - cp -v "$SECRETS_FILE" "$SECRETS_DESTINATION_FILE" + cp "$SECRETS_FILE" "$SECRETS_DESTINATION_FILE" exit 0 fi @@ -84,7 +84,7 @@ if [ -f "$LOCAL_SECRETS_FILE" ]; then echo "warning: Using local Secrets from $LOCAL_SECRETS_FILE. If you are an external contributor, this is expected and you can ignore this warning. If you are an internal contributor, make sure to use our shared credentials instead." echo "Applying Local Secrets" - cp -v "$LOCAL_SECRETS_FILE" "$SECRETS_DESTINATION_FILE" + cp "$LOCAL_SECRETS_FILE" "$SECRETS_DESTINATION_FILE" exit 0 fi @@ -106,6 +106,6 @@ case $CONFIGURATION in *) echo "warning: $COULD_NOT_FIND_SECRET_MSG. Falling back to $EXAMPLE_SECRETS_FILE. In a Release build, this would be an error. $INTERNAL_CONTRIBUTOR_MSG. $EXTERNAL_CONTRIBUTOR_MSG." echo "Applying Example Secrets" - cp -v "$EXAMPLE_SECRETS_FILE" "$SECRETS_DESTINATION_FILE" + cp "$EXAMPLE_SECRETS_FILE" "$SECRETS_DESTINATION_FILE" ;; esac From 99d99fd3191e682223cd4165d08bd1e302e047f9 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 5 Aug 2026 14:28:15 +1000 Subject: [PATCH 14/18] Move secrets decryption to aggregate target to DRY and avoid races --- WordPress/WordPress.xcodeproj/project.pbxproj | 200 +++++++++++++++++- 1 file changed, 194 insertions(+), 6 deletions(-) diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 5964c2e9431d..d53124fd28b9 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -7,6 +7,16 @@ objects = { /* Begin PBXAggregateTarget section */ + 0A4FB5FE91E0FB8978A881A4 /* Decrypt Secrets */ = { + isa = PBXAggregateTarget; + buildConfigurationList = D53494F78D616808DCB4A45E /* Build configuration list for PBXAggregateTarget "Decrypt Secrets" */; + buildPhases = ( + 038B974054F8161836A4FE44 /* Decrypt Secrets */, + ); + dependencies = ( + ); + name = "Decrypt Secrets"; + }; FFA8E22A1F94E3DE0002170F /* SwiftLint */ = { isa = PBXAggregateTarget; buildConfigurationList = FFA8E22F1F94E3DE0002170F /* Build configuration list for PBXAggregateTarget "SwiftLint" */; @@ -214,6 +224,13 @@ remoteGlobalIDString = 0107E0B128F97D5000DE87DB; remoteInfo = JetpackStatsWidgets; }; + 0622080DC83F4B988D9A7732 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0A4FB5FE91E0FB8978A881A4; + remoteInfo = "Decrypt Secrets"; + }; 0C3313C42E0439A9000C3760 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; @@ -228,6 +245,13 @@ remoteGlobalIDString = 0CED016F2D95B897003015CF; remoteInfo = Keystone; }; + 1D5A9F915AFDD37ADAE5B6B3 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0A4FB5FE91E0FB8978A881A4; + remoteInfo = "Decrypt Secrets"; + }; 3FCFFAFD2994A949002840C9 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; @@ -249,6 +273,13 @@ remoteGlobalIDString = 1D6058900D05DD3D006BFB54; remoteInfo = WordPress; }; + 67B2B1BD1B72EDCD56E09378 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0A4FB5FE91E0FB8978A881A4; + remoteInfo = "Decrypt Secrets"; + }; 7358E6BD210BD318002323EB /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; @@ -263,6 +294,13 @@ remoteGlobalIDString = 74576671202B558C00F42E40; remoteInfo = WordPressDraftActionExtension; }; + 769D3F36016EAF96E0A6942F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0A4FB5FE91E0FB8978A881A4; + remoteInfo = "Decrypt Secrets"; + }; 8096212628E5411400940A5D /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; @@ -291,6 +329,48 @@ remoteGlobalIDString = 932225A61C7CE50300443B02; remoteInfo = WordPressShare; }; + AC3931C50F6374EE6BE0878B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0A4FB5FE91E0FB8978A881A4; + remoteInfo = "Decrypt Secrets"; + }; + B6AD221EACD79608CD4592DA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0A4FB5FE91E0FB8978A881A4; + remoteInfo = "Decrypt Secrets"; + }; + B6C4FB8D0B592DC550A800C3 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0A4FB5FE91E0FB8978A881A4; + remoteInfo = "Decrypt Secrets"; + }; + B904E75B46BF37ED7B5187FD /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0A4FB5FE91E0FB8978A881A4; + remoteInfo = "Decrypt Secrets"; + }; + D1DAAEDC31CAA402FE8A1DD8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0A4FB5FE91E0FB8978A881A4; + remoteInfo = "Decrypt Secrets"; + }; + D59FA597D783ED86B07C8D4B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0A4FB5FE91E0FB8978A881A4; + remoteInfo = "Decrypt Secrets"; + }; E16AB93E14D978520047A2E5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; @@ -859,7 +939,7 @@ /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* Begin PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet section */ - 0C798C582ED8DD2E0012F3E2 /* Exceptions for "WordPressKitTests" folder in "Compile Sources" phase from "WordPressKitTests" target */ = { + 0C798C582ED8DD2E0012F3E2 /* Build phase membership exception set */ = { isa = PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet; buildPhase = 4A8280F92E5FE9B60037E180 /* Sources */; membershipExceptions = ( @@ -873,16 +953,22 @@ /* Begin PBXFileSystemSynchronizedRootGroup section */ 0C1CB0CD2D95C63C00494A8C /* Sources */ = { isa = PBXFileSystemSynchronizedRootGroup; + exceptions = ( + ); path = Sources; sourceTree = ""; }; 0C3313B82E0439A8000C3760 /* Miniature */ = { isa = PBXFileSystemSynchronizedRootGroup; + exceptions = ( + ); path = Miniature; sourceTree = ""; }; 0C3313C62E0439A9000C3760 /* MiniatureTests */ = { isa = PBXFileSystemSynchronizedRootGroup; + exceptions = ( + ); path = MiniatureTests; sourceTree = ""; }; @@ -936,11 +1022,15 @@ }; 0CED35262D959427003015CF /* Misc */ = { isa = PBXFileSystemSynchronizedRootGroup; + exceptions = ( + ); path = Misc; sourceTree = ""; }; 0CFC380E2DA408BB00DB3386 /* Recoleta */ = { isa = PBXFileSystemSynchronizedRootGroup; + exceptions = ( + ); path = Recoleta; sourceTree = ""; }; @@ -963,7 +1053,7 @@ 4A8280FE2E5FE9B60037E180 /* WordPressKitTests */ = { isa = PBXFileSystemSynchronizedRootGroup; exceptions = ( - 0C798C582ED8DD2E0012F3E2 /* Exceptions for "WordPressKitTests" folder in "Compile Sources" phase from "WordPressKitTests" target */, + 0C798C582ED8DD2E0012F3E2 /* Build phase membership exception set */, ); path = WordPressKitTests; sourceTree = ""; @@ -1240,7 +1330,7 @@ path = Classes; sourceTree = ""; }; - 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { + 29B97314FDCFA39411CA2CEA = { isa = PBXGroup; children = ( 3FD4B20E2DCC468200781DFA /* Modules */, @@ -1569,6 +1659,7 @@ buildRules = ( ); dependencies = ( + FD201323F47B01659717FF80 /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( 0C3E79892DB164B3000C7072 /* JetpackStatsWidgets */, @@ -1643,6 +1734,7 @@ ); dependencies = ( 0C5A8A7B2D9B22F100C25301 /* PBXTargetDependency */, + 6DB3D57911FC0C06F3D132CD /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( 0C5A3FAB2D9B1EF400C25301 /* Reader */, @@ -1703,6 +1795,7 @@ 932225B01C7CE50300443B02 /* PBXTargetDependency */, 7457667B202B558C00F42E40 /* PBXTargetDependency */, 7358E6BE210BD318002323EB /* PBXTargetDependency */, + 3828A866957B1D2DD25E64C4 /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( 0C3C98902DA04EF9009F3BFB /* WordPress */, @@ -1755,6 +1848,7 @@ buildRules = ( ); dependencies = ( + 65CC6335ECE100E214DE55FE /* PBXTargetDependency */, ); name = WordPressNotificationServiceExtension; packageProductDependencies = ( @@ -1777,6 +1871,7 @@ buildRules = ( ); dependencies = ( + 27FB1E0DB05514EA97FBA227 /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( 0C1CB0CD2D95C63C00494A8C /* Sources */, @@ -1802,6 +1897,7 @@ buildRules = ( ); dependencies = ( + 0502FF518F1263A191852804 /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( 0C1CB0CD2D95C63C00494A8C /* Sources */, @@ -1827,6 +1923,7 @@ buildRules = ( ); dependencies = ( + D4295A73403A34F65E19CC82 /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( 0C1CB0CD2D95C63C00494A8C /* Sources */, @@ -1852,6 +1949,7 @@ buildRules = ( ); dependencies = ( + CF65101CD8CB91DC81A54D2C /* PBXTargetDependency */, ); name = JetpackNotificationServiceExtension; packageProductDependencies = ( @@ -1874,6 +1972,7 @@ buildRules = ( ); dependencies = ( + 8852AC3D54E4A0AD8F746230 /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( 0C1CB0CD2D95C63C00494A8C /* Sources */, @@ -1933,6 +2032,7 @@ 8096212728E5411400940A5D /* PBXTargetDependency */, 8096219028E55F8600940A5D /* PBXTargetDependency */, 80F6D05F28EE88FC00953C1A /* PBXTargetDependency */, + 48675A72EB62C7BDFF515517 /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( 0C3C988F2DA04EEF009F3BFB /* Jetpack */, @@ -2086,9 +2186,7 @@ bg, sk, ); - mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; - packageReferences = ( - ); + mainGroup = 29B97314FDCFA39411CA2CEA; preferredProjectObjectVersion = 77; productRefGroup = 19C28FACFE9D520D11CA2CBB /* Products */; projectDirPath = ""; @@ -2110,6 +2208,7 @@ 0C3313B62E0439A8000C3760 /* Miniature */, 0C3313C22E0439A9000C3760 /* MiniatureTests */, 4A8280FC2E5FE9B60037E180 /* WordPressKitTests */, + 0A4FB5FE91E0FB8978A881A4 /* Decrypt Secrets */, ); }; /* End PBXProject section */ @@ -2261,6 +2360,25 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 038B974054F8161836A4FE44 /* Decrypt Secrets */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Decrypt Secrets"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "export PATH=\"$HOME/.local/bin:$PATH\"\n\necho \"=== DECRYPT-SECRETS-AGGREGATE at $(date +%H:%M:%S) TARGET_NAME=${TARGET_NAME:-unset} CONFIGURATION=${CONFIGURATION:-unset}\"\n\nif ! command -v a8c-secrets > /dev/null 2>&1; then\n echo \"warning: a8c-secrets not installed; skipping decrypt\"\n exit 0\nfi\n\na8c-secrets decrypt --non-interactive\n"; + }; 09607CE7281C9CA6002D2E5A /* [Lint] Check AppLocalizedString usage */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -2738,6 +2856,12 @@ target = 0107E0B128F97D5000DE87DB /* JetpackStatsWidgets */; targetProxy = 0107E0EC28F97E6100DE87DB /* PBXContainerItemProxy */; }; + 0502FF518F1263A191852804 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Decrypt Secrets"; + target = 0A4FB5FE91E0FB8978A881A4 /* Decrypt Secrets */; + targetProxy = D1DAAEDC31CAA402FE8A1DD8 /* PBXContainerItemProxy */; + }; 0C3313C52E0439A9000C3760 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 0C3313B62E0439A8000C3760 /* Miniature */; @@ -2748,6 +2872,18 @@ target = 0CED016F2D95B897003015CF /* Keystone */; targetProxy = 0C5A8A7A2D9B22F100C25301 /* PBXContainerItemProxy */; }; + 27FB1E0DB05514EA97FBA227 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Decrypt Secrets"; + target = 0A4FB5FE91E0FB8978A881A4 /* Decrypt Secrets */; + targetProxy = B904E75B46BF37ED7B5187FD /* PBXContainerItemProxy */; + }; + 3828A866957B1D2DD25E64C4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Decrypt Secrets"; + target = 0A4FB5FE91E0FB8978A881A4 /* Decrypt Secrets */; + targetProxy = AC3931C50F6374EE6BE0878B /* PBXContainerItemProxy */; + }; 3FCFFAFE2994A949002840C9 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = FFA8E22A1F94E3DE0002170F /* SwiftLint */; @@ -2758,11 +2894,29 @@ target = FFA8E22A1F94E3DE0002170F /* SwiftLint */; targetProxy = 3FCFFAFF2994AB25002840C9 /* PBXContainerItemProxy */; }; + 48675A72EB62C7BDFF515517 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Decrypt Secrets"; + target = 0A4FB5FE91E0FB8978A881A4 /* Decrypt Secrets */; + targetProxy = 1D5A9F915AFDD37ADAE5B6B3 /* PBXContainerItemProxy */; + }; 4A8281022E5FE9B60037E180 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1D6058900D05DD3D006BFB54 /* WordPress */; targetProxy = 4A8281012E5FE9B60037E180 /* PBXContainerItemProxy */; }; + 65CC6335ECE100E214DE55FE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Decrypt Secrets"; + target = 0A4FB5FE91E0FB8978A881A4 /* Decrypt Secrets */; + targetProxy = D59FA597D783ED86B07C8D4B /* PBXContainerItemProxy */; + }; + 6DB3D57911FC0C06F3D132CD /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Decrypt Secrets"; + target = 0A4FB5FE91E0FB8978A881A4 /* Decrypt Secrets */; + targetProxy = 0622080DC83F4B988D9A7732 /* PBXContainerItemProxy */; + }; 7358E6BE210BD318002323EB /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 7358E6B7210BD318002323EB /* WordPressNotificationServiceExtension */; @@ -2788,16 +2942,40 @@ target = 80F6D01F28EE866A00953C1A /* JetpackNotificationServiceExtension */; targetProxy = 80F6D05E28EE88FC00953C1A /* PBXContainerItemProxy */; }; + 8852AC3D54E4A0AD8F746230 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Decrypt Secrets"; + target = 0A4FB5FE91E0FB8978A881A4 /* Decrypt Secrets */; + targetProxy = 769D3F36016EAF96E0A6942F /* PBXContainerItemProxy */; + }; 932225B01C7CE50300443B02 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 932225A61C7CE50300443B02 /* WordPressShareExtension */; targetProxy = 932225AF1C7CE50300443B02 /* PBXContainerItemProxy */; }; + CF65101CD8CB91DC81A54D2C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Decrypt Secrets"; + target = 0A4FB5FE91E0FB8978A881A4 /* Decrypt Secrets */; + targetProxy = B6C4FB8D0B592DC550A800C3 /* PBXContainerItemProxy */; + }; + D4295A73403A34F65E19CC82 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Decrypt Secrets"; + target = 0A4FB5FE91E0FB8978A881A4 /* Decrypt Secrets */; + targetProxy = 67B2B1BD1B72EDCD56E09378 /* PBXContainerItemProxy */; + }; E16AB93F14D978520047A2E5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1D6058900D05DD3D006BFB54 /* WordPress */; targetProxy = E16AB93E14D978520047A2E5 /* PBXContainerItemProxy */; }; + FD201323F47B01659717FF80 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Decrypt Secrets"; + target = 0A4FB5FE91E0FB8978A881A4 /* Decrypt Secrets */; + targetProxy = B6AD221EACD79608CD4592DA /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -5345,6 +5523,16 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + D53494F78D616808DCB4A45E /* Build configuration list for PBXAggregateTarget "Decrypt Secrets" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2B337815727E4ACDF651E14C /* Release */, + EE6EA9F4BDC8A9037667035C /* Debug */, + 582CEF48BA2BE648DA780C1F /* Release-Alpha */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; E16AB93D14D978240047A2E5 /* Build configuration list for PBXNativeTarget "WordPressTest" */ = { isa = XCConfigurationList; buildConfigurations = ( From 98084072d6938b0d53661cdbea9794ce17c7659b Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 5 Aug 2026 14:43:11 +1000 Subject: [PATCH 15/18] Move decrypt run phase to a script and fix project format The AI use `xcodeproj` to make its changes, which smudged some of the comments and references. I opened the project in Xcode and added then removed a file to trigger a project file update. --- Scripts/BuildPhases/DecryptSecrets.sh | 19 +++++++ WordPress/WordPress.xcodeproj/project.pbxproj | 55 +++++++++++++------ 2 files changed, 56 insertions(+), 18 deletions(-) create mode 100755 Scripts/BuildPhases/DecryptSecrets.sh diff --git a/Scripts/BuildPhases/DecryptSecrets.sh b/Scripts/BuildPhases/DecryptSecrets.sh new file mode 100755 index 000000000000..63113f3d206b --- /dev/null +++ b/Scripts/BuildPhases/DecryptSecrets.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Runs from the `Decrypt Secrets` aggregate target so it happens once per build: +# `a8c-secrets decrypt` is not safe to run concurrently, and the ten targets that +# consume the secrets build in parallel. + +# Build phases don't inherit the shell's PATH, so point at a8c-secrets' default +# install location. +export PATH="$HOME/.local/bin:$PATH" + +# External contributors build with their own credentials and never install the tool. +if ! command -v a8c-secrets > /dev/null 2>&1; then + echo "warning: a8c-secrets not installed; skipping secrets decryption." + exit 0 +fi + +a8c-secrets decrypt --non-interactive diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index d53124fd28b9..917402529ba6 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ dependencies = ( ); name = "Decrypt Secrets"; + productName = "Decrypt Secrets"; }; FFA8E22A1F94E3DE0002170F /* SwiftLint */ = { isa = PBXAggregateTarget; @@ -939,7 +940,7 @@ /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* Begin PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet section */ - 0C798C582ED8DD2E0012F3E2 /* Build phase membership exception set */ = { + 0C798C582ED8DD2E0012F3E2 /* Exceptions for "WordPressKitTests" folder in "Compile Sources" phase from "WordPressKitTests" target */ = { isa = PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet; buildPhase = 4A8280F92E5FE9B60037E180 /* Sources */; membershipExceptions = ( @@ -953,22 +954,16 @@ /* Begin PBXFileSystemSynchronizedRootGroup section */ 0C1CB0CD2D95C63C00494A8C /* Sources */ = { isa = PBXFileSystemSynchronizedRootGroup; - exceptions = ( - ); path = Sources; sourceTree = ""; }; 0C3313B82E0439A8000C3760 /* Miniature */ = { isa = PBXFileSystemSynchronizedRootGroup; - exceptions = ( - ); path = Miniature; sourceTree = ""; }; 0C3313C62E0439A9000C3760 /* MiniatureTests */ = { isa = PBXFileSystemSynchronizedRootGroup; - exceptions = ( - ); path = MiniatureTests; sourceTree = ""; }; @@ -1022,15 +1017,11 @@ }; 0CED35262D959427003015CF /* Misc */ = { isa = PBXFileSystemSynchronizedRootGroup; - exceptions = ( - ); path = Misc; sourceTree = ""; }; 0CFC380E2DA408BB00DB3386 /* Recoleta */ = { isa = PBXFileSystemSynchronizedRootGroup; - exceptions = ( - ); path = Recoleta; sourceTree = ""; }; @@ -1053,7 +1044,7 @@ 4A8280FE2E5FE9B60037E180 /* WordPressKitTests */ = { isa = PBXFileSystemSynchronizedRootGroup; exceptions = ( - 0C798C582ED8DD2E0012F3E2 /* Build phase membership exception set */, + 0C798C582ED8DD2E0012F3E2 /* Exceptions for "WordPressKitTests" folder in "Compile Sources" phase from "WordPressKitTests" target */, ); path = WordPressKitTests; sourceTree = ""; @@ -1330,7 +1321,7 @@ path = Classes; sourceTree = ""; }; - 29B97314FDCFA39411CA2CEA = { + 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { isa = PBXGroup; children = ( 3FD4B20E2DCC468200781DFA /* Modules */, @@ -2186,7 +2177,9 @@ bg, sk, ); - mainGroup = 29B97314FDCFA39411CA2CEA; + mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; + packageReferences = ( + ); preferredProjectObjectVersion = 77; productRefGroup = 19C28FACFE9D520D11CA2CBB /* Products */; projectDirPath = ""; @@ -2377,7 +2370,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "export PATH=\"$HOME/.local/bin:$PATH\"\n\necho \"=== DECRYPT-SECRETS-AGGREGATE at $(date +%H:%M:%S) TARGET_NAME=${TARGET_NAME:-unset} CONFIGURATION=${CONFIGURATION:-unset}\"\n\nif ! command -v a8c-secrets > /dev/null 2>&1; then\n echo \"warning: a8c-secrets not installed; skipping decrypt\"\n exit 0\nfi\n\na8c-secrets decrypt --non-interactive\n"; + shellScript = "\"${SRCROOT}/../Scripts/BuildPhases/DecryptSecrets.sh\"\n"; }; 09607CE7281C9CA6002D2E5A /* [Lint] Check AppLocalizedString usage */ = { isa = PBXShellScriptBuildPhase; @@ -3951,6 +3944,32 @@ }; name = Release; }; + 3F004C7A3022F6B50020B519 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + PRODUCT_NAME = "Decrypt Secrets"; + }; + name = Debug; + }; + 3F004C7B3022F6B50020B519 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + PRODUCT_NAME = "Decrypt Secrets"; + }; + name = Release; + }; + 3F004C7C3022F6B50020B519 /* Release-Alpha */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "Decrypt Secrets"; + }; + name = "Release-Alpha"; + }; 4A8281032E5FE9B60037E180 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = F14B5F70208E648200439554 /* WordPress.debug.xcconfig */; @@ -5526,9 +5545,9 @@ D53494F78D616808DCB4A45E /* Build configuration list for PBXAggregateTarget "Decrypt Secrets" */ = { isa = XCConfigurationList; buildConfigurations = ( - 2B337815727E4ACDF651E14C /* Release */, - EE6EA9F4BDC8A9037667035C /* Debug */, - 582CEF48BA2BE648DA780C1F /* Release-Alpha */, + 3F004C7A3022F6B50020B519 /* Debug */, + 3F004C7B3022F6B50020B519 /* Release */, + 3F004C7C3022F6B50020B519 /* Release-Alpha */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; From f21ff47f625662e1c5c4468ff9a981c44a3455a0 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 5 Aug 2026 15:14:49 +1000 Subject: [PATCH 16/18] Rename install-secrets.sh to install-a8c-secrets.sh The script installs the `a8c-secrets` binary; naming it after the secrets invited reading it as the step that puts them on disk. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Code Opus 5 --- .buildkite/commands/build-and-upload-testflight.sh | 2 +- .buildkite/commands/build-for-testing.sh | 2 +- .../commands/{install-secrets.sh => install-a8c-secrets.sh} | 0 .buildkite/commands/prototype-build-jetpack.sh | 2 +- .buildkite/commands/prototype-build-wordpress.sh | 2 +- .buildkite/commands/release-build-jetpack.sh | 2 +- .buildkite/commands/release-build-wordpress.sh | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) rename .buildkite/commands/{install-secrets.sh => install-a8c-secrets.sh} (100%) diff --git a/.buildkite/commands/build-and-upload-testflight.sh b/.buildkite/commands/build-and-upload-testflight.sh index c69ad7af7c1e..45541bcc17a0 100755 --- a/.buildkite/commands/build-and-upload-testflight.sh +++ b/.buildkite/commands/build-and-upload-testflight.sh @@ -7,7 +7,7 @@ APP="${1:?Usage: build-and-upload-testflight.sh }" "$(dirname "${BASH_SOURCE[0]}")/shared-set-up.sh" "$(dirname "${BASH_SOURCE[0]}")/shared-set-up-distribution.sh" -source "$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" +source "$(dirname "${BASH_SOURCE[0]}")/install-a8c-secrets.sh" echo "--- :testflight: Building and uploading ${APP} to TestFlight" bundle exec fastlane build_and_upload_app_for_testflight app:"${APP}" diff --git a/.buildkite/commands/build-for-testing.sh b/.buildkite/commands/build-for-testing.sh index 90c93afaafac..dcd4e3db2045 100755 --- a/.buildkite/commands/build-for-testing.sh +++ b/.buildkite/commands/build-for-testing.sh @@ -16,7 +16,7 @@ fi "$(dirname "${BASH_SOURCE[0]}")/shared-set-up.sh" -source "$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" +source "$(dirname "${BASH_SOURCE[0]}")/install-a8c-secrets.sh" echo "--- :hammer_and_wrench: Building" bundle exec fastlane "build_${APP}_for_testing" diff --git a/.buildkite/commands/install-secrets.sh b/.buildkite/commands/install-a8c-secrets.sh similarity index 100% rename from .buildkite/commands/install-secrets.sh rename to .buildkite/commands/install-a8c-secrets.sh diff --git a/.buildkite/commands/prototype-build-jetpack.sh b/.buildkite/commands/prototype-build-jetpack.sh index e08e4eb6b5ee..4dcba08ca011 100644 --- a/.buildkite/commands/prototype-build-jetpack.sh +++ b/.buildkite/commands/prototype-build-jetpack.sh @@ -7,7 +7,7 @@ fi "$(dirname "${BASH_SOURCE[0]}")/shared-set-up.sh" "$(dirname "${BASH_SOURCE[0]}")/shared-set-up-distribution.sh" -source "$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" +source "$(dirname "${BASH_SOURCE[0]}")/install-a8c-secrets.sh" echo "--- :hammer_and_wrench: Building" bundle exec fastlane build_and_upload_jetpack_prototype_build diff --git a/.buildkite/commands/prototype-build-wordpress.sh b/.buildkite/commands/prototype-build-wordpress.sh index 2f02c85dc648..1300cb3f7e65 100644 --- a/.buildkite/commands/prototype-build-wordpress.sh +++ b/.buildkite/commands/prototype-build-wordpress.sh @@ -7,7 +7,7 @@ fi "$(dirname "${BASH_SOURCE[0]}")/shared-set-up.sh" "$(dirname "${BASH_SOURCE[0]}")/shared-set-up-distribution.sh" -source "$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" +source "$(dirname "${BASH_SOURCE[0]}")/install-a8c-secrets.sh" echo "--- :hammer_and_wrench: Building" bundle exec fastlane build_and_upload_wordpress_prototype_build diff --git a/.buildkite/commands/release-build-jetpack.sh b/.buildkite/commands/release-build-jetpack.sh index 67be73947e03..6dcd2b55cd20 100755 --- a/.buildkite/commands/release-build-jetpack.sh +++ b/.buildkite/commands/release-build-jetpack.sh @@ -3,7 +3,7 @@ "$(dirname "${BASH_SOURCE[0]}")/shared-set-up.sh" "$(dirname "${BASH_SOURCE[0]}")/shared-set-up-distribution.sh" -source "$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" +source "$(dirname "${BASH_SOURCE[0]}")/install-a8c-secrets.sh" echo "--- :hammer_and_wrench: Building" bundle exec fastlane build_and_upload_jetpack_for_app_store diff --git a/.buildkite/commands/release-build-wordpress.sh b/.buildkite/commands/release-build-wordpress.sh index e4ce9e4f893b..0ec8137dd8a2 100755 --- a/.buildkite/commands/release-build-wordpress.sh +++ b/.buildkite/commands/release-build-wordpress.sh @@ -3,7 +3,7 @@ "$(dirname "${BASH_SOURCE[0]}")/shared-set-up.sh" "$(dirname "${BASH_SOURCE[0]}")/shared-set-up-distribution.sh" -source "$(dirname "${BASH_SOURCE[0]}")/install-secrets.sh" +source "$(dirname "${BASH_SOURCE[0]}")/install-a8c-secrets.sh" echo "--- :hammer_and_wrench: Building" bundle exec fastlane build_and_upload_app_store_connect \ From a83b90d58f6153bf64042efdd86f2ced5e127f7a Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 5 Aug 2026 15:15:00 +1000 Subject: [PATCH 17/18] Stop decrypting the secrets on CI The `Decrypt Secrets` aggregate target now decrypts once per build, so doing it here as well only repeated the work. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Code Opus 5 --- .buildkite/commands/install-a8c-secrets.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.buildkite/commands/install-a8c-secrets.sh b/.buildkite/commands/install-a8c-secrets.sh index 267732b50bcf..45c6e4aac7ec 100755 --- a/.buildkite/commands/install-a8c-secrets.sh +++ b/.buildkite/commands/install-a8c-secrets.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash -# The `Generate Credentials` build phase resolves `a8c-secrets` off PATH, so the -# export below has to survive in the caller's shell. +# The `Decrypt Secrets` and `Generate Credentials` build phases resolve +# `a8c-secrets` off PATH, so the export below has to survive in the caller's shell. if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then echo "This script must be sourced, not executed, because it exports PATH." >&2 exit 1 @@ -9,11 +9,10 @@ fi set -euo pipefail +echo "--- :closed_lock_with_key: Installing a8c-secrets" + # `install_a8c-secrets_binary` comes from the a8c-ci-toolkit plugin. It pins the # a8c-secrets version and checks the download against a checksum vendored there. install_dir="$HOME/.local/bin" install_a8c-secrets_binary --install-dir "$install_dir" export PATH="$install_dir:$PATH" - -echo "--- :closed_lock_with_key: Installing Secrets" -a8c-secrets decrypt From 3064fe362227d9bb1942a81776e03371924058a7 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 5 Aug 2026 15:15:06 +1000 Subject: [PATCH 18/18] Stop decrypting the secrets from rake The `Decrypt Secrets` build phase covers local builds too, and it cannot go stale between a bootstrap and a build the way this task could. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Code Opus 5 --- Rakefile | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/Rakefile b/Rakefile index ecb6f01fe5b6..7d317e9cbb5c 100644 --- a/Rakefile +++ b/Rakefile @@ -17,7 +17,7 @@ desc 'Install required dependencies' task dependencies: %w[dependencies:check dependencies:gutenberg_xcframeworks] namespace :dependencies do - task check: %w[ruby:check bundler:check bundle:check credentials:apply] + task check: %w[ruby:check bundler:check bundle:check] namespace :ruby do task :check do @@ -75,23 +75,6 @@ namespace :dependencies do CLOBBER << '.bundle' end - namespace :credentials do - task :apply do - # External contributors build with their own credentials and never install the tool. - unless command?('a8c-secrets') - puts 'Skipping secrets decryption: `a8c-secrets` is not installed. Internal contributors, see https://github.com/Automattic/a8c-secrets.' - next - end - - sh('a8c-secrets', 'decrypt') do |ok, _res| - next if ok - - # Not fatal: the build phase falls back to the example secrets and errors on its own for Release builds. - puts 'Failed to decrypt secrets. See https://github.com/Automattic/a8c-secrets for setup and troubleshooting.' - end - end - end - desc 'Download and extract Gutenberg xcframeworks' task :gutenberg_xcframeworks do sh("#{PROJECT_DIR}/Scripts/download-gutenberg-xcframeworks.sh")