From 21542d97cfe1328eeada2ae9b9bacbde9c7d3e43 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Fri, 30 Oct 2026 11:42:54 +1100 Subject: [PATCH 1/5] Add Ruby and fastlane tooling fastlane will fetch the Developer ID certificate and sign and notarize the macOS binaries on Buildkite. `.xcode-version` selects the Buildkite agent image. --- Generated with the help of Claude Code, https://code.claude.com Co-Authored-By: Claude Opus 5.5 --- .bundle/config | 3 + .gitignore | 5 + .ruby-version | 1 + .xcode-version | 1 + Gemfile | 5 + Gemfile.lock | 373 +++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 388 insertions(+) create mode 100644 .bundle/config create mode 100644 .ruby-version create mode 100644 .xcode-version create mode 100644 Gemfile create mode 100644 Gemfile.lock diff --git a/.bundle/config b/.bundle/config new file mode 100644 index 00000000..f10e50fe --- /dev/null +++ b/.bundle/config @@ -0,0 +1,3 @@ +--- +BUNDLE_PATH: "vendor/bundle" +BUNDLE_FORCE_RUBY_PLATFORM: "true" diff --git a/.gitignore b/.gitignore index 13b643ec..ac2987fe 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,8 @@ node_modules/ /beeper-desktop-cli .upstream/ *.exe + +# Ruby and fastlane +/vendor/bundle/ +/fastlane/README.md +/fastlane/report.xml diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 00000000..7bcbb380 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.4.9 diff --git a/.xcode-version b/.xcode-version new file mode 100644 index 00000000..7363977a --- /dev/null +++ b/.xcode-version @@ -0,0 +1 @@ +26.6 diff --git a/Gemfile b/Gemfile new file mode 100644 index 00000000..ee407d5b --- /dev/null +++ b/Gemfile @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gem 'fastlane', '~> 2.241' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 00000000..41ae74e8 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,373 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.8) + abbrev (0.1.2) + addressable (2.9.0) + public_suffix (>= 2.0.2, < 8.0) + artifactory (3.0.17) + atomos (0.1.3) + aws-eventstream (1.4.1) + aws-partitions (1.1299.1) + aws-sdk-core (3.263.0) + aws-eventstream (~> 1, >= 1.4.1) + aws-partitions (~> 1, >= 1.992.0) + aws-sigv4 (~> 1.9) + base64 + bigdecimal + jmespath (~> 1, >= 1.6.1) + logger + rexml (~> 3.4, >= 3.4.2) + aws-sdk-kms (1.138.0) + aws-sdk-core (~> 3, >= 3.263.0) + aws-sigv4 (~> 1.5) + aws-sdk-s3 (1.237.0) + aws-sdk-core (~> 3, >= 3.263.0) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.5) + aws-sigv4 (1.12.1) + aws-eventstream (~> 1, >= 1.0.2) + babosa (1.0.4) + base64 (0.3.0) + benchmark (0.5.0) + bigdecimal (4.1.3) + cgi (0.5.2) + claide (1.1.0) + colored (1.2) + colored2 (3.1.2) + commander (4.6.0) + highline (~> 2.0.0) + csv (3.3.7) + declarative (0.0.20) + digest-crc (0.7.0) + rake (>= 12.0.0, < 14.0.0) + domain_name (0.7.20261007) + dotenv (2.8.1) + emoji_regex (3.2.3) + erb (6.0.7) + excon (1.10.0) + faraday (2.15.1) + faraday-net_http (>= 2.0, < 3.6) + json + logger + faraday-cookie_jar (0.0.8) + faraday (>= 0.8.0) + http-cookie (>= 1.0.0) + faraday-follow_redirects (0.5.0) + faraday (>= 1, < 3) + faraday-multipart (1.2.0) + multipart-post (~> 2.0) + faraday-net_http (3.5.0) + net-http (~> 0.5) + faraday-retry (2.4.0) + faraday (~> 2.0) + fastimage (2.4.3) + fastlane (2.241.2) + CFPropertyList (>= 2.3, < 5.0.0) + abbrev (~> 0.1) + addressable (>= 2.9.0, < 3.0.0) + artifactory (~> 3.0) + aws-sdk-s3 (~> 1.197) + babosa (>= 1.0.3, < 2.0.0) + base64 (~> 0.2) + benchmark (>= 0.1.0) + bundler (>= 2.4.0, < 5.0.0) + cgi (~> 0.4) + colored (~> 1.2) + commander (~> 4.6) + csv (~> 3.3) + dotenv (>= 2.1.1, < 3.0.0) + emoji_regex (>= 0.1, < 4.0) + erb (>= 4.0, < 7.0) + excon (>= 1.0.0, < 2.0.0) + faraday (~> 2.7) + faraday-cookie_jar (~> 0.0.8) + faraday-follow_redirects (~> 0.3) + faraday-multipart (~> 1.0) + faraday-retry (~> 2.0) + fastimage (>= 2.1.0, < 3.0.0) + fastlane-sirp (>= 1.1.0) + gh_inspector (>= 1.1.2, < 2.0.0) + google-apis-androidpublisher_v3 (~> 0.99) + google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-env (>= 1.6.0, < 2.5.0) + google-cloud-storage (~> 1.31) + highline (~> 2.0) + irb (>= 1.8) + json (< 3.0.0) + jwt (>= 2.10.3, < 4) + logger (>= 1.6, < 2.0) + mini_magick (>= 4.9.4, < 5.0.0) + multi_json (~> 1.12) + multipart-post (>= 2.0.0, < 3.0.0) + mutex_m (~> 0.3) + naturally (~> 2.2) + nkf (~> 0.2) + optparse (>= 0.1.1, < 1.0.0) + ostruct (>= 0.1.0) + plist (>= 3.1.0, < 4.0.0) + rubyzip (>= 3.4.0, < 4.0.0) + security (~> 0.3) + simctl (~> 1.6.3) + terminal-notifier (>= 3.1.0, < 4.0.0) + terminal-table (~> 4) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) + word_wrap (~> 1.0.0) + xcodeproj (>= 1.13.0, < 2.0.0) + xcpretty (~> 0.4.1) + xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) + fastlane-sirp (1.1.0) + gh_inspector (1.1.3) + google-apis-androidpublisher_v3 (0.110.0) + google-apis-core (>= 0.15.0, < 2.a) + google-apis-core (1.4.0) + addressable (~> 2.9) + faraday (~> 2.13) + faraday-follow_redirects (~> 0.3) + googleauth (~> 1.14) + mini_mime (~> 1.1) + multi_json (~> 1.11) + representable (~> 3.0) + retriable (>= 3.1, < 5.0) + google-apis-iamcredentials_v1 (0.28.0) + google-apis-core (>= 0.15.0, < 2.a) + google-apis-playcustomapp_v1 (0.18.0) + google-apis-core (>= 0.15.0, < 2.a) + google-apis-storage_v1 (0.70.0) + google-apis-core (>= 0.15.0, < 2.a) + google-cloud-core (1.9.1) + google-cloud-env (>= 1.0, < 3.a) + google-cloud-errors (~> 1.0) + google-cloud-env (2.4.1) + base64 (~> 0.2) + faraday (>= 1.0, < 3.a) + google-cloud-errors (1.7.1) + google-cloud-storage (1.62.1) + addressable (~> 2.8) + digest-crc (~> 0.4) + google-apis-core (>= 0.18, < 2) + google-apis-iamcredentials_v1 (~> 0.18) + google-apis-storage_v1 (>= 0.42) + google-cloud-core (~> 1.6) + googleauth (~> 1.9) + mini_mime (~> 1.0) + google-logging-utils (0.2.2) + googleauth (1.17.7) + faraday (>= 1.0, < 3.a) + google-cloud-env (~> 2.2) + google-logging-utils (~> 0.1) + jwt (>= 1.4, < 4.0) + os (>= 0.9, < 2.0) + pstore (~> 0.1) + signet (>= 0.16, < 2.a) + highline (2.0.3) + http-cookie (1.1.6) + domain_name (~> 0.5) + io-console (0.9.5) + irb (1.18.0) + pp (>= 0.6.0) + prism (>= 1.3.0) + rdoc (>= 4.0.0) + reline (>= 0.4.2) + jmespath (1.6.2) + json (2.21.2) + jwt (3.3.0) + base64 + logger (1.7.0) + mini_magick (4.13.2) + mini_mime (1.1.5) + multi_json (1.21.2) + multipart-post (2.4.1) + mutex_m (0.3.0) + nanaimo (0.4.0) + naturally (2.3.0) + net-http (0.10.0) + net-protocol (>= 0.3.0) + uri (>= 0.11.1) + net-protocol (0.4.0) + timeout + nkf (0.3.0) + optparse (0.8.1) + os (1.1.4) + ostruct (0.6.3) + plist (3.7.2) + pp (0.6.4) + prettyprint + prettyprint (0.2.1) + prism (2.1.0) + pstore (0.3.0) + public_suffix (7.0.5) + rake (13.4.2) + rbs (4.2.0) + logger + prism (>= 1.6.0) + tsort + rdoc (8.1.0) + erb + prism (>= 1.6.0) + rbs (>= 4.0.0) + tsort + reline (0.7.0) + io-console (~> 0.5) + representable (3.3.1) + declarative (< 0.1.0) + trailblazer-option (>= 0.1.1, < 0.2.0) + uber (< 0.2.0) + retriable (4.2.0) + rexml (3.4.4) + rouge (3.28.0) + rubyzip (3.7.0) + security (0.4.0) + signet (0.22.2) + addressable (~> 2.8) + faraday (>= 0.17.5, < 3.a) + jwt (>= 1.5, < 4.0) + simctl (1.6.10) + CFPropertyList + naturally + terminal-notifier (3.1.0) + terminal-table (4.0.0) + unicode-display_width (>= 1.1.1, < 4) + timeout (0.6.1) + trailblazer-option (0.1.2) + tsort (0.2.0) + tty-cursor (0.7.1) + tty-screen (0.8.2) + tty-spinner (0.9.3) + tty-cursor (~> 0.7) + uber (0.1.0) + unicode-display_width (3.3.0) + unicode-emoji (~> 4.3) + unicode-emoji (4.3.0) + uri (1.1.2) + word_wrap (1.0.0) + xcodeproj (1.28.1) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + base64 + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.4.0) + nkf + rexml (>= 3.3.6, < 4.0) + xcpretty (0.4.1) + rouge (~> 3.28.0) + xcpretty-travis-formatter (1.0.1) + xcpretty (~> 0.2, >= 0.0.7) + +PLATFORMS + ruby + +DEPENDENCIES + fastlane (~> 2.241) + +CHECKSUMS + CFPropertyList (3.0.8) sha256=2c99d0d980536d3d7ab252f7bd59ac8be50fbdd1ff487c98c949bb66bb114261 + abbrev (0.1.2) sha256=ad1b4eaaaed4cb722d5684d63949e4bde1d34f2a95e20db93aecfe7cbac74242 + addressable (2.9.0) sha256=7fdf6ac3660f7f4e867a0838be3f6cf722ace541dd97767fa42bc6cfa980c7af + artifactory (3.0.17) sha256=3023d5c964c31674090d655a516f38ca75665c15084140c08b7f2841131af263 + atomos (0.1.3) sha256=7d43b22f2454a36bace5532d30785b06de3711399cb1c6bf932573eda536789f + aws-eventstream (1.4.1) sha256=ceb6a99c61df4bb00344e54aed0351574beca24f87a0d1487d1d2ed80929ce96 + aws-partitions (1.1299.1) sha256=bf50f8edee6299b6b709973db2192a86caa005a4eee5712338728f7071bf69a6 + aws-sdk-core (3.263.0) sha256=9b6d396ed8b3e5ba19b0640fbdbfa1875b0c485353e1bb836f1e72b403c8892d + aws-sdk-kms (1.138.0) sha256=b3b4da50b962faa1333d6072f2eb04d8ad71569b32ee0d639657df3f8be8b37d + aws-sdk-s3 (1.237.0) sha256=1e8a96a5411124d66f85f397bd00a1d6df53da1946725b6d5980d921a8e11191 + aws-sigv4 (1.12.1) sha256=6973ff95cb0fd0dc58ba26e90e9510a2219525d07620c8babeb70ef831826c00 + babosa (1.0.4) sha256=18dea450f595462ed7cb80595abd76b2e535db8c91b350f6c4b3d73986c5bc99 + base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b + benchmark (0.5.0) sha256=465df122341aedcb81a2a24b4d3bd19b6c67c1530713fd533f3ff034e419236c + bigdecimal (4.1.3) sha256=61ebe1e5e559bdc3cc6f2c0ee7f427321fc838f59611c294356eb04d6e21cf66 + bundler (4.0.23) sha256=407ba8a1d928f412847f819aa5f8b6aef7c59fb51feb517112af8a165487287b + cgi (0.5.2) sha256=61ca30298171190fd4fa0d8018e57ada456eae9b7a2b78526debf7f0a0e6f8bb + claide (1.1.0) sha256=6d3c5c089dde904d96aa30e73306d0d4bd444b1accb9b3125ce14a3c0183f82e + colored (1.2) sha256=9d82b47ac589ce7f6cab64b1f194a2009e9fd00c326a5357321f44afab2c1d2c + colored2 (3.1.2) sha256=b13c2bd7eeae2cf7356a62501d398e72fde78780bd26aec6a979578293c28b4a + commander (4.6.0) sha256=7d1ddc3fccae60cc906b4131b916107e2ef0108858f485fdda30610c0f2913d9 + csv (3.3.7) sha256=15a3f16f6628da8664d455eb634e7f22031bcf53044923caf56975109e71b9f8 + declarative (0.0.20) sha256=8021dd6cb17ab2b61233c56903d3f5a259c5cf43c80ff332d447d395b17d9ff9 + digest-crc (0.7.0) sha256=64adc23a26a241044cbe6732477ca1b3c281d79e2240bcff275a37a5a0d78c07 + domain_name (0.7.20261007) sha256=0976c6ab837dbde991b433d03acc38fdb91fa8839df31a1ed75ce0318dc0441c + dotenv (2.8.1) sha256=c5944793349ae03c432e1780a2ca929d60b88c7d14d52d630db0508c3a8a17d8 + emoji_regex (3.2.3) sha256=ecd8be856b7691406c6bf3bb3a5e55d6ed683ffab98b4aa531bb90e1ddcc564b + erb (6.0.7) sha256=c5ca6dc25b0ef974a44dc8f59fe847577122483b1968a38dec305c60bf91ee92 + excon (1.10.0) sha256=868d456c6db29f965d7cc6c5eddbb4d77df08e2a2b2dca7ca3547f2a55afc4b4 + faraday (2.15.1) sha256=8708154deda739c5e86cc42b74960e23e8491fce0eba9e11639a6a34b1ac288f + faraday-cookie_jar (0.0.8) sha256=0140605823f8cc63c7028fccee486aaed8e54835c360cffc1f7c8c07c4299dbb + faraday-follow_redirects (0.5.0) sha256=5cde93c894b30943a5d2b93c2fe9284216a6b756f7af406a1e55f211d97d10ad + faraday-multipart (1.2.0) sha256=7d89a949693714176f612323ca13746a2ded204031a6ba528adee788694ef757 + faraday-net_http (3.5.0) sha256=2e7094c34e38754ee048cc3df47376f8657005d9375f8473bce1c3b526a22e36 + faraday-retry (2.4.0) sha256=7b79c48fb7e56526faf247b12d94a680071ff40c9fda7cf1ec1549439ad11ebe + fastimage (2.4.3) sha256=304457e3c35bfdaefda3f1dacab2222a96b230b8ce6977b6b54748c1cc7ec539 + fastlane (2.241.2) sha256=9c23f6d1b4aa5d8570ff8584186d5fdb1fdf7a01dd7ad168501b43fe360fe122 + fastlane-sirp (1.1.0) sha256=10bc94f9682efd8e1badfb31452a76dd8981f1f3a33717c765fde6d75b54d847 + gh_inspector (1.1.3) sha256=04cca7171b87164e053aa43147971d3b7f500fcb58177698886b48a9fc4a1939 + google-apis-androidpublisher_v3 (0.110.0) sha256=0b0b84af02fb7f3a062849bc60d545ff8b37670ea7e90bd947199cc671916513 + google-apis-core (1.4.0) sha256=74e838a334926e79ce685d3ff9f418956cc23e48c5fd7cade779fea933e96582 + google-apis-iamcredentials_v1 (0.28.0) sha256=0a92ffe6cc39c569554af2a77a25dfc61519ed8bbb64ab04cffdd352dc5ef106 + google-apis-playcustomapp_v1 (0.18.0) sha256=44b277b9dee4a59ac5e9d98be1485edc5e382d2f9d73c79ae8908a455786a254 + google-apis-storage_v1 (0.70.0) sha256=6a2925cc39c27a133239738130a4cf37601e00627a36d91e4f528f5a4620ad0c + google-cloud-core (1.9.1) sha256=6590e393cbeadf018e6880038e19348d2ccfc83000625c569a9b21ab3b450af0 + google-cloud-env (2.4.1) sha256=987cc58afc50ce2903128ab4dcd442159be4457246b8137e41d49d5c3fc590dd + google-cloud-errors (1.7.1) sha256=818bcf30998d10f28f30532a2595b49438cb7abf42f6ac495843078839987207 + google-cloud-storage (1.62.1) sha256=10dbf2ebda3af1b4b841335364cb889827c6cb17bf6c9f8bc5313b6bef7a4d3c + google-logging-utils (0.2.2) sha256=ad2436ef22e918e2b1c3ad2bbaf5949f42f5389d49fd37e41b43bbdd3068e27c + googleauth (1.17.7) sha256=9db21857ddbe055a8b0d44ddb75d4ceda97511167431e30121c77c25a9ce9fe5 + highline (2.0.3) sha256=2ddd5c127d4692721486f91737307236fe005352d12a4202e26c48614f719479 + http-cookie (1.1.6) sha256=ba4b82be64de61dc281243dac70e3c382c45142f20268ed9276a3670c93feaa9 + io-console (0.9.5) sha256=83dd9bbf4c4680416629245b39cd4212eb5f4d9a4ea91804870c1f6b846414d5 + irb (1.18.0) sha256=de9454a0703a54704b9811a5ef31a60c86949fbf4013fcf244fabc7c775248e3 + jmespath (1.6.2) sha256=238d774a58723d6c090494c8879b5e9918c19485f7e840f2c1c7532cf84ebcb1 + json (2.21.2) sha256=1f1d3b7cf2b3ba1a69beca0bb6db13d5438b80bff3cd54cdaaa620b9b07c1c6a + jwt (3.3.0) sha256=44cc34fbc341c148233cf66641522b4bce0dfb1ce55e8073f05c56f44f4ee546 + logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203 + mini_magick (4.13.2) sha256=71d6258e0e8a3d04a9a0a09784d5d857b403a198a51dd4f882510435eb95ddd9 + mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef + multi_json (1.21.2) sha256=245531eaf54bdba57aba515ff08b4503505c5e09911daa89c5a561e2f85bea8e + multipart-post (2.4.1) sha256=9872d03a8e552020ca096adadbf5e3cb1cd1cdd6acd3c161136b8a5737cdb4a8 + mutex_m (0.3.0) sha256=cfcb04ac16b69c4813777022fdceda24e9f798e48092a2b817eb4c0a782b0751 + nanaimo (0.4.0) sha256=faf069551bab17f15169c1f74a1c73c220657e71b6e900919897a10d991d0723 + naturally (2.3.0) sha256=459923cf76c2e6613048301742363200c3c7e4904c324097d54a67401e179e01 + net-http (0.10.0) sha256=1a2ff6e37a05724973c43f2bf7bf105f59c36a4cd0a7e9b1c021a0a566987c27 + net-protocol (0.4.0) sha256=f9f90c8c6f64794a45160bf422177a336db12809de3beeeaa26b88fcd2e8c853 + nkf (0.3.0) sha256=357a8dbeba38b727b75930f665146546076a394a1c243faf634ff176e3588895 + optparse (0.8.1) sha256=42bea10d53907ccff4f080a69991441d611fbf8733b60ed1ce9ee365ce03bd1a + os (1.1.4) sha256=57816d6a334e7bd6aed048f4b0308226c5fb027433b67d90a9ab435f35108d3f + ostruct (0.6.3) sha256=95a2ed4a4bd1d190784e666b47b2d3f078e4a9efda2fccf18f84ddc6538ed912 + plist (3.7.2) sha256=d37a4527cc1116064393df4b40e1dbbc94c65fa9ca2eec52edf9a13616718a42 + pp (0.6.4) sha256=dfcb0fce700c41456265922884f9fe195d7fbb0674a3578e6c0f69588e82b570 + prettyprint (0.2.1) sha256=d555d57ea6d7cf001d4774b693546a6bd88bec1e778ddffb5c60b68ceec4b7d4 + prism (2.1.0) sha256=1c0a7c6dea0e93183390fb123f007564dbe663198e2f86ad87204151147601f3 + pstore (0.3.0) sha256=97888d57cdc8b99b3587dde5e1d01fc5ca4a9124dfeb2afb84e3dd982e78f829 + public_suffix (7.0.5) sha256=1a8bb08f1bbea19228d3bed6e5ed908d1cb4f7c2726d18bd9cadf60bc676f623 + rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701 + rbs (4.2.0) sha256=51f7b886dcc05bc09e10b901daa6a81829f6adc03101d6ca9ea4aac6103e0674 + rdoc (8.1.0) sha256=befc37880a5cfd36dcb176c748b5fd5ee39dd3536a75e81824e4972ce230f60a + reline (0.7.0) sha256=5b012d8e55dbf9d450f12bde2cf7d15ff546ae80b3f8f3b30e570d431815583d + representable (3.3.1) sha256=8a5fc8eef99f598147eee0390f606386268b429a840419fcfd3f7a8ccc40f566 + retriable (4.2.0) sha256=90c3b257472a1c02f2a3dfa64dd35a420f7a624cef1a5981e20fdac5730f8cdc + rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142 + rouge (3.28.0) sha256=0d6de482c7624000d92697772ab14e48dca35629f8ddf3f4b21c99183fd70e20 + rubyzip (3.7.0) sha256=65c19294da75297a939006f3516deacc33185fbd721ff1954f7a231db6d3e121 + security (0.4.0) sha256=fd3fdbd2e50e45616082dbeec0bf0813b1134b2420a034ad35c3af2807f3fdbc + signet (0.22.2) sha256=9c6861bb599845ea0cb05ffadd3d64c7a3b07a29bdee0f5352bcbe87b7ade21d + simctl (1.6.10) sha256=b99077f4d13ad81eace9f86bf5ba4df1b0b893a4d1b368bd3ed59b5b27f9236b + terminal-notifier (3.1.0) sha256=073609e9da7bb60176ffadda903c8d9231fcdf18ffa7074dc9478b63fe25c69c + terminal-table (4.0.0) sha256=f504793203f8251b2ea7c7068333053f0beeea26093ec9962e62ea79f94301d2 + timeout (0.6.1) sha256=78f57368a7e7bbadec56971f78a3f5ecbcfb59b7fcbb0a3ed6ddc08a5094accb + trailblazer-option (0.1.2) sha256=20e4f12ea4e1f718c8007e7944ca21a329eee4eed9e0fa5dde6e8ad8ac4344a3 + tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f + tty-cursor (0.7.1) sha256=79534185e6a777888d88628b14b6a1fdf5154a603f285f80b1753e1908e0bf48 + tty-screen (0.8.2) sha256=c090652115beae764336c28802d633f204fb84da93c6a968aa5d8e319e819b50 + tty-spinner (0.9.3) sha256=0e036f047b4ffb61f2aa45f5a770ec00b4d04130531558a94bfc5b192b570542 + uber (0.1.0) sha256=5beeb407ff807b5db994f82fa9ee07cfceaa561dad8af20be880bc67eba935dc + unicode-display_width (3.3.0) sha256=4b7aa66a4b11db50f6f7e98411215cd0dd10eaecb665d36eec5bcacb3fa0b613 + unicode-emoji (4.3.0) sha256=11c02fa73290378c066bb0562cd4c87d8e1b706fbbe0059ca12746a4244de8ce + uri (1.1.2) sha256=89292e98eabbef6248b0a0ed5e7e398e152f83f17560023a6d94a7f492b169fb + word_wrap (1.0.0) sha256=f556d4224c812e371000f12a6ee8102e0daa724a314c3f246afaad76d82accc7 + xcodeproj (1.28.1) sha256=6f12670f00739d9817ca27ac89d6ef01cc86050e22a0bc08a3131487e5b5cddc + xcpretty (0.4.1) sha256=b14c50e721f6589ee3d6f5353e2c2cfcd8541fa1ea16d6c602807dd7327f3892 + xcpretty-travis-formatter (1.0.1) sha256=aacc332f17cb7b2cba222994e2adc74223db88724fe76341483ad3098e232f93 + +BUNDLED WITH + 4.0.23 From 0e107d2f03da2b632f4ae718e9df62be1c713fa5 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Fri, 30 Oct 2026 11:45:14 +1100 Subject: [PATCH 2/5] Add fastlane lanes to sign and notarize macOS CLI Same lanes as the Day One CLI, so Automattic's CLIs sign the same way. `sign_macos_binaries` keeps the `binaries.json` contract of `sign-macos-binaries.ts`: it updates the macOS checksums after signing, so the npm and Homebrew publish steps read the manifest unchanged. No explicit signing identifier: the CLI never touches the Keychain, and the file-name default matches what 0.6.2 shipped with. --- Generated with the help of Claude Code, https://code.claude.com Co-Authored-By: Claude Opus 5.5 --- fastlane/Fastfile | 163 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 fastlane/Fastfile diff --git a/fastlane/Fastfile b/fastlane/Fastfile new file mode 100644 index 00000000..9ee82af4 --- /dev/null +++ b/fastlane/Fastfile @@ -0,0 +1,163 @@ +# frozen_string_literal: true + +require 'digest' +require 'fileutils' +require 'json' +require 'shellwords' + +UI.user_error!('Please run fastlane via `bundle exec`') unless FastlaneCore::Helper.bundler? + +PROJECT_ROOT_FOLDER = File.dirname(File.expand_path(__dir__)) +BINARIES_MANIFEST = File.join(PROJECT_ROOT_FOLDER, 'packages', 'cli', 'dist', 'bin', 'binaries.json') + +APPLE_TEAM_ID = 'PZYM8XX95Q' +SIGNING_IDENTITY = "Developer ID Application: Automattic, Inc. (#{APPLE_TEAM_ID})" + +CODE_SIGNING_STORAGE_OPTIONS = { + storage_mode: 's3', + s3_bucket: 'a8c-fastlane-match', + s3_region: 'us-east-2' +}.freeze + +CODE_SIGNING_ENV_VARS = %w[ + MATCH_S3_ACCESS_KEY + MATCH_S3_SECRET_ACCESS_KEY + MATCH_PASSWORD +].freeze + +ASC_API_KEY_ENV_VARS = %w[ + APP_STORE_CONNECT_API_KEY_KEY_ID + APP_STORE_CONNECT_API_KEY_ISSUER_ID + APP_STORE_CONNECT_API_KEY_KEY +].freeze + +before_all do + # Ensures `match` works on CI by setting up a temporary keychain. No-op locally. + setup_ci +end + +# Fetch the Developer ID Application certificate into the keychain. +# +# @param readonly [Boolean] Use `true` to only fetch the existing certificate from S3 via +# `match`. Use `false` to create or renew it on App Store Connect. +# +lane :configure_code_signing do |readonly: true| + require_env_vars!(*CODE_SIGNING_ENV_VARS) + require_env_vars!(*ASC_API_KEY_ENV_VARS) unless readonly + + sync_code_signing( + type: 'developer_id', + platform: 'macos', + team_id: APPLE_TEAM_ID, + # A CLI has no bundle to carry a provisioning profile, so there is no app identifier + # to key storage on. + app_identifier: [], + api_key: readonly ? nil : app_store_connect_api_key, + readonly: readonly, + **CODE_SIGNING_STORAGE_OPTIONS + ) +end + +# Sign and notarize every macOS binary listed in the manifest `scripts/build-binaries.ts` +# writes, then update their checksums in it. +# +# Run `configure_code_signing` first, or run this on a machine that already holds the +# certificate. +# +# @param manifest [String] Path to `binaries.json`. Defaults to the one the build writes. +# +lane :sign_macos_binaries do |manifest: BINARIES_MANIFEST| + manifest = resolve_from_project_root(manifest) + UI.user_error!("No manifest at '#{manifest}'. Build the binaries first.") unless File.exist?(manifest) + + contents = JSON.parse(File.read(manifest)) + darwin_artifacts = contents.fetch('artifacts').select { |artifact| artifact.fetch('platform').start_with?('darwin-') } + UI.user_error!("No macOS binaries listed in '#{manifest}'") if darwin_artifacts.empty? + + darwin_artifacts.each do |artifact| + # The manifest's `path` is absolute on the machine that built it, so resolve `file` + # next to the manifest instead. + binary = File.join(File.dirname(manifest), artifact.fetch('file')) + sign_and_notarize(binary: binary) + artifact['sha256'] = Digest::SHA256.file(binary).hexdigest + end + + File.write(manifest, "#{JSON.pretty_generate(contents)}\n") +end + +# Sign a built CLI binary with the Developer ID certificate and submit it for notarization. +# +# Run `configure_code_signing` first, or run this on a machine that already holds the +# certificate. +# +# @param binary [String] Path to the binary to sign, e.g. `packages/cli/dist/bin/beeper-darwin-arm64`. +# +lane :sign_and_notarize do |binary:| + binary = resolve_from_project_root(binary) + UI.user_error!("No binary at '#{binary}'") unless File.exist?(binary) + require_env_vars!(*ASC_API_KEY_ENV_VARS) + + sh( + 'codesign', + '--sign', SIGNING_IDENTITY, + # The hardened runtime is a precondition for notarization. + '--options', 'runtime', + '--timestamp', + '--force', + binary + ) + + verify_code_signing(binary: binary) + + # `notarytool` takes only .zip/.dmg/.pkg, and fastlane's `notarize` compresses `.app` + # bundles and nothing else, so a bare binary has to be archived here. + archive = "#{binary}.zip" + sh('ditto', '-c', '-k', '--keepParent', binary, archive) + + notarize( + package: archive, + # Only bundles and disk images can carry a stapled ticket. A bare binary relies on + # the online Gatekeeper check. + skip_stapling: true, + api_key: app_store_connect_api_key, + print_log: true + ) + + FileUtils.rm_f(archive) +end + +# Verify that a binary carries an intact signature from our Developer ID, so a wrongly +# signed build fails CI instead of shipping. +# +# Gatekeeper acceptance (`spctl --assess`) is deliberately not asserted: a bare binary +# cannot be stapled, so that check needs an online lookup that lags a fresh submission. +# +# @param binary [String] Path to the binary to verify. +# +lane :verify_code_signing do |binary:| + binary = resolve_from_project_root(binary) + + sh('codesign', '--verify', '--strict', '--verbose=2', binary) + + # `codesign --display` reports on stderr, which `sh` does not capture. + details = sh("codesign --display --verbose=2 #{binary.shellescape} 2>&1", log: false) + + unless details.include?("Authority=#{SIGNING_IDENTITY}") + UI.user_error!("#{binary} is not signed by '#{SIGNING_IDENTITY}':\n#{details}") + end + + UI.user_error!("#{binary} is not signed with the hardened runtime:\n#{details}") unless details.include?('(runtime)') + + UI.success("#{binary} is signed by #{SIGNING_IDENTITY}") +end + +# fastlane runs lanes from the `fastlane/` directory, so a path a caller wrote +# relative to the repo root would otherwise resolve one level too deep. +def resolve_from_project_root(path) + File.absolute_path(path, PROJECT_ROOT_FOLDER) +end + +def require_env_vars!(*names) + missing = names.select { |name| ENV[name].to_s.empty? } + UI.user_error!("Missing required environment variable(s): #{missing.join(', ')}") unless missing.empty? +end From 5ce53cebef5cb5c7f3aa3ea960ac8d77a9699067 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Fri, 30 Oct 2026 11:46:15 +1100 Subject: [PATCH 3/5] Build, sign, and notarize binaries on Buildkite Releases had to come from Batuhan's Mac, the only machine with the signing secrets. The step builds all four binaries on one Mac agent, since Bun cross-compiles the Linux ones, so a release's artifacts come from one place. It publishes nothing: the npm and Homebrew steps read the archived `binaries.json` and binaries. The binaries go into a tarball because Buildkite artifacts drop the executable bit. --- Generated with the help of Claude Code, https://code.claude.com Co-Authored-By: Claude Opus 5.5 --- .buildkite/commands/build-sign-notarize.sh | 48 ++++++++++++++++++++++ .buildkite/pipeline.yml | 19 +++++++++ .buildkite/shared-pipeline-vars | 11 +++++ 3 files changed, 78 insertions(+) create mode 100755 .buildkite/commands/build-sign-notarize.sh create mode 100644 .buildkite/pipeline.yml create mode 100644 .buildkite/shared-pipeline-vars diff --git a/.buildkite/commands/build-sign-notarize.sh b/.buildkite/commands/build-sign-notarize.sh new file mode 100755 index 00000000..37cdcc16 --- /dev/null +++ b/.buildkite/commands/build-sign-notarize.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +set -euo pipefail + +bun_version="$(sed -nE 's/.*"packageManager": *"bun@([^"]+)".*/\1/p' package.json)" +if [ -z "$bun_version" ]; then + echo >&2 "could not read the Bun version from package.json's packageManager" + exit 1 +fi + +echo "--- :bun: install Bun $bun_version" +curl -fsSL https://bun.sh/install | bash -s "bun-v$bun_version" +export PATH="$HOME/.bun/bin:$PATH" +bun --version + +echo "--- :package: install dependencies" +bun install --frozen-lockfile + +echo "--- :hammer_and_wrench: build binaries" +bun run --cwd packages/cli binary + +bin_dir="packages/cli/dist/bin" + +echo "--- :key: set up Ruby tooling" +install_gems + +echo "--- :closed_lock_with_key: sign and notarize macOS binaries" +bundle exec fastlane configure_code_signing +bundle exec fastlane sign_macos_binaries + +echo "--- :mag: check binaries.json checksums" +ruby -rjson -e ' + JSON.parse(File.read(ARGV.fetch(0))).fetch("artifacts").each do |artifact| + puts "#{artifact.fetch("sha256")} #{artifact.fetch("file")}" + end +' "$bin_dir/binaries.json" | (cd "$bin_dir" && shasum -a 256 -c -) + +echo "--- :package: archive binaries" + +# dist/ is gitignored, and the step's `artifact_paths` glob picks it up even if a +# later command fails. +mkdir -p dist + +# Buildkite artifacts carry bytes, not file modes, so a bare binary downloads +# without its executable bit. Tar records the mode; extraction restores it. +tar -czf dist/beeper-cli-binaries.tar.gz -C "$bin_dir" \ + binaries.json beeper-darwin-arm64 beeper-darwin-x64 beeper-linux-arm64 beeper-linux-x64 +cp "$bin_dir/binaries.json" dist/binaries.json diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml new file mode 100644 index 00000000..aae2bc9e --- /dev/null +++ b/.buildkite/pipeline.yml @@ -0,0 +1,19 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/buildkite/pipeline-schema/main/schema.json +--- + +agents: + queue: mac + +env: + IMAGE_ID: $IMAGE_ID + +steps: + - label: ":apple: Build binaries, sign and notarize macOS" + key: build-sign-notarize + command: .buildkite/commands/build-sign-notarize.sh + plugins: [$CI_TOOLKIT_PLUGIN] + artifact_paths: + - dist/* + notify: + - github_commit_status: + context: Build, Sign & Notarize diff --git a/.buildkite/shared-pipeline-vars b/.buildkite/shared-pipeline-vars new file mode 100644 index 00000000..cd7898fd --- /dev/null +++ b/.buildkite/shared-pipeline-vars @@ -0,0 +1,11 @@ +#!/bin/sh + +# Sourced before `buildkite-agent pipeline upload` so the values land in the +# rendered pipeline, keeping plugin pins and the agent image id out of pipeline.yml. + +CI_TOOLKIT_PLUGIN_VERSION='7.1.0' + +XCODE_VERSION=$(sed -E 's/^~> ?//' .xcode-version) + +export IMAGE_ID="xcode-$XCODE_VERSION" +export CI_TOOLKIT_PLUGIN="automattic/a8c-ci-toolkit#$CI_TOOLKIT_PLUGIN_VERSION" From 935539d8d99c84c0c27491f311a4f46b2d85fe99 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Fri, 30 Oct 2026 13:36:57 +1100 Subject: [PATCH 4/5] Build on the Xcode 27.1 image --- Generated with the help of Claude Code, https://code.claude.com Co-Authored-By: Claude Opus 5.5 --- .xcode-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.xcode-version b/.xcode-version index 7363977a..6ef5383e 100644 --- a/.xcode-version +++ b/.xcode-version @@ -1 +1 @@ -26.6 +27.1 From 951c837e777859a0094ce96dd778d37bb25bdf7c Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Fri, 30 Oct 2026 13:57:29 +1100 Subject: [PATCH 5/5] Upload the release archives instead of a tarball `build-homebrew-archive.ts` reads each binary from the absolute `path` in `binaries.json`, which only exists on the agent that built it. Archiving downstream from the uploaded binaries would fail, so the job now builds the same archives, `homebrew.json`, and `binaries.json` a GitHub Release carries. Flagged by Codex review. --- Generated with the help of Claude Code, https://code.claude.com Co-Authored-By: Claude Opus 5.5 --- .buildkite/commands/build-sign-notarize.sh | 14 +++----------- .buildkite/pipeline.yml | 3 ++- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/.buildkite/commands/build-sign-notarize.sh b/.buildkite/commands/build-sign-notarize.sh index 37cdcc16..e1a86bd1 100755 --- a/.buildkite/commands/build-sign-notarize.sh +++ b/.buildkite/commands/build-sign-notarize.sh @@ -35,14 +35,6 @@ ruby -rjson -e ' end ' "$bin_dir/binaries.json" | (cd "$bin_dir" && shasum -a 256 -c -) -echo "--- :package: archive binaries" - -# dist/ is gitignored, and the step's `artifact_paths` glob picks it up even if a -# later command fails. -mkdir -p dist - -# Buildkite artifacts carry bytes, not file modes, so a bare binary downloads -# without its executable bit. Tar records the mode; extraction restores it. -tar -czf dist/beeper-cli-binaries.tar.gz -C "$bin_dir" \ - binaries.json beeper-darwin-arm64 beeper-darwin-x64 beeper-linux-arm64 beeper-linux-x64 -cp "$bin_dir/binaries.json" dist/binaries.json +echo "--- :package: build release archives" +# binaries.json records absolute paths on this agent, so the archives must be built here. +bun run --cwd packages/cli scripts/build-homebrew-archive.ts diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index aae2bc9e..9ca058df 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -13,7 +13,8 @@ steps: command: .buildkite/commands/build-sign-notarize.sh plugins: [$CI_TOOLKIT_PLUGIN] artifact_paths: - - dist/* + - packages/cli/dist/bin/binaries.json + - packages/cli/dist/release/* notify: - github_commit_status: context: Build, Sign & Notarize