Gatekeeper reported the Bare server binary as damaged because it only had a linker ad-hoc stamp after embed. Seal darwin server binaries with the same sign-macos path used for Electron apps (codesign / rcodesign).
This commit is contained in:
@@ -122,9 +122,9 @@ jobs:
|
|||||||
echo "==> npm ci done (electron binary deferred to forge package step)"
|
echo "==> npm ci done (electron binary deferred to forge package step)"
|
||||||
node -e "console.log('node', process.version); console.log('esbuild', require('esbuild').version)"
|
node -e "console.log('node', process.version); console.log('esbuild', require('esbuild').version)"
|
||||||
|
|
||||||
# Ad-hoc codesign for darwin .app bundles produced on Linux (fixes Gatekeeper "damaged").
|
# Codesign for darwin .app + peardock-server binaries on Linux (fixes Gatekeeper "damaged").
|
||||||
# Binary is vendored under tools/rcodesign/ (no GitHub download — runners often stall there).
|
# Binary is vendored under tools/rcodesign/ (no GitHub download — runners often stall there).
|
||||||
- name: Install rcodesign (macOS ad-hoc signing on Linux)
|
- name: Install rcodesign (macOS codesign on Linux)
|
||||||
timeout-minutes: 2
|
timeout-minutes: 2
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ Asset patterns:
|
|||||||
- `peardock-server-VERSION-HOST.tar.gz` (+ `.sha256`)
|
- `peardock-server-VERSION-HOST.tar.gz` (+ `.sha256`)
|
||||||
- `peardock-client-VERSION-HOST.tar.gz` (+ `.sha256`; macOS includes a `.app`)
|
- `peardock-client-VERSION-HOST.tar.gz` (+ `.sha256`; macOS includes a `.app`)
|
||||||
|
|
||||||
macOS clients from Linux CI are ad-hoc signed. If Gatekeeper blocks: right-click → Open, or `xattr -cr ~/Applications/peardock.app`. Re-sign: `npm run sign:macos -- out/peardock-darwin-arm64/peardock.app`.
|
macOS client (`.app`) and server (`peardock-server`) binaries from CI are codesigned (avoids Gatekeeper “damaged”). If Gatekeeper still blocks: right-click → Open, or `xattr -cr <path>`. Re-sign: `npm run sign:macos -- out/peardock-darwin-arm64/peardock.app` or `…/peardock-server-darwin-arm64/peardock-server`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -243,7 +243,7 @@ macOS clients from Linux CI are ad-hoc signed. If Gatekeeper blocks: right-click
|
|||||||
| `npm run soak` / `soak:24h` | Certification soak against Docker |
|
| `npm run soak` / `soak:24h` | Certification soak against Docker |
|
||||||
| `npm run make` | Cross-build all server + client hosts |
|
| `npm run make` | Cross-build all server + client hosts |
|
||||||
| `npm run make:server` / `make:client` | Server-only or client-only builds |
|
| `npm run make:server` / `make:client` | Server-only or client-only builds |
|
||||||
| `npm run sign:macos` | Ad-hoc / identity re-sign for `.app` |
|
| `npm run sign:macos` | Ad-hoc / identity re-sign for `.app` or `peardock-server` |
|
||||||
| `npm run release:checksums` | Tarball + SHA-256 (+ optional GPG) |
|
| `npm run release:checksums` | Tarball + SHA-256 (+ optional GPG) |
|
||||||
| `npm run release:rolling` | Local dry-run helper for rolling publish |
|
| `npm run release:rolling` | Local dry-run helper for rolling publish |
|
||||||
|
|
||||||
|
|||||||
@@ -343,7 +343,7 @@ v1 used Hyperswarm topics + ad-hoc JSON streams and is **not** wire-compatible.
|
|||||||
| Rate limit errors | Middleware | `server/utils/rateLimiter.js` |
|
| Rate limit errors | Middleware | `server/utils/rateLimiter.js` |
|
||||||
| Tunnel create fails | Holesail flag / SSRF | `ENABLE_HOLESAIL`; `PEARDOCK_TUNNEL_HOSTS` |
|
| Tunnel create fails | Holesail flag / SSRF | `ENABLE_HOLESAIL`; `PEARDOCK_TUNNEL_HOSTS` |
|
||||||
| Swarm empty / error | Swarm mode / flag | Engine swarm state; `ENABLE_SWARM` |
|
| Swarm empty / error | Swarm mode / flag | Engine swarm state; `ENABLE_SWARM` |
|
||||||
| macOS “damaged” app | Gatekeeper | `xattr -cr`; ad-hoc sign docs |
|
| macOS “damaged” app/binary | Gatekeeper | codesign in CI (`sign-macos-app.cjs`); `xattr -cr` / right-click Open |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ Build: `npm run build:client-bundle` → `scripts/build-client-bundle.cjs`.
|
|||||||
| `build-client-bundle.cjs` | esbuild client bundle |
|
| `build-client-bundle.cjs` | esbuild client bundle |
|
||||||
| `gitea-rolling-release.sh` | CI publish to `rolling` |
|
| `gitea-rolling-release.sh` | CI publish to `rolling` |
|
||||||
| `hosts.cjs` | Canonical 64-bit host list |
|
| `hosts.cjs` | Canonical 64-bit host list |
|
||||||
| `sign-macos-app.cjs` | Ad-hoc / identity sign |
|
| `sign-macos-app.cjs` | Ad-hoc / identity sign for `.app` + `peardock-server` |
|
||||||
| `healthcheck.js` | Docker socket probe |
|
| `healthcheck.js` | Docker socket probe |
|
||||||
| `soak.js` | Long-run certification |
|
| `soak.js` | Long-run certification |
|
||||||
| `release-checksums.sh` | Checksums / optional GPG |
|
| `release-checksums.sh` | Checksums / optional GPG |
|
||||||
|
|||||||
+1
-1
@@ -213,7 +213,7 @@ Admin-defined recurring maintenance (e.g. prune) persisted and restored at boot.
|
|||||||
| 6×64-bit client hosts | Electron forge |
|
| 6×64-bit client hosts | Electron forge |
|
||||||
| rolling tag | Continuous release channel |
|
| rolling tag | Continuous release channel |
|
||||||
| install.sh | Server systemd + client install |
|
| install.sh | Server systemd + client install |
|
||||||
| macOS ad-hoc sign | Gatekeeper-friendly CI builds |
|
| macOS codesign (client + server) | Gatekeeper-friendly CI builds (avoids “damaged”) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+7
-5
@@ -8,8 +8,8 @@ No 32-bit (`ia32` / `armv7`) builds.
|
|||||||
|------|---------------|-------------------|
|
|------|---------------|-------------------|
|
||||||
| `linux-x64` | yes (cross) | yes (cross via electron-forge) |
|
| `linux-x64` | yes (cross) | yes (cross via electron-forge) |
|
||||||
| `linux-arm64` | yes | yes |
|
| `linux-arm64` | yes | yes |
|
||||||
| `darwin-x64` | yes | yes (unsigned / ad-hoc from Linux CI) |
|
| `darwin-x64` | yes (codesigned in CI) | yes (codesigned in CI) |
|
||||||
| `darwin-arm64` | yes | yes (unsigned / ad-hoc from Linux CI) |
|
| `darwin-arm64` | yes (codesigned in CI) | yes (codesigned in CI) |
|
||||||
| `win32-x64` | yes | yes |
|
| `win32-x64` | yes | yes |
|
||||||
| `win32-arm64` | yes | yes |
|
| `win32-arm64` | yes | yes |
|
||||||
|
|
||||||
@@ -96,9 +96,11 @@ Published assets are consumed by:
|
|||||||
|
|
||||||
### Notes
|
### Notes
|
||||||
|
|
||||||
- **macOS clients** are **ad-hoc codesigned** after package (`scripts/sign-macos-app.cjs`) so Gatekeeper does not show “damaged / move to Trash”. CI installs `rcodesign` to ad-hoc sign darwin `.app`s built on Linux. For Developer ID + notarization, set `MAC_CODESIGN_IDENTITY` / `CSC_NAME` on a Mac (or import certs in CI).
|
- **macOS clients** (`.app`) and **peardock-server** binaries are **codesigned** after build (`scripts/sign-macos-app.cjs`) so Gatekeeper does not show “damaged / move to Trash”. Server signing runs inside `bare-standalone.cjs` for every `darwin-*` host; client signing runs in Electron Forge `postPackage`. CI installs vendored `rcodesign` to seal darwin artifacts built on Linux. For Developer ID + notarization, set `MAC_CODESIGN_IDENTITY` / `CSC_NAME` on a Mac (or import certs in CI).
|
||||||
- Re-sign a local/downloaded build: `npm run sign:macos -- out/peardock-darwin-arm64/peardock.app`
|
- Re-sign a local/downloaded build:
|
||||||
- If the app is still blocked: `xattr -cr ~/Applications/peardock.app` or right-click → Open.
|
- Client: `npm run sign:macos -- out/peardock-darwin-arm64/peardock.app`
|
||||||
|
- Server: `npm run sign:macos -- out/peardock-server-darwin-arm64/peardock-server`
|
||||||
|
- If still blocked: `xattr -cr <path>` or right-click → Open. Skip signing with `PEARDOCK_SKIP_MACOS_SIGN=1` (not recommended for release).
|
||||||
- **Native modules** must ship prebuilds for each target (Holepunch stack does). Rebuild-from-source is disabled for cross packages (`npm_config_build_from_source=false`).
|
- **Native modules** must ship prebuilds for each target (Holepunch stack does). Rebuild-from-source is disabled for cross packages (`npm_config_build_from_source=false`).
|
||||||
- **Server** cross-compile uses bare-runtime platform prebuilds (no Docker-in-Docker required to *build*; runtime still needs a Docker socket).
|
- **Server** cross-compile uses bare-runtime platform prebuilds (no Docker-in-Docker required to *build*; runtime still needs a Docker socket).
|
||||||
|
|
||||||
|
|||||||
@@ -202,6 +202,15 @@ async function buildOne(host, outRoot) {
|
|||||||
binary = flat
|
binary = flat
|
||||||
}
|
}
|
||||||
console.log(`[bare-standalone] wrote ${binary}`)
|
console.log(`[bare-standalone] wrote ${binary}`)
|
||||||
|
|
||||||
|
// Re-seal darwin binaries so Gatekeeper does not report "damaged".
|
||||||
|
// bare-runtime ships linker ad-hoc stamps; embedding invalidates them.
|
||||||
|
// Linux CI uses rcodesign (same path as Electron postPackage).
|
||||||
|
if (host.startsWith('darwin') && process.env.PEARDOCK_SKIP_MACOS_SIGN !== '1') {
|
||||||
|
console.log(`[bare-standalone] codesigning ${binary} for ${host}…`)
|
||||||
|
const { signBinary } = require('./sign-macos-app.cjs')
|
||||||
|
await signBinary(binary)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn(`[bare-standalone] WARN: expected binary not found under ${outDir}`)
|
console.warn(`[bare-standalone] WARN: expected binary not found under ${outDir}`)
|
||||||
console.warn(
|
console.warn(
|
||||||
@@ -221,6 +230,8 @@ async function buildOne(host, outRoot) {
|
|||||||
builtAt: new Date().toISOString(),
|
builtAt: new Date().toISOString(),
|
||||||
entry: 'bin/peardock-server.mjs',
|
entry: 'bin/peardock-server.mjs',
|
||||||
bundleId: entry.id,
|
bundleId: entry.id,
|
||||||
|
macosSigned:
|
||||||
|
host.startsWith('darwin') && process.env.PEARDOCK_SKIP_MACOS_SIGN !== '1',
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
2
|
2
|
||||||
|
|||||||
@@ -173,7 +173,10 @@ open peardock-darwin-arm64/peardock.app # macOS
|
|||||||
# Windows: peardock-win32-x64\\\\peardock-client.exe
|
# Windows: peardock-win32-x64\\\\peardock-client.exe
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
macOS builds from Linux CI are **unsigned** (Gatekeeper may require right-click → Open).
|
macOS **client** (`.app`) and **server** (`peardock-server`) binaries are codesigned in CI
|
||||||
|
(ad-hoc / self-signed via \`rcodesign\` on Linux, or \`codesign\` on macOS). That avoids the
|
||||||
|
Gatekeeper "**damaged** and can't be opened" false positive. First open may still need
|
||||||
|
right-click → Open (not notarized unless \`MAC_CODESIGN_IDENTITY\` + Apple Developer ID).
|
||||||
|
|
||||||
## Checksums
|
## Checksums
|
||||||
|
|
||||||
|
|||||||
+149
-18
@@ -1,23 +1,28 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
/**
|
/**
|
||||||
* Deep-sign a peardock .app so macOS Gatekeeper does not report
|
* Codesign peardock macOS artifacts so Gatekeeper does not report
|
||||||
* "is damaged and can't be opened. You should move it to the Trash."
|
* "is damaged and can't be opened. You should move it to the Trash."
|
||||||
*
|
*
|
||||||
* That message almost always means an *invalid* signature (Electron binary
|
* Targets:
|
||||||
* still has a partial linker-signed ad-hoc stamp after packager rewrites the
|
* - Electron .app bundles (deep sign / nested helpers)
|
||||||
* bundle, with no sealed resources).
|
* - Standalone peardock-server Mach-O binaries (Bare)
|
||||||
|
*
|
||||||
|
* That message almost always means an *invalid* signature (linker ad-hoc
|
||||||
|
* stamp after packager/embed rewrites the binary, or unsigned download).
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
* node scripts/sign-macos-app.cjs path/to/peardock.app
|
* node scripts/sign-macos-app.cjs path/to/peardock.app
|
||||||
* node scripts/sign-macos-app.cjs path/to/out/peardock-darwin-arm64
|
* node scripts/sign-macos-app.cjs path/to/out/peardock-darwin-arm64
|
||||||
|
* node scripts/sign-macos-app.cjs path/to/out/peardock-server-darwin-arm64
|
||||||
|
* node scripts/sign-macos-app.cjs path/to/peardock-server
|
||||||
*
|
*
|
||||||
* Identity (first match wins):
|
* Identity (first match wins):
|
||||||
* MAC_CODESIGN_IDENTITY / CSC_NAME — "Developer ID Application: …" or team identity
|
* MAC_CODESIGN_IDENTITY / CSC_NAME — "Developer ID Application: …" or team identity
|
||||||
* otherwise ad-hoc (`-`) which is enough to make the app *valid* (not "damaged")
|
* otherwise ad-hoc (`-`) which is enough to make the artifact *valid* (not "damaged")
|
||||||
*
|
*
|
||||||
* Tools:
|
* Tools:
|
||||||
* macOS: /usr/bin/codesign (required for production identities)
|
* macOS: /usr/bin/codesign (required for production identities)
|
||||||
* Linux CI: rcodesign (apple-codesign) for ad-hoc when present
|
* Linux CI: rcodesign (apple-codesign) for self-signed seal when present
|
||||||
*/
|
*/
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
@@ -26,6 +31,7 @@ const path = require('path')
|
|||||||
const { spawnSync, execFileSync } = require('child_process')
|
const { spawnSync, execFileSync } = require('child_process')
|
||||||
|
|
||||||
const ENTITLEMENTS = path.join(__dirname, 'entitlements.mac.plist')
|
const ENTITLEMENTS = path.join(__dirname, 'entitlements.mac.plist')
|
||||||
|
const SERVER_BIN_NAMES = new Set(['peardock-server', 'peardock-server.exe'])
|
||||||
|
|
||||||
function log(...a) {
|
function log(...a) {
|
||||||
console.log('[sign-macos]', ...a)
|
console.log('[sign-macos]', ...a)
|
||||||
@@ -44,6 +50,50 @@ function findApps(input) {
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find standalone peardock-server Mach-O binaries under a path.
|
||||||
|
* @param {string} input
|
||||||
|
* @returns {string[]}
|
||||||
|
*/
|
||||||
|
function findServerBinaries(input) {
|
||||||
|
if (!fs.existsSync(input)) return []
|
||||||
|
const st = fs.statSync(input)
|
||||||
|
if (st.isFile()) {
|
||||||
|
const base = path.basename(input)
|
||||||
|
if (SERVER_BIN_NAMES.has(base) || base === 'peardock-server') return [input]
|
||||||
|
// Allow explicit path to any file named like our server binary
|
||||||
|
if (!base.endsWith('.app') && !base.endsWith('.dmg') && !base.endsWith('.pkg')) {
|
||||||
|
// Heuristic: treat as binary if caller passed a file path that looks executable
|
||||||
|
if (base.includes('peardock-server')) return [input]
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
if (!st.isDirectory()) return []
|
||||||
|
const found = []
|
||||||
|
const stack = [input]
|
||||||
|
while (stack.length) {
|
||||||
|
const dir = stack.pop()
|
||||||
|
let entries
|
||||||
|
try {
|
||||||
|
entries = fs.readdirSync(dir, { withFileTypes: true })
|
||||||
|
} catch {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for (const ent of entries) {
|
||||||
|
const p = path.join(dir, ent.name)
|
||||||
|
if (ent.isDirectory()) {
|
||||||
|
if (ent.name === 'node_modules' || ent.name.endsWith('.app') || ent.name.startsWith('.')) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
stack.push(p)
|
||||||
|
} else if (ent.isFile() && SERVER_BIN_NAMES.has(ent.name)) {
|
||||||
|
found.push(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found
|
||||||
|
}
|
||||||
|
|
||||||
function which(cmd) {
|
function which(cmd) {
|
||||||
try {
|
try {
|
||||||
const r = spawnSync(process.platform === 'win32' ? 'where' : 'which', [cmd], {
|
const r = spawnSync(process.platform === 'win32' ? 'where' : 'which', [cmd], {
|
||||||
@@ -281,12 +331,16 @@ function ensureRcodesignSelfSignedP12(bin) {
|
|||||||
return { p12Path, password }
|
return { p12Path, password }
|
||||||
}
|
}
|
||||||
|
|
||||||
function codesignRcodesign(appPath, id) {
|
/**
|
||||||
|
* Sign a path (`.app` or standalone Mach-O) with rcodesign on Linux CI.
|
||||||
|
* Uses a self-signed p12 (not Developer ID) so the signature is *valid/sealed*.
|
||||||
|
*/
|
||||||
|
function codesignRcodesign(targetPath, id) {
|
||||||
const bin = which('rcodesign')
|
const bin = which('rcodesign')
|
||||||
if (!bin) {
|
if (!bin) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'rcodesign not found (needed to sign macOS .app on Linux). ' +
|
'rcodesign not found (needed to sign macOS artifacts on Linux). ' +
|
||||||
'CI installs tools/rcodesign/<host>/rcodesign, or package darwin clients on macOS.'
|
'CI installs tools/rcodesign/<host>/rcodesign, or build/sign on macOS.'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (id !== '-') {
|
if (id !== '-') {
|
||||||
@@ -299,7 +353,7 @@ function codesignRcodesign(appPath, id) {
|
|||||||
const entitlements = ensureEntitlements()
|
const entitlements = ensureEntitlements()
|
||||||
const { p12Path, password } = ensureRcodesignSelfSignedP12(bin)
|
const { p12Path, password } = ensureRcodesignSelfSignedP12(bin)
|
||||||
|
|
||||||
// Prefer full Electron-friendly sign: p12 + runtime + entitlements
|
// Prefer full Electron/Bare-friendly sign: p12 + runtime + entitlements
|
||||||
const attempts = [
|
const attempts = [
|
||||||
[
|
[
|
||||||
'sign',
|
'sign',
|
||||||
@@ -311,7 +365,7 @@ function codesignRcodesign(appPath, id) {
|
|||||||
'runtime',
|
'runtime',
|
||||||
'--entitlements-xml-file',
|
'--entitlements-xml-file',
|
||||||
entitlements,
|
entitlements,
|
||||||
appPath,
|
targetPath,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'sign',
|
'sign',
|
||||||
@@ -321,9 +375,9 @@ function codesignRcodesign(appPath, id) {
|
|||||||
password,
|
password,
|
||||||
'--code-signature-flags',
|
'--code-signature-flags',
|
||||||
'runtime',
|
'runtime',
|
||||||
appPath,
|
targetPath,
|
||||||
],
|
],
|
||||||
['sign', '--p12-file', p12Path, '--p12-password', password, appPath],
|
['sign', '--p12-file', p12Path, '--p12-password', password, targetPath],
|
||||||
]
|
]
|
||||||
|
|
||||||
let lastErr = ''
|
let lastErr = ''
|
||||||
@@ -343,6 +397,68 @@ function codesignRcodesign(appPath, id) {
|
|||||||
throw new Error(`rcodesign failed:\n${lastErr}`)
|
throw new Error(`rcodesign failed:\n${lastErr}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sign a standalone Mach-O binary (peardock-server) with Apple codesign.
|
||||||
|
*/
|
||||||
|
function codesignDarwinBinary(binPath, id) {
|
||||||
|
const entitlements = ensureEntitlements()
|
||||||
|
const hardened = id !== '-'
|
||||||
|
|
||||||
|
try {
|
||||||
|
execFileSync('xattr', ['-cr', binPath], { stdio: 'pipe' })
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
log(`codesign binary identity=${id === '-' ? 'ad-hoc' : id}`)
|
||||||
|
const args = ['--force', '--sign', id, '--entitlements', entitlements]
|
||||||
|
if (hardened) args.push('--options', 'runtime', '--timestamp')
|
||||||
|
else args.push('--timestamp=none')
|
||||||
|
// Stable identifier (bare-runtime defaults to peardock-server-<hash>)
|
||||||
|
args.push('--identifier', 'com.peardock.server', binPath)
|
||||||
|
|
||||||
|
const r = spawnSync('codesign', args, { encoding: 'utf8' })
|
||||||
|
if (r.status !== 0) {
|
||||||
|
throw new Error(`codesign failed for binary:\n${r.stderr || r.stdout}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const v = spawnSync('codesign', ['--verify', '--strict', '--verbose=2', binPath], {
|
||||||
|
encoding: 'utf8',
|
||||||
|
})
|
||||||
|
if (v.status !== 0) {
|
||||||
|
throw new Error(`codesign verify failed for binary:\n${v.stderr || v.stdout}`)
|
||||||
|
}
|
||||||
|
log('verify ok:', (v.stderr || v.stdout || '').trim().split('\n').slice(0, 3).join(' | '))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Codesign a standalone peardock-server binary (Bare).
|
||||||
|
* Call after bare-standalone embeds the runtime for each darwin host.
|
||||||
|
*
|
||||||
|
* @param {string} binPath
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
function signBinary(binPath) {
|
||||||
|
if (!fs.existsSync(binPath)) throw new Error(`Binary not found: ${binPath}`)
|
||||||
|
const id = identity()
|
||||||
|
log('binary:', binPath)
|
||||||
|
log('identity:', id === '-' ? 'ad-hoc (-)' : id)
|
||||||
|
|
||||||
|
if (process.platform === 'darwin') {
|
||||||
|
codesignDarwinBinary(binPath, id)
|
||||||
|
try {
|
||||||
|
execFileSync('xattr', ['-cr', binPath], { stdio: 'pipe' })
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Linux CI cross-compile of darwin server binaries
|
||||||
|
codesignRcodesign(binPath, id)
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
|
|
||||||
function signApp(appPath) {
|
function signApp(appPath) {
|
||||||
if (!fs.existsSync(appPath)) throw new Error(`App not found: ${appPath}`)
|
if (!fs.existsSync(appPath)) throw new Error(`App not found: ${appPath}`)
|
||||||
const id = identity()
|
const id = identity()
|
||||||
@@ -412,22 +528,37 @@ function signApp(appPath) {
|
|||||||
async function main() {
|
async function main() {
|
||||||
const input = process.argv[2]
|
const input = process.argv[2]
|
||||||
if (!input) {
|
if (!input) {
|
||||||
console.error('Usage: node scripts/sign-macos-app.cjs <path-to.app|dir>')
|
console.error(
|
||||||
|
'Usage: node scripts/sign-macos-app.cjs <path-to.app|peardock-server|dir>'
|
||||||
|
)
|
||||||
process.exit(2)
|
process.exit(2)
|
||||||
}
|
}
|
||||||
const resolved = path.resolve(input)
|
const resolved = path.resolve(input)
|
||||||
const apps = findApps(resolved)
|
if (!fs.existsSync(resolved)) {
|
||||||
if (!apps.length) {
|
console.error('Path not found:', resolved)
|
||||||
console.error('No .app found at', resolved)
|
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const apps = findApps(resolved)
|
||||||
|
const bins = findServerBinaries(resolved)
|
||||||
|
|
||||||
|
if (!apps.length && !bins.length) {
|
||||||
|
console.error('No .app or peardock-server binary found at', resolved)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
for (const app of apps) {
|
for (const app of apps) {
|
||||||
await signApp(app)
|
await signApp(app)
|
||||||
}
|
}
|
||||||
|
for (const bin of bins) {
|
||||||
|
// Avoid double-signing if someone nested a binary inside an .app (unlikely)
|
||||||
|
if (apps.some((a) => bin === a || bin.startsWith(a + path.sep))) continue
|
||||||
|
await signBinary(bin)
|
||||||
|
}
|
||||||
log('done')
|
log('done')
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { signApp, findApps, identity }
|
module.exports = { signApp, signBinary, findApps, findServerBinaries, identity }
|
||||||
|
|
||||||
if (require.main === module) {
|
if (require.main === module) {
|
||||||
main().catch((err) => {
|
main().catch((err) => {
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
# Vendored `rcodesign` (apple-codesign)
|
# Vendored `rcodesign` (apple-codesign)
|
||||||
|
|
||||||
Used by CI on Linux to **ad-hoc sign** macOS `.app` bundles produced by
|
Used by CI on Linux to **seal-sign** macOS artifacts produced on Linux:
|
||||||
electron-forge cross-packaging (avoids Gatekeeper “damaged / move to Trash”).
|
|
||||||
|
- Electron `.app` bundles (forge `postPackage` → `scripts/sign-macos-app.cjs`)
|
||||||
|
- Bare `peardock-server` binaries (`scripts/bare-standalone.cjs` for every `darwin-*` host)
|
||||||
|
|
||||||
|
so Gatekeeper does not report them as “damaged / move to Trash”.
|
||||||
|
|
||||||
| Path | Binary |
|
| Path | Binary |
|
||||||
|------|--------|
|
|------|--------|
|
||||||
|
|||||||
Reference in New Issue
Block a user