mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 03:51:25 +00:00
fix(gateway): fail fast exec approvals when no approvers are reachable
Co-authored-by: fanxian831-netizen <262880470+fanxian831-netizen@users.noreply.github.com>
This commit is contained in:
@@ -63,7 +63,7 @@ describe("exec approval forwarder", () => {
|
||||
resolveSessionTarget: () => ({ channel: "slack", to: "U1" }),
|
||||
});
|
||||
|
||||
await forwarder.handleRequested(baseRequest);
|
||||
await expect(forwarder.handleRequested(baseRequest)).resolves.toBe(true);
|
||||
expect(deliver).toHaveBeenCalledTimes(1);
|
||||
|
||||
await forwarder.handleResolved({
|
||||
@@ -82,7 +82,7 @@ describe("exec approval forwarder", () => {
|
||||
vi.useFakeTimers();
|
||||
const { deliver, forwarder } = createForwarder({ cfg: TARGETS_CFG });
|
||||
|
||||
await forwarder.handleRequested(baseRequest);
|
||||
await expect(forwarder.handleRequested(baseRequest)).resolves.toBe(true);
|
||||
expect(deliver).toHaveBeenCalledTimes(1);
|
||||
|
||||
await vi.runAllTimersAsync();
|
||||
@@ -93,7 +93,7 @@ describe("exec approval forwarder", () => {
|
||||
vi.useFakeTimers();
|
||||
const { deliver, forwarder } = createForwarder({ cfg: TARGETS_CFG });
|
||||
|
||||
await forwarder.handleRequested(baseRequest);
|
||||
await expect(forwarder.handleRequested(baseRequest)).resolves.toBe(true);
|
||||
|
||||
expect(getFirstDeliveryText(deliver)).toContain("Command: `echo hello`");
|
||||
});
|
||||
@@ -102,17 +102,50 @@ describe("exec approval forwarder", () => {
|
||||
vi.useFakeTimers();
|
||||
const { deliver, forwarder } = createForwarder({ cfg: TARGETS_CFG });
|
||||
|
||||
await forwarder.handleRequested({
|
||||
...baseRequest,
|
||||
request: {
|
||||
...baseRequest.request,
|
||||
command: "echo `uname`\necho done",
|
||||
},
|
||||
});
|
||||
await expect(
|
||||
forwarder.handleRequested({
|
||||
...baseRequest,
|
||||
request: {
|
||||
...baseRequest.request,
|
||||
command: "echo `uname`\necho done",
|
||||
},
|
||||
}),
|
||||
).resolves.toBe(true);
|
||||
|
||||
expect(getFirstDeliveryText(deliver)).toContain("Command:\n```\necho `uname`\necho done\n```");
|
||||
});
|
||||
|
||||
it("returns false when forwarding is disabled", async () => {
|
||||
const { deliver, forwarder } = createForwarder({
|
||||
cfg: {} as OpenClawConfig,
|
||||
});
|
||||
await expect(forwarder.handleRequested(baseRequest)).resolves.toBe(false);
|
||||
expect(deliver).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("returns false when all targets are skipped", async () => {
|
||||
vi.useFakeTimers();
|
||||
const cfg = {
|
||||
channels: {
|
||||
discord: {
|
||||
execApprovals: {
|
||||
enabled: true,
|
||||
approvers: ["123"],
|
||||
},
|
||||
},
|
||||
},
|
||||
approvals: { exec: { enabled: true, mode: "session" } },
|
||||
} as OpenClawConfig;
|
||||
|
||||
const { deliver, forwarder } = createForwarder({
|
||||
cfg,
|
||||
resolveSessionTarget: () => ({ channel: "discord", to: "channel:123" }),
|
||||
});
|
||||
|
||||
await expect(forwarder.handleRequested(baseRequest)).resolves.toBe(false);
|
||||
expect(deliver).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("forwards to discord when discord exec approvals handler is disabled", async () => {
|
||||
vi.useFakeTimers();
|
||||
const cfg = {
|
||||
@@ -124,7 +157,7 @@ describe("exec approval forwarder", () => {
|
||||
resolveSessionTarget: () => ({ channel: "discord", to: "channel:123" }),
|
||||
});
|
||||
|
||||
await forwarder.handleRequested(baseRequest);
|
||||
await expect(forwarder.handleRequested(baseRequest)).resolves.toBe(true);
|
||||
|
||||
expect(deliver).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
@@ -148,7 +181,7 @@ describe("exec approval forwarder", () => {
|
||||
resolveSessionTarget: () => ({ channel: "discord", to: "channel:123" }),
|
||||
});
|
||||
|
||||
await forwarder.handleRequested(baseRequest);
|
||||
await expect(forwarder.handleRequested(baseRequest)).resolves.toBe(false);
|
||||
|
||||
expect(deliver).not.toHaveBeenCalled();
|
||||
});
|
||||
@@ -185,13 +218,15 @@ describe("exec approval forwarder", () => {
|
||||
vi.useFakeTimers();
|
||||
const { deliver, forwarder } = createForwarder({ cfg: TARGETS_CFG });
|
||||
|
||||
await forwarder.handleRequested({
|
||||
...baseRequest,
|
||||
request: {
|
||||
...baseRequest.request,
|
||||
command: "echo ```danger```",
|
||||
},
|
||||
});
|
||||
await expect(
|
||||
forwarder.handleRequested({
|
||||
...baseRequest,
|
||||
request: {
|
||||
...baseRequest.request,
|
||||
command: "echo ```danger```",
|
||||
},
|
||||
}),
|
||||
).resolves.toBe(true);
|
||||
|
||||
expect(getFirstDeliveryText(deliver)).toContain("Command:\n````\necho ```danger```\n````");
|
||||
});
|
||||
|
||||
@@ -29,7 +29,7 @@ type PendingApproval = {
|
||||
};
|
||||
|
||||
export type ExecApprovalForwarder = {
|
||||
handleRequested: (request: ExecApprovalRequest) => Promise<void>;
|
||||
handleRequested: (request: ExecApprovalRequest) => Promise<boolean>;
|
||||
handleResolved: (resolved: ExecApprovalResolved) => Promise<void>;
|
||||
stop: () => void;
|
||||
};
|
||||
@@ -318,11 +318,11 @@ export function createExecApprovalForwarder(
|
||||
const resolveSessionTarget = deps.resolveSessionTarget ?? defaultResolveSessionTarget;
|
||||
const pending = new Map<string, PendingApproval>();
|
||||
|
||||
const handleRequested = async (request: ExecApprovalRequest) => {
|
||||
const handleRequested = async (request: ExecApprovalRequest): Promise<boolean> => {
|
||||
const cfg = getConfig();
|
||||
const config = cfg.approvals?.exec;
|
||||
if (!shouldForward({ config, request })) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
const filteredTargets = resolveForwardTargets({
|
||||
cfg,
|
||||
@@ -332,7 +332,7 @@ export function createExecApprovalForwarder(
|
||||
}).filter((target) => !shouldSkipDiscordForwarding(target, cfg));
|
||||
|
||||
if (filteredTargets.length === 0) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
const expiresInMs = Math.max(0, request.expiresAtMs - nowMs());
|
||||
@@ -353,17 +353,20 @@ export function createExecApprovalForwarder(
|
||||
pending.set(request.id, pendingEntry);
|
||||
|
||||
if (pending.get(request.id) !== pendingEntry) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
const text = buildRequestMessage(request, nowMs());
|
||||
await deliverToTargets({
|
||||
void deliverToTargets({
|
||||
cfg,
|
||||
targets: filteredTargets,
|
||||
text,
|
||||
deliver,
|
||||
shouldSend: () => pending.get(request.id) === pendingEntry,
|
||||
}).catch((err) => {
|
||||
log.error(`exec approvals: failed to deliver request ${request.id}: ${String(err)}`);
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleResolved = async (resolved: ExecApprovalResolved) => {
|
||||
|
||||
Reference in New Issue
Block a user