Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions forge.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,20 @@ const mimeTypeScheme = blueskyOAuthSchemeHandlerMimeTypeForMode(
let osxSign: OsxSignOptions | undefined;
let osxNotarize: NotaryToolCredentials | undefined;
if (process.env.MACOS_RELEASE === "true") {
// Set by scripts/make.js, which also preflights that this identity actually
// exists in the keychain. Signing must not fall back to a hardcoded string
// here, or the preflight could pass while signing uses a different identity.
const identity = process.env.MACOS_SIGNING_IDENTITY;
if (!identity) {
throw new Error(
"MACOS_SIGNING_IDENTITY is not set. Build macOS releases via " +
"`npm run publish-dev` / `npm run publish-prod` so scripts/make.js can " +
"set it and verify the identity is in the keychain.",
);
}

osxSign = {
identity: "Developer ID Application: Lockdown Systems LLC (G762K6CH36)",
identity,
optionsForFile: (filePath) => {
const entitlementDefault = path.join(
assetsPath,
Expand Down Expand Up @@ -254,7 +266,13 @@ const config: ForgeConfig = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
osxNotarize: osxNotarize as any,
},
rebuildConfig: {},
// Only better-sqlite3 is loaded inside Electron and needs rebuilding against
// Electron's headers. appdmg's native deps (macos-alias, fs-xattr) are
// build-time tools that run under Node, and macos-alias's nan does not
// compile against Electron 44's V8, which fails the whole package step.
rebuildConfig: {
onlyModules: ["better-sqlite3"],
},
makers: [
// Windows
new MakerSquirrel({
Expand Down
67 changes: 32 additions & 35 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
"authors": "Lockdown Systems LLC",
"scripts": {
"clean": "node ./scripts/clean.mjs",
"rebuild": "npx electron-rebuild --force",
"rebuild-clean": "rm -rf node_modules/better-sqlite3/build && npx electron-rebuild --force",
"rebuild": "npx electron-rebuild --force --only better-sqlite3",
"rebuild-clean": "rm -rf node_modules/better-sqlite3/build && npx electron-rebuild --force --only better-sqlite3",
"postinstall": "node scripts/postinstall.js",
"start": "electron-forge start",
"dev": "electron-forge start",
Expand Down Expand Up @@ -130,9 +130,13 @@
"macos-alias@0.2.12": true
},
"overrides": {
"yauzl": "^3.4.0",
"tar": "^7.5.22",
"tmp": "^0.2.7",
"image-size": "^2.0.4",
"appdmg": {
"image-size": "^1.2.1"
},
"mhtml2html": {
"jsdom": "^29.1.1"
},
Expand Down
72 changes: 72 additions & 0 deletions scripts/make.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,78 @@ if (platform == "win32") {
process.env.MACOS_RELEASE = command === "publish" ? "true" : "false";
}

// The Developer ID identity used to sign macOS releases. forge.config.ts reads
// this from the environment so the preflight check below and the actual signing
// can never drift apart.
const macosSigningIdentity =
"Developer ID Application: Lockdown Systems LLC (G762K6CH36)";
process.env.MACOS_SIGNING_IDENTITY = macosSigningIdentity;

// Preflight checks
//
// @electron/packager defaults to `continueOnError: true` when signing, so a
// missing identity does not fail the build. It leaves the stock ad-hoc Electron
// signature in place and the build dies minutes later inside notarization with
// "code object is not signed at all", which does not name the real cause. Fail
// up front instead.

function fail(message, hint) {
console.error(`\n❌ ${message}\n`);
console.error(` ${hint}\n`);
process.exit(1);
}

function requireEnv(name, hint) {
if (!process.env[name]) {
fail(`${name} is not set, which ${command} requires.`, hint);
}
}

if (command === "publish") {
requireEnv(
"DO_SPACES_KEY",
"Needed to upload the release to DigitalOcean Spaces.",
);
requireEnv(
"DO_SPACES_SECRET",
"Needed to upload the release to DigitalOcean Spaces.",
);

if (platform === "darwin") {
let identities = "";
try {
identities = execSync("security find-identity -v -p codesigning", {
encoding: "utf8",
});
} catch {
fail(
"Could not read code signing identities from the keychain.",
"Try running: security find-identity -v -p codesigning",
);
}

if (!identities.includes(macosSigningIdentity)) {
fail(
`No code signing identity matching "${macosSigningIdentity}" in your keychain.`,
"Import the Developer ID .p12, or create a new certificate at " +
"https://developer.apple.com/account/resources/certificates (Account " +
"Holder only), then confirm with: security find-identity -v -p codesigning",
);
}

console.log(`✅ Signing identity found: ${macosSigningIdentity}`);

requireEnv(
"APPLE_ID",
"The Apple ID used to notarize. Needed by notarytool.",
);
requireEnv(
"APPLE_PASSWORD",
"An app-specific password from https://appleid.apple.com, not your Apple ID password.",
);
}
}

try {
// Clean up previous builds and install dependencies
execSync(`node ./scripts/clean.mjs`, { stdio: "inherit" });
Expand Down
2 changes: 1 addition & 1 deletion scripts/postinstall.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ if (process.env.CI === "true" || process.env.CI === "1") {
console.log("Rebuilding native modules for Electron...");
console.log("- Searching dependency tree");
try {
execSync("npx electron-rebuild --force", {
execSync("npx electron-rebuild --force --only better-sqlite3", {
stdio: "inherit",
cwd: process.cwd(),
});
Expand Down
Loading