GPU_GUARD_MONOREPO/docs/code-wiki/entities/mysql-data-source.md
2026-05-20 21:39:12 +08:00

168 lines
8.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: MySQL 数据源与问数系统
created: 2026-05-15
updated: 2026-05-15
type: entity
tags: [database, tool, agent, backend, frontend]
sources: [packages/backend/src/modules/netaclaw/entity/data_source.ts, packages/backend/src/modules/netaclaw/entity/data_source_query_audit.ts, packages/backend/src/modules/netaclaw/service/data_source.ts, packages/backend/src/modules/netaclaw/service/mysql_pool.ts, packages/backend/src/modules/netaclaw/service/mysql_schema.ts, packages/backend/src/modules/netaclaw/service/mysql_query.ts, packages/backend/src/modules/netaclaw/service/secret_crypto.ts, packages/backend/src/modules/netaclaw/tools/builtin/mysql.ts, packages/backend/src/modules/netaclaw/controller/admin/data_source.ts, packages/frontend/src/modules/base/views/data-source.vue, packages/backend/skills/data-analyst-mysql/SKILL.md]
---
# MySQL 数据源与问数系统
MySQL 数据源与问数系统为 [[netaclaw-module]] 增加授权范围内的只读数据库分析能力。它由后台数据源配置页、连接密钥加密、连接池、schema/sample/query 服务、`mysql_*` 工具、SQL guard 和查询审计组成,并通过 [[tool-system]] 暴露给 Agent。
## 管理入口
前端入口在“系统管理 -> 数据源管理”,页面文件为 `packages/frontend/src/modules/base/views/data-source.vue`
该页面支持:
- 新增、编辑、删除、启停 MySQL 数据源。
- 配置 Host/IP、端口、数据库、用户名、密码和 SSL。
- 配置授权 Agent、表白名单、表黑名单、脱敏列、schema 可见性、最大返回行数、最大 JOIN 表数、查询超时和连接超时。
- 点击“测试连接”调用 `/admin/netaclaw/data-source/test`,不会直接把连接信息暴露给 Agent。
菜单来自 `base_sys_menu` 动态路由,不是前端静态路由。`packages/backend/src/modules/base/event/menu.ts` 在后端启动时会确保 `/sys/data-source` 被同步到“系统管理”下,并给 admin 角色补齐菜单权限;`packages/backend/src/modules/base/menu.json` 保留种子菜单配置。详见 [[base-module]] 和 [[frontend-architecture]]。
## 后端 API
`packages/backend/src/modules/netaclaw/controller/admin/data_source.ts` 暴露管理端接口:
| API | 方法 | 说明 |
| --- | --- | --- |
| `/admin/netaclaw/data-source/list` | GET | 管理员查看全部数据源;传 `agentId` 时返回该 Agent 授权摘要 |
| `/admin/netaclaw/data-source/save` | POST | 新增或部分更新数据源配置 |
| `/admin/netaclaw/data-source/delete` | POST | 删除数据源并关闭连接池 |
| `/admin/netaclaw/data-source/test` | POST | 使用现有或临时配置测试连接 |
`NetaClawDataSourceService` 对外返回管理安全投影:保留 host、database、username 等管理字段,但只返回 `hasPassword`,不返回明文密码或密文。给 Agent 的 `listForAgent()` 只返回 `name``label``database``status`,不返回连接地址、账号或密码。
## 数据模型
### netaclaw_data_source
`NetaClawDataSourceEntity` 存储连接配置与授权策略:
- `name` 唯一标识,供工具调用时作为 `source`
- `type` 当前固定为 `mysql`
- `host``port``database``username` 描述连接目标。
- `passwordEncrypted` 保存 AES-256-GCM 加密后的密码。
- `readonly` 固定为只读语义。
- `status` 控制是否可用。
- `allowedAgentIds` 限定哪些 Agent 可使用该数据源。
- `extra` 保存安全策略:`allowedTables``blockedTables``maskedColumns``schemaVisibility``maxRows``maxJoinTables``queryTimeoutMs``connectTimeout``poolConnectionLimit``ssl`
### netaclaw_data_source_query_audit
`NetaClawDataSourceQueryAuditEntity` 记录 `mysql_query` 的审计结果:
- `dataSourceId``agentId``userId``toolCallId` 绑定调用来源。
- `sqlHash` 保存 SQL 哈希,`sqlPreview` 保存前 1000 字符预览。
- `status``success``rejected``failed`
- `rejectReason` 记录 SQL guard 拒绝原因。
- `elapsedMs``rowCount``errorCode` 用于诊断查询表现和失败原因。
## 密钥加密
`SecretCryptoService` 使用 AES-256-GCM 加密连接密码。密钥来源优先级:
```text
NETA_SECRET_KEY -> APP_SECRET -> module.user.jwt.secret
```
本地开发环境没有配置 `NETA_SECRET_KEY` / `APP_SECRET` 时,会回退到用户模块已有的 JWT secret避免“测试连接”因为缺失环境变量失败。生产环境仍建议显式配置专用 `NETA_SECRET_KEY`,避免与登录 token 密钥耦合。
## 连接池
`MysqlPoolManager` 基于 `mysql2/promise` 创建连接池:
- `getPool(source)` 按数据源 ID 缓存连接池。
- `createTransientPool(source)` 用于测试连接,不进入长期缓存。
- `closePool(id)` 在保存或删除数据源后关闭旧池,避免连接配置变更后继续复用旧连接。
- pool 配置使用 `extra.poolConnectionLimit``extra.connectTimeout``extra.ssl`,并通过 `SecretCryptoService` 解密密码。
## 工具集
`packages/backend/src/modules/netaclaw/tools/builtin/mysql.ts` 注册四个工具toolset 为 `mysql`
| 工具 | 说明 |
| --- | --- |
| `mysql_list_sources` | 列出当前 Agent 授权的数据源摘要 |
| `mysql_schema` | 查询授权表的字段、索引、主键、外键和脱敏标记 |
| `mysql_table_sample` | 查询授权表少量未脱敏字段样本 |
| `mysql_query` | 执行经过 guard 校验的只读 SELECT并写审计 |
这些工具在 manifest 中统一走 `main-process-proxy`,即使被子 Agent 调用也必须回到主进程执行。这样连接池、密钥、授权、SQL guard 和审计不会落到 worker 进程。
## Schema 与 Sample
`MysqlIntrospectionService` 负责 schema 和样本读取。
关键规则:
- `schemaVisibility=allowed-only` 时,只返回白名单表详情。
- `schemaVisibility=all-names-only` 时,白名单外表只可见表名/表注释,不返回字段详情。
- `mysql_schema``information_schema.TABLES` 获取 `TABLE_COMMENT`,从 `information_schema.COLUMNS` 获取字段,避免误把 `TABLE_COMMENT` 当成 COLUMNS 字段。
- `mysql_table_sample` 默认只选择未脱敏字段。
- 采样校验使用小写映射,但实际 SQL 使用 schema 中的原始列名,兼容 `tenantId``isCrewMaster` 这类驼峰字段。
- 显式请求脱敏列会抛 `masked_column_denied`
典型成功链路:
```text
mysql_list_sources
-> mysql_schema
-> mysql_table_sample
-> 模型基于样本总结分析
```
复杂分析或聚合问题可进一步调用 `mysql_query`
## SQL Guard
`MysqlQueryService``validateMysqlReadOnlySql()` 在执行前做只读防护:
- 只允许 `SELECT`
- 拒绝 `SHOW``DESCRIBE``EXPLAIN`、DML、DDL、DCL、事务、`CALL`、CTE、UNION、用户变量、临时表、危险函数、文件输出、锁定读、隐式 JOIN、派生表和 offset limit。
- 拒绝 schema-qualified 表名,禁止跨库访问。
- 检查所有表都在 `allowedTables` 中,且不在 `blockedTables` 中。
- 限制 JOIN 表数和最大行数。
- 无显式 `LIMIT` 时包一层外部 LIMIT最多取 `maxRows + 1` 判断截断。
- 允许单个末尾分号,并在执行前去掉;真正多语句仍被拒绝。
- 对含脱敏字段的表,拒绝 `SELECT *``table.*`、别名通配以及脱敏列引用。
执行时使用 MySQL `execute()`,查询失败会写 `failed` 审计guard 拒绝会写 `rejected` 审计。
## Prompt Skill
`packages/backend/skills/data-analyst-mysql/SKILL.md` 是 prompt 类型 skill用于约束 Agent 的 MySQL 问数流程:
- 必须先 `mysql_list_sources`,不能猜数据源。
-`mysql_schema` 再设计 SQL。
- 只能使用 `mysql_*` 工具处理数据库问题。
- 输出需要包含结论、SQL、假设和限制。
- 明确禁止修改数据、绕过授权、暴露连接信息和输出未授权内容。
该 skill 需要与 [[skill-system]]、[[skill-runtime]] 和 [[tool-governance]] 共同理解skill 只是行为约束真正的安全边界由服务端授权、SQL guard、连接池和审计共同实现。
## 常见故障
| 症状 | 原因 | 修复点 |
| --- | --- | --- |
| “系统管理”里看不到“数据源管理” | 现有库菜单来自 `base_sys_menu`,不会自动读取 `menu.json` | `base/event/menu.ts` 启动同步 `/sys/data-source` |
| 测试连接报缺少 `NETA_SECRET_KEY` / `APP_SECRET` | 加密服务只读环境变量 | `SecretCryptoService` 回退到 `module.user.jwt.secret` |
| `mysql_schema``TABLE_COMMENT` 不存在 | 表注释来自 `information_schema.TABLES`,不是 COLUMNS | schema 查询拆分 TABLES 和 COLUMNS |
| `SELECT ... LIMIT 20;` 被拒绝 | SQL guard 把任意分号都当多语句 | 允许单个末尾分号并规范化 |
| `mysql_table_sample` 对驼峰字段报 `column_not_allowed` | 校验与执行列名大小写映射不一致 | 用小写校验、原始列名执行 |
## 相关页面
- [[netaclaw-module]]
- [[tool-system]]
- [[tool-catalog]]
- [[tool-governance]]
- [[skill-system]]
- [[frontend-architecture]]
- [[base-module]]
- [[database-entity-overview]]