write_file 入参形状校验收进 write_file_input,MCP 预检不再漏掉未知字段

- 其它 *_input 解析器都先调 ToolArgumentsRejection::check,只有 write_file_input 没有;工具桥路径靠 bridge_write_file_with_permit 里另一次 check 兜住,但独立客户端 MCP 预检 validate_write_file_arguments 只调 write_file_input,带未知字段的入参能通过预检、要等回客户端桥才被拒
- 在 write_file_input 开头补上同一份 check(path/content 白名单),两个入口共用一条规则;写文件门禁里的那次 check 保留,保证「先查形状、再过权限」的现有顺序不变
- 测试补一条:{"path":"game/index.html","content":"…","unexpected":1} 必须被 validate_write_file_arguments 拒绝

验证:cargo test --bin genarrative-ai-game-creator-shell -- agent::direct_tool_bridge:: 40 passed;agent::direct_tools_mcp::tests::tool_catalog_preserves_reviewed_resource_contracts 通过
This commit is contained in:
2026-10-01 14:08:52 +08:00
parent c9e4a7e397
commit b2d01ef8c1
2 changed files with 7 additions and 0 deletions
@@ -1718,6 +1718,7 @@ fn bridge_file_content_changed(root: &Path, path: &str, content: &[u8]) -> Optio
pub(in crate::agent) fn write_file_input(
arguments: &Value,
) -> Result<(String, String), WriteFileError> {
ToolArgumentsRejection::check(arguments, &["path", "content"])?;
let raw_path = arguments
.get("path")
.and_then(Value::as_str)
@@ -2849,6 +2849,12 @@ mod tests {
"content": "{}"
}))
.is_err());
assert!(validate_write_file_arguments(&json!({
"path": "game/index.html",
"content": "<html></html>",
"unexpected": 1
}))
.is_err());
assert_eq!(
direct_tool_bridge::prepare_game_art_input(&json!({ "brief": "美术包" }))
.expect("safe default")