修复+重构: 全库走查真bug+架构+P1/P2 后端 crate

- df-nodes: schema required 对齐 + docker POSIX 注入防御 + HumanNode timeout 1800 + parse_review_json(verdict规范/score clamp/正则兜底)
- df-mcp: update 实体校验(防跨实体 B-260801-01)
- df-storage: keyring 迁移失败达阈值清除明文
- df-ai: router estimated_context+tier tiebreak+DataReadOnly 兜底 + sanitize step4 显式不制造 orphan
- df-ideas: adversarial tier:None 对齐
This commit is contained in:
lxy
2026-08-02 10:44:09 +08:00
parent f1773dde4f
commit ea309c607b
11 changed files with 1512 additions and 96 deletions
+37 -1
View File
@@ -124,7 +124,12 @@ impl Node for AiNode {
"base_url": { "type": "string", "description": "(已废弃过渡)明文 API 地址,改用 provider_id" },
"api_key": { "type": "string", "description": "(已废弃过渡)明文 API 密钥,改用 provider_id;密钥经 secret 解析" }
},
// SW-260618-15: prompt/provider_id 均"留空走兜底"(prompt 取上游、provider_id 走默认 provider),与 required 矛盾。改 required=[] 对齐 execute 运行时,防前端按 schema 误拒合法配置。
// SW-260802-01: schema 与 handler 行为对齐 — config 层 required=[] 正确,但 prompt 运行时必填。
// prompt: execute → parse_params(ai_node_helpers.rs:189-200) 取 inputs["prompt"] > config.prompt,
// 两者皆无则 Err("缺少必填参数: prompt")。即 prompt 真必填,但可由上游节点注入,
// JSON Schema 只校验 config 属性无法表达"二选一",故 required 留空 + description 标注兜底来源,
// handler 兜底校验保证语义;前端不得按 required=[] 误以为 prompt 完全可省。
// provider_id: 空 → resolve_provider 路径 3 走默认 provider,非必填。
"required": []
}),
output: serde_json::json!({
@@ -420,4 +425,35 @@ mod tests {
// 自审闭环相关单测(parse_review_json / truncate_for_summary / gate_should_block /
// build_review_prompt / update_field_writes_output_json)已随 AiSelfReviewNode 迁移至
// ai_self_review_node.rs(与被测代码同位,纯搬运)。
// ============================================================
// SW-260802-01: schema required 与 handler 行为对齐测试
// ============================================================
//
// 真实 bug(误判修正):原注释称"prompt/provider_id 均留空走兜底",实则 prompt 运行时必填 ——
// parse_params(:189-200) 取 inputs["prompt"] > config.prompt,两者皆无则 Err("缺少必填参数: prompt")。
// 但 prompt 可由上游节点 inputs 注入(非 config 独占),JSON Schema required 只校验 config 属性
// 无法表达"二选一",故 config 层 required=[] 正确,handler 兜底校验补足语义。
//
// 已有 missing_prompt_errors 测试覆盖 handler 兜底(缺 prompt 报错),此处补 schema 这层契约:
// config 层 required 应为 [](prompt 来源可上游、provider_id 走默认),防前端按 schema 误判 +
// 防后续误把 prompt 塞进 required 拒掉合法的"上游注入 prompt"配置。
/// AiNode schema.required 应为 [](prompt 可来自上游 inputs、provider_id 走默认 provider)。
#[tokio::test]
async fn schema_required_empty_matches_handler() {
let db = Database::open_in_memory().await.expect("open_in_memory");
let node = AiNode::new(Arc::new(db));
let schema = node.schema();
let params = schema.params.as_object().expect("schema.params 应是 object");
let required = params
.get("required")
.and_then(|v| v.as_array())
.expect("schema 应有 required 数组");
assert!(
required.is_empty(),
"AiNode required 应为 [](prompt 可上游注入、provider_id 走默认),实际: {:?}",
required
);
}
}