mirror of
https://github.com/morluto/rea.git
synced 2026-11-03 13:26:10 +00:00
* feat(artifacts): inspect classic iNES container regions
* fix(artifacts): preserve iNES source disappearance as integrity failure
* fix(artifacts): revalidate iNES source before parsing header
* fix(artifacts): validate admitted roots before classification
* fix(artifacts): normalize source loss during root hashing
* fix(artifacts): bind iNES extraction admission to inventory
* test(artifacts): clarify non-executing inspection wording
* fix: preserve binary plist detection with extended magic probe
* test(browser): wait for popup document loads before capture
* fix(artifacts): honor cancellation across source validation
* fix(artifacts): prefer artifact magic over implicit database suffix
* fix(artifacts): select extraction readers from scanned format
* fix(artifacts): complete prefix reads and share ZIP format admission
* fix(browser): budget scenario cleanup for content drain and shutdown
* test(artifacts): admit valid universal inputs before routing
* test(artifacts): verify iNES workflows on macOS
* test(ci): own iNES macOS coverage and portable fixture paths
* fix: preserve cleanup retries and avoid duplicate inventory parsing
* fix(contracts): share ZIP target formats across MCP lifecycle schemas
* fix(target): preserve typed cancellation during descriptor admission
* refactor(artifacts): use JSON-safe inventory producer output directly
* test(artifacts): share file read setup and satisfy CI checks
* fix(artifacts): classify changed admission as integrity failure
* ci: run Mach-O summary delivery coverage on macOS
* test(javascript): align parameter provenance with main contract
* test(browser): await discoverable fixture pages before runtime verification
* fix(artifacts): pass target metadata to format detection
* fix(artifacts): bind extraction to opened target
* fix: repair the static-check failures on the default branch (#2895)
* fix: repair the static-check failures on the default branch
The default branch fails its own required `Static checks` job three ways, so
every pull request reports that job as failed regardless of its own change.
- `npm run format:check` reports `src/domain/functionComparison.test.ts` and
`src/ida/IdaOperationRunner.ts`.
- `npm run lint` reports a duplicate `import { join } from "node:path"` in
`tests/boundary/mcp/ghidraInventoryMcp.test.ts` (lines 4 and 17).
- `npm run typecheck` reports `format: "devin"` missing from the client format
union in `src/application/SupportedClients.ts`, and an unchecked index in
`tests/boundary/cli/clientProfileLifecycle.test.ts`, whose pair array is
inferred as `string[][]`.
Apply the pinned formatter, drop the duplicate import, list the `"devin"` format
that its own definition already uses, and mark the pair array `as const`.
Validation: `npm run check:fast` and `npm run format:check` pass.
* fix(setup): keep Devin on the JSON configuration dialect
---------
Co-authored-by: 吴佳浩 <wujiahao@supremind.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
(cherry picked from commit df3d96da80)
* fix(artifacts): bind session inventories to target identity
* test(browser): bound fixture readiness acknowledgements
---------
Co-authored-by: 64579525 <17373302683@163.com>
Co-authored-by: 吴佳浩Alben <35291372+XiaoBinGan@users.noreply.github.com>
Co-authored-by: 吴佳浩 <wujiahao@supremind.com>
232 lines
6.4 KiB
TypeScript
232 lines
6.4 KiB
TypeScript
import { ChildProcess } from "node:child_process";
|
|
import { createServer } from "node:http";
|
|
import { setImmediate } from "node:timers/promises";
|
|
import { afterEach, expect, it, vi } from "vitest";
|
|
import { z } from "zod";
|
|
import { awaitAcknowledgement } from "../../fixtures/lifecycleAcknowledgement.js";
|
|
|
|
const mock = vi.hoisted(() => ({ spawn: vi.fn(), port: vi.fn() }));
|
|
vi.mock("../../../dist/process/ProviderProcess.js", () => ({
|
|
spawnOwnedProviderProcess: mock.spawn,
|
|
ProviderProcessSupervisor: class {
|
|
constructor(
|
|
readonly launch: {
|
|
process: ChildProcess;
|
|
cleanup: () => Promise<unknown>;
|
|
},
|
|
) {}
|
|
snapshot() {
|
|
return { stderr: { text: "" } };
|
|
}
|
|
async stop() {
|
|
await this.launch.cleanup();
|
|
return { status: "complete" };
|
|
}
|
|
},
|
|
}));
|
|
vi.mock("../../../dist/process/ProcessOwnershipObservation.js", () => ({
|
|
createSystemProcessOwnershipHost: () => ({ listProcesses: async () => [] }),
|
|
}));
|
|
vi.mock("../../../scripts/lib/verifier-source-loader.mjs", () => ({
|
|
importVerifierSource: async () => ({
|
|
BROWSER_DEVTOOLS_STARTUP_TIMEOUT_MS: 60_000,
|
|
waitForBrowserDevtoolsPort: mock.port,
|
|
}),
|
|
}));
|
|
afterEach(() => vi.restoreAllMocks());
|
|
|
|
interface FixtureLease {
|
|
readonly port: number;
|
|
close(): Promise<void>;
|
|
}
|
|
type StartFixture = (
|
|
executable: string,
|
|
origin: string,
|
|
) => Promise<FixtureLease>;
|
|
|
|
const startFixture = async (): Promise<StartFixture> =>
|
|
z
|
|
.object({
|
|
startRuntimeFixtureBrowser: z.custom<StartFixture>(
|
|
(value) => typeof value === "function",
|
|
),
|
|
})
|
|
.parse(
|
|
await import(
|
|
new URL(
|
|
"../../../scripts/lib/browser-runtime-fixture-lifecycle.mjs",
|
|
import.meta.url,
|
|
).href
|
|
),
|
|
).startRuntimeFixtureBrowser;
|
|
|
|
const deferred = () => {
|
|
let resolve!: () => void;
|
|
const promise = new Promise<void>((complete) => {
|
|
resolve = complete;
|
|
});
|
|
return { promise, resolve };
|
|
};
|
|
|
|
const fixture = async (
|
|
mode: "empty targets" | "discovery timeout" | "malformed" | "exited",
|
|
) => {
|
|
let ready = false;
|
|
let requests = 0;
|
|
const listed = deferred();
|
|
const published = deferred();
|
|
const server = createServer((request, response) => {
|
|
requests += 1;
|
|
if (mode === "exited") {
|
|
listed.resolve();
|
|
return;
|
|
}
|
|
if (mode === "malformed") {
|
|
response.end("{broken");
|
|
return;
|
|
}
|
|
if (mode === "discovery timeout" && requests === 1) {
|
|
response.once("close", () => {
|
|
ready = true;
|
|
});
|
|
return;
|
|
}
|
|
response.end(
|
|
JSON.stringify(
|
|
request.url === "/json/version"
|
|
? {
|
|
Browser: "FixtureChrome/1",
|
|
"Protocol-Version": "1.3",
|
|
"User-Agent": "FixtureChrome",
|
|
"V8-Version": "1",
|
|
"WebKit-Version": "1",
|
|
webSocketDebuggerUrl: `ws://127.0.0.1:${port}/devtools/browser/fixture`,
|
|
}
|
|
: ready
|
|
? [{ id: "fixture", type: "page", title: "fixture", url: origin }]
|
|
: [],
|
|
),
|
|
);
|
|
if (request.url === "/json/list") listed.resolve();
|
|
});
|
|
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
const address = server.address();
|
|
if (address === null || typeof address === "string")
|
|
throw new Error("Missing fixture address");
|
|
const port = address.port;
|
|
const origin = `http://127.0.0.1:${port}`;
|
|
const child = new ChildProcess();
|
|
let signalCode: NodeJS.Signals | null = null;
|
|
Object.defineProperty(child, "signalCode", { get: () => signalCode });
|
|
vi.spyOn(child, "kill").mockImplementation(() => {
|
|
signalCode = "SIGTERM";
|
|
child.emit("exit", null, "SIGTERM");
|
|
return true;
|
|
});
|
|
const cleanup = vi.fn(async () => ({ cleaned: true }));
|
|
mock.spawn.mockResolvedValue({
|
|
process: child,
|
|
ownership: { processGroupId: 7 },
|
|
cleanup,
|
|
});
|
|
mock.port.mockImplementation(async () => {
|
|
published.resolve();
|
|
return port;
|
|
});
|
|
return {
|
|
origin,
|
|
listed: listed.promise,
|
|
published: published.promise,
|
|
cleanup,
|
|
exit: () => child.kill("SIGTERM"),
|
|
makeReady: () => {
|
|
ready = true;
|
|
},
|
|
requests: () => requests,
|
|
close: async () => {
|
|
server.closeAllConnections();
|
|
await new Promise<void>((resolve) => server.close(() => resolve()));
|
|
},
|
|
};
|
|
};
|
|
|
|
it.each(["empty targets", "discovery timeout"] as const)(
|
|
"does not hand out the owned fixture while CDP has %s",
|
|
async (mode) => {
|
|
const start = await startFixture();
|
|
const server = await fixture(mode);
|
|
const pending = start(process.execPath, server.origin);
|
|
let settled = false;
|
|
void pending.then(
|
|
() => {
|
|
settled = true;
|
|
},
|
|
() => {
|
|
settled = true;
|
|
},
|
|
);
|
|
try {
|
|
await awaitAcknowledgement(
|
|
server.published,
|
|
pending,
|
|
"fixture port publication",
|
|
);
|
|
await setImmediate();
|
|
expect(settled).toBe(false);
|
|
if (mode === "empty targets") {
|
|
await awaitAcknowledgement(
|
|
server.listed,
|
|
pending,
|
|
"fixture target listing",
|
|
);
|
|
expect(settled).toBe(false);
|
|
server.makeReady();
|
|
}
|
|
await pending;
|
|
expect(server.requests()).toBeGreaterThanOrEqual(3);
|
|
} finally {
|
|
server.makeReady();
|
|
await (await pending.catch(() => undefined))?.close();
|
|
await server.close();
|
|
}
|
|
},
|
|
);
|
|
|
|
it("preserves malformed discovery and closes the owned fixture", async () => {
|
|
const start = await startFixture();
|
|
const server = await fixture("malformed");
|
|
const pending = start(process.execPath, server.origin);
|
|
try {
|
|
await expect(pending).rejects.toMatchObject({
|
|
reason: "invalid_endpoint_response",
|
|
});
|
|
expect(server.requests()).toBe(1);
|
|
expect(server.cleanup).toHaveBeenCalledTimes(1);
|
|
} finally {
|
|
await (await pending.catch(() => undefined))?.close();
|
|
await server.close();
|
|
}
|
|
});
|
|
|
|
it("interrupts pending discovery when the owned fixture exits", async () => {
|
|
const start = await startFixture();
|
|
const server = await fixture("exited");
|
|
const pending = start(process.execPath, server.origin);
|
|
const rejected = expect(pending).rejects.toThrow(
|
|
"exited before CDP discovery",
|
|
);
|
|
try {
|
|
await awaitAcknowledgement(
|
|
server.listed,
|
|
pending,
|
|
"fixture target listing",
|
|
);
|
|
server.exit();
|
|
await rejected;
|
|
expect(server.cleanup).toHaveBeenCalledTimes(1);
|
|
} finally {
|
|
await (await pending.catch(() => undefined))?.close();
|
|
await server.close();
|
|
}
|
|
});
|