refactor(ipc): validate write payloads in preload

This commit is contained in:
ZacharyZhang-NY committed 2026-04-24 01:31:29 -04:00
1 parent 3609456ca5
commit 227fd7faf2
9 files changed
+302 -35

No files matched your search

+114
View File
@@ -4,10 +4,82 @@ import { describe, expect, it } from "vitest";
import {
IPC_CHANNELS,
PRELOAD_FORWARDERS,
PRELOAD_INPUT_SCHEMAS,
mapPreloadInvokeArgs,
type PreloadPayloadSpec,
} from "../../src/shared/contracts";
const validatedInputMethods = [
"addComment",
"assignSkillToAgent",
"bootstrapOnboarding",
"cancelBrowserAction",
"cancelOAuth",
"cancelRun",
"checkSkillUpdate",
"decideApproval",
"deleteAgent",
"deleteApproval",
"deleteAutomationRule",
"deleteBudgetPolicy",
"deleteCompany",
"deleteDocument",
"deleteGoal",
"deleteKnowledgeEntry",
"deleteMeeting",
"deleteProject",
"deleteSecret",
"deleteSkill",
"deleteSocialAccount",
"deleteSprint",
"deleteTask",
"deleteWorkflow",
"deleteWorkspace",
"importSkill",
"markMessageRead",
"openPath",
"openTerminalCommand",
"openWorkProduct",
"recoveryFail",
"recoveryRetry",
"removeCredential",
"removeSkillFromAgent",
"requestApproval",
"requestHire",
"resolveBudgetIncident",
"runWorkflow",
"saveAgent",
"saveAutomationRule",
"saveBudgetPolicy",
"saveCompany",
"saveConnector",
"saveCredential",
"saveDocument",
"saveGoal",
"saveKnowledgeEntry",
"saveMeeting",
"saveProject",
"saveSocialAccount",
"saveSprint",
"saveTask",
"saveWorkflow",
"saveWorkspace",
"sendAgentMessage",
"setConnectorDisabledModels",
"setCurrentCompany",
"setHeartbeat",
"startOAuth",
"startTaskRun",
"submitOAuthManualCode",
"submitOAuthPrompt",
"testConnector",
"testCredential",
"toggleAutomationRule",
"triggerBrowserLogin",
"triggerHeartbeat",
"updateSettings",
] as const;
describe("preload forwarders", () => {
it("keeps API methods and IPC channels unique", () => {
const apiNames = new Set<string>();
@@ -47,6 +119,48 @@ describe("preload forwarders", () => {
);
});
it("validates write and action payloads before invoking main", () => {
const startRun = PRELOAD_FORWARDERS.find((forwarder) => forwarder.api === "startTaskRun");
const importSkill = PRELOAD_FORWARDERS.find((forwarder) => forwarder.api === "importSkill");
expect(startRun).toBeDefined();
expect(importSkill).toBeDefined();
expect(() =>
mapPreloadInvokeArgs(startRun!.payload, [{ companyId: "bad", taskId: "bad" }], PRELOAD_INPUT_SCHEMAS.startTaskRun)
).toThrow();
expect(() =>
mapPreloadInvokeArgs(importSkill!.payload, ["company-1", ""], PRELOAD_INPUT_SCHEMAS.importSkill)
).toThrow();
});
it("keeps every preload input schema attached to a registered forwarder", () => {
const apiNames = new Set<string>(PRELOAD_FORWARDERS.map((forwarder) => forwarder.api));
for (const method of Object.keys(PRELOAD_INPUT_SCHEMAS)) {
expect(apiNames.has(method)).toBe(true);
}
});
it("keeps write and action preload inputs behind schemas", () => {
expect(Object.keys(PRELOAD_INPUT_SCHEMAS).sort()).toEqual([...validatedInputMethods].sort());
});
it("samples read-path payload mapping without runtime schemas", () => {
const readPathSamples = [
{ api: "getRunLog", args: [{ companyId: "bad", runId: "bad" }] },
{ api: "listSkills", args: ["bad-company"] },
{ api: "getBudgetStatus", args: ["bad-company"] },
] as const;
for (const sample of readPathSamples) {
const forwarder = PRELOAD_FORWARDERS.find((candidate) => candidate.api === sample.api);
expect(forwarder).toBeDefined();
expect(PRELOAD_INPUT_SCHEMAS[sample.api]).toBeUndefined();
expect(mapPreloadInvokeArgs(forwarder!.payload, sample.args)).toHaveLength(1);
}
});
it("keeps preload invoking through the shared registry", () => {
const preloadSource = readFileSync(join(process.cwd(), "src/preload/index.ts"), "utf8");
const staticChannelAccesses = [...preloadSource.matchAll(/IPC_CHANNELS\.([A-Za-z0-9_]+)/g)]