Archived
Agent consent: the pause contract + false-receipt kill (2 fixes, stricter only) #79
@@ -1680,8 +1680,16 @@ fn dispatch_tool(tool_name: String, tool_input: String) -> String {
|
|||||||
if !path_within_root(path, root) {
|
if !path_within_root(path, root) {
|
||||||
return json_safe("denied: path is outside the agent workspace root")
|
return json_safe("denied: path is outside the agent workspace root")
|
||||||
}
|
}
|
||||||
fs_write(resolve_in_root(path, root), content)
|
// BUG-6 fix (2026-07-17): never claim ok without disk truth. fs_write's result was
|
||||||
return json_safe("{\"ok\":true}")
|
// never checked, so a failed write reported ok — the exact false-receipt failure
|
||||||
|
// the run guards exist to kill. Verify the file landed and return the RESOLVED
|
||||||
|
// path so callers and the model can only narrate what is really on disk.
|
||||||
|
let dest: String = resolve_in_root(path, root)
|
||||||
|
fs_write(dest, content)
|
||||||
|
if !fs_exists(dest) {
|
||||||
|
return json_safe("{\"error\":\"write failed - nothing landed at " + dest + "\"}")
|
||||||
|
}
|
||||||
|
return json_safe("{\"ok\":true,\"path\":\"" + dest + "\"}")
|
||||||
}
|
}
|
||||||
if str_eq(tool_name, "web_get") {
|
if str_eq(tool_name, "web_get") {
|
||||||
let url: String = json_get(tool_input, "url")
|
let url: String = json_get(tool_input, "url")
|
||||||
|
|||||||
+7
-1
@@ -713,7 +713,13 @@ fn handle_session_approve(session_id: String, body: String) -> String {
|
|||||||
// For builtin tools with no client-provided content: fall back to
|
// For builtin tools with no client-provided content: fall back to
|
||||||
// dispatch_tool so those tools still execute correctly.
|
// dispatch_tool so those tools still execute correctly.
|
||||||
let client_content: String = json_get(body, "content")
|
let client_content: String = json_get(body, "content")
|
||||||
let use_client_content: Bool = !str_eq(client_content, "")
|
// BUG-6 fix (2026-07-17): the naive json_get scanner matches "content" ANYWHERE
|
||||||
|
// in the body — including INSIDE tool_input — so every approved write_file (whose
|
||||||
|
// input always carries a content field) was mistaken for client-executed, never
|
||||||
|
// dispatched, and narrated as done: a false receipt with no file on disk. Builtin
|
||||||
|
// tools now ALWAYS dispatch server-side; client content is only honored for
|
||||||
|
// non-builtin (MCP/client-executed) tools. Stricter only.
|
||||||
|
let use_client_content: Bool = !str_eq(client_content, "") && !is_builtin_tool(approve_tool_name)
|
||||||
let use_dispatch: Bool = is_builtin_tool(approve_tool_name) && !use_client_content
|
let use_dispatch: Bool = is_builtin_tool(approve_tool_name) && !use_client_content
|
||||||
let raw_input: String = json_get_raw(body, "tool_input")
|
let raw_input: String = json_get_raw(body, "tool_input")
|
||||||
let eff_input: String = if str_eq(raw_input, "") { "{}" } else { raw_input }
|
let eff_input: String = if str_eq(raw_input, "") { "{}" } else { raw_input }
|
||||||
|
|||||||
Reference in New Issue
Block a user