mirror of
https://github.com/morluto/rea
synced 2026-10-26 14:25:49 -04:00
efbc25fbea
Return the exact static initializer disassembly before Java projection can lose field assignments. Retain byte limits and representation markers, and verify fully folded and mixed initialization through the real CLI/MCP lane. Closes #1846 Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
131 lines
3.7 KiB
JavaScript
131 lines
3.7 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { Client } from "@modelcontextprotocol/client";
|
|
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
|
|
import { parseEvidence } from "../../../dist/domain/evidence.js";
|
|
import { hashAndroidFile } from "./digest.mjs";
|
|
|
|
/** Verify folded field assignments and remaining static-block calls through both public adapters. */
|
|
export const verifyAndroidInitializers = async ({
|
|
apk,
|
|
repository,
|
|
entrypoint,
|
|
environment,
|
|
execute,
|
|
}) => {
|
|
const digest = await hashAndroidFile(apk);
|
|
const cases = [
|
|
{
|
|
class_name: "fixture.InitializationPolicy",
|
|
witnesses: [
|
|
"declared-policy",
|
|
"->singletonList",
|
|
"->POLICY:Ljava/util/List;",
|
|
],
|
|
},
|
|
{
|
|
class_name: "fixture.MixedInitialization",
|
|
witnesses: ["field-value", "->LABEL:Ljava/lang/String;", "->touch()V"],
|
|
},
|
|
];
|
|
const check = (value, scenario) => {
|
|
const evidence = parseEvidence(value);
|
|
assert.equal(evidence.subject.digest.sha256, digest);
|
|
const result = evidence.normalized_result;
|
|
assert.equal(result.class_name, scenario.class_name);
|
|
assert.equal(result.method.name, "<clinit>");
|
|
assert.equal(result.overload_count, 1);
|
|
assert.equal(result.body_status, "available");
|
|
assert.equal(result.representation, "smali");
|
|
assert.equal(result.fell_back, true);
|
|
assert.ok(result.markers.includes("static_initializer_disassembly"));
|
|
assert.equal(result.source.status, "complete");
|
|
for (const witness of scenario.witnesses)
|
|
assert.ok(
|
|
result.source.text.includes(witness),
|
|
`Missing initializer evidence: ${witness}`,
|
|
);
|
|
return evidence;
|
|
};
|
|
const cli = new Map();
|
|
for (const scenario of cases) {
|
|
const response = await execute(
|
|
process.execPath,
|
|
[
|
|
entrypoint,
|
|
"inspect-android-method",
|
|
apk,
|
|
scenario.class_name,
|
|
"<clinit>",
|
|
"--format",
|
|
"json",
|
|
],
|
|
{
|
|
cwd: repository,
|
|
env: environment,
|
|
timeout: 150_000,
|
|
maxBuffer: 8 * 1024 * 1024,
|
|
},
|
|
);
|
|
cli.set(scenario.class_name, check(JSON.parse(response.stdout), scenario));
|
|
}
|
|
const transport = new StdioClientTransport({
|
|
command: process.execPath,
|
|
args: [entrypoint, "mcp"],
|
|
cwd: repository,
|
|
env: environment,
|
|
stderr: "pipe",
|
|
});
|
|
let stderr = "";
|
|
transport.stderr?.on("data", (chunk) => {
|
|
stderr += chunk.toString();
|
|
});
|
|
const client = new Client({
|
|
name: "rea-real-android-initializers",
|
|
version: "1",
|
|
});
|
|
try {
|
|
await client.connect(transport, { timeout: 30_000 });
|
|
for (const scenario of cases) {
|
|
const response = await client.callTool(
|
|
{
|
|
name: "inspect_android_method",
|
|
arguments: {
|
|
path: apk,
|
|
class_name: scenario.class_name,
|
|
method_name: "<clinit>",
|
|
},
|
|
},
|
|
{ timeout: 150_000 },
|
|
);
|
|
assert.notEqual(response.isError, true, JSON.stringify(response));
|
|
const evidence = check(response.structuredContent, scenario);
|
|
assert.deepEqual(
|
|
evidence.normalized_result,
|
|
cli.get(scenario.class_name).normalized_result,
|
|
);
|
|
assert.deepEqual(
|
|
evidence.parameters,
|
|
cli.get(scenario.class_name).parameters,
|
|
);
|
|
assert.deepEqual(
|
|
evidence.provider,
|
|
cli.get(scenario.class_name).provider,
|
|
);
|
|
}
|
|
await client.ping();
|
|
} catch (cause) {
|
|
process.stderr.write(stderr);
|
|
throw cause;
|
|
} finally {
|
|
await client.close();
|
|
}
|
|
assert.equal(
|
|
await hashAndroidFile(apk),
|
|
digest,
|
|
"Static inspection changed fixture bytes",
|
|
);
|
|
console.log(
|
|
"PASS real CLI/MCP static initializer evidence, identity, parity and unchanged APK",
|
|
);
|
|
};
|