feat(FN-5609): add macOS desktop signing configuration and entitlements
Adds macOS code signing and notarization infrastructure (FN-5609), introducing hardened runtime entitlements, electron-builder config for signed builds, and signing-enabled release workflows, with tests validating the configuration and docs covering the signing flow. Fusion-Task-Id: FN-5609 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> Fusion-Task-Id: FN-5609
This commit is contained in:
@@ -106,6 +106,31 @@ describe("electron-builder desktop config", () => {
|
||||
expect(linuxArchByTarget.get("deb")).toEqual(["arm64", "x64"]);
|
||||
expect(linuxArchByTarget.get("tar.gz")).toEqual(["arm64", "x64"]);
|
||||
});
|
||||
|
||||
it("locks mac signing and notarization configuration", async () => {
|
||||
const builderConfig = await readDesktopFile("electron-builder.yml");
|
||||
|
||||
expect(builderConfig).toMatch(/mac:\s*[\s\S]*?hardenedRuntime:\s*true/m);
|
||||
expect(builderConfig).toMatch(/mac:\s*[\s\S]*?gatekeeperAssess:\s*false/m);
|
||||
expect(builderConfig).toMatch(/mac:\s*[\s\S]*?entitlements:\s*build\/entitlements\.mac\.plist/m);
|
||||
expect(builderConfig).toMatch(/mac:\s*[\s\S]*?entitlementsInherit:\s*build\/entitlements\.mac\.plist/m);
|
||||
expect(builderConfig).toMatch(/mac:\s*[\s\S]*?notarize:\s*true/m);
|
||||
expect(builderConfig).not.toContain("mac.identity:");
|
||||
expect(builderConfig).not.toContain("appleId:");
|
||||
expect(builderConfig).not.toContain("teamId:");
|
||||
});
|
||||
|
||||
it("ships the expected hardened-runtime entitlements plist", async () => {
|
||||
const entitlements = await readDesktopFile("build/entitlements.mac.plist");
|
||||
|
||||
expect(entitlements).toContain("<?xml");
|
||||
expect(entitlements).toContain("</plist>");
|
||||
expect(entitlements).toContain("com.apple.security.cs.allow-jit");
|
||||
expect(entitlements).toContain("com.apple.security.cs.allow-unsigned-executable-memory");
|
||||
expect(entitlements).toContain("com.apple.security.cs.allow-dyld-environment-variables");
|
||||
expect(entitlements).toContain("com.apple.security.cs.disable-library-validation");
|
||||
expect(entitlements).toContain("com.apple.security.inherit");
|
||||
});
|
||||
});
|
||||
|
||||
describe("desktop windows workflow signing guards", () => {
|
||||
|
||||
@@ -69,6 +69,39 @@ describe("desktop release workflow wiring", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("desktop macos signing wiring", () => {
|
||||
it("wires signed and unsigned macOS packaging paths with verification", async () => {
|
||||
const release = await readRepoFile(".github/workflows/release.yml");
|
||||
const testRelease = await readRepoFile(".github/workflows/test-release.yml");
|
||||
|
||||
for (const workflow of [release, testRelease]) {
|
||||
expect(workflow).toContain("Package signed macOS desktop DMG/ZIP");
|
||||
expect(workflow).toContain("Package unsigned macOS desktop DMG/ZIP");
|
||||
expect(workflow).toContain("Verify signed and notarized macOS artifacts");
|
||||
|
||||
expect(workflow).toContain("secrets.APPLE_CERTIFICATE_BASE64");
|
||||
expect(workflow).toContain("secrets.APPLE_CERTIFICATE_PASSWORD");
|
||||
expect(workflow).toContain("secrets.APPLE_ID");
|
||||
expect(workflow).toContain("secrets.APPLE_TEAM_ID");
|
||||
expect(workflow).toContain("secrets.APPLE_APP_PASSWORD");
|
||||
|
||||
expect(workflow).toContain("CSC_LINK:");
|
||||
expect(workflow).toContain("CSC_KEY_PASSWORD:");
|
||||
expect(workflow).toContain("APPLE_APP_SPECIFIC_PASSWORD:");
|
||||
expect(workflow).toContain("APPLE_TEAM_ID:");
|
||||
|
||||
expect(workflow).toContain("APPLE_CERTIFICATE_BASE64 != ''");
|
||||
expect(workflow).toContain("APPLE_CERTIFICATE_BASE64 == ''");
|
||||
|
||||
expect(workflow).toContain("codesign --verify");
|
||||
expect(workflow).toContain("spctl --assess");
|
||||
expect(workflow).toContain("xcrun stapler validate");
|
||||
|
||||
expect(workflow).toContain("-c.mac.notarize=false");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("desktop linux signing wiring", () => {
|
||||
it("wires Linux GPG secret-guarded signing and asc uploads in both workflows", async () => {
|
||||
const release = await readRepoFile(".github/workflows/release.yml");
|
||||
|
||||
Reference in New Issue
Block a user