* feat(harmony): disclose unclassified inventory files * test(harmony): let createEvidence own JSON admission in the partial-inventory case * test(harmony): extract the projection assertion from the archive journey * docs(harmony): qualify the unclassified disclosure rules and pin exact-case manifests * test(harmony): replace limitation prose with structured coverage facts The partial-inventory control froze the sentence "Source inventory coverage is partial; absence is unknown." verbatim. docs/testing.md asserts structured limit facts instead of freezing explanatory sentences and puts documentation wording in review, so the sentence is no longer substring-matched. `coverage.status` is a disjunction of independent causes in this projection: incomplete inventory scope, unavailable content, and an exceeded bridge budget. Asserting only `status: "partial"` left that attribution unstated, so the two other causes are now pinned as well. `unavailable_components` being empty and `bridge_candidate_coverage` being complete with zero candidates make the partial result attributable to the missing occurrence alone. Also drops an `artifact_id` comparison that could not fail: the fixture's four files carry the same bytes, the preceding assertion already pins that shared digest, and `artifact_id` is derived from the digest. Distinct paths sharing content stay covered by the path array and the independent digest expectations. Narrows a comment that claimed exact-case matching for every name in the control; only the manifest names are case-sensitive, because the App Pack child suffix match is case-insensitive. * docs(harmony): name the disclosure location for a nested child package The unclassified-disclosure paragraph used "there" to refer back to a clause that had just named `app_pack_children`, so a reader could take a nested `.hap` or `.hsp` member of a HAP or HSP root to be reported as an App Pack child. It is reported in `unclassified_components`: the child list is populated only for an App Pack root. Names the location explicitly.
6.5 KiB
Static HarmonyOS package inventory
REA inventories HarmonyOS application packages through the shared hardened
ZIP artifact reader in src/artifacts/, then projects the authenticated
inventory into an execution-free application graph. This is the first
increment of the HarmonyOS roadmap (#1431): package identification and
component inventory only.
Recognized root formats:
.hap— installable application module.hsp— runtime shared package.app— distribution App Pack (HAP/HSP children are listed by path). The App Pack classification applies to verified-ZIP-magic root inputs only; a nested ZIP member ending in.appinside another package, such as an IPA, keeps the genericzipclassification.
HarmonyOS .har shared libraries are intentionally not classified by suffix:
.har also names HTTP Archive JSON, so a Harmony shared archive requires
verified ZIP bytes and is deferred with an explicit limitation.
Usage
No external SDK, toolchain, or engine is required. Inventory the package and project the graph; CLI and MCP use the same workflow and return artifact-bound Evidence inline:
rea inspect-artifact /path/to/Example.hap --format json > inspection.json
node --input-type=module -e 'import { readFileSync } from "node:fs"; console.log(JSON.stringify({ inventory_evidence: [JSON.parse(readFileSync("inspection.json", "utf8"))] }));' > projection-input.json
rea project-harmony-application-graph projection-input.json --format json
The MCP tool project_harmony_application_graph takes the same
inventory_evidence input. The projection reports:
- exact component paths, artifact IDs, and hashes (manifests, Ark bytecode, resources, native libraries, JavaScript, signing)
unclassified_componentswith the same paths and content identities for authenticated files outside those categories and the App Pack child list- a packaging-model hint: Stage is claimed only from an exactly cased
module.jsonentry outside a classified resource path, FA only fromconfig.jsonoutside a classified resource path, otherwiseunknown - FA resources under
assets/<module>/resources/as well as Stageresources/ - unavailable component paths with unknown IDs and hashes, including encrypted entries; these make projection coverage partial
- App Pack child package paths without recursive inventory
- runtime-family hints (
ark,native,javascript) from paths and formats - path-based N-API bridge hypotheses between bytecode and
libs/<abi>native libraries
An unavailable manifest can still supply a path-based model hint; its content identity remains unknown. Manifest names follow case-sensitive ZIP member names.
File and slice occurrences supply component and child-package paths; directory trees and symlinks retain their identities in the source inventory without being classified as code files. Ark and JavaScript runtime hints summarize the classified bytecode and JavaScript lists; supported source extensions share the same classification rule as their component rows.
unclassified_components preserves files such as pkgContextInfo.json,
.pages.info, a HarmonyOS .har shared library, and a non-certificate
META-INF entry without interpreting their contents. The .har suffix also
names HTTP Archive JSON, so identifying one needs verified ZIP bytes rather than
a path rule. Different paths sharing the same bytes remain separate entries. App
Pack children of an App Pack root are already reported in app_pack_children,
so they are not repeated as unclassified files. A nested .hap or .hsp member
of a HAP or HSP root is disclosed in unclassified_components instead, because
child-package inventory is not recursive. Unreadable or encrypted content remains
in unavailable_components with unknown identity instead.
coverage.status: "complete-within-inventory" describes the authenticated
source inventory and bounded bridge projection, not semantic understanding of
every file. Unclassified files do not make a complete inventory partial; missing
inventory pages, source coverage limits, unavailable content and bridge limits
still qualify coverage independently. An empty unclassified list on a partial
inventory does not establish that the whole package has no unclassified files.
Every claim is path-presence only. Manifest semantics (module identity,
abilities, entry points, permissions, dependencies), Ark bytecode contents and
versions, resource resolution, signing verification, and observed native
boundaries are out of scope for this increment and stay in the projection's
limitations array until a dedicated HarmonyOS provider exists. REA fails
closed on packages whose inventory cannot be authenticated.
Verification lane
npm run fixtures:harmony downloads the SHA-256-pinned 1.0.1 HAP release
from the MIT-licensed harmony-next-pipeline source repository
into ignored _reference/harmony-integration/. The pin records the source
revision, release asset ID, size, and digest. The downloaded artifact is not
redistributed; bundled component licenses have not been independently audited.
npm run fixtures:harmony
REA_HARMONY_TEST_HAP=_reference/harmony-integration/entry-default-unsigned.hap \
npm run verify:harmony
The lane exercises the compiled CLI and actual SDK-connected stdio MCP:
inspect_artifact authenticity, projection determinism, Stage-model path hints,
exact manifest/bytecode/resource component sets, empty native and bridge sets,
complete-inventory coverage, and CLI/MCP parity. It checks that this fixture has
no META-INF signing entries; that does not establish whether the package is signed.
The release artifact's compiler/SDK versions and reproducible source build have
not been independently established. This lane does not complete the pinned
toolchain acceptance in #1431 and does not verify Ark decoding or signatures.
Set REA_HARMONY_ENTRYPOINT to an installed package's scripts/rea.mjs to run
the same checks against that package; the default lane uses the repository build.
Packaging-model and App Pack child presence use inventoried file/slice paths even when encrypted content cannot be authenticated. Unavailable App Pack children retain their path, format, encryption and limitations with null artifact ID and digest; they do not establish decoded package semantics. Missing source nodes outside supplied pages retain the inventory limitation and partial coverage. The signing list includes inventoried META-INF RSA, DSA and EC certificate-block paths alongside the existing suffixes; opaque content does not establish a valid signature or certificate.