fix(harmony): exclude raw resources from manifests

Classify known resource paths once and keep a raw resource named module.json from changing the package model or appearing as a manifest. Add a filesystem-boundary regression and clarify the documented hint.

Fixes #6638
This commit is contained in:
morluto
2026-10-23 19:15:13 +08:00
parent 79b3f4694d
commit b443b5a89b
3 changed files with 40 additions and 9 deletions
+3 -2
View File
@@ -36,8 +36,9 @@ The MCP tool `project_harmony_application_graph` takes the same
- exact component paths, artifact IDs, and hashes (manifests, Ark bytecode,
resources, native libraries, JavaScript, signing)
- a packaging-model hint: Stage is claimed only from a `module.json` entry,
FA only from `config.json`, otherwise `unknown`
- a packaging-model hint: Stage is claimed only from a `module.json` entry
outside a classified resource path, FA only from `config.json` outside a
classified resource path, otherwise `unknown`
- FA resources under `assets/<module>/resources/` as well as Stage `resources/`
- unavailable component paths with unknown IDs and hashes, including encrypted entries; these make projection coverage partial
- App Pack child package paths without recursive inventory
+9 -7
View File
@@ -183,15 +183,13 @@ const packagingModel = (
};
const classify = (all: readonly Component[]) => ({
manifests: all.filter(({ path }) =>
/(?:^|\/)(?:module\.json|config\.json|pack\.info)$/iu.test(path),
manifests: all.filter(
({ path }) =>
/(?:^|\/)(?:module\.json|config\.json|pack\.info)$/iu.test(path) &&
!isResourcePath(path),
),
bytecode: all.filter(({ path }) => /\.(?:abc|pa)$/iu.test(path)),
resources: all.filter(
({ path }) =>
/(?:^|\/)resources\.index$/iu.test(path) ||
/^(?:resources\/|assets\/[^/]+\/resources\/)/iu.test(path),
),
resources: all.filter(({ path }) => isResourcePath(path)),
native_libraries: all.filter(
({ path, format }) =>
format === "elf" || /(?:^|\/)libs\/[^/]+\/[^/]+\.so$/iu.test(path),
@@ -205,6 +203,10 @@ const classify = (all: readonly Component[]) => ({
),
});
const isResourcePath = (path: string): boolean =>
/(?:^|\/)resources\.index$/iu.test(path) ||
/^(?:resources\/|assets\/[^/]+\/resources\/)/iu.test(path);
const runtimeFamilies = (
all: readonly Component[],
components: HarmonyApplicationProjectionResult["components"],
@@ -228,6 +228,34 @@ describe("HarmonyOS packaging boundaries", () => {
]);
});
it("does not classify a rawfile named module.json as a manifest", async () => {
const path = await writeApplicationZip(
"rea-harmony-rawfile-module-manifest-",
"Legacy.hap",
[
{ path: "config.json", content: '{"app":{}}' },
{
path: "assets/entry/resources/rawfile/module.json",
content: '{"note":"ordinary raw resource"}',
},
],
);
const inventory = await inventoryApplicationPackage(path);
const result = projectHarmonyApplicationEvidence({
inventory_evidence: [inventory],
});
const projection = harmonyApplicationProjectionResultSchema.parse(
requireSuccessfulProjection(result).normalized_result,
);
expect(projection.packaging_model).toBe("fa");
expect(projection.components.manifests.map(({ path }) => path)).toEqual([
"config.json",
]);
expect(projection.components.resources.map(({ path }) => path)).toEqual([
"assets/entry/resources/rawfile/module.json",
]);
});
it("rejects non-HarmonyOS inventory Evidence", async () => {
const inventory = await createNonApplicationZipInventory(
"rea-harmony-invalid-",