# @sandersyao/dsh-credentials-mysql
[English](README.md) | 中文
DeepSeek Harness 的 **MySQL 凭据保险库提供方**——`dsh-credentials` 能力接缝的一个具体 Provider。以插件加载后注册 `ctx.credentials`,把 refs 与 records 两空间的凭据持久化到 MySQL,与 `dsh-credentials-local` 行为契约等价,并支持**可选的字段级 AES-256-GCM 加密**。
## 配套插件(分布式 dsh 部署)
本保险库是**共享 MySQL 的分布式 dsh 部署**中的凭据组件,设计与三个配套插件
**协同**——`dsh-workspace-bootstrap` / `dsh-storage-mysql` / `dsh-session-persistence-mysql`
把默认工作区、存储与会话持久化后端切到共享 MySQL(本插件则切换凭据后端):
| 插件 | GitHub 仓库 | npm 包页面 |
| --- | --- | --- |
| `@sandersyao/dsh-workspace-bootstrap` | https://github.com/sandersyao/dsh-workspace-bootstrap | https://www.npmjs.com/package/@sandersyao/dsh-workspace-bootstrap |
| `@sandersyao/dsh-storage-mysql` | https://github.com/sandersyao/dsh-storage-mysql | https://www.npmjs.com/package/@sandersyao/dsh-storage-mysql |
| `@sandersyao/dsh-session-persistence-mysql` | https://github.com/sandersyao/dsh-session-persistence-mysql | https://www.npmjs.com/package/@sandersyao/dsh-session-persistence-mysql |
## 安装与使用
```ts
import { MysqlCredentialProvider } from '@sandersyao/dsh-credentials-mysql'
await ctx.plugin(MysqlCredentialProvider, {
connection: { tablePrefix: process.env.CREDENTIALS_TABLE_PREFIX },
})
// ctx.credentials 现在由 MySQL 保险库支撑。
```
## 指南
- **在 dsh profile 中试用且不影响现有凭据** —— `docs/DSH_PROFILE_TRIAL.md`。
- **生产 / npm 安装与 `cordis.patch.yml` 集成(替换默认文件提供方)** —— `docs/DEPLOYMENT.md` §8。
## 配置
连接凭据、表前缀与加密密钥来自环境变量 / `.env`(见 `.env.example`)。**独立 `CREDENTIALS_*` 优先,缺省回退到共享 `MYSQL_*`** —— 与 `dsh-session-persistence-mysql` 同库共存时可复用连接,也可独立配置。插件 `Config` 全部可选——**凭据只来自环境变量**(绝不硬编码密码)。
| 环境变量 | 回退 | 默认 | 作用 |
|---|---|---|---|
| `CREDENTIALS_HOST` | `MYSQL_HOST` | `127.0.0.1` | MySQL 主机。 |
| `CREDENTIALS_PORT` | `MYSQL_PORT` | `3306` | 端口。 |
| `CREDENTIALS_USER` | `MYSQL_USER` | —(必需) | 最小权限 DB 用户。 |
| `CREDENTIALS_PASSWORD` | `MYSQL_PASSWORD` | —(必需) | 密码。 |
| `CREDENTIALS_DATABASE` | `MYSQL_DATABASE` | —(必需) | 目标数据库。 |
| `CREDENTIALS_TABLE_PREFIX` | `MYSQL_TABLE_PREFIX` | —(必需) | 表前缀,校验 `^[A-Za-z0-9_]+$`;基名与 session 表不同,规避冲突。 |
| `CREDENTIALS_ENCRYPTION_KEY` | `ENCRYPTION_KEY` | (空) | 字段加密密钥;空 = 明文(启动告警)。 |
| `CREDENTIALS_SSL_REQUIRED` | `MYSQL_SSL_REQUIRED` | `false` | 预留 TLS 强制位(暂缓)。 |
| `CREDENTIALS_POOL_SIZE` | `MYSQL_POOL_SIZE` | `10` | 连接池大小。 |
| `CREDENTIALS_SCHEMA_AUTO_MIGRATE` | `MYSQL_SCHEMA_AUTO_MIGRATE` | `true` | 启动自动迁移 schema;`false` 仅校验。 |
> **测试隔离**:自动化测试(`vitest`)运行在**独立测试库**上,避免触碰生产库——`CREDENTIALS_TEST_DATABASE`(默认 `test`)在测试期间覆盖 `CREDENTIALS_DATABASE`;`MYSQL_ROOT_PASSWORD` 仅由测试引导建库/授权使用。见 `docs/MANUAL_TEST_PLAN.md`。
## 存储布局
三张表,均带 `CREDENTIALS_TABLE_PREFIX` 前缀:
- `${prefix}credential_refs` —— refs 空间:`ref_name`(PK) + `value`。
- `${prefix}credential_records` —— records 空间:`rec_key`(/, PK) + `kind` + `payload`(JSON)。
- `${prefix}credential_meta` —— 已应用的 schema 版本。
表基名刻意不同于 `dsh-session-persistence-mysql` 的 `sessions`/`events`/`_meta`,**即使同库同前缀也不冲突**。
## 取值分层(与 dsh-credentials-local 契约等价)
```text
继承的进程环境(只读, 始终优先)
> MySQL 受管存储(可写)
> project .env → user .env
```
- **空存储值 = 不存在**:MySQL 里空串不允许写入;`resolve` 跳过、`describe` 报告未配置。
- **遮蔽规则**:`set`/`unset` 在进程环境只读提供该引用时**显式拒绝**,`describe().writable=false`。
- 进程环境按次覆盖代表本次运行意图;写入 MySQL 后立即生效。
## 并发与崩溃语义
- **`modifyRecord` 跨进程互斥**:`SELECT … FOR UPDATE` + InnoDB 事务实现"读—决定—替换",token 刷新并发安全——这是相对文件提供方(跨进程文件写锁)的结构性优点。
- **事务原子**:写入单事务,无撕裂行;`ER_LOCK_DEADLOCK`(1213) 有限退避重试。
- **崩溃恢复**:InnoDB 保证已提交写入不丢失。
## Schema 与迁移
启动执行连接测试 + 幂等 `CREATE TABLE IF NOT EXISTS`,再读 `${prefix}credential_meta`;已应用版本高于期望则 fail-closed(不支持降级)。`CREDENTIALS_SCHEMA_AUTO_MIGRATE=false` 时版本不匹配即失败。
## 字段加密(本保险库特性)
配置 `CREDENTIALS_ENCRYPTION_KEY`(32 字节 hex 或任意字符串,经 SHA-256 导出密钥)时:
- ref 值、record 的 `key`/`env`/`payload` 在写入前以 **AES-256-GCM** 加密(每行随机 IV + auth tag),密钥**永不落库、绝不进日志**。
- 存储为带版本前缀的信封串(`v1:.`),非加密数据不受影响。
- 未配置密钥 = 明文模式(启动告警);加密开关不破坏与本地提供方的行为契约(值往返仍一致)。
## 模型体验
经由消费它的 LLM 适配器间接生效:解析出的值为适配器的提供方请求授权,所有模型可见接口都由适配器负责。凭据绝不进入请求前缀。
## 已知限制与待办
- **外部编辑不热发布**——无文件 watcher;MySQL 中直接修改的行需由消费者按操作 re-resolve(接缝本就按操作解析,通常无感)。
- **`set`/`unset` 被进程环境遮蔽时拒绝**(接缝规则,与本地提供方一致)。
- **无 `$DSH_HOME/.credentials.yaml` 自动迁移**——切换提供方后旧文件不会自动导入 MySQL(见 `docs/DEPLOYMENT.md` §8.3)。
- **TLS/传输暂缓**——`CREDENTIALS_SSL_REQUIRED` 为预留位。
- **peer 范围对齐 dsh `v0.1.5-rc.1`**(`^0.1.5-rc.1`)——官方接缝版本前移时需同步调 `peerDependencies`。