feat(v3): migrate workspace to API, Tauri desktop, and v3 crates; remove legacy MCP stack
Some checks failed
Secrets v3 CI / 检查 (push) Has been cancelled

- Add apps/api, desktop Tauri shell, domain/application/crypto/device-auth/infrastructure-db
- Replace desktop-daemon vault integration; drop secrets-core and secrets-mcp*
- Ignore apps/desktop/dist and generated Tauri icons; document icon/dist steps in AGENTS.md
- Apply rustfmt; fix clippy (collapsible_if, HTTP method as str)
This commit is contained in:
agent
2026-04-13 08:49:57 +08:00
parent cb5865b958
commit 0374899dab
130 changed files with 20447 additions and 21577 deletions

377
README.md
View File

@@ -1,110 +1,50 @@
# secrets-mcp
# Secrets
Workspace**`secrets-core`** + **`secrets-mcp`**HTTP Streamable MCP + Web+ **`secrets-mcp-local`**(可选:本机 MCP gateway。多租户密钥与元数据存 PostgreSQL用户通过 **Google OAuth** 登录,**API Key** 鉴权 MCP 请求;秘密数据用**用户密码短语派生的密钥**在客户端加密,服务端不持有原始密钥。
这是 v3 架构的仓库,当前主路径已经收敛为:
## 安装
- `apps/api`:远端 JSON API
- `apps/desktop/src-tauri`:桌面客户端
- `crates/desktop-daemon`:本地 MCP 入口
- `crates/application` / `domain` / `infrastructure-db`:业务与数据层
## 本地开发
```bash
cargo build --release -p secrets-mcp
# 产物: target/release/secrets-mcp
cp deploy/.env.example .env
# 远端 API
cargo run -p secrets-api --bin secrets-api
# 本地 daemon
cargo run -p secrets-desktop-daemon
# 桌面客户端
cargo run -p secrets-desktop
```
```bash
cargo build --release -p secrets-mcp-local
# 产物: target/release/secrets-mcp-local本机 MCP gateway见下节
```
## 当前能力
发版产物见 Gitea Releasetag`secrets-mcp-<version>`Linux musl 预编译);其它平台本地 `cargo build`
- 桌面端使用系统浏览器完成 Google Desktop OAuth 登录
- 登录成功后向 API 注册设备,并在当前桌面进程内维护登录会话
- 本地 daemon 提供显式拆分的 MCP 工具:
- `secrets_entry_find` / `secrets_entry_get`
- `secrets_entry_add` / `secrets_entry_update` / `secrets_entry_delete` / `secrets_entry_restore`
- `secrets_secret_add` / `secrets_secret_update` / `secrets_secret_delete`
- `secrets_secret_history` / `secrets_secret_rollback`
- `target_exec`
- 保留兼容别名:`secrets_find` / `secrets_add` / `secrets_update`
- 桌面端会自动把本地 daemon MCP 配置写入 `Cursor``Claude Code`
- 桌面端支持条目新建、搜索、按 type 筛选、元数据编辑、最近删除与恢复
- 桌面端支持 secret 新增、编辑、删除、明文显示、真实复制、历史查看与回滚
- 不保留 `secrets_env_map`
- 不做自动恢复登录;重启 app 后必须重新登录
## 环境变量与本地运行
复制 `deploy/.env.example` 为项目根目录 `.env`(已在 `.gitignore`),或导出同名变量:
| 变量 | 说明 |
|------|------|
| `SECRETS_DATABASE_URL` | **必填**。PostgreSQL 连接串(推荐使用域名,例如 `db.refining.ltd`,避免直连 IP。 |
| `SECRETS_DATABASE_SSL_MODE` | 可选但强烈建议生产必填。推荐 `verify-full`(至少 `verify-ca`),避免回退到弱 TLS 模式。 |
| `SECRETS_DATABASE_SSL_ROOT_CERT` | 可选。私有 CA 或自签链路时指定 CA 根证书路径(如 `/etc/secrets/pg-ca.crt`)。 |
| `SECRETS_ENV` | 可选。设为 `prod` / `production` 时会拒绝弱 PostgreSQL TLS 模式(`prefer``disable``allow``require`)。 |
| `BASE_URL` | 对外访问基址OAuth 回调为 `{BASE_URL}/auth/google/callback`。默认 `http://localhost:9315`。 |
| `SECRETS_MCP_BIND` | 监听地址,默认 `127.0.0.1:9315`。容器内或直接对外暴露端口时请改为 `0.0.0.0:9315`;反代时常为 `127.0.0.1:9315`。 |
| `GOOGLE_CLIENT_ID` / `GOOGLE_CLIENT_SECRET` | 可选;不配置则无 Google 登录入口。运行时从环境读取,勿写入 CI、勿打入二进制。换 token 须访问 `oauth2.googleapis.com`:工作区 **`reqwest` 已启用 `system-proxy`**,与浏览器一致可走 macOS/Windows **系统代理**(如 Clash 系统代理模式)。 |
| `HTTPS_PROXY` / `NO_PROXY` | 可选。仅当系统代理未被进程识别、又需走本地端口代理时设置;示例见 [`deploy/.env.example`](deploy/.env.example)。 |
| `RUST_LOG` | 可选;日志级别,如 `secrets_mcp=debug`。 |
| `SECRETS_DATABASE_POOL_SIZE` | 可选。连接池最大连接数,默认 `10`。 |
| `SECRETS_DATABASE_ACQUIRE_TIMEOUT` | 可选。获取连接超时秒数,默认 `5`。 |
| `RATE_LIMIT_GLOBAL_PER_SECOND` | 可选。全局限流速率,默认 `100` req/s。 |
| `RATE_LIMIT_GLOBAL_BURST` | 可选。全局限流突发量,默认 `200`。 |
| `RATE_LIMIT_IP_PER_SECOND` | 可选。单 IP 限流速率,默认 `20` req/s。 |
| `RATE_LIMIT_IP_BURST` | 可选。单 IP 限流突发量,默认 `40`。 |
| `TRUST_PROXY` | 可选。设为 `1`/`true`/`yes` 时从 `X-Forwarded-For` / `X-Real-IP` 提取客户端 IP仅在反代环境下启用。 |
## 提交前检查
```bash
cargo run -p secrets-mcp
```
生产推荐示例PostgreSQL TLS
```bash
SECRETS_DATABASE_URL=postgres://postgres:***@db.refining.ltd:5432/secrets-mcp
SECRETS_DATABASE_SSL_MODE=verify-full
SECRETS_DATABASE_SSL_ROOT_CERT=/etc/secrets/pg-ca.crt
SECRETS_ENV=production
```
- **Web**`BASE_URL`登录、Dashboard、设置密码短语、创建 API Key。**变更记录**页 **`/changelog`**:内容来自 `crates/secrets-mcp/CHANGELOG.md`(构建时嵌入并以 Markdown 渲染);首页页脚与 DashboardMCP页脚均提供入口。**条目**页 `/entries` 支持 folder 标签与条件筛选(含 **`tags`** 逗号分隔、多标签同时匹配);表格列可在「显示列」中开关(名称与操作固定),**文件夹**列为可选列且默认显示。列可见性持久化见 [AGENTS.md](AGENTS.md)「Web 条目页表格列」。
- **MCP**Streamable HTTP 基址 `{BASE_URL}/mcp`,需 `Authorization: Bearer <api_key>` + `X-Encryption-Key: <hex>` 请求头(读密文工具须带密钥)。
### 本地 MCP gateway`secrets-mcp-local`
`secrets-mcp-local` 现在是**独立的本地 MCP 入口**,不再依赖把远程 `/mcp` 原样透传到本机。它始终能完成 MCP `initialize` / `tools/list`,但会按状态暴露不同工具面:
- `bootstrap`:尚未绑定或尚未解锁,只暴露 `local_status``local_bind_start``local_bind_exchange``local_unlock_status``local_onboarding_info`
- `pendingUnlock`:远端授权已完成,但本地仍未完成 passphrase 解锁;仍只暴露 bootstrap 工具
- `ready`:绑定 + 解锁均完成,额外暴露 `secrets_find``secrets_search``secrets_history``secrets_overview``secrets_delete(dry_run)``target_exec`
上线流程:
1. 启动 `secrets-mcp-local`
2. 在浏览器打开本地首页 `http://127.0.0.1:9316/`
3. 点击“开始绑定”,打开页面给出的 `approve_url`
4. 在远端网页确认授权后,返回本地首页等待自动进入解锁阶段
5. 在本地页面或 `/unlock` 完成浏览器内 PBKDF2 派生、`key_check` 校验与本地解锁
6. 之后将 Cursor 等客户端的 MCP URL 配为 `http://127.0.0.1:9316/mcp`
这套流程下Cursor 会先稳定连上 local MCP未就绪时 AI 只能看到 bootstrap 工具,因此会明确告诉用户去打开本地 onboarding 页面或 `approve_url`,不会再因为 `401` 被误判成“连接失败”。
运行时说明:
- local gateway 的业务数据面已切到远端 JSON HTTP API`find/search/history/overview/delete-preview/decrypt` 直接走 `/api/local-mcp/...`
- `target_exec` 首次执行某个目标时,建议同时传入 `secrets_find/search` 返回的目标摘要local gateway 会按 `entry_id` 缓存解析后的执行上下文,后续同一目标可复用而不必重新读取密钥
- 远端 `key_version` 变化时,本地会自动从 `ready` 回退到 `pendingUnlock`
- 远端 API key 已失效或绑定用户不存在时,本地会自动清除 bound 状态并重新回到 `bootstrap`
`target_exec` 运行时会注入一组标准环境变量,例如:
- `TARGET_ENTRY_ID``TARGET_NAME``TARGET_FOLDER``TARGET_TYPE`
- `TARGET_HOST``TARGET_PORT``TARGET_USER``TARGET_BASE_URL`
- `TARGET_API_KEY``TARGET_TOKEN``TARGET_SSH_KEY`
- `TARGET_META_<KEY>``TARGET_SECRET_<KEY>`(对 metadata / secret 字段名做大写与下划线归一化)
典型用法:
-`secrets_find` 找到目标服务器,再用 `target_exec` 执行 `ssh -i <(printf '%s' \"$TARGET_SSH_KEY\") \"$TARGET_USER@$TARGET_HOST\" 'df -h'`
-`secrets_search` 找到 API 服务条目,再用 `target_exec` 执行 `curl -H \"Authorization: Bearer $TARGET_API_KEY\" \"$TARGET_BASE_URL/health\"`
本地状态行为:
- `POST /local/lock`:仅清除本地解锁缓存,保留绑定
- `POST /local/unbind`:同时清除本地绑定与解锁状态
- `GET /local/status`:返回 `bootstrap` / `pendingUnlock` / `ready`、待确认绑定会话、缓存目标数、`onboarding_url` / `unlock_url`
| 变量 | 说明 |
|------|------|
| `SECRETS_REMOTE_BASE_URL` | **必填**。远程 Web 基址,例如 `https://secrets.example.com`。 |
| `SECRETS_MCP_LOCAL_BIND` | 可选。监听地址,默认 `127.0.0.1:9316`。 |
| `SECRETS_LOCAL_UNLOCK_TTL_SECS` | 可选。默认解锁缓存秒数(`/local/unlock/complete` 可传 `ttl_secs` 覆盖)。 |
| `SECRETS_LOCAL_EXEC_CONTEXT_TTL_SECS` | 可选。按 `entry_id` 复用已解析执行上下文的缓存秒数;到期、`lock``unbind` 或远端 `key_version` 变化后会失效。 |
```bash
SECRETS_REMOTE_BASE_URL=https://secrets.example.com cargo run -p secrets-mcp-local
# 启动后直接打开 http://127.0.0.1:9316/
# 页面会引导你完成 bind -> approve -> unlock -> ready 全流程
cargo fmt -- --check
cargo clippy --locked -- -D warnings
cargo test --locked
```
## PostgreSQL TLS 加固
@@ -113,123 +53,57 @@ SECRETS_REMOTE_BASE_URL=https://secrets.example.com cargo run -p secrets-mcp-loc
- 数据库证书建议使用可校验链路(如 Let's Encrypt 或私有 CA并保证证书 `SAN` 包含 `db.refining.ltd`
- PostgreSQL 侧建议使用 `hostssl` 规则限制应用来源(如 `47.238.146.244/32`),逐步移除公网明文 `host` 访问。
- 应用端推荐 `SECRETS_DATABASE_SSL_MODE=verify-full`;仅在过渡阶段可临时用 `verify-ca`
- 可执行运维步骤见 [`deploy/postgres-tls-hardening.md`](deploy/postgres-tls-hardening.md)
- 可执行运维步骤见 `[deploy/postgres-tls-hardening.md](deploy/postgres-tls-hardening.md)`
## MCP 与 AI 工作流v0.3+
## MCP 与 AI 工作流v3
条目在逻辑上以 **`(folder, name)`** 在用户内唯一(数据库唯一索引:`user_id + folder + name`)。同名可在不同 folder 下各存一条(例如 `refining/aliyun``ricnsmart/aliyun`)。
当前 v3 以 **桌面端 + 本地 daemon** 为主路径:
### 工具列表
- 桌面端登录态仅在当前进程内有效,不持久化 `device token`
- 本地 daemon 默认监听 `http://127.0.0.1:9515/mcp`
- daemon 通过活跃 desktop 进程提供的本地会话转发访问 APIdesktop 进程退出后所有工具不可用
- `target_exec` 会显式读取真实 secret 值后再生成 `TARGET_*` 环境变量
- 不保留 `secrets_env_map`
| 工具 | 需要加密密钥 | 说明 |
|------|-------------|------|
| `secrets_find` | 否 | 发现条目(返回含 secret_fields schema支持 `name_query` 模糊匹配 |
| `secrets_search` | 否 | 搜索条目,支持 `query`/`folder`/`type`/`name` 过滤、`sort`/`offset` 分页、`summary` 摘要模式 |
| `secrets_get` | 是 | 按 UUID `id` 获取单条条目及解密后的 secrets |
| `secrets_add` | 是 | 添加新条目,支持 `meta_obj`/`secrets_obj` JSON 对象参数、`secret_types` 指定密钥类型、`link_secret_names` 关联已有 secret |
| `secrets_update` | 是 | 更新条目,支持 `id``name`+`folder` 定位 |
| `secrets_delete` | 否 | 删除条目,支持 `id``name`+`folder` 定位;`dry_run=true` 预览删除 |
| `secrets_history` | 否 | 查看条目历史,支持 `id``name`+`folder` 定位 |
| `secrets_rollback` | 否 | 回滚条目到指定历史版本(服务端按历史快照恢复元数据与密文关联),支持 `id`;仅需 **Bearer**,不要求 `X-Encryption-Key` |
| `secrets_export` | 是 | 导出条目(含解密明文),支持 JSON/TOML/YAML 格式 |
| `secrets_env_map` | 是 | 将 secrets 转为环境变量映射:`PREFIX_ENTRYNAME_FIELDNAME`(字段名中 `.``__``-``_` 再转大写,避免与纯下划线字段名碰撞),支持 `prefix` |
| `secrets_overview` | 否 | 返回各 folder 和 type 的 entry 计数概览 |
### Canonical MCP 工具
### 消歧规则
| 工具 | 说明 |
| --- | --- |
| `secrets_entry_find` | 从 desktop 已解锁本地 vault 搜索对象,支持 `query` / `folder` / `type` |
| `secrets_entry_get` | 读取单条本地对象,并返回当前 secrets 的真实值 |
| `secrets_entry_add` | 在本地 vault 创建对象,可选附带初始 secrets |
| `secrets_entry_update` | 更新本地对象的 folder / type / name / metadata |
| `secrets_entry_delete` | 将本地对象标记为删除 |
| `secrets_entry_restore` | 恢复本地已删除对象 |
| `secrets_secret_add` | 向已有本地对象新增 secret |
| `secrets_secret_update` | 更新本地 secret 名称、类型或内容 |
| `secrets_secret_delete` | 删除单个本地 secret |
| `secrets_secret_history` | 查看单个本地 secret 的历史版本 |
| `secrets_secret_rollback` | 将单个本地 secret 回滚到指定版本 |
| `target_exec` | 用本地对象的 metadata 和 secrets 生成 `TARGET_*` 环境变量并执行本地命令 |
- **按 `name` 定位的工具**`secrets_update` / `secrets_delete` / `secrets_history` / `secrets_rollback`):若该用户下仅一条匹配则直接执行;若多条(同 `name`、不同 `folder`)则返回错误并提示补全 `folder`。也可直接传 `id`UUID跳过消歧。
- **`secrets_get`** 仅支持通过 `id`UUID获取。
- **`secrets_delete`** 的 `dry_run=true` 与真实删除使用相同消歧规则——唯一则预览一条,多条则报错并要求 `folder`
### 兼容别名
### 共享密钥
以下旧名称仍可用,但内部已转发到 v3 工具:
N:N 关联下,删除 entry 仅解除关联,被共享的 secret 若仍被其他 entry 引用则保留;无引用时自动清理。
## 加密架构(混合 E2EE
### 密钥派生
用户在 Web Dashboard 设置**密码短语**,浏览器使用 **Web Crypto APIPBKDF2-SHA256600k 次迭代)**在本地派生 256-bit AES 密钥。
- **Salt32B**:首次设置时在浏览器生成,存入服务端 `users.key_salt`
- **key_check**:派生密钥加密已知常量 `"secrets-mcp-key-check"`,存入 `users.key_check`,用于登录时验证密码短语
- **服务端不存储原始密钥**,只存 salt + key_check
跨设备同步:新设备登录 → 输入相同密码短语 → 从服务端取 salt → 同样的 PBKDF2 → 得到相同密钥。
### 写入与读取流程
```mermaid
flowchart LR
subgraph Web["Web 浏览器E2E"]
P["密码短语"] --> K["PBKDF2 → 256-bit key"]
K --> Enc["AES-256-GCM 加密"]
K --> Dec["AES-256-GCM 解密"]
end
subgraph AI["AI 客户端MCP"]
HdrKey["X-Encryption-Key: hex"]
end
subgraph Server["secrets-mcp 服务端"]
Middleware["请求中临时持有 key\n请求结束即丢弃"]
DB[(PostgreSQL\nsecrets.encrypted = 密文\nentries.metadata = 明文)]
end
Enc -->|密文| Server
HdrKey -->|key + 请求| Middleware
Middleware <-->|加解密| DB
DB -->|密文| Dec
```
### 两种客户端对比
| | Web 浏览器 | AI 客户端MCP |
|---|---|---|
| 密钥位置 | 仅在浏览器内存 / sessionStorage | MCP 配置 headers 中 |
| 加解密位置 | 客户端(真正 E2E | 服务端临时(请求级生命周期) |
| 安全边界 | 服务端零知识 | 依赖 TLS + 服务端内存隔离 |
### 敏感数据传输
- **OAuth `client_secret`** 只存服务端环境变量,不发给浏览器
- **API Key** 当前存放在 `users.api_key`Dashboard 会明文展示并可重置
- **X-Encryption-Key** 随 MCP 请求经 TLS 传输,服务端仅在请求处理期间持有(不持久化)
- **生产环境必须走 HTTPS/TLS**
- `secrets_find` -> `secrets_entry_find`
- `secrets_add` -> `secrets_entry_add`
- `secrets_update` -> `secrets_entry_update`
## AI 客户端配置
在 Web Dashboard 设置密码短语后,解锁页面会按客户端格式生成配置。常见客户端示例如下
桌面端会自动把本地 daemon 写入以下配置
`Cursor / Claude Desktop` 风格:
- `~/.cursor/mcp.json`
- `~/.claude/mcp.json`
写入示例:
```json
{
"mcpServers": {
"secrets": {
"url": "https://secrets.example.com/mcp",
"headers": {
"Authorization": "Bearer sk_abc123...",
"X-Encryption-Key": "a1b2c3...64位hex"
}
}
}
}
```
`OpenCode` 风格:
```json
{
"mcp": {
"secrets": {
"type": "remote",
"enabled": true,
"url": "https://secrets.example.com/mcp",
"headers": {
"Authorization": "Bearer sk_abc123...",
"X-Encryption-Key": "a1b2c3...64位hex"
}
"url": "http://127.0.0.1:9515/mcp"
}
}
}
@@ -237,77 +111,76 @@ flowchart LR
## 数据模型
主表 **`entries`**`folder``type``name``notes``tags``metadata`,多租户时带 `user_id`+ 子表 **`secrets`**(每行一个加密字段:`name``type``encrypted`,通过 `entry_secrets` 中间表与 entry 建立 N:N 关联)。**唯一性**`UNIQUE(user_id, folder, name)``user_id` 为空时为遗留行唯一 `(folder, name)`)。另有 `entries_history``secrets_history``audit_log`,以及 **`users`**(含 `key_salt``key_check``key_params``api_key`)、**`oauth_accounts`**、**`local_mcp_bind_sessions`**(短时本地绑定确认会话)。首次连库自动迁移建表(`secrets-core``migrate`);已有库在进程启动时亦由同一 `migrate()` 增量补齐表、索引与 N:N 结构。若需从更早版本对照一次性 SQL可在 git 历史中检索已移除的 `scripts/migrate-v0.3.0.sql`。**Web 登录会话**tower-sessions使用同一 `SECRETS_DATABASE_URL`,进程启动时对会话存储执行迁移(见 `secrets-mcp``PostgresStore::migrate`),无需额外环境变量。
当前 v3 已切到**零知识同步模型**
- 服务端保存 `vault_objects``vault_object_revisions`
- desktop 本地保存 `vault_objects``vault_object_history``pending_changes``sync_state`
- 搜索、详情、reveal、history 主要在本地已解锁 vault 上完成
- 服务端负责 `auth/device``/sync/*`,不再承担明文搜索与明文 reveal
主要表:
- `users`
- `oauth_accounts`
- `devices`
- `device_login_tokens`
- `auth_events`
- `vault_objects`
- `vault_object_revisions`
字段职责:
| 位置 | 字段 | 说明 |
|------|------|------|
| entries | folder | 组织/隔离空间,如 `refining``ricnsmart`;参与唯一键 |
| entries | type | 软分类,用户自定义,如 `server``service``account``person``document`(不参与唯一键) |
| entries | name | 人类可读标识;与 `folder` 一起在用户内唯一 |
| entries | notes | 非敏感说明文本 |
| entries | metadata | 明文 JSONip、url、subtype 等) |
| secrets | name | 密钥名称(调用方提供) |
| secrets | type | 密钥类型(调用方提供,默认 `text` |
| secrets | encrypted | AES-GCM 密文(含 nonce |
| users | key_salt | PBKDF2 salt32B首次设置密码短语时写入 |
| users | key_check | 派生密钥加密已知常量,用于验证密码短语 |
| users | key_params | 派生算法参数,如 `{"alg":"pbkdf2-sha256","iterations":600000}` |
| --- | --- | --- |
| `vault_objects` | `object_id` | 同步对象标识 |
| `vault_objects` | `object_kind` | 当前对象类别,当前主要为 `cipher` |
| `vault_objects` | `revision` | 服务端对象版本 |
| `vault_objects` | `ciphertext` | 密文对象载荷 |
| `vault_objects` | `content_hash` | 密文摘要 |
| `vault_objects` | `deleted_at` | 对象级删除标记 |
| `vault_object_revisions` | `revision` / `ciphertext` | 服务端对象历史版本 |
### 共享密钥N:N 关联)
## 认证与事件
多个条目可共享同一密文字段,通过 `entry_secrets` 中间表实现 N:N 关联
- 添加条目时可通过 `link_secret_names` 参数关联已有的 secret`(user_id, name)` 精确匹配查找)
- 同一 secret 可被多个 entry 引用,删除某 entry 不会级联删除被共享的 secret
- 当 secret 不再被任何 entry 引用时,自动清理(`NOT EXISTS` 子查询)
当前登录流为 Google Desktop OAuth
### 类型Type
`type` 字段用于软分类,由用户自由填写,不做任何自动转换或归一化。常见示例:`server``service``account``person``document`,但任何值均可接受。
## 审计日志
`add``update``delete` 等写操作写入 **`audit_log`**(操作类型、对象、摘要,不含 secret 明文)。多租户场景下可写 **`user_id`**(可空,兼容遗留行)。
业务条目事件使用 **`folder` / `type` / `name`**;登录类事件使用 **`folder='auth'`**,此时 `type`/`name` 表示认证目标(例如 `oauth` / `google`),不表示某条 secrets entry。
```sql
SELECT action, folder, type, name, detail, user_id, created_at
FROM audit_log
ORDER BY created_at DESC
LIMIT 20;
```
- 桌面端使用系统浏览器拉起 Google 授权
- 使用本地 loopback callback + PKCE
- API 校验 Google userinfo 后发放 `device token`
- 登录与设备活动写入 `auth_events`
## 项目结构
```
```text
Cargo.toml
crates/secrets-core/ # db / crypto / models / audit / service
src/
taxonomy.rs # SECRET_TYPE_OPTIONSsecret 字段类型下拉选项)
service/ # 业务逻辑add, search, update, delete, export, env_map 等)
crates/secrets-mcp/ # MCP HTTP、Web、OAuth、API KeyCHANGELOG.md 嵌入 /changelog
crates/secrets-mcp-local/ # 可选:本机 MCP gatewaybootstrap + ready 双工具面)
scripts/
release-check.sh # 发版前 fmt / clippy / test
setup-gitea-actions.sh
sync-test-to-prod.sh # 测试库同步到生产(按需)
apps/
api/ # 远端 JSON API
desktop/src-tauri/ # Tauri 桌面端
crates/
application/ # v3 应用服务
client-integrations/ # Cursor / Claude Code mcp.json 注入
crypto/ # 通用加密辅助
desktop-daemon/ # 本地 MCP daemon
device-auth/ # Desktop OAuth / device token 辅助
domain/ # 领域模型
infrastructure-db/ # PostgreSQL 连接与迁移
deploy/
.env.example # 环境变量模板
secrets-mcp.service # systemd 服务文件(生产部署用)
postgres-tls-hardening.md # PostgreSQL TLS 加固运维手册
.env.example
secrets-mcp.service
postgres-tls-hardening.md
scripts/
release-check.sh
setup-gitea-actions.sh
```
## CI/CDGitea Actions
见 [`.gitea/workflows/secrets.yml`](.gitea/workflows/secrets.yml)
当前以 workspace 级检查为主,见 `[.gitea/workflows/secrets.yml](.gitea/workflows/secrets.yml)`
- **触发**:任意分支 `push`,且变更路径包含 `crates/**``deploy/**`、根目录 `Cargo.toml` / `Cargo.lock``.gitea/workflows/**`
- **流水线**:解析 `crates/secrets-mcp/Cargo.toml` 版本 → `cargo fmt` / `clippy --locked` / `test --locked` → 交叉编译 `x86_64-unknown-linux-musl``secrets-mcp` → 构建成功后打 tag `secrets-mcp-<version>`(若远端已存在同名 tag会先删除再于**当前提交**重建并推送,覆盖式发版)。
- **Release可选**:配置仓库 Secret `RELEASE_TOKEN`Gitea PAT明文勿 base64会通过 API **创建或更新**已指向该 tag 的 Release非 draft、上传 `tar.gz``.sha256`;未配置则跳过 API Release仅 tag + 构建结果。
- **部署(可选)**:仅在 `main``feat/mcp``mcp` 分支且构建成功时,若已配置 `vars.DEPLOY_HOST``vars.DEPLOY_USER``secrets.DEPLOY_SSH_KEY`,则 `deploy-mcp` 通过 SCP/SSH 更新目标机二进制并 `systemctl restart secrets-mcp`
- **通知(可选)**`vars.WEBHOOK_URL` 为飞书 Webhook 时,构建/部署/发布节点会推送简要状态。
提交前建议直接运行:
```bash
./scripts/setup-gitea-actions.sh # 通过 Gitea API 写入 RELEASE_TOKEN、WEBHOOK_URL、部署相关变量等
./scripts/release-check.sh
```
详见 [AGENTS.md](AGENTS.md)(发版规则、代码规范)。
详见 [AGENTS.md](AGENTS.md)(发版规则、代码规范)。