fix(artifacts): align projection provider targets

This commit is contained in:
morluto 2026-07-20 11:21:47 +00:00
parent 0cc9d468c4
commit 560dbda76d
4 changed files with 58 additions and 3 deletions

View File

@ -129,7 +129,10 @@ export const projectAppleApplication = (
const runtimeFamilies = identifyRuntimeFamilies(all);
const bridgeProjection = identifyBridgeCandidates(
retained.javascript,
[...retained.frameworks, ...retained.native_libraries],
deduplicateComponents([
...retained.executables,
...retained.native_libraries,
]),
parsed.limits.max_components,
);
const limitations = projectionLimitations(
@ -212,6 +215,11 @@ const retainComponents = <Groups extends Record<string, readonly Component[]>>(
const componentCount = (groups: Record<string, readonly Component[]>): number =>
Object.values(groups).reduce((total, values) => total + values.length, 0);
const deduplicateComponents = (values: readonly Component[]): Component[] =>
[...new Map(values.map((value) => [value.path, value])).values()].sort(
(left, right) => compare(left.path, right.path),
);
const identifyRuntimeFamilies = (all: readonly Component[]) => {
const paths = all.map(({ path }) => path.toLowerCase());
const families = new Set<

View File

@ -161,7 +161,7 @@ export const identifyRuntimes = (
remaining -= observations.length;
const omittedObservations = unique.length - observations.length;
omitted += omittedObservations;
const provider = PROVIDERS[family];
const provider = providerFor(family, inventory.manifest.root_format);
return {
family,
inspection: provider.inspection,
@ -208,11 +208,25 @@ export const identifyRuntimes = (
});
};
const providerFor = (
family: RuntimeFamily,
rootFormat: string,
): RuntimeProvider =>
family === "android" && rootFormat !== "apk"
? {
inspection: "provider-selection-required",
id: null,
reason:
"Extract or select an APK root before using the Android application provider.",
}
: PROVIDERS[family];
const familiesFor = (format: string, path: string): RuntimeFamily[] => {
const families = new Set<RuntimeFamily>();
if (
format === "apk" ||
format === "dex" ||
/(?:^|\/)[^/]+\.dex$/iu.test(path) ||
/(?:^|\/)AndroidManifest\.xml$/u.test(path)
)
families.add("android");

View File

@ -90,7 +90,14 @@ describe("Apple application projection", () => {
expect.arrayContaining(["javascript", "native", "react-native"]),
);
expect(left.bridge_candidates).toEqual([
expect.objectContaining({ basis: "react-native-convention" }),
expect.objectContaining({
basis: "javascript-and-native-content",
native_path: "Payload/Fixture.app/Fixture",
}),
expect.objectContaining({
basis: "react-native-convention",
native_path: "Payload/Fixture.app/Frameworks/React.framework/React",
}),
]);
expect(JSON.stringify(left)).not.toContain("opaque signing bytes");
});

View File

@ -127,4 +127,30 @@ describe("runtime identification", () => {
});
expect(result.coverage.omitted_observations).toBeGreaterThan(0);
});
it("does not route nested DEX content to the APK-only provider", async () => {
const root = await mkdtemp(join(tmpdir(), "rea-runtime-dex-"));
const path = join(root, "Fixture.zip");
const writer = new ZipWriter(new Uint8ArrayWriter());
await writer.add(
"classes.dex",
new Uint8ArrayReader(
Uint8Array.from([...Buffer.from("dex\n035\0"), 0, 0, 0, 0]),
),
);
await writeFile(path, await writer.close());
const inventory = parseEvidence(
await runProviderAnalysis(path, "inventory_artifact", {}),
);
const result = identifyRuntimes({ inventory_evidence: [inventory] });
expect(result.runtimes).toContainEqual(
expect.objectContaining({
family: "android",
inspection: "provider-selection-required",
provider_id: null,
}),
);
});
});