Files
reverse-engineering-anything/tests/acceptance/tools/wabtLauncherIdentity.test.ts
T
gensokyo-devandgensokyo-dev 07e4b700ac test: let the deadline policy own test waits
Vitest's expect.poll and vi.waitFor stop after one second by default, a
host-speed guess that the project's deadline policy does not see. Under
hosted-CI load, kunaProjectConcurrency failed that way twice on unrelated
PRs. Another 256 waits relied on the default, and 97 passed literals
picked to fit some host.

Waits now take as long as their test may run, less the reporting reserve
that children already keep. Each Vitest project sets expect.poll's
default, and the new waitFor in tests/support/testWait.ts replaces
vi.waitFor. Fixture readiness waits (awaitAcknowledgement and the provider
process waits) default to the same deadline, and their host-speed literal
arguments are removed. One remainingTestDeadline owns the arithmetic for
both children and waits.

Ten waits whose short timeout was the real check now assert it directly
(Kuna version probe, Cutter discovery, doctor and Inspector cancellation,
apktool fixture teardown, JADX disconnect): settlement before the
production deadline that would otherwise also satisfy the wait, or a
deadline pinned beyond every test deadline.

The rea/project-wait-deadline lint rule rejects vi.waitFor and explicit
expect.poll timeouts. The testing guide and the CI tests audit skill now
document the policy.

Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
2026-11-14 19:28:38 +08:00

322 lines
11 KiB
TypeScript

