docs(provider): 记录本地密钥加密边界
This commit is contained in:
@@ -76,20 +76,11 @@ uv run uvicorn app.main:app --reload --host 127.0.0.1 --port 8000
|
|||||||
|
|
||||||
#### 开发环境使用外部模型
|
#### 开发环境使用外部模型
|
||||||
|
|
||||||
当前仓库尚未包含 Tauri Host 与 Stronghold。需要联调外部模型时,应在启动后端的同一个终端会话中,通过进程环境注入密钥,再启动 AI Core:
|
在“设置 → 模型提供商”中选择 DeepSeek 或 OpenAI 预设后,直接在密码输入框填写 API Key。前端只在提交期间持有该值,不写入 Pinia 或 localStorage;AI Core 将其加密保存到本机 `backend/data/credentials/`,Provider 配置只保留内部 Credential ID。
|
||||||
|
|
||||||
- DeepSeek 预设的 Credential ID 为 `deepseek`,开发环境读取 `DEEPSEEK_API_KEY`,也兼容 Host 约定的 `AINOTE_CREDENTIAL_DEEPSEEK`;
|
该目录同时包含本地开发用主密钥和密文,并已加入 `.gitignore`。这提供本地静态加密和完整性校验,但不能替代操作系统凭据库。开始 Tauri 桌面集成后,应将存储实现迁移到 Stronghold,保留现有 Credential API 与 Provider 接口边界。
|
||||||
- OpenAI 预设的 Credential ID 为 `openai`,开发环境读取 `OPENAI_API_KEY`,也兼容 `AINOTE_CREDENTIAL_OPENAI`。
|
|
||||||
|
|
||||||
PowerShell 7 中可以在启动后端的同一终端安全输入 DeepSeek Key,输入内容不会回显,也不会进入命令历史:
|
无界面或自动化环境仍可使用 `DEEPSEEK_API_KEY`、`OPENAI_API_KEY` 或 `AINOTE_CREDENTIAL_<ID>` 注入;设置页保存的本地密钥优先,环境变量仅在本地未保存对应 Credential ID 时作为回退。密钥不得写入仓库文件、README、Issue、提交信息或聊天记录。
|
||||||
|
|
||||||
```powershell
|
|
||||||
$env:DEEPSEEK_API_KEY = Read-Host "DeepSeek API Key" -MaskInput
|
|
||||||
cd backend
|
|
||||||
uv run uvicorn app.main:app --reload --host 127.0.0.1 --port 8000
|
|
||||||
```
|
|
||||||
|
|
||||||
环境变量只应配置在本机或当前进程中,不要写入仓库文件、README、Issue、提交信息或聊天记录。设置环境变量后必须重新启动后端进程,已经运行的进程无法读取之后才添加的变量。前端 Provider 表单中的 Credential ID 不是 API Key,不能把密钥明文粘贴到该字段。
|
|
||||||
|
|
||||||
### 终端二:启动前端
|
### 终端二:启动前端
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -75,7 +75,7 @@
|
|||||||
| GET | `/api/providers/{provider_id}/models` | 获取模型及 Capability 列表 |
|
| GET | `/api/providers/{provider_id}/models` | 获取模型及 Capability 列表 |
|
||||||
| POST | `/api/providers/test` | 测试 Provider 连接 |
|
| POST | `/api/providers/test` | 测试 Provider 连接 |
|
||||||
|
|
||||||
Provider Contract 只传递 `credential_id` 或临时 `credential_context_id`,不通过普通 JSON 接口传递明文 API Key。
|
Provider Contract 只传递 `credential_id` 或临时 `credential_context_id`。当前前后端开发阶段通过独立的 `PUT /api/credentials/{credential_id}` 接收 API Key,并立即加密落盘;该接口只返回配置状态,不返回密钥。Provider CRUD、模型列表和测试接口均不携带明文 API Key。Tauri 集成后由 Stronghold 接管存储实现。
|
||||||
|
|
||||||
### Tasks、Media 与 Index
|
### Tasks、Media 与 Index
|
||||||
|
|
||||||
|
|||||||
+13
-3
@@ -67,11 +67,21 @@ Provider Adapter 的错误在 FastAPI 路由转换为统一 API Error:
|
|||||||
|
|
||||||
## 3. 凭据边界
|
## 3. 凭据边界
|
||||||
|
|
||||||
设置页只保存 `credential_id`。桌面 Host 负责将 Stronghold 中的密钥以临时凭据上下文注入 AI Core,`EnvironmentCredentialResolver` 根据 Credential ID 解析。API Key 明文不会进入 Provider Contract、Pinia、localStorage、日志或本文档。
|
设置页选择 OpenAI 或 DeepSeek 预设后展示密码类型的 API Key 输入框,不再要求用户理解 Credential ID。输入值只存在于表单的临时 `ref`,不会写入 Pinia 或 localStorage;请求完成、取消表单或失败后都会清空。
|
||||||
|
|
||||||
当前尚未实现 Tauri Host 的开发环境中,`openai` 和 `deepseek` Credential ID 分别兼容标准的 `OPENAI_API_KEY` 和 `DEEPSEEK_API_KEY` 进程环境变量。Host 注入的 `AINOTE_CREDENTIAL_OPENAI`、`AINOTE_CREDENTIAL_DEEPSEEK` 优先级更高。环境变量必须在启动 AI Core 前设置;Provider 明确指定了 Credential ID 但进程内无法解析时,Adapter 会在网络请求前返回 `PROVIDER_CREDENTIAL_MISSING`,避免把本地配置缺失误报为厂商 401。
|
API Key 通过独立接口写入:
|
||||||
|
|
||||||
本次没有创建或使用本机 OpenAI API Key,也没有对 OpenAI、DeepSeek 发起真实请求。外部模型列表的联调需要在桌面 Host 完成 Stronghold 注入后进行。
|
```http
|
||||||
|
GET /api/credentials/{credential_id}
|
||||||
|
PUT /api/credentials/{credential_id}
|
||||||
|
DELETE /api/credentials/{credential_id}
|
||||||
|
```
|
||||||
|
|
||||||
|
PUT 请求使用 Pydantic `SecretStr` 接收密钥,响应仅包含 Credential ID 和 `configured` 状态。后端使用 Fernet 认证加密,将密文保存到 `data/credentials/credentials.json`,主密钥保存到 `data/credentials/master.key`;目录和文件尽可能设置为仅当前用户可访问并整体排除版本控制。写入采用临时文件替换,避免进程中断留下半写文件。Provider 发起请求时按 Credential ID 解密,解密失败转换为统一 Provider Error,任何读取接口均不返回明文。
|
||||||
|
|
||||||
|
本地开发存储的主密钥与密文仍位于同一用户数据目录,因此它解决的是仓库泄漏、普通配置误提交和静态明文暴露,不等同于操作系统安全硬件或 Stronghold。Tauri 集成后应以 Stronghold 实现替换 `EncryptedCredentialStore`。无界面环境仍兼容 `OPENAI_API_KEY`、`DEEPSEEK_API_KEY` 和 Host 注入的 `AINOTE_CREDENTIAL_<ID>`;设置页保存的本地密钥优先,环境变量仅作为回退。
|
||||||
|
|
||||||
|
自动化测试仅使用虚构测试值,验证磁盘文件不包含明文、加解密往返、API 响应不泄密,以及 Provider 能用解密后的值构造 Authorization Header。本次没有使用真实 OpenAI 或 DeepSeek Key,也没有向厂商发起真实请求。
|
||||||
|
|
||||||
## 4. 验证
|
## 4. 验证
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user