mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
fix(harmony): retain path-only package and signing observations
This commit is contained in:
1 parent
6c4313b93e
commit
ebe4e879e8
3 files changed
+93
-8
No files matched your search
@@ -84,3 +84,12 @@ 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.
|
||||
@@ -44,7 +44,9 @@ export const harmonyApplicationProjectionResultSchema = z.strictObject({
|
||||
signing: z.array(projectedComponentSchema),
|
||||
}),
|
||||
unavailable_components: z.array(unavailableComponentSchema),
|
||||
app_pack_children: z.array(projectedComponentSchema),
|
||||
app_pack_children: z.array(
|
||||
z.union([projectedComponentSchema, unavailableComponentSchema]),
|
||||
),
|
||||
runtime_families: z.array(
|
||||
z.enum(["ark", "native", "javascript", "react-native", "flutter", "unity"]),
|
||||
),
|
||||
@@ -82,6 +84,17 @@ export const projectHarmonyInventory = (
|
||||
const unavailable = entries.flatMap(({ unavailable }) =>
|
||||
unavailable === undefined ? [] : [unavailable],
|
||||
);
|
||||
const fileEntries = entries.filter(
|
||||
({ kind }) => kind === "file" || kind === "slice",
|
||||
);
|
||||
const children: HarmonyApplicationProjectionResult["app_pack_children"] = [];
|
||||
if (rootFormat === "app-pack") {
|
||||
for (const entry of fileEntries) {
|
||||
if (!/\.(?:hap|hsp)$/iu.test(entry.path)) continue;
|
||||
const child = entry.component ?? entry.unavailable;
|
||||
if (child !== undefined) children.push(child);
|
||||
}
|
||||
}
|
||||
const classified = classify(all);
|
||||
const bridgeProjection = bridgeCandidates(
|
||||
classified.bytecode,
|
||||
@@ -122,13 +135,12 @@ export const projectHarmonyInventory = (
|
||||
source_evidence_ids: evidence
|
||||
.map(({ evidence_id: id }) => id)
|
||||
.sort(compareUnicodeCodePoints),
|
||||
packaging_model: packagingModel(classified.manifests),
|
||||
packaging_model: packagingModel(
|
||||
fileEntries.filter(({ path }) => !isResourcePath(path)),
|
||||
),
|
||||
components: classified,
|
||||
unavailable_components: unavailable,
|
||||
app_pack_children:
|
||||
rootFormat === "app-pack"
|
||||
? all.filter(({ path }) => /\.(?:hap|hsp)$/iu.test(path))
|
||||
: [],
|
||||
app_pack_children: children,
|
||||
runtime_families: runtimeFamilies(all, classified),
|
||||
bridge_candidates: bridgeProjection.candidates,
|
||||
bridge_candidate_coverage: bridgeProjection.coverage,
|
||||
@@ -171,7 +183,7 @@ const harmonyRootFormat = (
|
||||
};
|
||||
|
||||
const packagingModel = (
|
||||
manifests: readonly Component[],
|
||||
manifests: readonly { readonly path: string }[],
|
||||
): HarmonyApplicationProjectionResult["packaging_model"] => {
|
||||
const stage = manifests.some(({ path }) =>
|
||||
/(?:^|\/)module\.json$/iu.test(path),
|
||||
@@ -199,7 +211,9 @@ const classify = (all: readonly Component[]) => ({
|
||||
format === "javascript-bundle" || /\.(?:m?js|cjs)$/iu.test(path),
|
||||
),
|
||||
signing: all.filter(({ path }) =>
|
||||
/^META-INF\/[^/]+\.(?:p7b|sig|cer|crt|pem|provision)$/iu.test(path),
|
||||
/^META-INF\/[^/]+\.(?:p7b|sig|cer|crt|pem|provision|rsa|dsa|ec)$/iu.test(
|
||||
path,
|
||||
),
|
||||
),
|
||||
});
|
||||
|
||||
|
||||
@@ -36,6 +36,68 @@ const stageHapEntries = [
|
||||
{ path: "META-INF/FIXTURE.p7b", content: "opaque signing" },
|
||||
] as const;
|
||||
|
||||
it.each(["hap", "app"] as const)(
|
||||
"retains encrypted path-only packaging facts for a %s inventory",
|
||||
async (suffix) => {
|
||||
const root = await createTestTempDirectory("rea-harmony-encrypted-paths-");
|
||||
const path = join(root, `Fixture.${suffix}`);
|
||||
const writer = new ZipWriter(new Uint8ArrayWriter());
|
||||
const member = suffix === "app" ? "entry.hap" : "module.json";
|
||||
await writer.add(member, new TextReader("opaque inaccessible content"), {
|
||||
password: "fixture-only",
|
||||
});
|
||||
await writeFile(path, await writer.close());
|
||||
const inventory = await inventoryApplicationPackage(path);
|
||||
const graph = requireDeterministicProjection(
|
||||
projectHarmonyApplicationEvidence,
|
||||
inventory,
|
||||
harmonyApplicationProjectionResultSchema,
|
||||
);
|
||||
expect(graph.unavailable_components).toContainEqual(
|
||||
expect.objectContaining({
|
||||
path: member,
|
||||
artifact_id: null,
|
||||
sha256: null,
|
||||
encrypted: true,
|
||||
}),
|
||||
);
|
||||
expect(graph.coverage.status).toBe("partial");
|
||||
if (suffix === "app")
|
||||
expect(graph.app_pack_children).toContainEqual(
|
||||
expect.objectContaining({
|
||||
path: member,
|
||||
artifact_id: null,
|
||||
sha256: null,
|
||||
}),
|
||||
);
|
||||
else expect(graph.packaging_model).toBe("stage");
|
||||
},
|
||||
);
|
||||
|
||||
it("retains inventoried certificate-block suffixes without claiming verified signatures", async () => {
|
||||
const names = ["CERT.RSA", "CERT.DSA", "CERT.EC", "FIXTURE.p7b"];
|
||||
const path = await writeApplicationZip(
|
||||
"rea-harmony-certificate-paths-",
|
||||
"Fixture.hap",
|
||||
[
|
||||
...names.map((name) => ({
|
||||
path: `META-INF/${name}`,
|
||||
content: "opaque bytes",
|
||||
})),
|
||||
{ path: "META-INF/MANIFEST.MF", content: "manifest" },
|
||||
{ path: "META-INF/CERT.SF", content: "signature file" },
|
||||
],
|
||||
);
|
||||
const graph = requireDeterministicProjection(
|
||||
projectHarmonyApplicationEvidence,
|
||||
await inventoryApplicationPackage(path),
|
||||
harmonyApplicationProjectionResultSchema,
|
||||
);
|
||||
expect(graph.components.signing.map(({ path }) => path).sort()).toEqual(
|
||||
names.map((name) => `META-INF/${name}`).sort(),
|
||||
);
|
||||
});
|
||||
|
||||
describe("HarmonyOS application projection", () => {
|
||||
it.each(["js", "mjs", "cjs", "jsx", "ts", "tsx", "mts", "cts"])(
|
||||
"retains the JavaScript runtime hint for an authenticated .%s component",
|
||||
|
||||
Reference in new issue
Block a user