fix(gateway): bind node exec approvals to nodeId

This commit is contained in:
Peter Steinberger
2026-02-24 03:05:36 +00:00
parent 9530c01085
commit 4a3f8438e5
18 changed files with 231 additions and 5 deletions

View File

@@ -44,6 +44,7 @@ export function createExecApprovalHandlers(
id?: string;
command: string;
cwd?: string;
nodeId?: string;
host?: string;
security?: string;
ask?: string;
@@ -57,6 +58,16 @@ export function createExecApprovalHandlers(
const timeoutMs =
typeof p.timeoutMs === "number" ? p.timeoutMs : DEFAULT_EXEC_APPROVAL_TIMEOUT_MS;
const explicitId = typeof p.id === "string" && p.id.trim().length > 0 ? p.id.trim() : null;
const host = typeof p.host === "string" ? p.host.trim() : "";
const nodeId = typeof p.nodeId === "string" ? p.nodeId.trim() : "";
if (host === "node" && !nodeId) {
respond(
false,
undefined,
errorShape(ErrorCodes.INVALID_REQUEST, "nodeId is required for host=node"),
);
return;
}
if (explicitId && manager.getSnapshot(explicitId)) {
respond(
false,
@@ -68,7 +79,8 @@ export function createExecApprovalHandlers(
const request = {
command: p.command,
cwd: p.cwd ?? null,
host: p.host ?? null,
nodeId: host === "node" ? nodeId : null,
host: host || null,
security: p.security ?? null,
ask: p.ask ?? null,
agentId: p.agentId ?? null,

View File

@@ -698,6 +698,7 @@ export const nodeHandlers: GatewayRequestHandlers = {
return;
}
const forwardedParams = sanitizeNodeInvokeParamsForForwarding({
nodeId,
command,
rawParams: p.params,
client,

View File

@@ -248,6 +248,7 @@ describe("exec approval handlers", () => {
const defaultExecApprovalRequestParams = {
command: "echo ok",
cwd: "/tmp",
nodeId: "node-1",
host: "node",
timeoutMs: 2000,
} as const;
@@ -323,6 +324,7 @@ describe("exec approval handlers", () => {
const params = {
command: "echo hi",
cwd: "/tmp",
nodeId: "node-1",
host: "node",
};
expect(validateExecApprovalRequestParams(params)).toBe(true);
@@ -332,6 +334,7 @@ describe("exec approval handlers", () => {
const params = {
command: "echo hi",
cwd: "/tmp",
nodeId: "node-1",
host: "node",
resolvedPath: "/usr/bin/echo",
};
@@ -342,6 +345,7 @@ describe("exec approval handlers", () => {
const params = {
command: "echo hi",
cwd: "/tmp",
nodeId: "node-1",
host: "node",
resolvedPath: undefined,
};
@@ -352,6 +356,7 @@ describe("exec approval handlers", () => {
const params = {
command: "echo hi",
cwd: "/tmp",
nodeId: "node-1",
host: "node",
resolvedPath: null,
};
@@ -359,6 +364,25 @@ describe("exec approval handlers", () => {
});
});
it("rejects host=node approval requests without nodeId", async () => {
const { handlers, respond, context } = createExecApprovalFixture();
await requestExecApproval({
handlers,
respond,
context,
params: {
nodeId: undefined,
},
});
expect(respond).toHaveBeenCalledWith(
false,
undefined,
expect.objectContaining({
message: "nodeId is required for host=node",
}),
);
});
it("broadcasts request + resolve", async () => {
const { handlers, broadcasts, respond, context } = createExecApprovalFixture();