From b443b5a89bebbbdad7f7ea8b26f21b7016f22096 Mon Sep 17 00:00:00 2001 From: morluto <76467478+morluto@users.noreply.github.com> Date: Fri, 23 Oct 2026 19:15:13 +0800 Subject: [PATCH] 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 --- docs/harmony-analysis.md | 5 ++-- src/domain/harmony/harmonyApplication.ts | 16 ++++++----- .../filesystem/harmony/application.test.ts | 28 +++++++++++++++++++ 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/docs/harmony-analysis.md b/docs/harmony-analysis.md index c36bb4f917..b5817b7236 100644 --- a/docs/harmony-analysis.md +++ b/docs/harmony-analysis.md @@ -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//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 diff --git a/src/domain/harmony/harmonyApplication.ts b/src/domain/harmony/harmonyApplication.ts index 88e3c695e3..de48b6e265 100644 --- a/src/domain/harmony/harmonyApplication.ts +++ b/src/domain/harmony/harmonyApplication.ts @@ -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"], diff --git a/tests/boundary/filesystem/harmony/application.test.ts b/tests/boundary/filesystem/harmony/application.test.ts index 4e4d71d0be..b1ee89bb59 100644 --- a/tests/boundary/filesystem/harmony/application.test.ts +++ b/tests/boundary/filesystem/harmony/application.test.ts @@ -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-",