From 8637e842b6ef0ca20c30c7f7e1e02574d8043f87 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Sun, 26 Jul 2026 09:36:13 +0200 Subject: [PATCH 1/3] Harden CI and update vulnerable gems The pipeline only ever built the simulator slice of one configuration, so anything that breaks in Release or on device surfaced at deploy time. It also rebuilt every conan package from scratch on every run. - add a build job that compiles both flavors for iphoneos in their release configurations. Signing needs secrets this workflow does not have, so it builds with CODE_SIGNING_ALLOWED=NO and only proves things compile and link - cache ~/.conan2/p keyed on the conan-odr-index commit plus conanfile and profiles, restored before the recipe export so current recipes win over stale ones from the archive - ruby/setup-ruby with bundler-cache instead of installing bundler and all gems from scratch every run - macos-14 and Xcode 16.2 were about two Xcode majors behind. Pinned to Xcode 26.0.1 on macos-26, matching what this was verified against locally - bundle update, which clears the four open dependabot alerts: addressable 2.8.7 -> 2.9.0, excon 0.112.0 -> 1.6.0, faraday 1.10.5 -> 1.10.6, jwt 2.10.1 -> 3.2.0, pulling fastlane 2.227.2 -> 2.237.0 - pin fastlane, add .ruby-version and the runner platforms to the lockfile - add dependabot config so gems and actions stay current The tests lane no longer clears derived data or resets the simulator. CI runners start clean and locally it only threw away the incremental build of a C++ heavy project. --- .github/dependabot.yml | 25 +++++ .github/workflows/ios_main.yml | 116 ++++++++++++++++++++++-- .ruby-version | 1 + Gemfile | 2 +- Gemfile.lock | 161 +++++++++++++++++++-------------- fastlane/Fastfile | 4 +- fastlane/README.md | 46 ++++++---- 7 files changed, 257 insertions(+), 98 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 .ruby-version diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..11d3bc7 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,25 @@ +version: 2 + +updates: + - package-ecosystem: bundler + directory: "/" + schedule: + interval: weekly + groups: + fastlane: + patterns: + - "*" + + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: weekly + groups: + actions: + patterns: + - "*" + + - package-ecosystem: cocoapods + directory: "/" + schedule: + interval: weekly diff --git a/.github/workflows/ios_main.yml b/.github/workflows/ios_main.yml index 6a31dfa..29f9583 100644 --- a/.github/workflows/ios_main.yml +++ b/.github/workflows/ios_main.yml @@ -11,9 +11,12 @@ concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true +env: + xcode_version: "26.0.1" + jobs: test: - runs-on: macos-14 + runs-on: macos-26 steps: - name: checkout uses: actions/checkout@v4 @@ -28,17 +31,15 @@ jobs: - uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: "16.2" + xcode-version: ${{ env.xcode_version }} + + - uses: ruby/setup-ruby@v1 + with: + bundler-cache: true - name: install pods run: pod install - # https://stackoverflow.com/a/57758679/198996 - - name: install bundler - run: gem install bundler - - name: install fastlane - run: bundle install - # conan itself is pinned by conan-odr-index so recipes and client stay in sync - name: install conan run: pip3 install -r conan-odr-index/requirements.txt @@ -46,6 +47,20 @@ jobs: - name: conan profile run: conan profile detect + - name: conan cache key + id: conan-cache-key + run: echo "key=conan2-${{ runner.os }}-xcode${{ env.xcode_version }}-simulator-index$(git rev-parse HEAD:conan-odr-index)-${{ hashFiles('conan/conanfile.py', 'conan/profiles/*') }}" >> "$GITHUB_OUTPUT" + + # restore before exporting the recipes: the export must run on top of the + # restored cache so current recipes win over stale ones from the archive + - name: conan cache + uses: actions/cache@v4 + with: + path: ~/.conan2/p + key: ${{ steps.conan-cache-key.outputs.key }} + restore-keys: | + conan2-${{ runner.os }}-xcode${{ env.xcode_version }}-simulator- + # recipes are exported from the submodule into the local cache, which is # why no private remote has to be configured - name: export conan-odr-index @@ -64,9 +79,94 @@ jobs: - name: run tests run: bundle exec fastlane tests + # drop temporary download/source/build folders so only built packages get cached + - name: clean conan cache + if: always() + run: conan cache clean "*" + - uses: actions/upload-artifact@v4 if: always() with: name: logs path: | /Users/runner/Library/Developer/Xcode/DerivedData/OpenDocumentReader-*/ + + # the test job only ever builds the simulator slice of one configuration, so + # release-only and device-only breakage used to surface at deploy time + build: + runs-on: macos-26 + strategy: + fail-fast: false + matrix: + include: + - { scheme: "ODR Full", configuration: "Release" } + - { scheme: "ODR Lite", configuration: "Release Lite" } + steps: + - name: checkout + uses: actions/checkout@v4 + + - name: checkout conan-odr-index + run: git submodule update --init --depth 1 conan-odr-index + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: ${{ env.xcode_version }} + + - uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + + - name: install pods + run: pod install + + - name: install conan + run: pip3 install -r conan-odr-index/requirements.txt + + - name: conan profile + run: conan profile detect + + - name: conan cache key + id: conan-cache-key + run: echo "key=conan2-${{ runner.os }}-xcode${{ env.xcode_version }}-device-index$(git rev-parse HEAD:conan-odr-index)-${{ hashFiles('conan/conanfile.py', 'conan/profiles/*') }}" >> "$GITHUB_OUTPUT" + + - name: conan cache + uses: actions/cache@v4 + with: + path: ~/.conan2/p + key: ${{ steps.conan-cache-key.outputs.key }} + restore-keys: | + conan2-${{ runner.os }}-xcode${{ env.xcode_version }}-device- + + - name: export conan-odr-index + run: python3 conan-odr-index/scripts/conan_export_all_packages.py + + - name: conan install + run: > + conan install conan/ + --output-folder=conan-output + --build=missing + --profile:host=conan/profiles/ios + --deployer=conan/conandeployer.py + --deployer-folder=conan-assets + -o "configuration=${{ matrix.configuration }}" + + # signing needs secrets this workflow does not have, so this only proves + # that the device slice compiles and links + - name: build + run: > + xcodebuild + -workspace OpenDocumentReader.xcworkspace + -scheme "${{ matrix.scheme }}" + -configuration "${{ matrix.configuration }}" + -sdk iphoneos + -destination 'generic/platform=iOS' + CODE_SIGNING_ALLOWED=NO + build + + - name: clean conan cache + if: always() + run: conan cache clean "*" diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..f989260 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.4.4 diff --git a/Gemfile b/Gemfile index 7a118b4..a42a311 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,3 @@ source "https://rubygems.org" -gem "fastlane" +gem "fastlane", "~> 2.237" diff --git a/Gemfile.lock b/Gemfile.lock index 5369a06..c227048 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,17 +1,15 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.7) - base64 - nkf - rexml - addressable (2.8.7) - public_suffix (>= 2.0.2, < 7.0) + 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.0) - aws-partitions (1.1196.0) - aws-sdk-core (3.240.0) + aws-partitions (1.1273.0) + aws-sdk-core (3.254.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) aws-sigv4 (~> 1.9) @@ -19,31 +17,34 @@ GEM bigdecimal jmespath (~> 1, >= 1.6.1) logger - aws-sdk-kms (1.118.0) - aws-sdk-core (~> 3, >= 3.239.1) + aws-sdk-kms (1.130.0) + aws-sdk-core (~> 3, >= 3.254.0) aws-sigv4 (~> 1.5) - aws-sdk-s3 (1.208.0) - aws-sdk-core (~> 3, >= 3.234.0) + aws-sdk-s3 (1.228.1) + aws-sdk-core (~> 3, >= 3.254.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) - bigdecimal (4.0.1) + benchmark (0.5.0) + bigdecimal (4.1.2) claide (1.1.0) colored (1.2) colored2 (3.1.2) commander (4.6.0) highline (~> 2.0.0) + csv (3.3.5) declarative (0.0.20) digest-crc (0.7.0) rake (>= 12.0.0, < 14.0.0) domain_name (0.6.20240107) dotenv (2.8.1) emoji_regex (3.2.3) - excon (0.112.0) - faraday (1.10.5) + excon (1.6.0) + logger + faraday (1.10.6) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) @@ -55,9 +56,9 @@ GEM faraday-rack (~> 1.0) faraday-retry (~> 1.0) ruby2_keywords (>= 0.0.4) - faraday-cookie_jar (0.0.7) + faraday-cookie_jar (0.0.8) faraday (>= 0.8.0) - http-cookie (~> 1.0.0) + http-cookie (>= 1.0.0) faraday-em_http (1.0.0) faraday-em_synchrony (1.0.1) faraday-excon (1.1.0) @@ -68,40 +69,49 @@ GEM faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) faraday-rack (1.0.0) - faraday-retry (1.0.3) + faraday-retry (1.0.4) faraday_middleware (1.2.1) faraday (~> 1.0) - fastimage (2.4.0) - fastlane (2.227.2) - CFPropertyList (>= 2.3, < 4.0.0) - addressable (>= 2.8, < 3.0.0) + fastimage (2.4.1) + fastlane (2.237.0) + CFPropertyList (>= 2.3, < 5.0.0) + abbrev (~> 0.1) + addressable (>= 2.9.0, < 3.0.0) artifactory (~> 3.0) - aws-sdk-s3 (~> 1.0) + aws-sdk-s3 (~> 1.197) babosa (>= 1.0.3, < 2.0.0) - bundler (>= 1.12.0, < 3.0.0) + base64 (~> 0.2) + benchmark (>= 0.1.0) + bundler (>= 2.4.0, < 5.0.0) colored (~> 1.2) commander (~> 4.6) + csv (~> 3.3) dotenv (>= 2.1.1, < 3.0.0) emoji_regex (>= 0.1, < 4.0) - excon (>= 0.71.0, < 1.0.0) + excon (>= 0.71.0, < 2.0.0) faraday (~> 1.0) faraday-cookie_jar (~> 0.0.6) faraday_middleware (~> 1.0) fastimage (>= 2.1.0, < 3.0.0) - fastlane-sirp (>= 1.0.0) + fastlane-sirp (>= 1.1.0) gh_inspector (>= 1.1.2, < 2.0.0) google-apis-androidpublisher_v3 (~> 0.3) google-apis-playcustomapp_v1 (~> 0.1) - google-cloud-env (>= 1.6.0, < 2.0.0) + google-cloud-env (>= 1.6.0, < 2.3.0) google-cloud-storage (~> 1.31) highline (~> 2.0) http-cookie (~> 1.0.5) json (< 3.0.0) - jwt (>= 2.1.0, < 3) + 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 (>= 2.0.0, < 3.0.0) security (= 0.1.5) @@ -114,44 +124,48 @@ GEM xcodeproj (>= 1.13.0, < 2.0.0) xcpretty (~> 0.4.1) xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) - fastlane-sirp (1.0.0) - sysrandom (~> 1.0) + fastlane-sirp (1.1.0) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.54.0) - google-apis-core (>= 0.11.0, < 2.a) - google-apis-core (0.11.3) + google-apis-androidpublisher_v3 (0.105.0) + google-apis-core (>= 0.15.0, < 2.a) + google-apis-core (0.18.0) addressable (~> 2.5, >= 2.5.1) - googleauth (>= 0.16.2, < 2.a) - httpclient (>= 2.8.1, < 3.a) + googleauth (~> 1.9) + httpclient (>= 2.8.3, < 3.a) mini_mime (~> 1.0) + mutex_m representable (~> 3.0) retriable (>= 2.0, < 4.a) - rexml - google-apis-iamcredentials_v1 (0.17.0) - google-apis-core (>= 0.11.0, < 2.a) - google-apis-playcustomapp_v1 (0.13.0) - google-apis-core (>= 0.11.0, < 2.a) - google-apis-storage_v1 (0.31.0) - google-apis-core (>= 0.11.0, < 2.a) - google-cloud-core (1.8.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.65.0) + google-apis-core (>= 0.15.0, < 2.a) + google-cloud-core (1.9.0) google-cloud-env (>= 1.0, < 3.a) google-cloud-errors (~> 1.0) - google-cloud-env (1.6.0) - faraday (>= 0.17.3, < 3.0) - google-cloud-errors (1.5.0) - google-cloud-storage (1.47.0) + google-cloud-env (2.2.2) + base64 (~> 0.2) + faraday (>= 1.0, < 3.a) + google-cloud-errors (1.7.0) + google-cloud-storage (1.62.0) addressable (~> 2.8) digest-crc (~> 0.4) - google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.31.0) + google-apis-core (>= 0.18, < 2) + google-apis-iamcredentials_v1 (~> 0.18) + google-apis-storage_v1 (>= 0.42) google-cloud-core (~> 1.6) - googleauth (>= 0.16.2, < 2.a) + googleauth (~> 1.9) mini_mime (~> 1.0) - googleauth (1.8.1) - faraday (>= 0.17.3, < 3.a) - jwt (>= 1.4, < 3.0) - multi_json (~> 1.11) + google-logging-utils (0.2.0) + googleauth (1.17.2) + 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.0.8) @@ -159,42 +173,42 @@ GEM httpclient (2.9.0) mutex_m jmespath (1.6.2) - json (2.12.2) - jwt (2.10.1) + json (2.21.1) + jwt (3.2.0) base64 logger (1.7.0) mini_magick (4.13.2) mini_mime (1.1.5) - multi_json (1.15.0) + multi_json (1.21.1) multipart-post (2.4.1) mutex_m (0.3.0) nanaimo (0.4.0) - naturally (2.2.2) - nkf (0.2.0) - optparse (0.6.0) + naturally (2.3.0) + nkf (0.3.0) + optparse (0.8.1) os (1.1.4) + ostruct (0.6.3) plist (3.7.2) - public_suffix (6.0.2) - rake (13.3.0) + pstore (0.2.1) + public_suffix (7.0.5) + rake (13.4.2) representable (3.2.0) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) - retriable (3.1.2) - rexml (3.4.2) + retriable (3.8.0) + rexml (3.4.4) rouge (3.28.0) ruby2_keywords (0.0.5) rubyzip (2.4.1) security (0.1.5) - signet (0.20.0) + signet (0.22.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) - jwt (>= 1.5, < 3.0) - multi_json (~> 1.10) + jwt (>= 1.5, < 4.0) simctl (1.6.10) CFPropertyList naturally - sysrandom (1.0.5) terminal-notifier (2.0.0) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) @@ -206,12 +220,14 @@ GEM uber (0.1.0) unicode-display_width (2.6.0) word_wrap (1.0.0) - xcodeproj (1.27.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) @@ -220,10 +236,15 @@ GEM PLATFORMS arm64-darwin-24 + arm64-darwin-25 ruby + x86_64-darwin-25 DEPENDENCIES - fastlane + fastlane (~> 2.237) + +RUBY VERSION + ruby 3.4.4p34 BUNDLED WITH 2.6.9 diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 94d383a..ded682c 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -41,12 +41,12 @@ platform :ios do end lane :tests do - clear_derived_data + # no clear_derived_data here: CI runners start clean anyway and locally it + # only throws away the incremental build of a C++ heavy project run_tests( workspace: "OpenDocumentReader.xcworkspace", scheme: "ODR Full", prelaunch_simulator: true, - reset_simulator: true, xcargs: "-allowProvisioningUpdates" ) end diff --git a/fastlane/README.md b/fastlane/README.md index 80d2eb7..bf3eea2 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -1,44 +1,56 @@ fastlane documentation -================ +---- + # Installation Make sure you have the latest version of the Xcode command line tools installed: -``` +```sh xcode-select --install ``` -Install _fastlane_ using -``` -[sudo] gem install fastlane -NV -``` -or alternatively using `brew install fastlane` +For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane) # Available Actions + ## iOS + ### ios deployPro + +```sh +[bundle exec] fastlane ios deployPro ``` -fastlane ios deployPro -``` + Push a new release build to the App Store + ### ios deployLite + +```sh +[bundle exec] fastlane ios deployLite ``` -fastlane ios deployLite -``` + Push a new release build to the App Store + ### ios tests + +```sh +[bundle exec] fastlane ios tests ``` -fastlane ios tests -``` + + ### ios uploadSymbols -``` -fastlane ios uploadSymbols + +```sh +[bundle exec] fastlane ios uploadSymbols ``` + ---- This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run. -More information about fastlane can be found on [fastlane.tools](https://fastlane.tools). -The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools). + +More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools). + +The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools). From 3b90e9919ed5578a96f2015738814e0577a631f2 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Sun, 26 Jul 2026 09:52:33 +0200 Subject: [PATCH 2/3] Fix bundler frozen mode failure in CI ruby/setup-ruby installs with frozen mode on. The lockfile still carried a RUBY VERSION entry from an earlier iteration of the Gemfile, so bundler wanted to rewrite it and refused. The clean conan cache steps also ran on failure, where conan is not installed yet, turning any earlier failure into a confusing 'conan: command not found'. --- .github/workflows/ios_main.yml | 2 -- Gemfile.lock | 2 -- 2 files changed, 4 deletions(-) diff --git a/.github/workflows/ios_main.yml b/.github/workflows/ios_main.yml index 29f9583..ed6564f 100644 --- a/.github/workflows/ios_main.yml +++ b/.github/workflows/ios_main.yml @@ -81,7 +81,6 @@ jobs: # drop temporary download/source/build folders so only built packages get cached - name: clean conan cache - if: always() run: conan cache clean "*" - uses: actions/upload-artifact@v4 @@ -168,5 +167,4 @@ jobs: build - name: clean conan cache - if: always() run: conan cache clean "*" diff --git a/Gemfile.lock b/Gemfile.lock index c227048..404ac1b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -243,8 +243,6 @@ PLATFORMS DEPENDENCIES fastlane (~> 2.237) -RUBY VERSION - ruby 3.4.4p34 BUNDLED WITH 2.6.9 From 565fec42acf41072f5f07a0a1b542ba98092389d Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Sun, 26 Jul 2026 10:14:48 +0200 Subject: [PATCH 3/3] Pin the runner's default Xcode Xcode 26.0.1 is present on macos-26 but its iOS platform bundle is not, so every storyboard compile failed with 'iOS 26.0 Platform Not Installed'. 26.5 is the image default and has it installed. --- .github/workflows/ios_main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ios_main.yml b/.github/workflows/ios_main.yml index ed6564f..0f65f15 100644 --- a/.github/workflows/ios_main.yml +++ b/.github/workflows/ios_main.yml @@ -12,7 +12,9 @@ concurrency: cancel-in-progress: true env: - xcode_version: "26.0.1" + # the runner image only ships the iOS platform bundle for its default Xcode; + # older ones fail in ibtool with "iOS 26.0 Platform Not Installed" + xcode_version: "26.5" jobs: test: