fix(apple): preserve own artifact metadata through schema projection

This commit is contained in:
morluto committed 2026-10-26 23:06:36 +08:00
1 parent b7e76a57cd
commit fef76a02fb
3 files changed
+43 -6

No files matched your search

@@ -659,3 +659,34 @@ it.each(["Toolbar", "MissingToolbar"])(
expect(result.resource_key_coverage.status).toBe("complete");
},
);
it("preserves every own JSON metadata field through catalog inspection and page projection", async () => {
const bundle = await createTestTempDirectory("rea-asset-metadata-members-");
const catalog = Buffer.from("inert catalog for the output-decoding boundary");
await writeFile(join(bundle, "Assets.car"), catalog);
// Authored producer text exercises the accepted metadata contract; it is not
// evidence that native assetutil emits these additional field names.
const output =
'[{"Name":"Toolbar","RenditionName":"Toolbar@2x","__proto__":{"Name":"metadata, not an inherited asset name"},"constructor":"retained constructor metadata","toString":false,"Unknown":{"__proto__":{"value":0}},"Empty":"","Zero":0,"Absent":null}]';
const result = await analyzeAppleAssetCatalogs({
bundlePath: bundle,
targetSha256: "a".repeat(64),
environment: {},
runAssetUtil: async (path) => {
expect(path).toBe(join(bundle, "Assets.car"));
return output;
},
});
const expected: unknown = JSON.parse(output);
expect(result.records.map(({ metadata }) => metadata)).toEqual(expected);
expect(result.records[0]).toMatchObject({
asset_name: "Toolbar",
rendition_name: "Toolbar@2x",
catalog_path: "Assets.car",
catalog_sha256: createHash("sha256").update(catalog).digest("hex"),
});
const metadata = result.records[0]?.metadata;
if (metadata === undefined) throw new Error("missing catalog metadata");
expect(Object.hasOwn(metadata, "__proto__")).toBe(true);
expect(Object.getPrototypeOf(metadata)).toBe(Object.prototype);
});
+3 -3
View File
@@ -1,7 +1,7 @@
import { z } from "zod";
import { bundleResourceBoundResultSchema } from "./bundleResourceRoot.js";
import { jsonValueSchema } from "../jsonValue.js";
import { jsonObjectSchema, jsonValueSchema } from "../jsonValue.js";
import { AnalysisOutputError } from "../analysisErrorCore.js";
import {
artifactInventoryCoverageSchema,
@@ -51,7 +51,7 @@ const recordSchema = z.strictObject({
kind: z.enum(["catalog", "rendition"]),
asset_name: z.string().nullable(),
rendition_name: z.string().nullable(),
metadata: z.record(z.string(), jsonValueSchema),
metadata: jsonObjectSchema,
});
const resourceKeyMatchSchema = z.strictObject({
@@ -116,7 +116,7 @@ export const parseAppleAssetCatalogRecords = (
"assetutil output must be a JSON array",
);
return value.map((record, index) => {
const parsed = z.record(z.string(), jsonValueSchema).safeParse(record);
const parsed = jsonObjectSchema.safeParse(record);
if (!parsed.success)
throw new AnalysisOutputError(
"inspect_asset_catalog",