From 3354d7ec45cebd6b4cf903d944f04fe513412289 Mon Sep 17 00:00:00 2001 From: Bohdan Triapitsyn Date: Fri, 22 May 2026 10:43:56 +0300 Subject: [PATCH] ci: preserve macOS app permissions in migration Transfers Electron app as a tarball between release jobs Verifies the macOS app executable before packaging Documents permission risk in Tauri migration flow --- .github/workflows/release.yml | 28 +++++++++++++++++++--------- docs/TAURI_TO_ELECTRON_CUTOVER.md | 14 +++++++++----- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 91940d18..9764939d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -259,12 +259,13 @@ jobs: rm -rf electron-app-artifact mkdir -p electron-app-artifact cp -R "$APP_PATH" electron-app-artifact/OpenChamber.app + tar -C electron-app-artifact -czf electron-app-${{ matrix.arch }}.tar.gz OpenChamber.app - name: Upload signed Electron app for Tauri updater repackage uses: actions/upload-artifact@v4 with: name: electron-app-${{ matrix.arch }} - path: electron-app-artifact/OpenChamber.app + path: electron-app-${{ matrix.arch }}.tar.gz retention-days: 1 - name: Upload per-arch latest-mac.yml for merge @@ -308,15 +309,24 @@ jobs: run: | set -euo pipefail + if [ -f staged/electron-app-${{ matrix.arch }}.tar.gz ]; then + tar -C staged -xzf staged/electron-app-${{ matrix.arch }}.tar.gz + elif [ ! -d staged/OpenChamber.app ] && [ -d staged/Contents ]; then + mkdir -p staged/OpenChamber.app + mv staged/Contents staged/OpenChamber.app/Contents + fi + if [ ! -d staged/OpenChamber.app ]; then - if [ -d staged/Contents ]; then - mkdir -p staged/OpenChamber.app - mv staged/Contents staged/OpenChamber.app/Contents - else - echo "Error: staged/OpenChamber.app not found" - ls -la staged - exit 1 - fi + echo "Error: staged/OpenChamber.app not found" + ls -la staged + exit 1 + fi + + APP_EXECUTABLE=$(find staged/OpenChamber.app/Contents/MacOS -type f -maxdepth 1 -print -quit) + if [ -z "$APP_EXECUTABLE" ] || [ ! -x "$APP_EXECUTABLE" ]; then + echo "Error: Electron app executable is missing or not executable" + ls -la staged/OpenChamber.app/Contents/MacOS + exit 1 fi cd staged diff --git a/docs/TAURI_TO_ELECTRON_CUTOVER.md b/docs/TAURI_TO_ELECTRON_CUTOVER.md index 6f7c61f7..ec5b596d 100644 --- a/docs/TAURI_TO_ELECTRON_CUTOVER.md +++ b/docs/TAURI_TO_ELECTRON_CUTOVER.md @@ -96,7 +96,8 @@ create-release The transition works like this: 1. `build-desktop-electron-macos` builds, signs, and notarizes the Electron app. -2. It uploads the signed `OpenChamber.app` as a short-lived Actions artifact. +2. It wraps the signed `OpenChamber.app` in a tarball and uploads that tarball + as a short-lived Actions artifact. 3. `repackage-electron-as-tauri-update` downloads that Electron `.app`. 4. It packs it into `OpenChamber--darwin-*.app.tar.gz`. 5. It signs that tarball with `tauri signer sign` and the existing Tauri signing key. @@ -114,10 +115,13 @@ only verifies the signature and extracts the bundle over the existing `/Applications/OpenChamber.app`. After restart, the app is Electron and future updates use `latest-mac.yml` through `electron-updater`. -Note: `actions/upload-artifact` can download a `.app` directory artifact as its -inner `Contents/` folder instead of `OpenChamber.app/Contents`. The repackage -job handles both shapes and wraps `Contents/` back into `OpenChamber.app` before -creating the tarball. +Note: do not upload the `.app` directory directly with `actions/upload-artifact`. +That action can flatten the app to its inner `Contents/` folder and can also +normalize file modes. Losing the executable bit on `Contents/MacOS/*` makes the +updated app fail to launch with a permissions/package error. The workflow wraps +the `.app` in a tarball before upload so permissions survive the handoff between +jobs, then verifies the app executable is still executable before creating the +Tauri updater tarball. ## Historical release workflow changes