Fix the "App is damaged and can't be opened" error on macOS ARM64 builds of VRT, while ensuring the bundled Chromium browser doesn't cause code signing failures during the build process.
- "Damaged" Error: macOS Gatekeeper marks unsigned or improperly signed apps downloaded/created as "quarantined". On Apple Silicon (ARM64), code signing is enforced. If an app has no signature (
identity: null), it is rejected immediately. - Previous Signing Failure: The previous build failed signing because
electron-buildertried to sign the bundled Chromium application, which has a complex internal structure (nested apps likeChromium Helper), andcodesignchoked on file paths or existing signatures.
Run the following command in the terminal to remove the quarantine attribute from the "damaged" app:
xattr -cr /path/to/VRT.appWe need to re-enable ad-hoc signing (which satisfies ARM64 requirements) but prevent the build from failing on the Chromium files.
Electron-builder tries to sign everything in the app bundle. The Chromium build we are copying contains its own valid signatures, but electron-builder tries to re-sign or timestamp them, causing conflicts.
To avoid codesign trying to sign the thousands of complex files inside Chromium during the build:
- Compress: Zip the
chromium-xxxxfolder inprepare-browsers.sh. - Package: Include the
.zipfile inextraResourcesinstead of the raw folder. - Runtime: In
browser-installer.ts, check if the zip exists, and unzip it touserDataon first run if needed (or keep it in resources and unzip to a temporary spot).- Actually, sticking to the current path structure is better. We can unzip on first run.
- Wait, if we unzip at runtime, the unzipped app will still need to be valid. On ARM64, running an unsigned binary extracted from a zip might still trigger issues, but usually ad-hoc created files are okay locally.
Instead of null, we use - which stands for ad-hoc signing. This is often the default if no ID is found, but setting null explicitly disabled it.
We also need to see if we can tell electron-builder to ignore the playwright-browsers folder during signing.
Configuration:
"mac": {
"identity": "-",
"startOnLogin": false,
...
}And potentially signIgnore if applicable? Electron-builder has forceCodeSigning.
Refined Plan:
-
Restore Ad-Hoc Signing: Change
identityinpackage.jsonto-(or removenullto let it default to ad-hoc/auto). -
Handle Chromium Signing Issues: The error we saw earlier was:
Chromium Helper (Alerts).app: No such file or directoryorreplacing existing signature. This often happens because of deep path lengths or file attributes. We will modifypackage.jsonto useasar: true(it is already true) but ensureplaywright-browsersis inextraResources(it is).extraResourcesare signed by default.We should try to configure
customSignorsignIgnore?electron-builderdoesn't strictly have asignIgnorefor extraResources easily exposed.Alternative: Copy the browser files after packaging? No, that's hard with
electron-builder.Best Approach: Go with Strategy B (Zip it). It solves the "Build failed because of signing errors" issue completely. It solves the "File path too long" issues potentially. It keeps the package cleaner.
We will:
- Update
prepare-browsers.shto zip the browser folder. - Update
package.jsonto copy the.zipfile. - Update
browser-installer.tsto detect if the folder exists, if not check for zip, and unzip if needed.
Wait,
browser-installer.tsruns in the main process. Unzipping 300MB might take a few seconds on first launch. We can show a "Initializing..." status. - Update
-
Modify
scripts/prepare-browsers.sh:- Find the browser.
- Create a
browsers.zipcontaining the chromium and ffmpeg folders. - Update
package.jsonto includebrowsers.zipinextraResources.
-
Modify
src/main/browser-installer.ts:- Add logic to check if
playwright-browsersis a directory. - If not, look for
browsers.zipin resources. - Unzip it to
app.getPath('userData')/playwright-browsers(Writability is guaranteed there!). - Update
PLAYWRIGHT_BROWSERS_PATHto point to theuserDatalocation.
Benefits:
- Fixes the code signing build error (we just sign a zip file).
- Fixes the "ReadOnly" issue completely because we execute from
UserData. - Fixes the "Damaged App" issue because we can enable standard Ad-Hoc signing for the main app container without the inner Chromium signatures conflicting.
- Add logic to check if
- Run
npm run dist:mac. - Verify build succeeds (no signing errors).
- Run the app (ARM64).
- Verify it launches (no "damaged" error).
- Verify it unpacks and finds the browser.