Files
reverse-engineering-anything/src/process/RegexMatcher.test.ts
T
bea6b98e84 test: prefer structured assertions over recovery prose (#6379)
* test: prefer structured assertions over recovery prose

Lock regex, IDA, Hopper/Kuna, MCP budget, capture-heap, and pcap
failures on error codes and reported limits instead of full recovery
sentences.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* test: keep decoder heap negatives off the Windows reserve

"512 MiB" also appears in the Bun Windows reserve sentence. The
negative check stays on "512 MiB (source setting)", which is the other
adapter's heap.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* test: keep the one-retry cap and deadline recovery tokens

The lost-connection guidance must say once only, so an unlimited
"whenever it is safe" rewrite fails. Deadline recovery still has to
name set, restart, the floor, and the maximum constant.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* test: keep heap, MCP, pcap, and preload recovery tokens

Codex still wanted the set/restart/floor/maximum heap guidance, MCP
default/floor/maximum bounds, Wireshark install guidance, and the
dropped-preload attribution limit as separate tokens.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* test: keep shared-context and transport recovery tokens

Shared-context capture must still exclude requests without a known root
or descendant frame. Shutdown must end the REA process before starting
again, and a failed HTTP listen must offer another port or stopping the
process that holds it.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* test: keep handoff, input-check, and budget format tokens

Skill and server guidance must still tell the user to restart the MCP
client. Process failures must still say to check the input files. Invalid
MCP phase budgets must still say positive decimal integer and ms.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* test: bind budget floors and active deadline sources

The phase-budget minimum is the start of "from N to M ms", so a digit
inside the maximum no longer satisfies it. Capability text must contain
the active "N ms (source ...)" pair, not the default number and a heap
source mentioned apart.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* test: bind heap MiB sources and pcap host tokens

A configured 256 MiB request must appear as "256 MiB (source setting)",
so a byte-sized 256 no longer passes. Unsupported pcap hosts must still
name Linux, util-linux, Windows, and owned Job Objects as separate tokens.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* test: bind the selected decoder heap to MiB and source

The two-adapter limitation must contain "256 MiB (source setting)".
The exhaustion message binds that capacity as "256 MiB V8 old-generation
heap (source setting)", so a byte-sized 256 no longer passes.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* test: bind doctor client seconds and prlimit absolute guidance

Doctor recovery must name startup_timeout_sec of the policy's seconds,
so a hardcoded 60 no longer passes while the policy stays 30. A relative
prlimit must say the value must be absolute and tell the user to check
REA_TSHARK_PRLIMIT_COMMAND.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* test: assert integrity codes for rehashed evidence and coverage

Independently rehashed process Evidence and a tampered digest project
evidence_integrity_mismatch. An unsupported comparison operation stays
invalid_request. Unsupported inventory coverage status is an integrity
failure whose reason carries the coverage.status schema issue.

Co-authored-by: morluto <morluto@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
2026-10-23 04:47:39 +08:00

551 lines
18 KiB
TypeScript

import { expect, it } from "vitest";
import {
DEFAULT_REGEX_MATCHING_DEADLINE,
REGEX_MATCHING_DEADLINE_SETTING,
} from "../config/regexMatchingDeadline.js";
import { REGEX_WORKER_HEAP_REQUEST_SETTING } from "../config/regexWorkerHeapRequest.js";
import { projectAnalysisError } from "../domain/analysisErrorProjection.js";
import {
execArgvFromCommandLine,
readLaunchExecArgv,
readLaunchNodeOptions,
regexMatchingLimitation,
regexWorkerHeapError,
resolveLaunchRegexWorkerHeap,
resolveRegexWorkerHeap,
type RegexWorkerHeapLimit,
} from "./RegexMatcher.js";
const effective = (mib: number, overridden: boolean): RegexWorkerHeapLimit => ({
kind: "effective",
mib,
overridden,
});
it.each([
{
name: "uses the 128 MiB request when no flag is set",
execArgv: [],
nodeOptions: undefined,
heap: effective(128, false),
},
{
name: "lets a smaller execArgv flag override the request",
execArgv: ["--max-old-space-size=64"],
nodeOptions: undefined,
heap: effective(64, true),
},
{
name: "lets a larger execArgv flag override the request",
execArgv: ["--require", "./preload.js", "--max_old_space_size=256"],
nodeOptions: undefined,
heap: effective(256, true),
},
{
name: "reads a positive NODE_OPTIONS flag that is absent from execArgv",
execArgv: [],
nodeOptions: "--no-warnings --max-old-space-size=192",
heap: effective(192, true),
},
{
name: "lets the last execArgv flag win over NODE_OPTIONS",
execArgv: ["--max-old-space-size=256"],
nodeOptions: "--max-old-space-size=96",
heap: effective(256, true),
},
{
name: "treats a final zero flag as leaving the 128 MiB request in effect",
execArgv: ["--max-old-space-size=0"],
nodeOptions: "--max-old-space-size=256",
heap: effective(128, false),
},
{
name: "accepts quoted NODE_OPTIONS and a leading plus or zeros",
execArgv: ["--max-old-space-size=+0256"],
nodeOptions: '"--max-old-space-size=144"',
heap: effective(256, true),
},
{
name: "uses the last positive flag",
execArgv: ["--max-old-space-size=256", "--max-old-space-size=96"],
nodeOptions: undefined,
heap: effective(96, true),
},
{
name: "leaves the effective heap unknown for an unparsed flag",
execArgv: ["--max-old-space-size=256.5"],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "keeps a later positive flag after an unparsed one",
execArgv: ["--max-old-space-size=256.5", "--max-old-space-size=80"],
nodeOptions: undefined,
heap: effective(80, true),
},
{
name: "leaves an untokenizable NODE_OPTIONS value unknown until execArgv decides",
execArgv: [],
nodeOptions: '"--max-old-space-size=256',
heap: { kind: "unknown" } as const,
},
{
name: "lets execArgv decide when NODE_OPTIONS cannot be tokenized",
execArgv: ["--max-old-space-size=80"],
nodeOptions: '"--max-old-space-size=256',
heap: effective(80, true),
},
{
name: "leaves a percentage flag unestablished instead of the 128 MiB request",
execArgv: ["--max-old-space-size-percentage=50"],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "lets a percentage flag win over a later absolute flag",
execArgv: ["--max-old-space-size-percentage=50", "--max-old-space-size=64"],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "lets a percentage flag win over an earlier absolute flag",
execArgv: ["--max-old-space-size=64", "--max-old-space-size-percentage=50"],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "lets a NODE_OPTIONS percentage win over an execArgv absolute flag",
execArgv: ["--max-old-space-size=64"],
nodeOptions: "--max-old-space-size-percentage=50",
heap: { kind: "unknown" } as const,
},
{
name: "lets an execArgv percentage win over a NODE_OPTIONS absolute flag",
execArgv: ["--max-old-space-size-percentage=50"],
nodeOptions: "--max-old-space-size=64",
heap: { kind: "unknown" } as const,
},
{
name: "recognizes an underscore percentage flag",
execArgv: ["--max_old_space_size_percentage=50"],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "recognizes a percentage flag split from its value",
execArgv: [
"--max-old-space-size=64",
"--max-old-space-size-percentage",
"50",
],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "does not let a later absolute flag replace an invalid percentage",
execArgv: ["--max-old-space-size-percentage=0", "--max-old-space-size=64"],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "leaves a fractional percentage unestablished",
execArgv: ["--max-old-space-size-percentage=50.5"],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "does not treat a final zero absolute flag as 128 MiB after a percentage",
execArgv: ["--max-old-space-size-percentage=50", "--max-old-space-size=0"],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "leaves an env-file launch unestablished when NODE_OPTIONS was absent",
execArgv: ["--env-file=rea.env"],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "leaves an env-file-if-exists launch unestablished when NODE_OPTIONS was absent",
execArgv: ["--env-file-if-exists=.env"],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "does not let an absolute flag hide NODE_OPTIONS supplied by an env file",
execArgv: ["--env-file=rea.env", "--max-old-space-size=64"],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "recognizes an env-file flag split from its path",
execArgv: ["--env-file", "rea.env"],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "keeps an inherited NODE_OPTIONS value when an env file cannot override it",
execArgv: ["--env-file=rea.env"],
nodeOptions: "--max-old-space-size=64",
heap: effective(64, true),
},
{
name: "lets a later absolute flag win when an inherited NODE_OPTIONS blocks the env file",
execArgv: ["--max-old-space-size=32", "--env-file-if-exists=rea.env"],
nodeOptions: "--max-old-space-size=64",
heap: effective(32, true),
},
{
name: "keeps the 128 MiB request when an empty NODE_OPTIONS blocks the env file",
execArgv: ["--env-file=rea.env"],
nodeOptions: "",
heap: effective(128, false),
},
{
name: "leaves a config-file percentage source unestablished",
execArgv: ["--experimental-config-file=node.config.json"],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "leaves a default config-file launch unestablished",
execArgv: ["--experimental-default-config-file"],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "recognizes a config-file flag split from its path",
execArgv: ["--experimental-config-file", "node.config.json"],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "does not let an absolute flag hide a config-file heap option",
execArgv: [
"--experimental-config-file=node.config.json",
"--max-old-space-size=64",
],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "does not let a recovered NODE_OPTIONS hide a config-file heap option",
execArgv: ["--experimental-default-config-file"],
nodeOptions: "--max-old-space-size=64",
heap: { kind: "unknown" } as const,
},
{
name: "leaves a config-file flag in recovered NODE_OPTIONS unestablished",
execArgv: ["--max-old-space-size=256"],
nodeOptions: "--experimental-config-file=node.config.json",
heap: { kind: "unknown" } as const,
},
{
name: "leaves a positive --max-heap-size unestablished instead of the 128 MiB request",
execArgv: ["--max-heap-size=64"],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "recognizes an underscore --max-heap-size",
execArgv: ["--max_heap_size=+064"],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "leaves a NODE_OPTIONS --max-heap-size unestablished",
execArgv: [],
nodeOptions: "--max-heap-size=64",
heap: { kind: "unknown" } as const,
},
{
name: "does not let an old-space flag hide a positive --max-heap-size",
execArgv: ["--max-heap-size=64", "--max-old-space-size=256"],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "does not let a later --max-heap-size hide an old-space flag",
execArgv: ["--max-old-space-size=64"],
nodeOptions: "--max_heap_size=256",
heap: { kind: "unknown" } as const,
},
{
name: "lets a final zero --max-heap-size clear the total-heap cap",
execArgv: ["--max-heap-size=64", "--max-heap-size=0"],
nodeOptions: undefined,
heap: effective(128, false),
},
{
name: "keeps an old-space flag when a final --max-heap-size is zero",
execArgv: ["--max-old-space-size=256", "--max-heap-size="],
nodeOptions: undefined,
heap: effective(256, true),
},
{
name: "leaves an unparsed --max-heap-size unestablished",
execArgv: ["--max-heap-size=64.5", "--max-old-space-size=80"],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
{
name: "does not let a later zero clear an unparsed --max-heap-size",
execArgv: ["--max-heap-size=64.5", "--max-heap-size=0"],
nodeOptions: undefined,
heap: { kind: "unknown" } as const,
},
] as const)(
"resolveRegexWorkerHeap $name",
({ execArgv, nodeOptions, heap }) => {
expect(resolveRegexWorkerHeap(execArgv, nodeOptions)).toEqual(heap);
},
);
it("does not treat a rewritten NODE_OPTIONS value as the launch heap", () => {
const previous = process.env.NODE_OPTIONS;
const rewritten = "--max-old-space-size=61-rewritten";
process.env.NODE_OPTIONS = rewritten;
try {
const launch = readLaunchNodeOptions();
if (process.platform === "linux") {
expect(launch.kind).toBe("recovered");
if (launch.kind === "recovered")
expect(launch.value ?? "").not.toContain("61-rewritten");
} else {
expect(launch).toEqual({ kind: "unrecoverable" });
}
expect(
resolveLaunchRegexWorkerHeap(
{ kind: "recovered", value: ["--max-old-space-size=256"] },
{ kind: "unrecoverable" },
),
).toEqual({ kind: "unknown" });
expect(
resolveLaunchRegexWorkerHeap(
{ kind: "recovered", value: [] },
{ kind: "recovered", value: "--max_heap_size=64" },
),
).toEqual({ kind: "unknown" });
expect(
resolveLaunchRegexWorkerHeap(
{ kind: "unrecoverable" },
{ kind: "recovered", value: "--max-old-space-size=64" },
),
).toEqual({ kind: "unknown" });
if (launch.kind === "recovered") {
expect(launch.value).not.toBe(rewritten);
expect(
resolveLaunchRegexWorkerHeap(
{ kind: "recovered", value: ["--max-old-space-size=32"] },
launch,
),
).toEqual(
resolveRegexWorkerHeap(["--max-old-space-size=32"], launch.value),
);
}
} finally {
if (previous === undefined) delete process.env.NODE_OPTIONS;
else process.env.NODE_OPTIONS = previous;
}
});
const commandLine = (...tokens: readonly string[]): Buffer =>
Buffer.from(`${tokens.join("\0")}\0`);
it("recovers launch exec argv from the command line, not process.execArgv", () => {
expect(
execArgvFromCommandLine(
commandLine(
"node",
"--max-old-space-size=64",
"script.js",
"--max-old-space-size=256",
),
),
).toEqual({ kind: "recovered", value: ["--max-old-space-size=64"] });
expect(
resolveLaunchRegexWorkerHeap(
execArgvFromCommandLine(
commandLine("node", "--max-old-space-size=64", "script.js"),
),
{ kind: "recovered", value: undefined },
),
).toEqual({ kind: "effective", mib: 64, overridden: true });
expect(resolveRegexWorkerHeap([], undefined)).toEqual({
kind: "effective",
mib: 128,
overridden: false,
});
expect(
execArgvFromCommandLine(
commandLine(
"node",
"--require",
"preload.cjs",
"--max_old_space_size=64",
"script.js",
),
),
).toEqual({
kind: "recovered",
value: ["--require", "preload.cjs", "--max_old_space_size=64"],
});
expect(
execArgvFromCommandLine(
commandLine("node", "-e", "code", "--max-old-space-size=80"),
),
).toEqual({
kind: "recovered",
value: ["-e", "code", "--max-old-space-size=80"],
});
expect(
execArgvFromCommandLine(
commandLine("node", "--", "--max-old-space-size=64", "script.js"),
),
).toEqual({ kind: "recovered", value: [] });
expect(
execArgvFromCommandLine(
commandLine("node", "--not-a-real-node-option", "script.js"),
),
).toEqual({ kind: "unrecoverable" });
expect(execArgvFromCommandLine(Buffer.alloc(0))).toEqual({
kind: "unrecoverable",
});
expect(execArgvFromCommandLine(Buffer.from([0xff, 0]))).toEqual({
kind: "unrecoverable",
});
expect(execArgvFromCommandLine(commandLine("rea"))).toEqual({
kind: "unrecoverable",
});
expect(
execArgvFromCommandLine(
Buffer.concat([Buffer.from("rea\0"), Buffer.alloc(32)]),
),
).toEqual({ kind: "unrecoverable" });
expect(
resolveLaunchRegexWorkerHeap(
execArgvFromCommandLine(
Buffer.concat([Buffer.from("rea\0"), Buffer.alloc(32)]),
),
{ kind: "recovered", value: undefined },
),
).toEqual({ kind: "unknown" });
expect(execArgvFromCommandLine(commandLine("node", "script.js"))).toEqual({
kind: "recovered",
value: [],
});
const before = readLaunchExecArgv();
const snapshot = [...process.execArgv];
process.execArgv.length = 0;
try {
expect(process.execArgv).toEqual([]);
expect(readLaunchExecArgv()).toEqual(before);
if (before.kind === "recovered") expect(before.value).toEqual(snapshot);
else expect(before).toEqual({ kind: "unrecoverable" });
} finally {
process.execArgv.push(...snapshot);
}
});
it("describes the effective heap and the configurable matching deadline", () => {
for (const heap of [
effective(128, false),
effective(256, true),
{ kind: "unknown" } as const,
]) {
const limitation = regexMatchingLimitation(heap);
expect(limitation).toContain(REGEX_MATCHING_DEADLINE_SETTING);
expect(limitation).toContain(
`${String(DEFAULT_REGEX_MATCHING_DEADLINE.deadlineMs)} ms (source ${DEFAULT_REGEX_MATCHING_DEADLINE.source}`,
);
expect(limitation).toContain(REGEX_WORKER_HEAP_REQUEST_SETTING);
expect(limitation).not.toContain("no runtime override");
const projected = projectAnalysisError(
regexWorkerHeapError("search_procedures", new Error("heap"), heap),
);
expect(projected.remediation.action).not.toContain("no runtime override");
expect(projected.remediation.action).toContain("--max-old-space-size");
expect(projected.remediation.action).toContain(
"--max-old-space-size-percentage",
);
if (heap.kind === "unknown") {
expect(limitation).toContain("was not established");
expect(limitation).toContain("--max-old-space-size-percentage");
expect(limitation).toContain("--max-heap-size");
expect(limitation).toContain("--experimental-config-file");
expect(projected.remediation.action).toContain("--max-heap-size");
expect(projected.remediation.action).toContain(
"--experimental-default-config-file",
);
expect(projected.message).toContain("was not established");
expect(projected.details).toMatchObject({
reported_limits: {
requested_worker_heap_mib: 128,
requested_worker_heap_source: "default",
},
});
expect(projected.details?.reported_limits).toEqual({
requested_worker_heap_mib: 128,
requested_worker_heap_source: "default",
});
} else {
expect(limitation).toContain(`effective ${String(heap.mib)} MiB`);
expect(projected.message).toContain(`effective ${String(heap.mib)} MiB`);
expect(projected.details).toMatchObject({
reported_limits: {
worker_heap_mib: heap.mib,
requested_worker_heap_mib: 128,
requested_worker_heap_source: "default",
},
});
}
}
});
it("keeps a selected heap request unless a positive Node flag overrides it", () => {
const request = { heapMiB: 256, source: "setting" as const };
expect(resolveRegexWorkerHeap([], undefined, request)).toEqual(
effective(256, false),
);
expect(
resolveRegexWorkerHeap(["--max-old-space-size=64"], undefined, request),
).toEqual(effective(64, true));
const selected = regexMatchingLimitation(
effective(256, false),
DEFAULT_REGEX_MATCHING_DEADLINE,
request,
);
expect(selected).toContain("effective 256 MiB");
expect(selected).toContain(REGEX_WORKER_HEAP_REQUEST_SETTING);
expect(selected).toContain("256 MiB (source setting");
const overridden = regexMatchingLimitation(
effective(64, true),
DEFAULT_REGEX_MATCHING_DEADLINE,
request,
);
expect(overridden).toContain("effective 64 MiB");
expect(overridden).toContain(REGEX_WORKER_HEAP_REQUEST_SETTING);
expect(overridden).toContain("256 MiB (source setting");
const projected = projectAnalysisError(
regexWorkerHeapError(
"search_procedures",
new Error("heap"),
effective(64, true),
request,
),
);
expect(projected.details).toMatchObject({
reported_limits: {
worker_heap_mib: 64,
requested_worker_heap_mib: 256,
requested_worker_heap_source: "setting",
},
});
expect(projected.remediation.action).toContain(
REGEX_WORKER_HEAP_REQUEST_SETTING,
);
expect(projected.remediation.action).toContain("256 MiB (source setting");
expect(projected.remediation.action).not.toContain("no runtime override");
});