mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
Batch macOS signing calls for adhoc releases (#31340)
This commit is contained in:
@@ -640,6 +640,7 @@ module.exports = {
|
||||
icon: 'resources/build/icon.icns',
|
||||
entitlements: 'resources/build/entitlements.mac.plist',
|
||||
entitlementsInherit: 'resources/build/entitlements.mac.plist',
|
||||
...(isMacAdhoc ? { sign: resolve(__dirname, 'scripts/sign-adhoc-mac-app.mjs') } : {}),
|
||||
signIgnore: [
|
||||
...bundledRipgrepMacSignIgnore,
|
||||
...orcadTemplateMacSignIgnore,
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { createRequire } from 'node:module'
|
||||
|
||||
export function signAdhocMacApp(options, { sign, retry }) {
|
||||
// A custom signer bypasses electron-builder's retry wrapper.
|
||||
return retry(() => sign({ ...options, batchCodesignCalls: true }), {
|
||||
retries: 3,
|
||||
interval: 5000,
|
||||
backoff: 5000
|
||||
})
|
||||
}
|
||||
|
||||
export default async function sign(options) {
|
||||
const { sign: signApplication } = await import('@electron/osx-sign')
|
||||
const builderRequire = createRequire(createRequire(import.meta.url).resolve('electron-builder'))
|
||||
const require = createRequire(builderRequire.resolve('app-builder-lib'))
|
||||
const { retry } = require('builder-util')
|
||||
const started = performance.now()
|
||||
await signAdhocMacApp(options, { sign: signApplication, retry })
|
||||
console.log(
|
||||
`[mac-sign] batched signing completed in ${Math.round(performance.now() - started)}ms`
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
import { createRequire } from 'node:module'
|
||||
import { resolve } from 'node:path'
|
||||
import { expect, it } from 'vitest'
|
||||
import { signAdhocMacApp } from './sign-adhoc-mac-app.mjs'
|
||||
|
||||
const require = createRequire(import.meta.url)
|
||||
const builderRequire = createRequire(require.resolve('electron-builder'))
|
||||
const appBuilderRequire = createRequire(builderRequire.resolve('app-builder-lib'))
|
||||
const { resolveFunction } = appBuilderRequire('app-builder-lib/out/util/resolve')
|
||||
|
||||
it('preserves file-specific signing policy and retries with fresh options', async () => {
|
||||
const calls = []
|
||||
const failure = new Error('timestamp service unavailable')
|
||||
const options = {
|
||||
app: '/fixture/Orca.app',
|
||||
platform: 'darwin',
|
||||
type: 'distribution',
|
||||
identity: 'SIGNING_IDENTITY',
|
||||
identityValidation: false,
|
||||
keychain: '/fixture/signing.keychain',
|
||||
binaries: ['/fixture/extra-helper'],
|
||||
optionsForFile: (path) => ({ entitlements: `${path}.plist`, hardenedRuntime: true }),
|
||||
ignore: [(path) => path.includes('/orcad-template/')],
|
||||
preAutoEntitlements: false
|
||||
}
|
||||
let policy
|
||||
const result = await signAdhocMacApp(options, {
|
||||
async retry(task, retryOptions) {
|
||||
policy = retryOptions
|
||||
try {
|
||||
return await task()
|
||||
} catch (error) {
|
||||
expect(error).toBe(failure)
|
||||
return task()
|
||||
}
|
||||
},
|
||||
async sign(received) {
|
||||
calls.push(received)
|
||||
if (calls.length === 1) {
|
||||
throw failure
|
||||
}
|
||||
return 'signed'
|
||||
}
|
||||
})
|
||||
expect(result).toBe('signed')
|
||||
expect(policy).toEqual({ retries: 3, interval: 5000, backoff: 5000 })
|
||||
expect(calls).toHaveLength(2)
|
||||
expect(calls[0]).not.toBe(calls[1])
|
||||
for (const received of calls) {
|
||||
expect(received).toEqual({ ...options, batchCodesignCalls: true })
|
||||
expect(received.optionsForFile).toBe(options.optionsForFile)
|
||||
expect(received.optionsForFile('/fixture/helper')).toEqual({
|
||||
entitlements: '/fixture/helper.plist',
|
||||
hardenedRuntime: true
|
||||
})
|
||||
expect(received.ignore[0]('/fixture/orcad-template/helper')).toBe(true)
|
||||
}
|
||||
expect(options).not.toHaveProperty('batchCodesignCalls')
|
||||
})
|
||||
|
||||
it('propagates signing failure after the retry policy is exhausted', async () => {
|
||||
const failure = new Error('signature verification failed')
|
||||
await expect(
|
||||
signAdhocMacApp(
|
||||
{},
|
||||
{
|
||||
retry: (task) => task(),
|
||||
sign: async () => {
|
||||
throw failure
|
||||
}
|
||||
}
|
||||
)
|
||||
).rejects.toBe(failure)
|
||||
})
|
||||
|
||||
it.each([
|
||||
{ ORCA_MAC_ADHOC: '1' },
|
||||
{},
|
||||
{ ORCA_MAC_RELEASE: '1' },
|
||||
{ ORCA_MAC_HOURLY: '1' },
|
||||
{ ORCA_MAC_DAILY: '1' },
|
||||
{ ORCA_WIN_ADHOC: '1' }
|
||||
])('only selects the batched signer for adhoc macOS builds: %j', async (env) => {
|
||||
const configPath = resolve('config/electron-builder.config.cjs')
|
||||
const saved = { ...process.env }
|
||||
try {
|
||||
for (const name of Object.keys(process.env)) {
|
||||
if (name.startsWith('ORCA_')) {
|
||||
delete process.env[name]
|
||||
}
|
||||
}
|
||||
Object.assign(process.env, env)
|
||||
delete require.cache[configPath]
|
||||
const config = require(configPath)
|
||||
if (env.ORCA_MAC_ADHOC === '1') {
|
||||
expect(config.mac.sign).toBe(resolve('config/scripts/sign-adhoc-mac-app.mjs'))
|
||||
const hook = await resolveFunction(undefined, config.mac.sign, 'sign', process.cwd())
|
||||
expect(typeof hook).toBe('function')
|
||||
expect(hook.name).toBe('sign')
|
||||
expect(config.mac.signIgnore).toContain('/orcad-template/')
|
||||
expect(config.forceCodeSigning).toBe(true)
|
||||
expect(config.mac.hardenedRuntime).toBe(true)
|
||||
expect(config.mac.notarize).toBe(true)
|
||||
} else {
|
||||
expect(config.mac.sign).toBeUndefined()
|
||||
}
|
||||
} finally {
|
||||
process.env = saved
|
||||
delete require.cache[configPath]
|
||||
}
|
||||
})
|
||||
@@ -226,6 +226,7 @@
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@electron-toolkit/tsconfig": "^2.0.0",
|
||||
"@electron/osx-sign": "2.7.0",
|
||||
"@electron/rebuild": "^4.2.1",
|
||||
"@monaco-editor/react": "^4.7.0",
|
||||
"@noble/hashes": "1.8.0",
|
||||
|
||||
Generated
+17
@@ -287,6 +287,9 @@ importers:
|
||||
'@electron-toolkit/tsconfig':
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0(@types/node@24.19.2)
|
||||
'@electron/osx-sign':
|
||||
specifier: 2.7.0
|
||||
version: 2.7.0(supports-color@7.2.0)
|
||||
'@electron/rebuild':
|
||||
specifier: ^4.2.1
|
||||
version: 4.2.1(supports-color@7.2.0)
|
||||
@@ -1041,6 +1044,11 @@ packages:
|
||||
engines: {node: '>=12.0.0'}
|
||||
hasBin: true
|
||||
|
||||
'@electron/osx-sign@2.7.0':
|
||||
resolution: {integrity: sha512-9DGhNqKMl6ibkhUoXbN7OHX2gZznfY10L3ZwG0u6r667Kfb6kec4JEfFTXftoqzmOfZ+OzwDbr4p/nKBMHnz0g==}
|
||||
engines: {node: '>=22.12.0'}
|
||||
hasBin: true
|
||||
|
||||
'@electron/rebuild@4.2.1':
|
||||
resolution: {integrity: sha512-IS4pG3BysRrCLJ8xTAfvg+IQDbiUoAzdJy2SfjcYKnLDy5DpCdjnPdhS5Zf5UMfrkB24xu0KC+TqcOxg+eG+6w==}
|
||||
engines: {node: '>=22.12.0'}
|
||||
@@ -8944,6 +8952,15 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@electron/osx-sign@2.7.0(supports-color@7.2.0)':
|
||||
dependencies:
|
||||
debug: 4.4.3(supports-color@7.2.0)
|
||||
isbinaryfile: 4.0.10
|
||||
plist: 3.1.0
|
||||
semver: 7.8.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@electron/rebuild@4.2.1(supports-color@7.2.0)':
|
||||
dependencies:
|
||||
'@malept/cross-spawn-promise': 2.0.0
|
||||
|
||||
Reference in New Issue
Block a user