mirror of https://github.com/openclaw/openclaw.git
fix(exec): honor exec-approvals ask=off for gateway/node runs
Landed from contributor PR #26789 by @pandego. Co-authored-by: Miguel Miranda Dias <7780875+pandego@users.noreply.github.com>
This commit is contained in:
parent
79e3d1f956
commit
173132165d
|
|
@ -312,6 +312,7 @@ Docs: https://docs.openclaw.ai
|
|||
- Agents/strict OpenAI turn ordering: apply assistant-first transcript bootstrap sanitization to strict OpenAI-compatible providers (for example vLLM/Gemma via `openai-completions`) without adding Google-specific session markers, preventing assistant-first history rejections. (#39252) Thanks @scoootscooob.
|
||||
- Discord/exec approvals gateway auth: pass resolved shared gateway credentials into the Discord exec-approvals gateway client so token-auth installs stop failing approvals with `gateway token mismatch`. Related to #38179. Thanks @0riginal-claw for the adjacent PR #35147 investigation.
|
||||
- Subagents/workspace inheritance: propagate parent workspace directory to spawned subagent runs so child sessions reliably inherit workspace-scoped instructions (`AGENTS.md`, `SOUL.md`, etc.) without exposing workspace override through tool-call arguments. (#39247) Thanks @jasonQin6.
|
||||
- Exec approvals/gateway-node policy: honor explicit `ask=off` from `exec-approvals.json` even when runtime defaults are stricter, so trusted full/off setups stop re-prompting on gateway and node exec paths. Landed from contributor PR #26789 by @pandego. Thanks @pandego.
|
||||
|
||||
## 2026.3.2
|
||||
|
||||
|
|
|
|||
|
|
@ -133,7 +133,9 @@ export function resolveExecHostApprovalContext(params: {
|
|||
ask: params.ask,
|
||||
});
|
||||
const hostSecurity = minSecurity(params.security, approvals.agent.security);
|
||||
const hostAsk = maxAsk(params.ask, approvals.agent.ask);
|
||||
// An explicit ask=off policy in exec-approvals.json must be able to suppress
|
||||
// prompts even when tool/runtime defaults are stricter (for example on-miss).
|
||||
const hostAsk = approvals.agent.ask === "off" ? "off" : maxAsk(params.ask, approvals.agent.ask);
|
||||
const askFallback = approvals.agent.askFallback;
|
||||
if (hostSecurity === "deny") {
|
||||
throw new Error(`exec denied: host=${params.host} security=deny`);
|
||||
|
|
|
|||
|
|
@ -187,6 +187,43 @@ describe("exec approvals", () => {
|
|||
expect(calls).not.toContain("exec.approval.request");
|
||||
});
|
||||
|
||||
it("uses exec-approvals ask=off to suppress gateway prompts", async () => {
|
||||
const approvalsPath = path.join(process.env.HOME ?? "", ".openclaw", "exec-approvals.json");
|
||||
await fs.mkdir(path.dirname(approvalsPath), { recursive: true });
|
||||
await fs.writeFile(
|
||||
approvalsPath,
|
||||
JSON.stringify(
|
||||
{
|
||||
version: 1,
|
||||
defaults: { security: "full", ask: "off", askFallback: "full" },
|
||||
agents: {
|
||||
main: { security: "full", ask: "off", askFallback: "full" },
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
|
||||
const calls: string[] = [];
|
||||
vi.mocked(callGatewayTool).mockImplementation(async (method) => {
|
||||
calls.push(method);
|
||||
return { ok: true };
|
||||
});
|
||||
|
||||
const tool = createExecTool({
|
||||
host: "gateway",
|
||||
ask: "on-miss",
|
||||
security: "full",
|
||||
approvalRunningNoticeMs: 0,
|
||||
});
|
||||
|
||||
const result = await tool.execute("call3b", { command: "echo ok" });
|
||||
expect(result.details.status).toBe("completed");
|
||||
expect(calls).not.toContain("exec.approval.request");
|
||||
expect(calls).not.toContain("exec.approval.waitDecision");
|
||||
});
|
||||
|
||||
it("requires approval for elevated ask when allowlist misses", async () => {
|
||||
const calls: string[] = [];
|
||||
let resolveApproval: (() => void) | undefined;
|
||||
|
|
|
|||
Loading…
Reference in New Issue