From cd90abd3feaa06e44767728dcb64b18a4cdaf4cf Mon Sep 17 00:00:00 2001 From: Nico <47644445+nicotsx@users.noreply.github.com> Date: Tue, 23 Jun 2026 11:38:11 +0200 Subject: [PATCH] feat(desktop): automatic release pipeline (#1006) * feat(desktop): automatic release pipeline * refactor(desktop-release): remove build number infer since we won't release locally * fix(desktop): correct MAS TestFlight release config --- .github/workflows/desktop-release.yml | 125 +++++++ .github/workflows/release.yml | 10 + apps/desktop/.gitignore | 9 + apps/desktop/Gemfile | 3 + apps/desktop/Gemfile.lock | 341 ++++++++++++++++++ apps/desktop/assets/icon.icns | Bin 76622 -> 161401 bytes apps/desktop/electron-builder.config.cjs | 82 ++++- apps/desktop/electron/desktop-runtime.ts | 6 +- .../electron/entitlements.mas.inherit.plist | 10 + apps/desktop/electron/entitlements.mas.plist | 18 + apps/desktop/fastlane/.env.example | 3 + apps/desktop/fastlane/Fastfile | 118 ++++++ apps/desktop/package.json | 3 + 13 files changed, 718 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/desktop-release.yml create mode 100644 apps/desktop/Gemfile create mode 100644 apps/desktop/Gemfile.lock create mode 100644 apps/desktop/electron/entitlements.mas.inherit.plist create mode 100644 apps/desktop/electron/entitlements.mas.plist create mode 100644 apps/desktop/fastlane/.env.example create mode 100644 apps/desktop/fastlane/Fastfile diff --git a/.github/workflows/desktop-release.yml b/.github/workflows/desktop-release.yml new file mode 100644 index 00000000..72e81b04 --- /dev/null +++ b/.github/workflows/desktop-release.yml @@ -0,0 +1,125 @@ +name: Desktop Release + +on: + workflow_call: + inputs: + release_tag: + required: true + type: string + publish_testflight: + required: false + type: boolean + default: false + upload_github_release: + required: false + type: boolean + default: false + +permissions: + contents: read + +jobs: + testflight: + if: inputs.publish_testflight + environment: release + timeout-minutes: 30 + runs-on: macos-15 + permissions: + contents: read + env: + APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }} + APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }} + APP_STORE_CONNECT_API_KEY_BASE64: ${{ secrets.APP_STORE_CONNECT_API_KEY_BASE64 }} + CSC_LINK: ${{ secrets.CSC_LINK }} + CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} + ZEROBYTE_DESKTOP_VERSION: ${{ inputs.release_tag }} + ZEROBYTE_EXPORT_COMPLIANCE_CODE: ${{ secrets.ZEROBYTE_EXPORT_COMPLIANCE_CODE }} + ZEROBYTE_MAS_PROVISIONING_PROFILE_BASE64: ${{ secrets.ZEROBYTE_MAS_PROVISIONING_PROFILE_BASE64 }} + steps: + - name: Checkout code + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + with: + fetch-depth: 0 + ref: ${{ github.ref }} + + - name: Install dependencies + uses: "./.github/actions/install-dependencies" + + - name: Install Fastlane dependencies + working-directory: apps/desktop + run: bundle install + + - name: Write MAS provisioning profile + run: | + : "${ZEROBYTE_MAS_PROVISIONING_PROFILE_BASE64:?Set ZEROBYTE_MAS_PROVISIONING_PROFILE_BASE64 secret}" + profile_path="$RUNNER_TEMP/mac-app-store.provisionprofile" + echo "ZEROBYTE_MAS_PROVISIONING_PROFILE=$profile_path" >> "$GITHUB_ENV" + printf '%s' "$ZEROBYTE_MAS_PROVISIONING_PROFILE_BASE64" | base64 --decode > "$profile_path" + chmod 600 "$profile_path" + + - name: Build and upload to TestFlight + working-directory: apps/desktop + env: + FASTLANE_HIDE_CHANGELOG: "true" + FASTLANE_SKIP_UPDATE_CHECK: "true" + run: bundle exec fastlane mac beta + + - name: Clean TestFlight release secrets + if: always() + run: | + if [ -n "${ZEROBYTE_MAS_PROVISIONING_PROFILE:-}" ]; then + rm -f "$ZEROBYTE_MAS_PROVISIONING_PROFILE" + fi + rm -rf apps/desktop/dist/mas-arm64 + + github-release: + if: inputs.upload_github_release + environment: release + timeout-minutes: 30 + runs-on: macos-15 + permissions: + contents: read + env: + APP_STORE_CONNECT_API_KEY_BASE64: ${{ secrets.APP_STORE_CONNECT_API_KEY_BASE64 }} + APPLE_API_KEY: ${{ runner.temp }}/AuthKey.p8 + APPLE_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }} + APPLE_API_ISSUER: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }} + CSC_LINK: ${{ secrets.CSC_LINK }} + CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} + ZEROBYTE_DESKTOP_VERSION: ${{ inputs.release_tag }} + ZEROBYTE_EXPORT_COMPLIANCE_CODE: ${{ secrets.ZEROBYTE_EXPORT_COMPLIANCE_CODE }} + ZEROBYTE_MAC_SIGN: "true" + steps: + - name: Checkout code + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + with: + fetch-depth: 0 + ref: ${{ github.ref }} + + - name: Install dependencies + uses: "./.github/actions/install-dependencies" + + - name: Write App Store Connect API key + run: | + printf '%s' "$APP_STORE_CONNECT_API_KEY_BASE64" | base64 --decode > "$APPLE_API_KEY" + chmod 600 "$APPLE_API_KEY" + + - name: Build DMG + working-directory: apps/desktop + run: bun run make + + - name: Upload DMG artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: desktop-github-release + path: | + apps/desktop/dist/*.dmg + if-no-files-found: error + retention-days: 1 + compression-level: 0 + + - name: Clean GitHub release secrets + if: always() + run: | + rm -f "$APPLE_API_KEY" + rm -rf apps/desktop/dist diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6a7bd27e..26b8c055 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -107,6 +107,16 @@ jobs: build-args: | APP_VERSION=${{ needs.determine-release-type.outputs.tagname }} + publish-desktop-testflight: + needs: [determine-release-type, checks, e2e-tests, integration-tests] + uses: ./.github/workflows/desktop-release.yml + permissions: + contents: read + with: + release_tag: ${{ needs.determine-release-type.outputs.tagname }} + publish_testflight: true + secrets: inherit + publish-release: runs-on: ubuntu-latest needs: [build-images, determine-release-type] diff --git a/apps/desktop/.gitignore b/apps/desktop/.gitignore index ee3e6136..07b400e6 100644 --- a/apps/desktop/.gitignore +++ b/apps/desktop/.gitignore @@ -2,3 +2,12 @@ .runtime out dist +profiles/*.provisionprofile +fastlane/.env +fastlane/.env.* +!fastlane/.env.example +fastlane/AuthKey_*.p8 +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output diff --git a/apps/desktop/Gemfile b/apps/desktop/Gemfile new file mode 100644 index 00000000..b7cf8e78 --- /dev/null +++ b/apps/desktop/Gemfile @@ -0,0 +1,3 @@ +source "https://rubygems.org" + +gem "fastlane", "~> 2.236" diff --git a/apps/desktop/Gemfile.lock b/apps/desktop/Gemfile.lock new file mode 100644 index 00000000..d0fbd7b8 --- /dev/null +++ b/apps/desktop/Gemfile.lock @@ -0,0 +1,341 @@ +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.0) + aws-partitions (1.1261.0) + aws-sdk-core (3.252.0) + aws-eventstream (~> 1, >= 1.3.0) + aws-partitions (~> 1, >= 1.992.0) + aws-sigv4 (~> 1.9) + base64 + bigdecimal + jmespath (~> 1, >= 1.6.1) + logger + aws-sdk-kms (1.129.0) + aws-sdk-core (~> 3, >= 3.248.0) + aws-sigv4 (~> 1.5) + aws-sdk-s3 (1.226.0) + aws-sdk-core (~> 3, >= 3.248.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.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) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0) + faraday-multipart (~> 1.0) + faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.0) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) + faraday-retry (~> 1.0) + ruby2_keywords (>= 0.0.4) + faraday-cookie_jar (0.0.8) + faraday (>= 0.8.0) + http-cookie (>= 1.0.0) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.1) + faraday-excon (1.1.0) + faraday-httpclient (1.0.1) + faraday-multipart (1.2.0) + multipart-post (~> 2.0) + faraday-net_http (1.0.2) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) + faraday-retry (1.0.4) + faraday_middleware (1.2.1) + faraday (~> 1.0) + fastimage (2.4.1) + fastlane (2.236.1) + CFPropertyList (>= 2.3, < 5.0.0) + abbrev (~> 0.1) + addressable (>= 2.8, < 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) + 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) + faraday (~> 1.0) + faraday-cookie_jar (~> 0.0.6) + faraday_middleware (~> 1.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.3) + google-apis-playcustomapp_v1 (~> 0.1) + 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.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) + simctl (~> 1.6.3) + terminal-notifier (>= 2.0.0, < 3.0.0) + terminal-table (~> 3) + 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.102.0) + google-apis-core (>= 0.15.0, < 2.a) + google-apis-core (0.18.0) + addressable (~> 2.5, >= 2.5.1) + googleauth (~> 1.9) + httpclient (>= 2.8.3, < 3.a) + mini_mime (~> 1.0) + mutex_m + representable (~> 3.0) + retriable (>= 2.0, < 4.a) + google-apis-iamcredentials_v1 (0.27.0) + google-apis-core (>= 0.15.0, < 2.a) + google-apis-playcustomapp_v1 (0.17.0) + google-apis-core (>= 0.15.0, < 2.a) + google-apis-storage_v1 (0.63.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 (2.2.2) + base64 (~> 0.2) + faraday (>= 1.0, < 3.a) + google-cloud-errors (1.6.0) + google-cloud-storage (1.61.0) + 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.0) + googleauth (1.17.1) + 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) + domain_name (~> 0.5) + httpclient (2.9.0) + mutex_m + jmespath (1.6.2) + json (2.19.9) + jwt (3.2.0) + base64 + logger (1.7.0) + mini_magick (4.13.2) + mini_mime (1.1.5) + multi_json (1.21.1) + multipart-post (2.4.1) + mutex_m (0.3.0) + nanaimo (0.4.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) + 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.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.22.0) + addressable (~> 2.8) + faraday (>= 0.17.5, < 3.a) + jwt (>= 1.5, < 4.0) + simctl (1.6.10) + CFPropertyList + naturally + terminal-notifier (2.0.0) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) + trailblazer-option (0.1.2) + 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 (2.6.0) + word_wrap (1.0.0) + xcodeproj (1.27.0) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.4.0) + 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 + arm64-darwin-25 + ruby + +DEPENDENCIES + fastlane (~> 2.236) + +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.0) sha256=116bf85c436200d1060811e6f5d2d40c88f65448f2125bc77ffce5121e6e183b + aws-partitions (1.1261.0) sha256=89eda89781c1ea4e1be2a2dcdc72318c62c6171a01cdaeaa0cbecf3cea6f9fdc + aws-sdk-core (3.252.0) sha256=09c042cbfc2acf2239441cc9b982ebab2a999bed2ef6bdc51849e7b3d6e48a1c + aws-sdk-kms (1.129.0) sha256=363f548df321f4a4fcfd05523384e591060b400f8e65133ed7ef0793155a3343 + aws-sdk-s3 (1.226.0) sha256=e599f431e006ec9b92c61ee0f14d3f658a1f6c8a1d623d2160be927ac958e2bf + 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.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd + 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.5) sha256=6e5134ac3383ef728b7f02725d9872934f523cb40b961479f69cf3afa6c8e73f + declarative (0.0.20) sha256=8021dd6cb17ab2b61233c56903d3f5a259c5cf43c80ff332d447d395b17d9ff9 + digest-crc (0.7.0) sha256=64adc23a26a241044cbe6732477ca1b3c281d79e2240bcff275a37a5a0d78c07 + domain_name (0.6.20240107) sha256=5f693b2215708476517479bf2b3802e49068ad82167bcd2286f899536a17d933 + dotenv (2.8.1) sha256=c5944793349ae03c432e1780a2ca929d60b88c7d14d52d630db0508c3a8a17d8 + emoji_regex (3.2.3) sha256=ecd8be856b7691406c6bf3bb3a5e55d6ed683ffab98b4aa531bb90e1ddcc564b + excon (0.112.0) sha256=daf9ac3a4c2fc9aa48383a33da77ecb44fa395111e973084d5c52f6f214ae0f0 + faraday (1.10.5) sha256=b144f1d2b045652fa820b5f532723e1643cc28b93dae911d784e5c5f88e8f6ed + faraday-cookie_jar (0.0.8) sha256=0140605823f8cc63c7028fccee486aaed8e54835c360cffc1f7c8c07c4299dbb + faraday-em_http (1.0.0) sha256=7a3d4c7079789121054f57e08cd4ef7e40ad1549b63101f38c7093a9d6c59689 + faraday-em_synchrony (1.0.1) sha256=bf3ce45dcf543088d319ab051f80985ea6d294930635b7a0b966563179f81750 + faraday-excon (1.1.0) sha256=b055c842376734d7f74350fe8611542ae2000c5387348d9ba9708109d6e40940 + faraday-httpclient (1.0.1) sha256=4c8ff1f0973ff835be8d043ef16aaf54f47f25b7578f6d916deee8399a04d33b + faraday-multipart (1.2.0) sha256=7d89a949693714176f612323ca13746a2ded204031a6ba528adee788694ef757 + faraday-net_http (1.0.2) sha256=63992efea42c925a20818cf3c0830947948541fdcf345842755510d266e4c682 + faraday-net_http_persistent (1.2.0) sha256=0b0cbc8f03dab943c3e1cc58d8b7beb142d9df068b39c718cd83e39260348335 + faraday-patron (1.0.0) sha256=dc2cd7b340bb3cc8e36bcb9e6e7eff43d134b6d526d5f3429c7a7680ddd38fa7 + faraday-rack (1.0.0) sha256=ef60ec969a2bb95b8dbf24400155aee64a00fc8ba6c6a4d3968562bcc92328c0 + faraday-retry (1.0.4) sha256=dc659233777fabf96c69c2ffe56c0a5d2c102af90321a42cc6c90157bcd716aa + faraday_middleware (1.2.1) sha256=d45b78c8ee864c4783fbc276f845243d4a7918a67301c052647bacabec0529e9 + fastimage (2.4.1) sha256=c64bebd46b6fd8943ab70c1e6e85ff728f970f2e48f92ecd249b6bc3a540ad20 + fastlane (2.236.1) sha256=fb89e618e0f38636e487743622cf710ad722723f5d33a63f19e367f84d3770bc + fastlane-sirp (1.1.0) sha256=10bc94f9682efd8e1badfb31452a76dd8981f1f3a33717c765fde6d75b54d847 + gh_inspector (1.1.3) sha256=04cca7171b87164e053aa43147971d3b7f500fcb58177698886b48a9fc4a1939 + google-apis-androidpublisher_v3 (0.102.0) sha256=562415c44bd7f81cc808abbea11845ede16cdc3696d95f95efcf50aaffb159cf + google-apis-core (0.18.0) sha256=96b057816feeeab448139ed5b5c78eab7fc2a9d8958f0fbc8217dedffad054ee + google-apis-iamcredentials_v1 (0.27.0) sha256=9289f29968610754ef11d98b9ec627f0153f3e2616fef839aef096de529f6d1e + google-apis-playcustomapp_v1 (0.17.0) sha256=d5bc90b705f3f862bab4998086449b0abe704ee1685a84821daa90ca7fa95a78 + google-apis-storage_v1 (0.63.0) sha256=7063a6c19c40f5ef96d5894df33c4f9ac915e3107e632b1870ba5247e3bb633f + google-cloud-core (1.9.0) sha256=ab55409f51488e8deefb6edcc1ce4771dfb5da2fe7b3bc075709a030c2b682a4 + google-cloud-env (2.2.2) sha256=94bed40e05a67e9468ce1cb38389fba9a90aa8fc62fc9e173204c1dca59e21e7 + google-cloud-errors (1.6.0) sha256=1da8476dd706ad04b9d32e3c4b90d07d3463b37d6407cb56d41342ea7647d0a1 + google-cloud-storage (1.61.0) sha256=a77f10f4a603289948b09e81c3e23d762a18733fd69d70a4c1399663fbd96002 + google-logging-utils (0.2.0) sha256=675462b4ea5affa825a3442694ca2d75d0069455a1d0956127207498fca3df7b + googleauth (1.17.1) sha256=0f7e6fc70e204cee1b2d71f1e1de2d3b349d432404197fe68ebf7fa23d0821b9 + highline (2.0.3) sha256=2ddd5c127d4692721486f91737307236fe005352d12a4202e26c48614f719479 + http-cookie (1.0.8) sha256=b14fe0445cf24bf9ae098633e9b8d42e4c07c3c1f700672b09fbfe32ffd41aa6 + httpclient (2.9.0) sha256=4b645958e494b2f86c2f8a2f304c959baa273a310e77a2931ddb986d83e498c8 + jmespath (1.6.2) sha256=238d774a58723d6c090494c8879b5e9918c19485f7e840f2c1c7532cf84ebcb1 + json (2.19.9) sha256=9b9025b7cdddafa38d316eca0b2358488e42d417045c1b90d216a9fefe46b79a + jwt (3.2.0) sha256=5419b1fe37b1da0982bd07051f573a8b8789ab724c2aa7e785e4784a3ed217d7 + logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203 + mini_magick (4.13.2) sha256=71d6258e0e8a3d04a9a0a09784d5d857b403a198a51dd4f882510435eb95ddd9 + mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef + multi_json (1.21.1) sha256=e6126a31808e3b4d19f483c775ceac34df190dffa62adfb63a165ee14ba68080 + 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 + 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 + pstore (0.2.1) sha256=03904d0f2c66579e96d1e6704cdabc0c88df7ea8ed8782d9f3569f6f6c702c1a + public_suffix (7.0.5) sha256=1a8bb08f1bbea19228d3bed6e5ed908d1cb4f7c2726d18bd9cadf60bc676f623 + rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701 + representable (3.2.0) sha256=cc29bf7eebc31653586849371a43ffe36c60b54b0a6365b5f7d95ec34d1ebace + retriable (3.8.0) sha256=9f2f1b0207594c7817f17f671587b8ec7587387ac6cebda6c941a802bb98a8e5 + rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142 + rouge (3.28.0) sha256=0d6de482c7624000d92697772ab14e48dca35629f8ddf3f4b21c99183fd70e20 + ruby2_keywords (0.0.5) sha256=ffd13740c573b7301cf7a2e61fc857b2a8e3d3aff32545d6f8300d8bae10e3ef + rubyzip (2.4.1) sha256=8577c88edc1fde8935eb91064c5cb1aef9ad5494b940cf19c775ee833e075615 + security (0.1.5) sha256=3a977a0eca7706e804c96db0dd9619e0a94969fe3aac9680fcfc2bf9b8a833b7 + signet (0.22.0) sha256=b76d495ccb07ad35dbc89f3e920665a9d8ed717141955034005d7843dcfe4780 + simctl (1.6.10) sha256=b99077f4d13ad81eace9f86bf5ba4df1b0b893a4d1b368bd3ed59b5b27f9236b + terminal-notifier (2.0.0) sha256=7a0d2b2212ab9835c07f4b2e22a94cff64149dba1eed203c04835f7991078cea + terminal-table (3.0.2) sha256=f951b6af5f3e00203fb290a669e0a85c5dd5b051b3b023392ccfd67ba5abae91 + trailblazer-option (0.1.2) sha256=20e4f12ea4e1f718c8007e7944ca21a329eee4eed9e0fa5dde6e8ad8ac4344a3 + 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 (2.6.0) sha256=12279874bba6d5e4d2728cef814b19197dbb10d7a7837a869bab65da943b7f5a + word_wrap (1.0.0) sha256=f556d4224c812e371000f12a6ee8102e0daa724a314c3f246afaad76d82accc7 + xcodeproj (1.27.0) sha256=8cc7a73b4505c227deab044dce118ede787041c702bc47636856a2e566f854d3 + xcpretty (0.4.1) sha256=b14c50e721f6589ee3d6f5353e2c2cfcd8541fa1ea16d6c602807dd7327f3892 + xcpretty-travis-formatter (1.0.1) sha256=aacc332f17cb7b2cba222994e2adc74223db88724fe76341483ad3098e232f93 + +BUNDLED WITH + 4.0.11 diff --git a/apps/desktop/assets/icon.icns b/apps/desktop/assets/icon.icns index 42e8d36ccb22b44fac33b3364e7eedd6f9ebd226..5957e4e1697cd0b2b4df0d89dd00cb998958eb15 100644 GIT binary patch delta 85412 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[Bspo2tQhAIYUv?W(t)7j_Ua}@ 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 delta 34 qcmezQhV$Gt7LLs1ykZ7MZNH5i(_$E arg === "mas" || arg === "mas-dev" || arg.includes("--mac=mas")); +const shouldSign = process.env.ZEROBYTE_MAC_SIGN === "true" || shouldNotarize || isMasTarget; + +const readCurrentGitTag = () => { + try { + return execFileSync("git", ["describe", "--tags", "--exact-match"], { + cwd: repoRoot, + encoding: "utf-8", + stdio: ["ignore", "pipe", "ignore"], + }).trim(); + } catch { + return undefined; + } +}; + +let releaseVersion = process.env.ZEROBYTE_DESKTOP_VERSION; +if (!releaseVersion) releaseVersion = process.env.APP_VERSION; +if (!releaseVersion) releaseVersion = process.env.GITHUB_REF_NAME; +if (!releaseVersion) releaseVersion = readCurrentGitTag(); + +const releaseTag = releaseVersion?.replace(/^refs\/tags\//, ""); +const appStoreVersion = releaseTag?.replace(/^v/, "").match(/^\d+\.\d+\.\d+/)?.[0]; +const buildNumber = process.env.ZEROBYTE_BUILD_NUMBER || process.env.GITHUB_RUN_NUMBER; +const exportComplianceCode = + process.env.ZEROBYTE_EXPORT_COMPLIANCE_CODE || process.env.APP_STORE_EXPORT_COMPLIANCE_CODE; +const masProvisioningProfile = + process.env.ZEROBYTE_MAS_PROVISIONING_PROFILE || path.join(desktopDir, "profiles", "mac-app-store.provisionprofile"); +const masDevProvisioningProfile = + process.env.ZEROBYTE_MAS_DEV_PROVISIONING_PROFILE || + path.join(desktopDir, "profiles", "mac-development.provisionprofile"); + +if (releaseTag && !process.env.APP_VERSION) { + process.env.APP_VERSION = releaseTag; +} +if (releaseTag && !process.env.VITE_APP_VERSION) { + process.env.VITE_APP_VERSION = releaseTag; +} + +if (!releaseTag || !appStoreVersion) { + throw new Error("Desktop builds require a release version like v0.39.0 or v0.39.0-beta.3."); +} + +const archNames = { + [Arch.x64]: "x64", + [Arch.arm64]: "arm64", +}; const run = (command, args) => new Promise((resolve, reject) => { @@ -27,17 +74,24 @@ const run = (command, args) => }); }); -const prepareRuntime = async ({ electronPlatformName }) => { +const prepareRuntime = async ({ electronPlatformName, arch }) => { + const archName = archNames[arch]; + const runtimePlatformName = electronPlatformName === "mas" ? "darwin" : electronPlatformName; + if (!archName) { + throw new Error(`Unsupported desktop target architecture: ${arch}`); + } + await run("bun", ["run", "build:electron"]); - await run("bun", ["scripts/prepare-runtime.ts", "--platform", electronPlatformName, "--arch", "arm64"]); + await run("bun", ["scripts/prepare-runtime.ts", "--platform", runtimePlatformName, "--arch", archName]); }; /** @type {import("electron-builder").Configuration} */ const config = { appId: "com.nicotsx.zerobyte", productName: "Zerobyte", + extraMetadata: { version: appStoreVersion }, asar: true, - artifactName: "${productName}-${version}-${os}-${arch}.${ext}", + artifactName: `\${productName}-${releaseTag}-\${os}-\${arch}.\${ext}`, directories: { output: "dist", buildResources: "assets", @@ -56,22 +110,32 @@ const config = { mac: { category: "public.app-category.utilities", icon: "assets/icon.icns", + extendInfo: { + ITSAppUsesNonExemptEncryption: Boolean(exportComplianceCode), + ...(exportComplianceCode ? { ITSEncryptionExportComplianceCode: exportComplianceCode } : {}), + }, target: [ { target: "dmg", arch: ["arm64"], }, - { - target: "zip", - arch: ["arm64"], - }, ], hardenedRuntime: true, entitlements: "electron/entitlements.mac.plist", entitlementsInherit: "electron/entitlements.mac.plist", + ...(buildNumber ? { bundleVersion: buildNumber } : {}), ...(shouldSign ? {} : { identity: null }), ...(shouldNotarize ? { notarize: true } : {}), }, + mas: { + hardenedRuntime: false, + entitlements: "electron/entitlements.mas.plist", + entitlementsInherit: "electron/entitlements.mas.inherit.plist", + provisioningProfile: masProvisioningProfile, + }, + masDev: { + provisioningProfile: masDevProvisioningProfile, + }, dmg: { background: "assets/dmg-background.png", icon: "assets/icon.icns", diff --git a/apps/desktop/electron/desktop-runtime.ts b/apps/desktop/electron/desktop-runtime.ts index a2eefee9..def7f850 100644 --- a/apps/desktop/electron/desktop-runtime.ts +++ b/apps/desktop/electron/desktop-runtime.ts @@ -24,6 +24,10 @@ export type DesktopRuntime = { const ownerOnlyDirMode = 0o700; const ownerOnlyFileMode = 0o600; +const desktopAppVersion = import.meta.env.VITE_APP_VERSION; +if (app.isPackaged && !desktopAppVersion) { + throw new Error("Packaged desktop app is missing VITE_APP_VERSION."); +} const chmodIfSupported = async (targetPath: string, mode: number) => { if (process.platform !== "win32") { @@ -99,7 +103,7 @@ const createServerEnv = (port: number, dirs: DesktopDirs, serverUrl: string, lau BASE_URL: serverUrl, TRUSTED_ORIGINS: serverUrl, APP_SECRET: dirs.appSecret, - APP_VERSION: app.getVersion(), + APP_VERSION: desktopAppVersion, ZEROBYTE_RUNTIME: "desktop", ZEROBYTE_DESKTOP_LAUNCH_SECRET: launchSecret, ZEROBYTE_DATABASE_URL: path.join(dirs.dataDir, "zerobyte.db"), diff --git a/apps/desktop/electron/entitlements.mas.inherit.plist b/apps/desktop/electron/entitlements.mas.inherit.plist new file mode 100644 index 00000000..794eada1 --- /dev/null +++ b/apps/desktop/electron/entitlements.mas.inherit.plist @@ -0,0 +1,10 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.inherit + + + diff --git a/apps/desktop/electron/entitlements.mas.plist b/apps/desktop/electron/entitlements.mas.plist new file mode 100644 index 00000000..c197360d --- /dev/null +++ b/apps/desktop/electron/entitlements.mas.plist @@ -0,0 +1,18 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.files.user-selected.read-write + + com.apple.security.network.client + + com.apple.security.network.server + + + diff --git a/apps/desktop/fastlane/.env.example b/apps/desktop/fastlane/.env.example new file mode 100644 index 00000000..c124beff --- /dev/null +++ b/apps/desktop/fastlane/.env.example @@ -0,0 +1,3 @@ +APP_STORE_CONNECT_API_KEY_ID= +APP_STORE_CONNECT_ISSUER_ID= +APP_STORE_CONNECT_API_KEY_PATH=fastlane/AuthKey_YOUR_KEY_ID.p8 diff --git a/apps/desktop/fastlane/Fastfile b/apps/desktop/fastlane/Fastfile new file mode 100644 index 00000000..9b1dee1a --- /dev/null +++ b/apps/desktop/fastlane/Fastfile @@ -0,0 +1,118 @@ +require "shellwords" +require "fileutils" + +opt_out_usage +default_platform(:mac) + +DESKTOP_DIR = File.expand_path("..", __dir__) +APP_IDENTIFIER = "com.nicotsx.zerobyte" + +def env_value(*names) + names.each do |name| + value = ENV[name] + return value unless value.nil? || value.empty? + end + + nil +end + +def latest_mas_pkg + configured_pkg = env_value("ZEROBYTE_MAS_PKG") + return File.expand_path(configured_pkg, DESKTOP_DIR) if configured_pkg + + packages = Dir[File.join(DESKTOP_DIR, "dist", "mas-arm64", "*.pkg")] + UI.user_error!("No MAS package found. Run `bundle exec fastlane mac build_mas` first.") if packages.empty? + + packages.max_by { |path| File.mtime(path) } +end + +def prepare_mas_output + output_dir = File.join(DESKTOP_DIR, "dist", "mas-arm64") + app_dir = File.join(output_dir, "Zerobyte.app") + return unless File.exist?(app_dir) + return if File.stat(app_dir).uid == Process.uid && File.writable?(app_dir) + + stale_output_dir = "#{output_dir}.stale.#{Time.now.strftime("%Y%m%d%H%M%S")}" + FileUtils.mv(output_dir, stale_output_dir) + FileUtils.mkdir_p(output_dir) + UI.important("Moved stale MAS output to #{stale_output_dir}") +end + +def app_store_api_key + return @app_store_api_key if @app_store_api_key + + key_id = env_value("APP_STORE_CONNECT_API_KEY_ID", "ASC_KEY_ID") + issuer_id = env_value("APP_STORE_CONNECT_ISSUER_ID", "ASC_ISSUER_ID") + key_filepath = env_value("APP_STORE_CONNECT_API_KEY_PATH", "ASC_KEY_PATH") + key_content = env_value("APP_STORE_CONNECT_API_KEY_CONTENT", "ASC_KEY_CONTENT") + key_content_base64 = env_value("APP_STORE_CONNECT_API_KEY_BASE64", "ASC_KEY_BASE64") + + UI.user_error!("Set APP_STORE_CONNECT_API_KEY_ID or ASC_KEY_ID.") unless key_id + UI.user_error!("Set APP_STORE_CONNECT_ISSUER_ID or ASC_ISSUER_ID.") unless issuer_id + + options = { + key_id: key_id, + issuer_id: issuer_id, + } + + if key_filepath + options[:key_filepath] = File.expand_path(key_filepath, DESKTOP_DIR) + elsif key_content_base64 + options[:key_content] = key_content_base64 + options[:is_key_content_base64] = true + elsif key_content + options[:key_content] = key_content + else + UI.user_error!( + "Set APP_STORE_CONNECT_API_KEY_PATH, APP_STORE_CONNECT_API_KEY_CONTENT, or APP_STORE_CONNECT_API_KEY_BASE64.", + ) + end + + @app_store_api_key = app_store_connect_api_key(**options) +end + +def mas_build_number + explicit_build_number = env_value("ZEROBYTE_BUILD_NUMBER") + return explicit_build_number if explicit_build_number + + run_number = env_value("GITHUB_RUN_NUMBER") + run_attempt = env_value("GITHUB_RUN_ATTEMPT") + return [run_number, run_attempt].compact.join(".") if run_number + + UI.user_error!("Set ZEROBYTE_BUILD_NUMBER or GITHUB_RUN_NUMBER.") +end + +platform :mac do + desc "Build the signed Mac App Store package" + lane :build_mas do + build_number = mas_build_number + env = "ZEROBYTE_BUILD_NUMBER=#{Shellwords.escape(build_number)} " + + prepare_mas_output + sh("cd #{Shellwords.escape(DESKTOP_DIR)} && #{env}bun run make:mas") + end + + desc "Upload the latest signed Mac App Store package to App Store Connect" + lane :upload_testflight do + pkg = latest_mas_pkg + UI.message("Uploading #{pkg}") + + upload_to_app_store( + api_key: app_store_api_key, + app_identifier: APP_IDENTIFIER, + pkg: pkg, + platform: "osx", + skip_metadata: true, + skip_screenshots: true, + skip_app_version_update: true, + force: true, + run_precheck_before_submit: false, + ) + end + + desc "Build and upload the Mac App Store package to App Store Connect" + lane :beta do |options| + build_mas unless options[:skip_build] || ENV["ZEROBYTE_SKIP_MAS_BUILD"] == "true" + upload_testflight + end +end diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 6a540006..3f740d51 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -9,6 +9,9 @@ "build:electron": "vite build --config vite.main.config.ts", "package": "electron-builder --config electron-builder.config.cjs --mac dir --publish never", "make": "electron-builder --config electron-builder.config.cjs --mac --publish never", + "make:mas": "electron-builder --config electron-builder.config.cjs --mac mas --publish never", + "make:mas-dev": "electron-builder --config electron-builder.config.cjs --mac mas-dev --publish never", + "publish": "electron-builder --config electron-builder.config.cjs --mac --publish always", "tsc": "tsc --noEmit" }, "dependencies": {