From 074d1aa5a973e6040259424cbf5c9511b0b6686a Mon Sep 17 00:00:00 2001 From: zhuyongxin Date: Thu, 6 Aug 2026 17:46:53 +0800 Subject: [PATCH] docs(harness): add MySQL sandbox learning note and mark tool domain complete - Add MySQL sandbox note: three defense layers (semantic/connection/output), fail-closed validation, allowlist, parameterization, cancellation, redaction - Mark tool domain complete in roadmap; next: guard --- ...ySQL 沙箱学习笔记-从 SQL 校验到脱敏投影.md | 158 ++++++++++++++++++ .../harness/Harness组件学习路线-进度追踪.md | 19 ++- 2 files changed, 169 insertions(+), 8 deletions(-) create mode 100644 mvp/engineering/harness/Harness MySQL 沙箱学习笔记-从 SQL 校验到脱敏投影.md diff --git a/mvp/engineering/harness/Harness MySQL 沙箱学习笔记-从 SQL 校验到脱敏投影.md b/mvp/engineering/harness/Harness MySQL 沙箱学习笔记-从 SQL 校验到脱敏投影.md new file mode 100644 index 0000000..03969a4 --- /dev/null +++ b/mvp/engineering/harness/Harness MySQL 沙箱学习笔记-从 SQL 校验到脱敏投影.md @@ -0,0 +1,158 @@ +# Harness MySQL 沙箱学习笔记:从 SQL 校验到脱敏投影 + +**更新日期**:2026-08-04 +**主题**:query_mysql 工具完整链路——三层防线(语义/连接/输出) +**配套**:[tool 域代码学习笔记](Harness%20tool%20域代码学习笔记-工具的注册调用与执行链路.md)(注册/调用/执行全链路) + +## 1. 定位:可查询、不可破坏、不可越界、不可拖库 + +query_mysql 让模型查询授权数据库,但封死三种攻击面: + +```text +破坏:写/删/改(非 SELECT)→ 语义层拒绝 +越界:未授权表/列 → 白名单拒绝 +拖库:全表通配(*)/无界读取 → 禁通配符 + 三重有界截断 +``` + +**为什么 MySQL 要安全层而 RAG 不要**:Milvus 天然只读检索无破坏面;MySQL 直接连数据库,SELECT 之外全是风险面——**安全设计随攻击面走**。 + +## 2. 架构总览(三层防线 + 接线员) + +```mermaid +flowchart LR + E["MysqlToolAdapter
接线员"] -->|"parse 请求"| V["第 1 层 语义层
MysqlSqlValidator
AST fail-closed"] + V -->|"MysqlQueryPlan"| X["第 2 层 连接层
JdbcMysqlReadOnlyExecutor
JDBC 只读+超时+取消"] + X -->|"MysqlRawResult
(Harness-only)"| P["第 3 层 输出层
MysqlResultProjector
脱敏+有界"] + P -->|"MysqlToolResult
(冻结契约)"| B["ToolBoundary
统一门禁"] +``` + +**接线员**:Adapter 把 validator/executor/projector 组装进 ToolBoundary;任何安全/参数异常统一映射 INVALID_REQUEST(不泄露内部细节)。 + +## 3. 定义层(6 个小文件) + +| 类 | 作用 | +|---|---| +| `MysqlReadOnlyExecutor` | 函数式接口(执行端口):plan + RunContext → raw 结果 | +| `MysqlQueryPlan` | 执行计划:request + dataSource + normalizedSql + params(params 深拷贝) | +| `MysqlRawResult` | Harness-only raw 结果:columns + rows + truncated(不直接给 Agent) | +| `MysqlSecurityException` | 安全异常:Adapter 映射稳定错误码 | +| `MysqlToolLimits` | 限额:100 行 / 2000 字单元 / 64KB 总字节 / 5 秒超时 | +| `MysqlDataSourceDefinition` | 逻辑数据源 + **schema → table → 列三级白名单**(访问边界) | + +**白名单深拷贝**(TreeSet 保证确定性)+ `defaultSchema 必须出现在白名单里`——配置即边界。 + +## 4. 第 1 层:Validator——语义层(fail-closed) + +### 4.1 禁止清单(JSqlParser 解析 AST,逐节点拒绝) + +```text +非 SELECT / 多条语句 / WITH / 子查询(SubSelect) / 通配符投影(* 和 t.*) +窗口函数(Analytic) / CASE / EXISTS / 分层查询(OracleHierarchical) +锁读(FOR UPDATE / SKIP LOCKED) / OFFSET/FETCH/TOP/SKIP/FIRST/OPTIMIZE FOR +字面量:StringValue/LongValue/DoubleValue/HexValue/DateValue/TimeValue/TimestampValue + —— 全部必须参数化(防注入的最强形态) +``` + +### 4.2 允许清单 + +```text +白名单内表列的 INNER/LEFT JOIN(禁 CROSS/RIGHT/FULL/OUTER) +聚合函数:COUNT/SUM/AVG/MIN/MAX(COUNT(*) 只允许 COUNT) +占位符参数 ?(PreparedStatement 绑定) +``` + +### 4.3 附加校验 + +```text +恰好一条语句 + 必须是 Select + 无 WITH + 普通 PlainSelect(禁集合操作/值语句) +FROM 必须是白名单内实体表(禁子查询来源);重复别名拒绝(不区分大小写) +列校验:限定表 → 查该表列白名单;未限定 → 已注册表恰好一个命中(防歧义/未授权) +占位符数量 == params 数量(防参数错位/少传) +``` + +### 4.4 fail-closed 原则 + +```text +任何解析/校验异常 → 统一转 MysqlSecurityException(默认拒绝,不是默认放行) +业务规则违规原样穿出;解析/未知异常包装统一信息(不泄露内部细节) +→ 安全策略是「拒绝清单外的全允许」的反面:「允许清单外的全拒绝」 +``` + +## 5. 第 2 层:Executor——连接层(双保险) + +```text +connection.setReadOnly(true) ← JDBC 连接层强制只读(语义层之外的物理防线) +PreparedStatement 参数化 ← 占位符绑定(防注入第二道) +setQueryTimeout(5s) ← 慢查询截断 +setMaxRows(maxRows+1) ← 多取一行用于检测截断 +context.cancellation().onCancel → statement.cancel() ← Run 取消联动 +checkRun 每行检查 ← 取消/超时即刻中止(与 core 终态联动) +jsonSafe:byte[] → Base64;字符串截断 maxCellChars +estimatedBytes:字节预算超限移除末行并标记截断 +``` + +**关键**:查询不是独立资源——**受 Run 生命周期管**(取消 → 立即 cancel 语句),与 RAG 检索同理(checkRun 与 Harness core 终态联动)。 + +## 6. 第 3 层:Projector——输出层 + +### 6.1 脱敏(输出时,不是查询时) + +```text +列名含 password/passwd/token/secret/api_key/apikey/credential → [REDACTED] +→ raw 保留真实值,只对 Agent 可见层脱敏(查询照常执行,输出才遮) +``` + +### 6.2 有界(三重截断 + 兜底) + +```text +行数(maxRows) + 单元格字符(maxCellChars) + 总字节(maxResultBytes) +列名必须非空且唯一(防歧义投影) +fitBudget 兜底:逐行裁掉尾部 → 裁空诚实降级 NO_EVIDENCE → 仍超限 fail closed +``` + +### 6.3 客观证据语义 + +```text +rows 空 → NO_EVIDENCE;非空 → EVIDENCE_FOUND +→ 与 RAG 的 evidence_status 同一套契约(证据状态由「有没有内容」客观决定) +``` + +## 7. 与 RAG 对照(同类架构,不同复杂度) + +| | query_mysql | lookup_knowledge | +|---|---|---| +| 安全层 | 有(Validator + 只读连接 + 脱敏) | 无(Milvus 天然只读检索) | +| 后端复杂度 | 简单(Validator→Executor→Projector) | 复杂(三段 + 降级 + 双 trace) | +| raw → 契约 | MysqlRawResult → MysqlToolResult | LookupResult → RagToolResult | +| 数量限制 | maxRows=100 / 64KB | returnN=5 / 8 条 / 16KB | +| 证据语义 | rows 空不空(NO_EVIDENCE/EVIDENCE_FOUND) | evidenceBlocks + relevance_level | +| 与 Harness 衔接 | 同为 Boundary/Projector/Adapter 模式 | 同为 Boundary/Projector/Adapter 模式 | + +## 8. 易错点 + +| 易错 | 正确 | +|---|---| +| Validator 只查 SELECT | 还有白名单表列、禁字面量、禁通配符、占位符计数 | +| 语义层够了 | 连接层 setReadOnly + 参数化是物理防线(纵深防御) | +| 查询独立于 Run | 查询受 Run 取消/超时联动(onCancel → statement.cancel) | +| 脱敏在查询层 | 脱敏在投影层(raw 保留真实值,只对 Agent 脱敏) | +| 有界只限行数 | 行 + 单元格 + 字节三重截断 + fitBudget 兜底 | +| 安全异常抛原样 | 统一映射 INVALID_REQUEST(不泄露内部细节) | +| 字面量可以清洗放行 | 字面量全拒必须参数化(清洗是弱防线,参数化是强防线) | + +## 9. 面试话术(30 秒) + +> "query_mysql 是三层防线的只读沙箱:**语义层**(JSqlParser 解析 AST,fail-closed 拒绝一切不安全形态——非 SELECT、多语句、子查询、通配符、字面量、未授权表列、锁读全部拒绝,只允许白名单表列的 INNER/LEFT JOIN 和聚合 + 参数化占位符,且占位符数量必须与 params 匹配);**连接层**(JDBC setReadOnly + PreparedStatement 参数化 + 超时 + maxRows + 取消联动——Run 取消立即 cancel 语句);**输出层**(敏感列脱敏 [REDACTED] + 行/单元格/字节三重截断 + rows 空不空定证据状态)。安全异常统一映射稳定错误码,不泄露内部细节。" + +## 10. 代码位置索引 + +| 类 | 文件 | +|---|---| +| `MysqlToolAdapter` | `src/main/java/com/superbiz/agent/harness/tool/adapter/MysqlToolAdapter.java` | +| `MysqlSqlValidator` | `src/main/java/com/superbiz/agent/harness/tool/mysql/MysqlSqlValidator.java` | +| `JdbcMysqlReadOnlyExecutor` | `src/main/java/com/superbiz/agent/harness/tool/mysql/JdbcMysqlReadOnlyExecutor.java` | +| `MysqlResultProjector` | `src/main/java/com/superbiz/agent/harness/tool/mysql/MysqlResultProjector.java` | +| `MysqlDataSourceDefinition` | `src/main/java/com/superbiz/agent/harness/tool/mysql/MysqlDataSourceDefinition.java` | +| `MysqlReadOnlyExecutor` | `src/main/java/com/superbiz/agent/harness/tool/mysql/MysqlReadOnlyExecutor.java` | +| `MysqlQueryPlan` / `MysqlRawResult` | `src/main/java/com/superbiz/agent/harness/tool/mysql/MysqlQueryPlan.java` 等 | +| 契约(MysqlToolRequest/Result) | `src/main/java/com/superbiz/agent/harness/tool/contract/MysqlTool*.java` | diff --git a/mvp/engineering/harness/Harness组件学习路线-进度追踪.md b/mvp/engineering/harness/Harness组件学习路线-进度追踪.md index 5db1140..d95cc7d 100644 --- a/mvp/engineering/harness/Harness组件学习路线-进度追踪.md +++ b/mvp/engineering/harness/Harness组件学习路线-进度追踪.md @@ -30,7 +30,7 @@ ### 0.4 当前会话的起始上下文(供追溯) -本次学习从 Harness 入口文档开始,已完整走过:入口导读 → 面试速查 → RunContext → 执行控制(budget/cancel/lifecycle/checkActive)→ 取消广播与打断机制 → RunBudget 深挖 → retry(设计+实现+超时+幂等性)→ progress(设计+代码双视角,含 ToolBoundary/canonical/Release 衔接)。当前停在「progress ✅ 已完成,下一步 tool」的位置。 +本次学习从 Harness 入口文档开始,已完整走过:入口导读 → 面试速查 → RunContext → 执行控制(budget/cancel/lifecycle/checkActive)→ RunBudget 深挖 → retry → progress(设计+代码双视角)→ tool 域(49 文件全注释 + 注册调用执行链路 + Tool 调用链旅程)→ RAG 检索体系(lookup_knowledge 后端:L0/多路召回+RRF/qualityScore/降级/契约/审计/离线评测,已闭环)。当前停在「tool 域只差 MySQL 沙箱线,下一步 tool 收尾」的位置。 ### 0.5 面试准备策略(学习目标) @@ -88,7 +88,7 @@ | `application` | **Run 应用所有者**:创建 Run / 路由意图 / 执行分支 / 持久化 / SSE 输出 | ⬜ 部分 | ChatApplicationUseCase 入口(cancel 链路) | — | | `guard` | **验证分离**:EvidenceGuard 机械验引用真实性 + SemanticGuard 隔离判结论支持度 | ⬜ 部分 | GuardModelCall(预算/超时/取消订阅) | — | | `release` | **唯一发布点**:SUCCESS / FALLBACK 裁决,EvidenceRepair 只修引用,SafeFallback 确定性构造 | ⬜ 部分 | DiagnosisReleaseResult(结果类型) | — | -| `tool` | **证据边界**:ToolBoundary 统一执行规则、canonical 保存真相、projector 有界投影、MySQL 只读沙箱 | ⬜ 空白 | JdbcMysqlReadOnlyExecutor(取消订阅) | — | +| `tool` | **证据边界**:ToolBoundary 统一执行规则、canonical 保存真相、projector 有界投影、MySQL 只读沙箱 | ✅ 深入 | 49 文件全注释、Boundary/Contract/Projection/Store/Adapter/注册链、RAG 后端(L0/RRF/qualityScore/降级)、MySQL 沙箱(Validator/Executor/Projector 三层防线) | [tool 域注册调用执行链路](Harness%20tool%20域代码学习笔记-工具的注册调用与执行链路.md)、[Tool 调用链旅程](Harness%20Tool%20调用链-一次工具调用的完整旅程.md)、[RAG 检索体系](Harness%20RAG%20检索体系学习笔记-从%20query%20到可验证证据.md)、[MySQL 沙箱](Harness%20MySQL%20沙箱学习笔记-从%20SQL%20校验到脱敏投影.md) | | `progress` | **收敛控制**:信息增益(GAINED/NO_GAIN)、重复检测、饱和停止(预算之外的第二套停止机制) | ✅ 深入 | 设计动机、Tracker 双计数/pending/软硬停止、拦截器五道门、canonical 生命周期、Projector 投影、Release 消费 | [代码学习笔记](Harness progress 代码学习笔记-从拦截器五道门到唯一发布点.md)(与[设计视角](Harness信息增益停止-让无证据诊断正常收敛.md)配套) | 图例:✅ 深入 = 已完整学透,能面试讲 2 分钟;⬜ 部分 = 接触过但没系统学;⬜ 空白 = 未开始 @@ -102,6 +102,10 @@ | [Retry 重试机制-显式可计量的 attempt 循环](Retry重试机制-显式可计量的attempt循环.md) | Retry 设计动机 / 分类裁决 / 剩余超时 / 幂等性 | ✅ 已沉淀 | | [Harness 信息增益停止-让无证据诊断正常收敛](Harness信息增益停止-让无证据诊断正常收敛.md) | progress 设计视角:双停止机制 / 三方判断权 / 状态机 / 协议 / 真实问题 | ✅ 已沉淀(设计视角) | | [Harness progress 代码学习笔记-从拦截器五道门到唯一发布点](Harness%20progress%20代码学习笔记-从拦截器五道门到唯一发布点.md) | progress 代码视角:类地图 / 五道门 / Tracker 状态机 / canonical 生命周期 / 门禁 / 投影发布 / 易错点 / 面试话术 | ✅ 已沉淀(代码视角) | +| [Harness tool 域代码学习笔记-工具的注册调用与执行链路](Harness%20tool%20域代码学习笔记-工具的注册调用与执行链路.md) | tool 域:装配/注册(bridge/callbacks)/调用/执行(ToolBoundary)/返回全链路 + 面试话术 | ✅ 已沉淀 | +| [Harness Tool 调用链-一次工具调用的完整旅程](Harness%20Tool%20调用链-一次工具调用的完整旅程.md) | 动态时序:模型决定 → 拦截器 → invoke → Adapter → ToolBoundary → 返回 → 模型观察 | ✅ 已沉淀 | +| [Harness RAG 检索体系学习笔记-从 query 到可验证证据](Harness%20RAG%20检索体系学习笔记-从%20query%20到可验证证据.md) | RAG 后端:L0/多路召回+RRF/qualityScore/去重判级/降级/契约/审计/离线评测/讨论沉淀 | ✅ 已沉淀 | +| [Harness MySQL 沙箱学习笔记-从 SQL 校验到脱敏投影](Harness%20MySQL%20沙箱学习笔记-从%20SQL%20校验到脱敏投影.md) | MySQL 工具:三层防线(语义/连接/输出)/白名单/参数化强制/取消联动/脱敏/与 RAG 对照 | ✅ 已沉淀 | ## 3. 一次请求的完整学习主线 @@ -109,7 +113,7 @@ flowchart LR A["core
执行控制 ✅"] --> B["retry
重试 ✅"] B --> C["progress
信息增益 ✅"] - C --> D["tool
事实边界 ⬜"] + C --> D["tool
事实边界 ✅"] D --> E["guard
验证 ⬜"] E --> F["release
发布 ⬜"] F --> G["application + audit
收尾 ⬜"] @@ -119,14 +123,13 @@ flowchart LR ## 4. 下一步规划 ```text -progress ✅ 已完成(设计+代码双视角笔记沉淀,代码核心类全部加注释) +tool 域 ✅ 完成(49 文件全注释 + 5 篇笔记:注册执行链路 / Tool 调用链 / RAG 检索体系 / MySQL 沙箱) -下一个:tool(49 个文件,按四层理解:Boundary → Canonical → Projector → Adapter) - —— 已在 progress 学习中顺带摸过 ToolBoundary / CanonicalInvocationStore / Adapter / Projector - —— 正式系统学时按四层主线走,把投影器、JPA store、MySQL 沙箱补齐 +下一个:guard(15 个文件:EvidenceGuard + SemanticGuard) + —— 证据安全链核心:机械验引用真实性 + 语义判结论支持度 + —— 面试高频:如何防止 Agent 编造证据 之后顺序: - guard(15 个文件:EvidenceGuard + SemanticGuard) release(6 个文件,小而关键:唯一发布点——已接触 DiagnosisReleaseUseCase) 补 application(路由/执行器/SSE 收尾)和 audit(Trace 回放) 最后状态流(RunState ↔ ReleaseOutcome ↔ SseOutcome 正交全景)