fix(fit): preserve leading U+FEFF in property strings (#8083)

This commit is contained in:
ShuaixinHuang authored and GitHub committed 2026-10-30 17:19:38 +08:00
1 parent cce33142ed
commit d77104daab
3 files changed
+88 -1

No files matched your search

+34
View File
@@ -62,6 +62,40 @@ const singleImage = (properties: Record<string, Buffer>): Buffer =>
});
describe("FIT image facts", () => {
it("preserves a leading U+FEFF in string facts and configuration references", () => {
const structure = read(
fitFixture({
images: [kernel({ description: dtString("\uFEFFkernel description") })],
configurations: {
name: "configurations",
properties: { default: dtString("\uFEFFconf-1") },
children: [
{
name: "conf-1",
properties: {
kernel: dtString("\uFEFFkernel"),
loadables: dtString("kernel\0\uFEFFkernel"),
},
},
],
},
}),
);
expect(structure.images[0]?.metadata.description).toBe(
"\uFEFFkernel description",
);
expect(structure.metadata.default_configuration).toBe("\uFEFFconf-1");
expect(structure.metadata.configurations[0]).toMatchObject({
name: "conf-1",
kernel: ["\uFEFFkernel"],
loadables: ["kernel", "\uFEFFkernel"],
unresolved_reference_count: 2,
});
expect(structure.limitations).toContain(
"/configurations: default \uFEFFconf-1 names no configuration",
);
});
it("decodes embedded root and image facts with property ranges", () => {
const structure = read(FIT_EMBEDDED);
expect(structure.metadata).toMatchObject({
+2 -1
View File
@@ -88,7 +88,8 @@ const propertyOf = (node: FitNode, name: string): FitProperty | undefined =>
const valueOf = (fdt: Buffer, property: FitProperty): Buffer =>
fdt.subarray(property.offset, property.offset + property.bytes);
const utf8 = new TextDecoder("utf-8", { fatal: true });
// A property value is data: a leading U+FEFF is not a file encoding signature.
const utf8 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
const nulCount = (raw: Buffer): number => {
let count = 0;
for (const byte of raw) if (byte === 0) count += 1;
+52
View File
@@ -1,3 +1,4 @@
import { createHash } from "node:crypto";
import { readFile, rm, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect, onTestFinished } from "vitest";
@@ -413,3 +414,54 @@ cliTest.for([
?.declared_size,
).toBe(item.bytes);
});
cliTest.for([
{ algo: "sha256", verified: 1, unverified: 0 },
{ algo: "Xsha256", verified: 0, unverified: 1 },
{ algo: "\uFEFFsha256", verified: 0, unverified: 1 },
])(
"preserves the exact FIT hash algorithm $algo through the CLI",
async ({ algo, verified, unverified }, { cli }) => {
const directory = await createTestTempDirectory("rea-fit-algorithm-cli-");
const source = join(directory, "boot.itb");
await writeFile(
source,
fitFixture({
images: [
{
name: "kernel",
data: FIT_KERNEL,
children: [
{
name: "hash-1",
properties: {
algo: dtString(algo),
value: createHash("sha256").update(FIT_KERNEL).digest(),
},
},
],
},
],
}),
);
const inspected = await cli.run({
arguments: ["inspect-artifact", source, "--json"],
});
expect(inspected.exitCode, inspected.stdout + inspected.stderr).toBe(0);
const inspection = artifactInspectionResultSchema.parse(
parseEvidence(inspected.json).normalized_result,
);
const graph = artifactInventoryResultSchema.parse(
inspection.substeps[0]?.evidence.normalized_result,
);
expect(
graph.occurrences.find((row) => row.logical_path === "images/kernel.bin")
?.format_metadata,
).toMatchObject({
kind: "fit-image",
hash_algorithms: [algo],
hashes_verified: verified,
hashes_unverified: unverified,
});
},
);