The first release could not be opened: macOS said "WarpEngine Store is damaged and can't be opened. You should move it to the Bin." Not a wording problem — an integrity one. electron-builder found no signing identity and skipped signing, so the bundle kept only the linker's ad-hoc signature on its main executable, with no resource seal. `codesign --verify` said "code has no resources but signature indicates they must be present", and Gatekeeper reports that as damaged and offers no way past it, unlike an un-notarised app which can at least be approved. `scripts/after-pack.js` now signs the bundle itself during packaging. Measured on a copy unzipped from the artifact with the quarantine flag set by hand: before code has no resources but signature indicates they must be present after valid on disk; satisfies its Designated Requirement and the identifier is ours rather than `Electron`. `syspolicy_check` is down to its expected "adhoc signed" warning. A downloaded copy still has to be approved — that is Gatekeeper policy for anything un-notarised, and notarisation needs a paid Developer ID — so the README and the release notes lead with the one command that does it. Two smaller things the failure turned up: - The self-test was passing silently. With a copy of the app already open, the second process lost the single-instance lock and exited 0 with no output, which reads exactly like success. It now uses its own user-data directory and skips the lock, and it caught a real launch failure immediately afterwards. - The README claimed right-click ▸ Open was enough. It was not, and I had not checked it — replaced with what the measurements support. v1.0.0's attachments are withdrawn rather than left downloadable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
33 lines
1.6 KiB
JavaScript
33 lines
1.6 KiB
JavaScript
'use strict'
|
|
// Ad-hoc sign the macOS bundle after packing.
|
|
//
|
|
// Without this the bundle carries only the linker's ad-hoc signature on the main
|
|
// executable, with no resource seal — `codesign --verify` says "code has no
|
|
// resources but signature indicates they must be present". That runs fine
|
|
// locally, but a browser download adds the quarantine flag, Gatekeeper evaluates
|
|
// the broken seal, and macOS reports the app as *damaged* rather than merely
|
|
// unverified. The first release shipped exactly that.
|
|
//
|
|
// An ad-hoc signature is not a Developer ID and does not notarise anything: the
|
|
// user still has to right-click ▸ Open the first time. It is the difference
|
|
// between "unidentified developer" and "move it to the Bin".
|
|
|
|
const { execFileSync } = require('node:child_process')
|
|
const path = require('node:path')
|
|
|
|
exports.default = async function afterPack (context) {
|
|
if (context.electronPlatformName !== 'darwin') return
|
|
if (process.platform !== 'darwin') {
|
|
console.log(' • ad-hoc signing skipped reason=codesign only exists on macOS')
|
|
return
|
|
}
|
|
|
|
const app = path.join(context.appOutDir, `${context.packager.appInfo.productFilename}.app`)
|
|
// --deep is the pragmatic choice for ad-hoc signing a bundle with nested
|
|
// frameworks and helpers; Apple discourages it for real identities, where the
|
|
// inner-to-outer order matters.
|
|
execFileSync('codesign', ['--force', '--deep', '--sign', '-', app], { stdio: 'inherit' })
|
|
execFileSync('codesign', ['--verify', '--deep', '--strict', '--verbose=1', app], { stdio: 'inherit' })
|
|
console.log(` • ad-hoc signed ${app}`)
|
|
}
|