fix(apple): keep unrooted extensionless Mach-O in IPA executables (#3300)

IPA projections keep components outside every application root, but
executables required root membership and native_libraries matched only
.dylib/.so names, so an unrooted extensionless Mach-O such as
SwiftSupport/HelperTool was in neither list and formed no bridge
candidate. List unrooted Mach-O images under executables unless they
are already native libraries.

Fixes #3174
This commit is contained in:
Wade authored and GitHub committed 2026-10-14 16:52:32 +08:00
1 parent 5f0065c542
commit ffeb2d4367
2 files changed
+36 -2

No files matched your search

+29
View File
@@ -600,6 +600,35 @@ describe("Apple application bridge candidates", () => {
status: "complete",
});
});
it("keeps an extensionless Mach-O without an application root as a native component", () => {
const result = project(
inventoryEvidence("ipa", "Fixture.ipa", [
{ path: "Payload/Fixture.app/Info.plist" },
macho("Payload/Fixture.app/Fixture"),
{ path: "SwiftSupport/outside.js", format: "javascript-bundle" },
macho("SwiftSupport/HelperTool"),
macho("SwiftSupport/iphoneos/libswiftCore.dylib"),
]),
);
expect(result.components.executables.map(({ path }) => path)).toEqual([
"Payload/Fixture.app/Fixture",
"SwiftSupport/HelperTool",
]);
expect(result.bridge_candidates).toEqual([
{
source_path: "SwiftSupport/outside.js",
native_path: "SwiftSupport/HelperTool",
basis: "javascript-and-native-content",
},
{
source_path: "SwiftSupport/outside.js",
native_path: "SwiftSupport/iphoneos/libswiftCore.dylib",
basis: "javascript-and-native-content",
},
]);
});
});
describe("Apple path conventions", () => {
+7 -2
View File
@@ -249,6 +249,9 @@ const appleRootFormat = (format: string): RootFormat => {
return root;
};
const isNativeLibrary = (path: string): boolean =>
/\.(?:dylib|so)$/iu.test(path);
const classifyComponents = (
entries: readonly AppleInventoryEntry[],
all: readonly Component[],
@@ -271,11 +274,13 @@ const classifyComponents = (
bundle_metadata: all.filter(({ path }) =>
anatomyNameIs(lastSegment(path), "Info.plist"),
),
// An unrooted IPA library is listed only under native_libraries.
executables: all.filter(
({ path, format }) => withinApp(path) && isMachOFormat(format),
({ path, format }) =>
isMachOFormat(format) && (withinApp(path) || !isNativeLibrary(path)),
),
frameworks: all.filter(({ path }) => /\.framework\//u.test(path)),
native_libraries: all.filter(({ path }) => /\.(?:dylib|so)$/iu.test(path)),
native_libraries: all.filter(({ path }) => isNativeLibrary(path)),
javascript: all.filter(({ format }) => format === "javascript-bundle"),
signing: all.filter(
({ path }) =>