fix: cover elevated ask approvals (#1636)
This commit is contained in:
committed by
GitHub
parent
9f8e66359e
commit
a4f6b3528a
@@ -13,6 +13,7 @@ Docs: https://docs.clawd.bot
|
|||||||
### Fixes
|
### Fixes
|
||||||
- Web UI: hide internal `message_id` hints in chat bubbles.
|
- Web UI: hide internal `message_id` hints in chat bubbles.
|
||||||
- Heartbeat: normalize target identifiers for consistent routing.
|
- Heartbeat: normalize target identifiers for consistent routing.
|
||||||
|
- Exec: keep approvals for elevated ask unless full mode. (#1616) Thanks @ivancasco.
|
||||||
- Gateway: reduce log noise for late invokes + remote node probes; debounce skills refresh. (#1607) Thanks @petter-b.
|
- Gateway: reduce log noise for late invokes + remote node probes; debounce skills refresh. (#1607) Thanks @petter-b.
|
||||||
- macOS: default direct-transport `ws://` URLs to port 18789; document `gateway.remote.transport`. (#1603) Thanks @ngutman.
|
- macOS: default direct-transport `ws://` URLs to port 18789; document `gateway.remote.transport`. (#1603) Thanks @ngutman.
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ read_when:
|
|||||||
# Elevated Mode (/elevated directives)
|
# Elevated Mode (/elevated directives)
|
||||||
|
|
||||||
## What it does
|
## What it does
|
||||||
- `/elevated on` is a **shortcut** for `exec.host=gateway` + `exec.security=full` (approvals still apply).
|
- `/elevated on` runs on the gateway host and keeps exec approvals (same as `/elevated ask`).
|
||||||
- `/elevated full` runs on the gateway host **and** auto-approves exec (skips exec approvals).
|
- `/elevated full` runs on the gateway host **and** auto-approves exec (skips exec approvals).
|
||||||
- `/elevated ask` runs on the gateway host but keeps exec approvals (same as `/elevated on`).
|
- `/elevated ask` runs on the gateway host but keeps exec approvals (same as `/elevated on`).
|
||||||
|
- `on`/`ask` do **not** force `exec.security=full`; configured security/ask policy still applies.
|
||||||
- Only changes behavior when the agent is **sandboxed** (otherwise exec already runs on the host).
|
- Only changes behavior when the agent is **sandboxed** (otherwise exec already runs on the host).
|
||||||
- Directive forms: `/elevated on|off|ask|full`, `/elev on|off|ask|full`.
|
- Directive forms: `/elevated on|off|ask|full`, `/elev on|off|ask|full`.
|
||||||
- Only `on|off|ask|full` are accepted; anything else returns a hint and does not change state.
|
- Only `on|off|ask|full` are accepted; anything else returns a hint and does not change state.
|
||||||
@@ -18,8 +19,8 @@ read_when:
|
|||||||
- **Per-session state**: `/elevated on|off|ask|full` sets the elevated level for the current session key.
|
- **Per-session state**: `/elevated on|off|ask|full` sets the elevated level for the current session key.
|
||||||
- **Inline directive**: `/elevated on|ask|full` inside a message applies to that message only.
|
- **Inline directive**: `/elevated on|ask|full` inside a message applies to that message only.
|
||||||
- **Groups**: In group chats, elevated directives are only honored when the agent is mentioned. Command-only messages that bypass mention requirements are treated as mentioned.
|
- **Groups**: In group chats, elevated directives are only honored when the agent is mentioned. Command-only messages that bypass mention requirements are treated as mentioned.
|
||||||
- **Host execution**: elevated forces `exec` onto the gateway host with full security.
|
- **Host execution**: elevated forces `exec` onto the gateway host; `full` also sets `security=full`.
|
||||||
- **Approvals**: `full` skips exec approvals; `on`/`ask` still honor them.
|
- **Approvals**: `full` skips exec approvals; `on`/`ask` honor them when allowlist/ask rules require.
|
||||||
- **Unsandboxed agents**: no-op for location; only affects gating, logging, and status.
|
- **Unsandboxed agents**: no-op for location; only affects gating, logging, and status.
|
||||||
- **Tool policy still applies**: if `exec` is denied by tool policy, elevated cannot be used.
|
- **Tool policy still applies**: if `exec` is denied by tool policy, elevated cannot be used.
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ Background sessions are scoped per agent; `process` only sees sessions from the
|
|||||||
- `security` (`deny | allowlist | full`): enforcement mode for `gateway`/`node`
|
- `security` (`deny | allowlist | full`): enforcement mode for `gateway`/`node`
|
||||||
- `ask` (`off | on-miss | always`): approval prompts for `gateway`/`node`
|
- `ask` (`off | on-miss | always`): approval prompts for `gateway`/`node`
|
||||||
- `node` (string): node id/name for `host=node`
|
- `node` (string): node id/name for `host=node`
|
||||||
- `elevated` (bool): alias for `host=gateway` + `security=full` when sandboxed and allowed
|
- `elevated` (bool): request elevated mode (gateway host); `security=full` is only forced when elevated resolves to `full`
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
- `host` defaults to `sandbox`.
|
- `host` defaults to `sandbox`.
|
||||||
|
|||||||
@@ -150,4 +150,35 @@ describe("exec approvals", () => {
|
|||||||
expect(result.details.status).toBe("completed");
|
expect(result.details.status).toBe("completed");
|
||||||
expect(calls).not.toContain("exec.approval.request");
|
expect(calls).not.toContain("exec.approval.request");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("requires approval for elevated ask when allowlist misses", async () => {
|
||||||
|
const { callGatewayTool } = await import("./tools/gateway.js");
|
||||||
|
const calls: string[] = [];
|
||||||
|
let resolveApproval: (() => void) | undefined;
|
||||||
|
const approvalSeen = new Promise<void>((resolve) => {
|
||||||
|
resolveApproval = resolve;
|
||||||
|
});
|
||||||
|
|
||||||
|
vi.mocked(callGatewayTool).mockImplementation(async (method) => {
|
||||||
|
calls.push(method);
|
||||||
|
if (method === "exec.approval.request") {
|
||||||
|
resolveApproval?.();
|
||||||
|
return { decision: "deny" };
|
||||||
|
}
|
||||||
|
return { ok: true };
|
||||||
|
});
|
||||||
|
|
||||||
|
const { createExecTool } = await import("./bash-tools.exec.js");
|
||||||
|
const tool = createExecTool({
|
||||||
|
ask: "on-miss",
|
||||||
|
security: "allowlist",
|
||||||
|
approvalRunningNoticeMs: 0,
|
||||||
|
elevated: { enabled: true, allowed: true, defaultLevel: "ask" },
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await tool.execute("call4", { command: "echo ok", elevated: true });
|
||||||
|
expect(result.details.status).toBe("approval-pending");
|
||||||
|
await approvalSeen;
|
||||||
|
expect(calls).toContain("exec.approval.request");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user