Fix rcodesign CLI: self-signed p12 instead of removed --ad-hoc
Release rolling / release (push) Has been cancelled

apple-codesign 0.29 rejects --ad-hoc. Generate a self-signed P12 and
sign darwin .app bundles with --p12-file so Linux CI produces a sealed
signature instead of failing postPackage.
This commit is contained in:
Raven Scott
2026-07-11 15:16:15 -04:00
parent 172ed58383
commit 05fc14862a
2 changed files with 124 additions and 13 deletions
+120 -13
View File
@@ -211,29 +211,136 @@ function codesignDarwin(appPath, id) {
log('verify ok:', (v.stderr || v.stdout || '').trim().split('\n').slice(0, 3).join(' | '))
}
/**
* rcodesign 0.29+ does not accept `--ad-hoc`.
* "Ad-hoc" equivalent for Linux CI: self-signed cert via p12/pem, then `rcodesign sign`.
* Self-signed is enough for a *valid* sealed signature (avoids Gatekeeper "damaged");
* it is NOT Developer ID / notarization.
*/
function ensureRcodesignSelfSignedP12(bin) {
const certDir =
process.env.PEARDOCK_RCODESIGN_CERT_DIR ||
path.join(__dirname, '..', 'tools', 'rcodesign', 'ci-cert')
const p12Path = path.join(certDir, 'peardock-ci.p12')
const password = process.env.PEARDOCK_RCODESIGN_P12_PASSWORD || 'peardock-ci-sign'
fs.mkdirSync(certDir, { recursive: true })
if (fs.existsSync(p12Path) && fs.statSync(p12Path).size > 100) {
return { p12Path, password }
}
log('generating self-signed signing cert for rcodesign…')
// Flags match apple-codesign 0.29 generate-self-signed-certificate CLI
const gen = spawnSync(
bin,
[
'generate-self-signed-certificate',
'--p12-file',
p12Path,
'--p12-password',
password,
'--person-name',
'peardock-ci',
'--country-name',
'US',
'--validity-days',
'3650',
'--team-id',
'NONE',
'--profile',
'developer-id-application',
],
{ encoding: 'utf8', stdio: 'pipe' }
)
if (gen.status !== 0 || !fs.existsSync(p12Path)) {
// Older/newer flag variants
const gen2 = spawnSync(
bin,
[
'generate-self-signed-certificate',
'--p12-file',
p12Path,
'--p12-password',
password,
'--person-name',
'peardock-ci',
'--country-name',
'US',
'--validity-days',
'3650',
],
{ encoding: 'utf8', stdio: 'pipe' }
)
if (gen2.status !== 0 || !fs.existsSync(p12Path)) {
throw new Error(
`rcodesign generate-self-signed-certificate failed:\n` +
`${gen.stderr || gen.stdout}\n${gen2.stderr || gen2.stdout}`
)
}
}
log('wrote', p12Path)
return { p12Path, password }
}
function codesignRcodesign(appPath, id) {
const bin = which('rcodesign')
if (!bin) {
throw new Error(
'rcodesign not found (needed to ad-hoc sign macOS .app on Linux). ' +
'Install apple-codesign / rcodesign in CI, or package darwin clients on macOS.'
'rcodesign not found (needed to sign macOS .app on Linux). ' +
'CI installs tools/rcodesign/<host>/rcodesign, or package darwin clients on macOS.'
)
}
if (id !== '-') {
log('WARN: rcodesign path only used for ad-hoc here; Developer ID needs codesign on macOS + certs')
log(
'WARN: Linux rcodesign path uses self-signed cert only; ' +
'Developer ID needs codesign on macOS + Apple certs'
)
}
// Clear extended attrs if possible (mac only usually)
const args = ['sign', '--ad-hoc', appPath]
log('rcodesign', args.join(' '))
const r = spawnSync(bin, args, { encoding: 'utf8', stdio: 'pipe' })
if (r.status !== 0) {
// newer CLI variants
const r2 = spawnSync(bin, ['sign', appPath, '--ad-hoc'], { encoding: 'utf8', stdio: 'pipe' })
if (r2.status !== 0) {
throw new Error(`rcodesign failed:\n${r.stderr || r.stdout}\n${r2.stderr || r2.stdout}`)
const entitlements = ensureEntitlements()
const { p12Path, password } = ensureRcodesignSelfSignedP12(bin)
// Prefer full Electron-friendly sign: p12 + runtime + entitlements
const attempts = [
[
'sign',
'--p12-file',
p12Path,
'--p12-password',
password,
'--code-signature-flags',
'runtime',
'--entitlements-xml-file',
entitlements,
appPath,
],
[
'sign',
'--p12-file',
p12Path,
'--p12-password',
password,
'--code-signature-flags',
'runtime',
appPath,
],
['sign', '--p12-file', p12Path, '--p12-password', password, appPath],
]
let lastErr = ''
for (const args of attempts) {
// Never log the password
log(
'rcodesign',
args.map((a) => (a === password ? '***' : a)).join(' ')
)
const r = spawnSync(bin, args, { encoding: 'utf8', stdio: 'pipe' })
if (r.status === 0) {
log('rcodesign sign complete (self-signed / sealed)')
return
}
lastErr += `${r.stderr || r.stdout || ''}\n`
}
log('rcodesign ad-hoc sign complete')
throw new Error(`rcodesign failed:\n${lastErr}`)
}
function signApp(appPath) {