Files
rea/tests/acceptance/elfNotesAbiEndian.test.ts

114 lines
4.0 KiB
TypeScript

import { createHash } from "node:crypto";
import { readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect } from "vitest";
import { toolContract } from "../../src/contracts/toolContracts.js";
import {
elfNote,
elfNoteFixture,
} from "../../src/native/elf/ElfNotes.fixture.js";
import { createTestTempDirectory } from "../fixtures/temporaryDirectory.js";
import { cliTest } from "../support/cli/cliFixture.js";
// Literal big-endian descriptors keep the expected values independent of the
// fixture's integer writers and the parser's byte-order branch.
const knownAbi = Buffer.from("00000000010203041020304080010203", "hex");
const unknownAbi = Buffer.from("01000000010203041020304080010203", "hex");
const extendedAbi = Buffer.concat([knownAbi, Buffer.from("01020304", "hex")]);
const shortAbi = knownAbi.subarray(0, 12);
const descriptorHash = (bytes: Buffer): string =>
createHash("sha256").update(bytes).digest("hex");
for (const { bits, ownership, machine } of [
{ bits: 32, ownership: "program", machine: 20 },
{ bits: 64, ownership: "section", machine: 21 },
] as const)
cliTest(
`preserves big-endian ELF${String(bits)} ABI facts through CLI and stdio MCP`,
async ({ cli }) => {
const root = await createTestTempDirectory("rea-elf-abi-endian-");
const path = join(root, "selected.elf");
const descriptors = [
knownAbi,
unknownAbi,
shortAbi,
extendedAbi,
knownAbi,
];
const notes = Buffer.concat([
...descriptors
.slice(0, 4)
.map((bytes) => elfNote("GNU", 1, bytes, false)),
elfNote("OTHER", 1, knownAbi, false),
]);
const bytes = elfNoteFixture({
bits,
ownership,
machine,
little: false,
notes,
});
await writeFile(path, bytes);
const output = await cli.sharedCliRun!({
arguments: ["inspect-elf-notes", path, "--json"],
});
expect(output.exitCode, output.stderr).toBe(0);
const call = await cli.sharedMcpCall!();
const response = await call("inspect_elf_notes", { path });
expect(response.isError, JSON.stringify(response.content)).not.toBe(true);
const schema = toolContract("inspect_elf_notes").outputSchema;
const reports = [output.json, response.structuredContent].map((value) => {
const evidence = schema.parse(value);
expect(evidence.subject).toMatchObject({
local_path: path,
digest: { sha256: descriptorHash(bytes) },
});
const report = evidence.normalized_result;
expect(report).toMatchObject({
format: `elf${String(bits)}`,
byte_order: "big",
machine,
coverage: {
status: "complete",
examined_tables: 1,
examined_entries: 5,
},
});
expect(report.entries).toHaveLength(5);
expect(report.entries[0]?.gnu?.abi_tag).toEqual({
os: 0,
os_name: "linux",
major: 0x01020304,
minor: 0x10203040,
subminor: 0x80010203,
});
expect(report.entries[1]?.gnu?.abi_tag).toEqual({
os: 0x01000000,
os_name: null,
major: 0x01020304,
minor: 0x10203040,
subminor: 0x80010203,
});
// Unexpected lengths stay raw; no ABI values are invented or truncated.
for (const index of [2, 3])
expect(report.entries[index]?.gnu?.abi_tag).toBeNull();
expect(report.entries[4]).toMatchObject({
owner: "OTHER",
type_name: "unknown",
gnu: null,
});
for (const [index, descriptor] of descriptors.entries())
expect(report.entries[index]?.descriptor).toMatchObject({
bytes: descriptor.length,
sha256: descriptorHash(descriptor),
});
return report;
});
expect(reports[0]).toEqual(reports[1]);
expect((await readFile(path)).equals(bytes)).toBe(true);
},
);