mirror of
https://github.com/morluto/rea.git
synced 2026-11-10 00:36:35 +00:00
* feat(native): decode Android .note.android.ident ELF notes Decode Android NDK NT_ANDROID_TYPE_IDENT (.note.android.ident, owner Android, type 1) notes in inspect_elf_notes across legacy 4-byte and modern >=132-byte descriptors with bounded TextBudget accounting. * fix(native): isolate Android note scan budget test, scope contract import, and add feature spec * test(native): use domain tool contract in elfNotesMcp boundary test
103 lines
3.3 KiB
TypeScript
103 lines
3.3 KiB
TypeScript
import { writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { expect } from "vitest";
|
|
|
|
import { BINARY_DIAGNOSTICS_TOOL_CONTRACTS } from "../../src/contracts/native/binaryDiagnosticsToolContracts.js";
|
|
import {
|
|
androidIdentNote,
|
|
elfNote,
|
|
elfNoteFixture,
|
|
gnuBuildIdNote,
|
|
} from "../../src/native/elf/ElfNotes.fixture.js";
|
|
import { createTestTempDirectory } from "../fixtures/temporaryDirectory.js";
|
|
import { cliTest } from "../support/cli/cliFixture.js";
|
|
|
|
const inspectElfNotesContract = BINARY_DIAGNOSTICS_TOOL_CONTRACTS.find(
|
|
(
|
|
candidate,
|
|
): candidate is Extract<
|
|
(typeof BINARY_DIAGNOSTICS_TOOL_CONTRACTS)[number],
|
|
{ readonly name: "inspect_elf_notes" }
|
|
> => candidate.name === "inspect_elf_notes",
|
|
);
|
|
if (inspectElfNotesContract === undefined)
|
|
throw new Error("Missing inspect_elf_notes contract");
|
|
|
|
for (const target of [
|
|
{
|
|
label: "little-endian ELF64",
|
|
bits: 64 as const,
|
|
little: true,
|
|
machine: 183,
|
|
},
|
|
{ label: "big-endian ELF32", bits: 32 as const, little: false, machine: 8 },
|
|
])
|
|
cliTest(
|
|
`decodes ${target.label} Android .note.android.ident through CLI and stdio MCP`,
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-elf-android-notes-");
|
|
const path = join(root, "libtarget.so");
|
|
const notes = Buffer.concat([
|
|
androidIdentNote({
|
|
androidApi: 24,
|
|
ndkVersion: "r27c",
|
|
ndkBuildNumber: "12297006",
|
|
little: target.little,
|
|
}),
|
|
androidIdentNote({
|
|
androidApi: 21,
|
|
ndkVersion: null,
|
|
ndkBuildNumber: null,
|
|
little: target.little,
|
|
}),
|
|
elfNote("Android", 2, Buffer.from([0xde, 0xad]), target.little),
|
|
gnuBuildIdNote(undefined, target.little),
|
|
]);
|
|
await writeFile(
|
|
path,
|
|
elfNoteFixture({
|
|
bits: target.bits,
|
|
little: target.little,
|
|
machine: target.machine,
|
|
ownership: "section",
|
|
sectionName: ".note.android.ident",
|
|
notes,
|
|
}),
|
|
);
|
|
|
|
const cliOut = await cli.sharedCliRun!({
|
|
arguments: ["inspect-elf-notes", path, "--json"],
|
|
});
|
|
expect(cliOut.exitCode, cliOut.stderr).toBe(0);
|
|
const call = await cli.sharedMcpCall!();
|
|
const mcpOut = await call("inspect_elf_notes", { path });
|
|
expect(mcpOut.isError, JSON.stringify(mcpOut.content)).not.toBe(true);
|
|
|
|
const schema = inspectElfNotesContract.outputSchema;
|
|
const cliReport = schema.parse(cliOut.json).normalized_result;
|
|
const mcpReport = schema.parse(
|
|
mcpOut.structuredContent,
|
|
).normalized_result;
|
|
expect(cliReport).toEqual(mcpReport);
|
|
expect(cliReport.byte_order).toBe(target.little ? "little" : "big");
|
|
expect(cliReport.entries.map((entry) => entry.type_name)).toEqual([
|
|
"android_ident",
|
|
"android_ident",
|
|
"unknown",
|
|
"gnu_build_id",
|
|
]);
|
|
expect(cliReport.entries[0]?.android).toEqual({
|
|
android_api: 24,
|
|
ndk_version: "r27c",
|
|
ndk_build_number: "12297006",
|
|
});
|
|
expect(cliReport.entries[1]?.android).toEqual({
|
|
android_api: 21,
|
|
ndk_version: null,
|
|
ndk_build_number: null,
|
|
});
|
|
expect(cliReport.entries[2]?.android).toBeNull();
|
|
expect(cliReport.entries[3]?.android).toBeNull();
|
|
},
|
|
);
|