import { createHash } from "node:crypto";
import {
access,
chmod,
mkdir,
readFile,
readdir,
symlink,
writeFile,
} from "node:fs/promises";
import { join } from "node:path";
import { fileURLToPath } from "node:url";
import { expect } from "vitest";
import { z } from "zod";
import { analysisErrorProjectionSchema } from "../../../src/contracts/errorSchemas.js";
import { parseEvidence } from "../../../src/domain/evidence.js";
import { wasmArtifactSchema } from "../../../src/domain/wasm/wasmArtifact.js";
import { observeProcessStartIdentity } from "../../../src/process/ProcessOwnershipObservation.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { cliTest } from "../../support/cli/cliFixture.js";
const tools = ["wasm-validate", "wasm-objdump", "wasm2wat"] as const;
const commandTraceSchema = z.object({
tool: z.enum(tools),
pid: z.int().positive(),
cwd: z.string(),
run_id: z.string(),
version: z.boolean(),
snapshot_sha256: z.string().nullable(),
});
const fixtureUrl = (name: string) =>
fileURLToPath(new URL(`../../fixtures/wasm/${name}`, import.meta.url));
/** Real shell/Node launchers with authored WABT output, not installed WABT engines. */
const createFixture = async () => {
const root = await createTestTempDirectory("rea-wabt-launcher-");
const artifact = join(root, "selected module.wasm");
const hold = join(root, "hold-decoder");
const trace = join(root, "commands.jsonl");
const scratch = join(root, "scratch");
const runner = join(root, "wabt-runner.cjs");
await mkdir(scratch);
const bytes = Buffer.from(
"0061736d01000000010401600000020b0103656e7603666f6f0000030201000503010001071002066d656d6f727902000372756e00010a0601040001010b000c04746573747061796c6f6164",
"hex",
);
await writeFile(artifact, bytes);
await writeFile(
runner,
`
const fs = require("node:fs");
const tool = process.argv[2];
const version = process.argv[3] === "--version";
const snapshot_sha256 = version ? null : require("node:crypto").createHash("sha256").update(fs.readFileSync("module.wasm")).digest("hex");
fs.appendFileSync(process.env.REA_WABT_TEST_TRACE, JSON.stringify({ tool, pid: process.pid, version, cwd: process.cwd(), run_id: process.env.REA_PROCESS_RUN_ID, snapshot_sha256 }) + "\\n");
if (version) {
process.stdout.write("1.0.42\\n");
if (tool === "wasm-validate" && process.env.REA_WABT_TEST_REVOKE_COMMAND)
fs.chmodSync(process.env.REA_WABT_TEST_REVOKE_COMMAND, 0);
}
else if (tool === "wasm-objdump") { process.stdout.write(fs.readFileSync(process.env.REA_WABT_TEST_DUMP)); }
else if (tool === "wasm2wat") {
const decode = () => process.stdout.write(fs.readFileSync(process.env.REA_WABT_TEST_WAT));
if (fs.existsSync(process.env.REA_WABT_TEST_HOLD)) {
setTimeout(decode, 4000);
} else { decode(); }
}
`,
);
const install = async (directory: string, decoy = false) => {
await mkdir(directory, { recursive: true });
for (const tool of tools)
await writeFile(
join(directory, tool),
decoy
? "#!/bin/sh\nprintf 'unselected-decoy\\n'\n"
: `#!/bin/sh\nexec "$REA_WABT_TEST_NODE" "$REA_WABT_TEST_RUNNER" "${tool}" "$@"\n`,
{ mode: 0o700 },
);
};
const environment = {
...process.env,
REA_WABT_TEST_NODE: process.execPath,
REA_WABT_TEST_RUNNER: runner,
REA_WABT_TEST_DUMP: fixtureUrl("objdump.txt"),
REA_WABT_TEST_WAT: fixtureUrl("decoded.wat"),
REA_WABT_TEST_HOLD: hold,
REA_WABT_TEST_TRACE: trace,
TMPDIR: scratch,
TMP: scratch,
TEMP: scratch,
};
return {
root,
artifact,
bytes,
hold,
trace,
scratch,
install,
environment,
};
};
cliTest.skipIf(process.platform === "win32")(
"cleans up real selected WABT interpreter shims after a command deadline",
async ({ cli }) => {
const fixture = await createFixture();
const selected = join(fixture.root, "selected tools");
await fixture.install(selected);
const invoke = (timeout: number) =>
cli.run({
arguments: [
"inspect-wasm-artifact",
fixture.artifact,
"--command-timeout-ms",
String(timeout),
"--json",
],
environment: {
...fixture.environment,
REA_WABT_BIN_DIRECTORY: selected,
},
});
const control = await invoke(10_000);
expect(control.exitCode, `${control.stderr}\n${control.stdout}`).toBe(0);
const evidence = parseEvidence(control.json);
const report = wasmArtifactSchema.parse(evidence.normalized_result);
expect(report.artifact.sha256).toBe(
createHash("sha256").update(fixture.bytes).digest("hex"),
);
expect(report.validation).toBe("valid");
const trace = (await readFile(fixture.trace, "utf8"))
.trim()
.split("\n")
.map((line) => commandTraceSchema.parse(JSON.parse(line)));
expect(trace.length).toBeGreaterThan(0);
expect(new Set(trace.map(({ cwd }) => cwd)).size).toBe(1);
for (const command of trace) {
expect(command.cwd.startsWith(join(fixture.scratch, "rea-wabt-"))).toBe(
true,
);
expect(command.run_id).toMatch(/^rea-wabt-/u);
expect(command.snapshot_sha256).toBe(
command.version ? null : report.artifact.sha256,
);
}
expect(await readdir(fixture.scratch)).toEqual([]);
await writeFile(fixture.hold, "hold this invocation");
try {
const invocation = await invoke(2_000);
expect(invocation.exitCode, invocation.stderr).toBe(1);
const failure = analysisErrorProjectionSchema.parse(invocation.json);
expect(failure, invocation.stdout).toMatchObject({
code: "provider_timeout",
details: {
partial_observation: {
normalized_result: {
validation: "valid",
artifact: { sha256: report.artifact.sha256 },
},
},
},
});
expect(await readdir(fixture.scratch)).toEqual([]);
expect((await readFile(fixture.artifact)).equals(fixture.bytes)).toBe(
true,
);
} finally {
// The authored shim self-exits even on the unfixed cleanup-refusal path.
// Observe its actual process lifetime; token-owned cleanup can use SIGKILL.
const commands = (await readFile(fixture.trace, "utf8"))
.trim()
.split("\n")
.map((line) => commandTraceSchema.parse(JSON.parse(line)));
const decoder = commands.findLast(
(command) => command.tool === "wasm2wat" && !command.version,
);
if (decoder === undefined)
throw new Error("No decoder process was observed");
await expect
.poll(() =>
observeProcessStartIdentity(decoder.pid, undefined, decoder.run_id),
)
.toBeUndefined();
}
},
);
cliTest.skipIf(process.platform === "win32" || process.getuid?.() === 0)(
"retains completed WABT version output when its post-command fingerprint read is denied",
async ({ cli }) => {
const fixture = await createFixture();
const selected = join(fixture.root, "tools");
await fixture.install(selected);
const revoked = join(selected, "wasm-validate");
try {
const invocation = await cli.run({
arguments: ["inspect-wasm-artifact", fixture.artifact, "--json"],
environment: {
...fixture.environment,
REA_WABT_BIN_DIRECTORY: selected,
REA_WABT_TEST_REVOKE_COMMAND: revoked,
},
});
expect(invocation.exitCode, invocation.stderr).toBe(1);
const failure = analysisErrorProjectionSchema.parse(invocation.json);
expect(failure, invocation.stdout).toMatchObject({
code: "capability_unavailable",
details: {
captured_output: {
stdout: "1.0.42\n",
stderr: "",
truncated: false,
exit_code: 0,
signal: null,
},
},
});
expect((await readFile(fixture.artifact)).equals(fixture.bytes)).toBe(
true,
);
expect(await readdir(fixture.scratch)).toEqual([]);
} finally {
await chmod(revoked, 0o700);
}
},
);
cliTest.skipIf(process.platform === "win32")(
"launches selected WABT symlinks with their own sibling resources and fingerprints canonical tools",
async ({ cli }) => {
const fixture = await createFixture();
const targets = join(fixture.root, "canonical tools");
const selected = join(fixture.root, "selected links");
await fixture.install(targets);
await mkdir(selected);
await writeFile(
join(selected, "wabt-environment"),
"# selected installation resource\n",
);
for (const tool of tools) {
const target = join(targets, tool);
const script = await readFile(target, "utf8");
await writeFile(
target,
script.replace(
"#!/bin/sh\n",
'#!/bin/sh\n. "${0%/*}/wabt-environment"\n',
),
);
await symlink(target, join(selected, tool));
}
const invocation = await cli.run({
arguments: ["inspect-wasm-artifact", fixture.artifact, "--json"],
environment: { ...fixture.environment, REA_WABT_BIN_DIRECTORY: selected },
});
expect(
invocation.exitCode,
`${invocation.stderr}\n${invocation.stdout}`,
).toBe(0);
const report = wasmArtifactSchema.parse(
parseEvidence(invocation.json).normalized_result,
);
expect(report.tool_profile.commands.map(({ path }) => path)).toEqual(
tools.map((tool) => join(targets, tool)),
);
for (const command of report.tool_profile.commands)
expect(command.sha256).toBe(
createHash("sha256")
.update(await readFile(command.path))
.digest("hex"),
);
expect((await readFile(fixture.artifact)).equals(fixture.bytes)).toBe(true);
expect(await readdir(fixture.scratch)).toEqual([]);
},
);
cliTest.skipIf(process.platform === "win32")(
"selects a WABT directory through literal symlink and parent traversal",
async ({ cli }) => {
const fixture = await createFixture();
const intended = join(fixture.root, "intended");
await mkdir(join(intended, "nested"), { recursive: true });
await symlink(join(intended, "nested"), join(fixture.root, "alias"));
const selected = join(intended, "tools");
await fixture.install(selected);
await fixture.install(join(fixture.root, "tools"), true);
const invocation = await cli.run({
arguments: ["inspect-wasm-artifact", fixture.artifact, "--json"],
environment: {
...fixture.environment,
REA_WABT_BIN_DIRECTORY: `${fixture.root}/alias/../tools`,
},
});
expect(
invocation.exitCode,
`${invocation.stderr}\n${invocation.stdout}`,
).toBe(0);
const report = wasmArtifactSchema.parse(
parseEvidence(invocation.json).normalized_result,
);
expect(report.tool_profile.commands.map(({ path }) => path)).toEqual(
tools.map((tool) => join(selected, tool)),
);
for (const command of report.tool_profile.commands)
expect(command.sha256).toBe(
createHash("sha256")
.update(await readFile(command.path))
.digest("hex"),
);
expect(report.artifact.path).toBe(fixture.artifact);
expect((await readFile(fixture.artifact)).equals(fixture.bytes)).toBe(true);
expect(await readdir(fixture.scratch)).toEqual([]);
await expect(
access(join(fixture.root, "tools", "wasm-validate")),
).resolves.toBeUndefined();
},
);