You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maka.apache.org by "sosyz (via GitHub)" <gi...@apache.org> on 2026/10/09 08:38:59 UTC

[PR] fix(desktop): give macOS executables their own LC_UUID [maka]

sosyz opened a new pull request, #6027:
URL: https://github.com/apache/maka/pull/6027

   ## Summary
   
   electron-builder renames Electron's prebuilt executables without relinking them, so `Maka` and its four helpers shipped Electron 43.4.1's stock Mach-O `LC_UUID`. Every other app on that Electron release has the same UUID. macOS Local Network Privacy identifies a program by that UUID, so a grant or denial for another app could apply to Maka. Details and a real collision are in the issue.
   
   - New `afterPack` hook (`scripts/macos-executable-uuid.mjs`). It rewrites the `LC_UUID` of the main executable and every helper app before signing, so the stamped binaries are what electron-builder signs and notarizes.
   - The new UUID is a UUIDv5 of `appId/executable name/CPU type`. It is deterministic rather than random, so the UUID stays the same across releases and a user's Local Network decision survives updates. arm64 and x64 builds get different UUIDs.
   - `verify:macos` now rejects a package whose executables lack the expected UUID, so a hook that stops running fails the release check instead of shipping the stock UUID.
   - Windows and Linux packaging are unaffected because the hook returns early off `darwin`.
   
   Fixes #6026
   
   ## Verification
   
   - `node --test scripts/macos-executable-uuid.test.mjs`: 12 passing. Covers synthetic thin and fat Mach-O, idempotence, rejection of the stock UUID, and Electron's real arm64 executable on macOS.
   - `node --test scripts/verify-packaged-app.test.mjs scripts/desktop-nightly.test.mjs scripts/desktop-release-targets.test.mjs scripts/ci-test-plan.test.mjs scripts/macos-executable-uuid.test.mjs`: 99/99 passing.
   - `biome lint .`, `biome format .` and `knip --workspace apps/desktop` are clean.
   - Ran a local `electron-builder --mac dir --arm64` (ad-hoc signed, not notarized):
     - `dwarfdump --uuid` shows all five executables with new UUIDs. The main executable went from `4C4C4470-5555-3144-A124-518576DD11E3` to `E08E3A84-68A1-5189-9663-A4FEC17A5EE5`.
     - `codesign --verify --deep --strict` passes.
     - The new release check accepts the package.
     - The app launches and spawns its helper processes.
   - Not run: a full signed and notarized `package:macos-*` / `verify:macos`, which needs the release signing credentials.
   
   ## AI use
   
   Select exactly one:
   
   - [ ] No generative tool made a substantive contribution
   - [x] Generative tooling made a substantive contribution
   
   Tool(s) and scope: Claude Code (Claude Opus 5.5) did the investigation, implementation and tests. A human reviewed the change. The commit carries a `Generated-by` trailer.
   
   ## Checklist
   
   - [x] Tests cover the change and fail without it
   - [x] Lint, format, typecheck and the affected suites pass locally
   
   Does this PR entail a change in behavior?
   
   - [x] Yes — described under Summary above
   - [ ] No
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org


Re: [PR] fix(desktop): give macOS executables their own LC_UUID [maka]

Posted by "Astro-Han (via GitHub)" <gi...@apache.org>.
Astro-Han commented on code in PR #6027:
URL: https://github.com/apache/maka/pull/6027#discussion_r4228512859


##########
scripts/macos-executable-uuid.mjs:
##########
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// electron-builder ships Electron's prebuilt executables renamed, not relinked,
+// so every app on the same Electron release carries the same Mach-O LC_UUID.
+// macOS Local Network Privacy (NECP) identifies a program by its main
+// executable's LC_UUID, so a shared UUID lets one app's grant or denial land on
+// another. The packaging hook stamps each executable with a UUID of its own
+// before signing; the release verifier checks the stamp survived.
+
+import { createHash } from 'node:crypto';
+import { readFile, readdir, writeFile } from 'node:fs/promises';
+import { join } from 'node:path';
+
+const MH_MAGIC_64 = 0xfeedfacf;
+const FAT_MAGIC = 0xcafebabe;
+const LC_UUID = 0x1b;
+const MACH_HEADER_64_SIZE = 32;
+const FAT_ARCH_SIZE = 20;
+
+// Fixed namespace for the UUIDv5 names below. Changing it changes every
+// shipped UUID, which macOS treats as a different program.
+const MAKA_EXECUTABLE_UUID_NAMESPACE = Buffer.from('4195730630d44e84a842a14db6f67a8f', 'hex');

Review Comment:
   P3: this namespace and the `appId/executableName/cputype` name format are now a persistent identity contract, as is `productName`, because it names the executables. Consider a golden-value test, for example the expected UUID for `com.maka.desktop`/`Maka`/arm64, so a refactor can't silently re-key users' Local Network decisions.



