2026-05-20 21:39:12 +08:00

8.9 KiB
Raw Permalink Blame History

title created updated type tags sources
MySQL 数据源与问数系统 2026-05-15 2026-05-15 entity
database
tool
agent
backend
frontend
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-modulefrontend-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() 只返回 namelabeldatabasestatus,不返回连接地址、账号或密码。

数据模型

netaclaw_data_source

NetaClawDataSourceEntity 存储连接配置与授权策略:

  • name 唯一标识,供工具调用时作为 source
  • type 当前固定为 mysql
  • hostportdatabaseusername 描述连接目标。
  • passwordEncrypted 保存 AES-256-GCM 加密后的密码。
  • readonly 固定为只读语义。
  • status 控制是否可用。
  • allowedAgentIds 限定哪些 Agent 可使用该数据源。
  • extra 保存安全策略:allowedTablesblockedTablesmaskedColumnsschemaVisibilitymaxRowsmaxJoinTablesqueryTimeoutMsconnectTimeoutpoolConnectionLimitssl

netaclaw_data_source_query_audit

NetaClawDataSourceQueryAuditEntity 记录 mysql_query 的审计结果:

  • dataSourceIdagentIduserIdtoolCallId 绑定调用来源。
  • sqlHash 保存 SQL 哈希,sqlPreview 保存前 1000 字符预览。
  • statussuccessrejectedfailed
  • rejectReason 记录 SQL guard 拒绝原因。
  • elapsedMsrowCounterrorCode 用于诊断查询表现和失败原因。

密钥加密

SecretCryptoService 使用 AES-256-GCM 加密连接密码。密钥来源优先级:

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.poolConnectionLimitextra.connectTimeoutextra.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_schemainformation_schema.TABLES 获取 TABLE_COMMENT,从 information_schema.COLUMNS 获取字段,避免误把 TABLE_COMMENT 当成 COLUMNS 字段。
  • mysql_table_sample 默认只选择未脱敏字段。
  • 采样校验使用小写映射,但实际 SQL 使用 schema 中的原始列名,兼容 tenantIdisCrewMaster 这类驼峰字段。
  • 显式请求脱敏列会抛 masked_column_denied

典型成功链路:

mysql_list_sources
  -> mysql_schema
  -> mysql_table_sample
  -> 模型基于样本总结分析

复杂分析或聚合问题可进一步调用 mysql_query

SQL Guard

MysqlQueryServicevalidateMysqlReadOnlySql() 在执行前做只读防护:

  • 只允许 SELECT
  • 拒绝 SHOWDESCRIBEEXPLAIN、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-systemskill-runtimetool-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_schemaTABLE_COMMENT 不存在 表注释来自 information_schema.TABLES,不是 COLUMNS schema 查询拆分 TABLES 和 COLUMNS
SELECT ... LIMIT 20; 被拒绝 SQL guard 把任意分号都当多语句 允许单个末尾分号并规范化
mysql_table_sample 对驼峰字段报 column_not_allowed 校验与执行列名大小写映射不一致 用小写校验、原始列名执行

相关页面