##########
apps/desktop/electron-builder.config.mjs:
##########
@@ -73,6 +84,7 @@ const baseDesktopBuilderConfig = {
   artifactName: 'Maka-${version}-mac-${arch}.${ext}',
   asar: true,
   beforePack: stageReleaseManifests,
+  afterPack: stampMacExecutableUuids,

Review Comment:
   P3 note: I verified that in electron-builder 26.17.0 the config `afterPack` runs before fuses and `doSignAfterPack`, and `mac.forceCodeSigning: true` prevents an unsigned (linker-signature-invalidated) arm64 build. PR CI never runs this hook on macOS, though. The first real run is the post-merge signed Desktop Nightly (macos-15 / macos-15-intel), so please watch that run.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org


Re: [PR] fix(desktop): give macOS executables their own LC_UUID [maka]

Posted by "Astro-Han (via GitHub)" <gi...@apache.org>.
Astro-Han commented on code in PR #6027:
URL: https://github.com/apache/maka/pull/6027#discussion_r4230442908


##########
scripts/macos-executable-uuid.mjs:
##########
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// electron-builder ships Electron's prebuilt executables renamed, not relinked,
+// so every app on the same Electron release carries the same Mach-O LC_UUID.
+// macOS Local Network Privacy (NECP) identifies a program by its main
+// executable's LC_UUID, so a shared UUID lets one app's grant or denial land on
+// another. The packaging hook stamps each executable with a UUID of its own
+// before signing; the release verifier checks the stamp survived.
+
+import { createHash } from 'node:crypto';
+import { readFile, readdir, writeFile } from 'node:fs/promises';
+import { join } from 'node:path';
+
+const MH_MAGIC_64 = 0xfeedfacf;
+const FAT_MAGIC = 0xcafebabe;
+const LC_UUID = 0x1b;
+const MACH_HEADER_64_SIZE = 32;
+const FAT_ARCH_SIZE = 20;
+
+// Fixed namespace for the UUIDv5 names below. Changing it changes every
+// shipped UUID, which macOS treats as a different program.
+const MAKA_EXECUTABLE_UUID_NAMESPACE = Buffer.from('4195730630d44e84a842a14db6f67a8f', 'hex');
+
+/**
+ * The UUID an executable ships with. Deterministic on purpose: it stays the same
+ * from one release to the next, so a user's Local Network decision survives an
+ * update, while the app id keeps it distinct from every other Electron app and
+ * the CPU type keeps the arm64 and x64 builds apart.
+ */
+export function expectedExecutableUuid({ appId, executableName, cputype }) {
+  const digest = createHash('sha1')

Review Comment:
   [P3] Preserve native-build identity, or validate the deliberate loss of it. Two different native payloads/upstream UUIDs currently get the same output UUID for the same app/name/CPU. Apple's [TN3178](https://developer.apple.com/documentation/technotes/tn3178-checking-for-and-resolving-build-uuid-problems) distinguishes native images for symbol matching. There is no repository crash-upload pipeline, but that does not eliminate OS crash-report or external-symbol costs. I have not reproduced an application failure; this is a follow-up tradeoff, not a P2 regression claim.



##########
scripts/macos-executable-uuid.mjs:
##########
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// electron-builder ships Electron's prebuilt executables renamed, not relinked,
+// so every app on the same Electron release carries the same Mach-O LC_UUID.
+// macOS Local Network Privacy (NECP) identifies a program by its main
+// executable's LC_UUID, so a shared UUID lets one app's grant or denial land on
+// another. The packaging hook stamps each executable with a UUID of its own
+// before signing; the release verifier checks the stamp survived.
+
+import { createHash } from 'node:crypto';
+import { readFile, readdir, writeFile } from 'node:fs/promises';
+import { join } from 'node:path';
+
+const MH_MAGIC_64 = 0xfeedfacf;
+const FAT_MAGIC = 0xcafebabe;
+const LC_UUID = 0x1b;
+const MACH_HEADER_64_SIZE = 32;
+const FAT_ARCH_SIZE = 20;
+
+// Fixed namespace for the UUIDv5 names below. Changing it changes every
+// shipped UUID, which macOS treats as a different program.
+const MAKA_EXECUTABLE_UUID_NAMESPACE = Buffer.from('4195730630d44e84a842a14db6f67a8f', 'hex');
+
+/**
+ * The UUID an executable ships with. Deterministic on purpose: it stays the same
+ * from one release to the next, so a user's Local Network decision survives an
+ * update, while the app id keeps it distinct from every other Electron app and
+ * the CPU type keeps the arm64 and x64 builds apart.
+ */
+export function expectedExecutableUuid({ appId, executableName, cputype }) {
+  const digest = createHash('sha1')
+    .update(MAKA_EXECUTABLE_UUID_NAMESPACE)
+    .update(`${appId}/${executableName}/${cputype}`)
+    .digest();
+  const uuid = digest.subarray(0, 16);
+  uuid[6] = (uuid[6] & 0x0f) | 0x50;
+  uuid[8] = (uuid[8] & 0x3f) | 0x80;
+  return formatUuid(uuid);
+}
+
+function formatUuid(bytes) {
+  const hex = bytes.toString('hex').toUpperCase();
+  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
+}
+
+function sliceOffsets(binary) {
+  if (binary.length >= 4 && binary.readUInt32BE(0) === FAT_MAGIC) {
+    const count = binary.readUInt32BE(4);

Review Comment:
   [P3] Reject empty or malformed slices before treating the UUID check as successful. `Buffer.from('cafebabe00000000', 'hex')` yields `[]`, so `assertMacAppExecutableUuids` accepts a helper containing only this zero-slice header. The parser also accepts an `LC_UUID` declaring `cmdsize=8` and writes past that declared command. Require a nonempty bounded fat table, bounded slices/load commands, and a full 24-byte UUID command; add negative tests. Later codesign/Gatekeeper/launch checks remain, so this is parser hardening, not a demonstrated invalid-release bypass.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org