501 lines
23 KiB
Markdown
501 lines
23 KiB
Markdown
# 12-2 [process] 本地 vaultd + Agent Token 读密路径(不依赖 mnote-web)v1
|
||||
|
|
|
|||
|
|
> 创建时间:2026-07-23
|
|||
|
|
> 状态:`PROCESS`(**P0 L-Access 已落地**;**P1a–P1d 已落地**:web AI list/get/resolve/login/session → core;`mnote-vault serve` UDS + CLI sock→内嵌 fallback;**login/session 不依赖 mnote-web**)
|
|||
|
|
> Owner:`12-vault`
|
|||
|
|
> 建议 repo 落点:`design/12-vault/process/12-2-vaultd-local-token-agent-read-path-v1.md`
|
|||
|
|
>
|
|||
|
|
> 上位依据:
|
|||
|
|
> - `design/12-vault/process/12-1-password-vault-dedicated-crud-workbench-v1.md`(vault 系统空间、AI 密码本策略、文件真源)
|
|||
|
|
> - `/home/lix/.agent-infra/vault-policy.md`(多 agent 唯一策略 SSOT)
|
|||
|
|
> - `skills/mnote-vault` / `$mnote-vault`
|
|||
|
|
> - `design/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.md`(禁裸读敏感路径)
|
|||
|
|
> - `ARCHITECTURE.md` local-first 原则
|
|||
|
|
>
|
|||
|
|
> 触发证据:
|
|||
|
|
> - Paseo session `21242fc0-db03-454c-a1e5-723688351ee7`:取密依赖 mnote-web 存活 + `auth-e2e` cookie,步骤膨胀、失败面大。
|
|||
|
|
> - 用户目标:**读库本质是本地文件**;解密/受控读取只需轻量常驻服务,**不**应绑庞大 mnote-web;agent 内部保存 **token** 做授权取密。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. Overview
|
|||
|
|
|
|||
|
|
### 1.1 一句话
|
|||
|
|
|
|||
|
|
> **文件是库;`mnote-vaultd` 是受控读密网关(及未来 master key 匣);agent 只持 capability token,不持 master key,也不依赖 mnote-web 进程。**
|
|||
|
|
|
|||
|
|
### 1.2 与 12-1 的关系
|
|||
|
|
|
|||
|
|
| 维度 | 12-1(已落地主线) | 12-2(本文) |
|
|||
|
|
|------|-------------------|--------------|
|
|||
|
|
| 真源 | `{workspaceRoot}/.mnote/vault/**` 结构化文件 | **不变** |
|
|||
|
|
| 人用 UI | `/vault` + mnote-web `/api/vault/*` | **保留**;不作为 agent 读密必经 |
|
|||
|
|
| AI 策略 | 单 AI 本 + 单 resolve 通道 + 禁扫 vault 文件 | **策略不变**;**transport 换** |
|
|||
|
|
| Agent 通道 | HTTP → mnote-web(需 cookie / auth-e2e) | UDS/loopback → **vaultd**(Bearer token) |
|
|||
|
|
| 常驻进程 | 整站 mnote-web | 可选 **极小 vaultd** |
|
|||
|
|
|
|||
|
|
12-1 P1「多 agent 唯一策略」中的语义(只读 AI 本、`resolve` 唯一取密、禁通用 file)**冻结保留**。
|
|||
|
|
本文只改 **谁持进程、用什么凭证、是否依赖 3000**。
|
|||
|
|
|
|||
|
|
### 1.3 现状诚实声明(实现前必读)
|
|||
|
|
|
|||
|
|
当前实现(2026-07):
|
|||
|
|
|
|||
|
|
- 条目为 workspace 下 **结构化 Markdown + frontmatter**(`mnote.kind: credential`)。
|
|||
|
|
- `cipher-book.json` 是 **片段占位符展开**(如 `[A]` → 共享串),**不是** 磁盘 AES 整库加密。
|
|||
|
|
- 尚无「用户 master password → 内存 master key → 密文 at rest」完整链路。
|
|||
|
|
- 「解密」在产品语言上 = **load 文件 + cipher 展开 + nested secret 解析 + 策略门闩**。
|
|||
|
|
|
|||
|
|
因此 12-2 分两层能力,**禁止混称**:
|
|||
|
|
|
|||
|
|
| 层 | 名称 | P0 是否必须 | 说明 |
|
|||
|
|
|----|------|-------------|------|
|
|||
|
|
| **L-Access** | 受控读密网关 | **是** | token 鉴权、只暴露 list/get/resolve、审计、不依赖 mnote-web |
|
|||
|
|
| **L-Crypto** | 真·at-rest 加密 | **P2 可选** | master key 仅驻 vaultd 内存;token **永不**等于 master key |
|
|||
|
|
|
|||
|
|
P0 交付 **L-Access** 即可消除「3000 挂了就不能取密」。
|
|||
|
|
L-Crypto 在文件格式与迁移就绪后再做,不阻塞 agent 读路径瘦身。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. Goals / Non-Goals
|
|||
|
|
|
|||
|
|
### 2.1 Goals
|
|||
|
|
|
|||
|
|
1. Agent 读密(list / get / resolve / login 所需密钥字段)**不依赖 mnote-web 运行**。
|
|||
|
|
2. 常驻面缩小为 **`mnote-vaultd`**(或等价 one-shot CLI 内嵌同一 core,见 §5.4),不跑 SSR/Sidebar/文档编辑。
|
|||
|
|
3. Agent **内部保存 vault_token**;每次调用带 token;**禁止**把 master password / master key 写入 agent 配置。
|
|||
|
|
4. 保持 12-1 策略:仅 AI 密码本 actor;禁通用工具扫 `.mnote/vault/**`;resolve 审计不落明文到日志。
|
|||
|
|
5. CLI / Pi 工具 / skill 语义对齐:稳态 **1~2 次调用**完成取密(已知 id 时仅 `resolve`)。
|
|||
|
|
6. mnote-web UI 与 human CRUD **可继续用现网路径**;演进期可与 vaultd 并行,终态共享 `mnote-vault-core`。
|
|||
|
|
|
|||
|
|
### 2.2 Non-Goals(本设计不承诺)
|
|||
|
|
|
|||
|
|
- 不重做 `/vault` 工作台 UI。
|
|||
|
|
- 不把 vault 变成 graph / `tree.*` 节点。
|
|||
|
|
- 不要求远程多机共享 vaultd(本机 local-first;跨机另案)。
|
|||
|
|
- 不在 P0 强制引入 at-rest 加密迁移(L-Crypto = P2)。
|
|||
|
|
- 不取消「禁扫 vault 文件」策略(即便未来密文 at rest,仍禁止 agent 把 vault 目录当通用笔记读)。
|
|||
|
|
- 不把 Cloudflare 过人机验证自动化为无人值守(仍 human → `session` 回写)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. 问题根因(为何要拆)
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
今天 Agent 取密关键路径:
|
|||
|
|
|
|||
|
|
skill/policy
|
|||
|
|
→ mnote-vault-cli auth-e2e # 需要 mnote-web + 用户 auth API
|
|||
|
|
→ list / resolve HTTP # 需要 3000 存活 + cookie
|
|||
|
|
→ (可选)login / session
|
|||
|
|
|
|||
|
|
失败面:
|
|||
|
|
- web 未启动 / 崩溃 / 端口占用
|
|||
|
|
- cookie eval / FORCE_COLOR / 环境变量污染
|
|||
|
|
- agent 探索路径、读 policy、猜 URL → 工具次数爆炸
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
根因归类:
|
|||
|
|
|
|||
|
|
| 误绑定 | 正确归属 |
|
|||
|
|
|--------|----------|
|
|||
|
|
| 读本地文件 → 需要 Web 服务器 | 读文件 → 本地 IO + 可选小网关 |
|
|||
|
|
| Agent 身份 → mnote-web session cookie | Agent 身份 → vault capability token |
|
|||
|
|
| 解密权 → 与 SSR 同进程 | 解密/受控 resolve → vaultd(或 CLI 内嵌 core) |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. 目标架构
|
|||
|
|
|
|||
|
|
### 4.1 分层图
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
┌──────────────────────────────────────────────────────────────┐
|
|||
|
|
│ Agent runtime(Grok / Codex / Hermes / Pi / Paseo) │
|
|||
|
|
│ - 持有 vault_token(env / 0600 文件 / 可选 keyring) │
|
|||
|
|
│ - 薄客户端:CLI 或 Pi tool → 只打 vaultd │
|
|||
|
|
│ - 禁止:通用 file 扫 .mnote/vault/** │
|
|||
|
|
└────────────────────────────┬─────────────────────────────────┘
|
|||
|
|
│ Authorization: Bearer <token>
|
|||
|
|
│ 优先 Unix Domain Socket
|
|||
|
|
▼
|
|||
|
|
┌──────────────────────────────────────────────────────────────┐
|
|||
|
|
│ mnote-vaultd(常驻 · 小 · 本机) │
|
|||
|
|
│ - 校验 token(iss/aud/exp/scope/actor) │
|
|||
|
|
│ - 解析 vault root(workspace / AI actor root) │
|
|||
|
|
│ - load index / credential md + cipher expand + nested secret │
|
|||
|
|
│ - L-Crypto 时:内存持 master key;lock 清空 │
|
|||
|
|
│ - 审计 jsonl(无 plaintext value) │
|
|||
|
|
│ - 不托管:SSR、树、Page AI、control-plane 全站逻辑 │
|
|||
|
|
└────────────────────────────┬─────────────────────────────────┘
|
|||
|
|
│ 受控读写 FS
|
|||
|
|
▼
|
|||
|
|
┌──────────────────────────────────────────────────────────────┐
|
|||
|
|
│ 本地文件真源(SSOT,与 12-1 相同) │
|
|||
|
|
│ {workspaceRoot}/.mnote/vault/ │
|
|||
|
|
│ vault-index.json │
|
|||
|
|
│ credentials|*.md(条目) │
|
|||
|
|
│ cipher-book.json │
|
|||
|
|
│ audit.jsonl │
|
|||
|
|
│ AI 本:MNOTE_AI_VAULT_ACTOR 对应 root(实现沿用 12-1) │
|
|||
|
|
└──────────────────────────────────────────────────────────────┘
|
|||
|
|
|
|||
|
|
旁路(可选,非读密阻塞路径):
|
|||
|
|
mnote-web /vault UI、human CRUD、共享到 AI 本
|
|||
|
|
vault-login-helper resolve 后外站登录 / session 回写
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.2 两类密钥(禁止混用)
|
|||
|
|
|
|||
|
|
| 名称 | 持有者 | 用途 | 落盘? |
|
|||
|
|
|------|--------|------|--------|
|
|||
|
|
| **Master key**(L-Crypto) | 仅 vaultd 内存 | 解密 at-rest 密文包 | 否(仅 unlock 后内存) |
|
|||
|
|
| **Vault token**(capability) | Agent 配置 / runtime | 向 vaultd 证明「谁、何 scope、何 actor」 | 可:`~/.config/mnote/vault-tokens/*.token`,`0600` |
|
|||
|
|
|
|||
|
|
**硬规则:**
|
|||
|
|
|
|||
|
|
1. Token **不能**派生或编码 master key。
|
|||
|
|
2. 泄露 token ⇒ 在 vaultd 存活且已 unlock 时可 resolve;**不能**离线解密磁盘(L-Crypto 后更强)。
|
|||
|
|
3. 泄露 master password ⇒ 可 unlock 整库;**不得**写入任何 agent skill / env 默认模板。
|
|||
|
|
|
|||
|
|
### 4.3 Token 声明(逻辑 schema)
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"v": 1,
|
|||
|
|
"iss": "mnote-vaultd",
|
|||
|
|
"aud": "local-vaultd",
|
|||
|
|
"sub": "agent:paseo",
|
|||
|
|
"actor": "mnote-e2e",
|
|||
|
|
"scope": ["list", "get", "resolve", "login", "session"],
|
|||
|
|
"workspace": "optional-stable-id-or-path-hash",
|
|||
|
|
"iat": 0,
|
|||
|
|
"exp": 0,
|
|||
|
|
"jti": "uuid"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- 序列化:紧凑 JSON + **HMAC-SHA256**(本机 secret)或 ed25519(若未来多签发方)。
|
|||
|
|
- 传输:`Authorization: Bearer <base64url(payload).base64url(sig)>`(类 JWT 即可,不必上完整 OIDC)。
|
|||
|
|
- P0 默认 scope:`list` + `get` + `resolve`;`login`/`session` 可同 token 或分 token。
|
|||
|
|
- `actor` **必须**等于 AI 密码本 actor(默认 `mnote-e2e`,env `MNOTE_AI_VAULT_ACTOR` 可覆盖签发时固化进 token)。
|
|||
|
|
|
|||
|
|
### 4.4 Bootstrap(token 从哪来)
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
一次(人或安装脚本):
|
|||
|
|
1. 启动 vaultd(或 CLI doctor)
|
|||
|
|
2. (L-Crypto)用户 unlock → master key 入内存
|
|||
|
|
3. vaultd issue-token \
|
|||
|
|
--agent paseo \
|
|||
|
|
--actor mnote-e2e \
|
|||
|
|
--scope list,get,resolve,login,session \
|
|||
|
|
--ttl 90d
|
|||
|
|
4. 写入 ~/.config/mnote/vault-tokens/default.token(0600)
|
|||
|
|
5. 各 agent skill / env:MNOTE_VAULT_TOKEN_FILE 或 MNOTE_VAULT_TOKEN
|
|||
|
|
|
|||
|
|
日常 agent:
|
|||
|
|
读 token → 调 resolve → 用完 value(不写聊天、不写无关日志)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
轮换:`revoke jti` + 重新 issue;vaultd 维护 deny jti 集合(内存 + 可选小文件)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. `mnote-vaultd` 规格
|
|||
|
|
|
|||
|
|
### 5.1 进程与监听
|
|||
|
|
|
|||
|
|
| 项 | P0 决定 |
|
|||
|
|
|----|---------|
|
|||
|
|
| 二进制名 | `mnote-vaultd`(或 `mnote vault-daemon` 子命令) |
|
|||
|
|
| 默认传输 | **Unix Domain Socket**:`$XDG_RUNTIME_DIR/mnote-vaultd.sock`(回退 `/tmp/mnote-vaultd-$UID.sock`) |
|
|||
|
|
| TCP 备选 | `127.0.0.1:17300`,**默认关**;仅显式 `--listen-tcp` |
|
|||
|
|
| 权限 | sock `0600`、属主当前用户;拒绝非本 uid(若 OS 支持 peer cred) |
|
|||
|
|
| 启动 | user systemd / 登录脚本 / 首次 CLI 自动拉起(见 §5.4) |
|
|||
|
|
| 资源 | 目标:常驻 RSS 远小于 mnote-web;无浏览器、无 leptos SSR |
|
|||
|
|
|
|||
|
|
### 5.2 API 表面(JSON over HTTP/1.1 on UDS,或 length-prefixed JSON)
|
|||
|
|
|
|||
|
|
与现 Pi / CLI 语义对齐,路径前缀建议 `/v1/`:
|
|||
|
|
|
|||
|
|
| 方法 | 路径 | scope | 解密/展开 | 说明 |
|
|||
|
|
|------|------|-------|-----------|------|
|
|||
|
|
| GET | `/v1/health` | 无 token 也可 | 否 | `ok`, `unlocked`, `version`, `actorDefault` |
|
|||
|
|
| GET | `/v1/items` | `list` | 否* | L0 列表;同现 `list_ai` |
|
|||
|
|
| GET | `/v1/items/{id}` | `get` | 否* | 元数据 + 掩码;无 password 明文 |
|
|||
|
|
| POST | `/v1/items/{id}/resolve` | `resolve` | **是** | body: `field`, `accountId?`, `secretId?` |
|
|||
|
|
| POST | `/v1/items/{id}/login` | `login` | 内部 resolve | 可 P1 仍代理或旁路 helper |
|
|||
|
|
| POST | `/v1/items/{id}/session` | `session` | 写 session | 人机回写 |
|
|||
|
|
| POST | `/v1/lock` | admin | — | 清 master key(L-Crypto) |
|
|||
|
|
| POST | `/v1/unlock` | admin | — | 本机交互/钥匙环;**不**给 agent 默认 scope |
|
|||
|
|
| POST | `/v1/tokens/issue` | admin | — | 签发 agent token |
|
|||
|
|
| POST | `/v1/tokens/revoke` | admin | — | 吊销 jti |
|
|||
|
|
|
|||
|
|
\* list/get:若未来元数据也加密,仅解密标题等非 secret 字段;password 永不出现在 list/get。
|
|||
|
|
|
|||
|
|
**错误码(稳定字符串,CLI/skill 可分支):**
|
|||
|
|
|
|||
|
|
| code | HTTP | 含义 | Agent 动作 |
|
|||
|
|
|------|------|------|------------|
|
|||
|
|
| `vaultd_unavailable` | — | sock 连不上 | 尝试 autostart 或提示用户起服务 |
|
|||
|
|
| `vault_token_missing` | 401 | 无 Bearer | 检查 token 文件 / env |
|
|||
|
|
| `vault_token_invalid` | 401 | 签名/格式错 | 重新 issue |
|
|||
|
|
| `vault_token_expired` | 401 | exp | 轮换 token |
|
|||
|
|
| `vault_scope_denied` | 403 | scope 不足 | 重新签发含所需 scope |
|
|||
|
|
| `vault_actor_mismatch` | 403 | token.actor ≠ AI 本 | 用正确 actor token |
|
|||
|
|
| `vault_locked` | 423 | L-Crypto 未 unlock | 提示用户 `unlock`(**不是**启动 mnote-web) |
|
|||
|
|
| `vault_item_not_found` | 404 | id 不存在 / 非 AI 本 | list 再选 |
|
|||
|
|
| `vault_resolve_field_invalid` | 400 | 字段不合法 | 对齐 schema |
|
|||
|
|
| `vault_resolve_ai_only` | 403 | 试图 resolve 用户本 | 策略拒绝(与 12-1 一致) |
|
|||
|
|
|
|||
|
|
### 5.3 与文件布局(概念,兼容 12-1)
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
{workspaceRoot}/.mnote/vault/ # SSOT,vaultd 与 mnote-web 共享读
|
|||
|
|
vault-index.json
|
|||
|
|
… credential markdown …
|
|||
|
|
cipher-book.json
|
|||
|
|
audit.jsonl # 可继续追加;vaultd 写 agent 通道审计
|
|||
|
|
|
|||
|
|
~/.config/mnote/
|
|||
|
|
vaultd.toml # 可选:root 覆盖、ttl 默认、tcp 开关
|
|||
|
|
vault-tokens/
|
|||
|
|
default.token # agent 用,0600
|
|||
|
|
vaultd-hmac.key # 签发 secret,0600;仅 vaultd/admin CLI 读
|
|||
|
|
|
|||
|
|
$XDG_RUNTIME_DIR/mnote-vaultd.sock
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Workspace root 解析顺序(P0):**
|
|||
|
|
|
|||
|
|
1. 请求头 / CLI 显式 `--workspace`
|
|||
|
|
2. env `MNOTE_VAULT_WORKSPACE`
|
|||
|
|
3. `vaultd.toml` 默认
|
|||
|
|
4. 与现 mnote-web 一致的「当前 dev workspace」约定(实现时对齐 `vault.rs` AI root 解析,避免双根)
|
|||
|
|
|
|||
|
|
AI actor root:继续 `MNOTE_AI_VAULT_ACTOR`;token 内 `actor` 必须匹配。
|
|||
|
|
|
|||
|
|
### 5.4 无常驻时的退化(仍不依赖 mnote-web)
|
|||
|
|
|
|||
|
|
若用户不愿常驻 daemon:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
mnote-vault-cli resolve --id X
|
|||
|
|
→ 若 sock 可达:走 vaultd
|
|||
|
|
→ 若不可达:CLI 内嵌 mnote-vault-core(同代码)+ 本机 token 校验
|
|||
|
|
校验密钥来自 ~/.config/mnote/vaultd-hmac.key(用户可读则等同本机信任)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**注意:** 内嵌模式仍 **禁止** 无 token 裸读;仍 **禁止** agent 用通用 Read 打开 vault 文件。
|
|||
|
|
Autostart:CLI 可 `spawn` 一次 vaultd(user 级),避免每个 agent 拉起全站 3000。
|
|||
|
|
|
|||
|
|
### 5.5 login / session 边界
|
|||
|
|
|
|||
|
|
| 能力 | 建议 owner | 依赖 |
|
|||
|
|
|------|------------|------|
|
|||
|
|
| resolve 密码字段 | **vaultd 必含** | 仅本地文件 |
|
|||
|
|
| list/get | **vaultd 必含** | 仅本地文件 |
|
|||
|
|
| 外站 login playbook | vaultd 插件 **或** `vault-login-helper` | 网络 + 可选浏览器 |
|
|||
|
|
| Cloudflare session 回写 | 同 login helper | 人 + chrome-bridge |
|
|||
|
|
|
|||
|
|
P0 最小闭环:**health + list + get + resolve**。
|
|||
|
|
login/session 可 P0.5 从现 mnote-web 逻辑迁出或短期仍调 web(但 **resolve 不得回退依赖 web**)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. Agent 侧合同
|
|||
|
|
|
|||
|
|
### 6.1 环境变量
|
|||
|
|
|
|||
|
|
| 变量 | 含义 |
|
|||
|
|
|------|------|
|
|||
|
|
| `MNOTE_VAULT_TOKEN` | 直接 token 字符串(会话级优先) |
|
|||
|
|
| `MNOTE_VAULT_TOKEN_FILE` | 默认 `~/.config/mnote/vault-tokens/default.token` |
|
|||
|
|
| `MNOTE_VAULT_SOCK` | 覆盖 UDS 路径 |
|
|||
|
|
| `MNOTE_VAULT_WORKSPACE` | workspace root |
|
|||
|
|
| `MNOTE_AI_VAULT_ACTOR` | 与签发 token 一致(文档提示;以 token.actor 为准) |
|
|||
|
|
| ~~`MNOTE_BASE_URL` + `MNOTE_COOKIE`~~ | **读密路径废弃**;仅 human/web 调试保留 |
|
|||
|
|
|
|||
|
|
### 6.2 CLI 稳态(目标)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 一次安装(人)
|
|||
|
|
mnote-vault doctor # sock / token / unlock 状态
|
|||
|
|
mnote-vault unlock # 仅 L-Crypto
|
|||
|
|
mnote-vault issue-token … # 写入 token 文件
|
|||
|
|
|
|||
|
|
# Agent 每次取密(已知 id)
|
|||
|
|
mnote-vault resolve --id <id> --field password [--account-id …] [--raw]
|
|||
|
|
|
|||
|
|
# 未知 id
|
|||
|
|
mnote-vault list
|
|||
|
|
mnote-vault resolve --id <id> --field password
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**删除读密对 `auth-e2e` 的依赖。**
|
|||
|
|
`auth-e2e` 可留作「测 mnote-web UI」工具,**不得**再出现在 `$mnote-vault` skill 稳态步骤。
|
|||
|
|
|
|||
|
|
### 6.3 Skill / policy 修订点(实现阶段同步,本文先钉文案)
|
|||
|
|
|
|||
|
|
`/home/lix/.agent-infra/vault-policy.md` 与 `$mnote-vault` 将改为:
|
|||
|
|
|
|||
|
|
1. 读密:**token + vaultd/CLI**,不经 mnote-web。
|
|||
|
|
2. 仍禁扫 `.mnote/vault/**`。
|
|||
|
|
3. 登录仍优先 `login`;CF 仍 human + `session`。
|
|||
|
|
4. 故障树:`vault_locked` → 用户 unlock;`vaultd_unavailable` → 起 vaultd / CLI 内嵌;**不要**默认 `desktop:hot`。
|
|||
|
|
|
|||
|
|
### 6.4 Pi tools
|
|||
|
|
|
|||
|
|
| 现名 | 后端切换 |
|
|||
|
|
|------|----------|
|
|||
|
|
| `mnote.vault.list\|get\|resolve\|login\|session` | 默认连 vaultd;失败策略见 §5.4 |
|
|||
|
|
| 鉴权 | Bearer token,不再注入 web cookie |
|
|||
|
|
|
|||
|
|
### 6.5 安全行为(agent)
|
|||
|
|
|
|||
|
|
- 聊天 / transcript:只写 `transcriptHint`,不写 password / cookieHeader。
|
|||
|
|
- resolve value 仅用于当前工具链下一步(登录、填表),不回显用户除非用户明确要求。
|
|||
|
|
- 禁止把 token 贴进公开 issue / 截图。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. mnote-web 关系与迁移阶段
|
|||
|
|
|
|||
|
|
### 7.1 阶段
|
|||
|
|
|
|||
|
|
| 阶段 | 内容 | 退出标准 |
|
|||
|
|
|------|------|----------|
|
|||
|
|
| **A 现状** | Agent → mnote-web cookie → 文件 | — |
|
|||
|
|
| **B 并行(P0)** | 抽出 `mnote-vault-core`;`vaultd` + CLI token 路径;web 仍可直读文件 | **不启 3000 可 resolve** smoke 绿 |
|
|||
|
|
| **C 收口(P1)** | web `/api/vault/ai/*` 改为调 core 或代理 vaultd;skill 去 auth-e2e | 双路径一致;旧 cookie AI 路径标 deprecated |
|
|||
|
|
| **D 可选(P2)** | L-Crypto at-rest;web unlock UI 只负责把 key 交给 vaultd | 磁盘密文;无 key 不可读 |
|
|||
|
|
|
|||
|
|
### 7.2 代码落点(建议)
|
|||
|
|
|
|||
|
|
| crate / 路径 | 职责 |
|
|||
|
|
|--------------|------|
|
|||
|
|
| `rust/crates/mnote-vault-core`(新) | index/load/parse、cipher expand、nested secret resolve、audit append、(P2)encrypt |
|
|||
|
|
| `rust/crates/mnote-vaultd`(新)或 `mnote-vault` bin | UDS 服务、token 校验、issue/revoke |
|
|||
|
|
| `mnote-web` `vault_store` | 逐步 thin wrapper → core;UI 路由保留 |
|
|||
|
|
| `scripts/mnote-vault-cli.js` | 默认 sock+token;保留 `--via-web` 仅调试 |
|
|||
|
|
|
|||
|
|
**禁止:** 在 vaultd 内重新实现第二套 frontmatter schema。
|
|||
|
|
|
|||
|
|
### 7.3 兼容
|
|||
|
|
|
|||
|
|
- 文件 schema(`mnote.vault.credential.v1` 等)**不**为 12-2 破坏性变更。
|
|||
|
|
- 现有 AI 本条目无需迁移即可被 vaultd list/resolve(L-Access)。
|
|||
|
|
- L-Crypto 若上:单独 migration 设计 + 双读窗口,不在本文展开实现细节,只保留扩展点。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. 威胁模型(摘要)
|
|||
|
|
|
|||
|
|
| 威胁 | 缓解 |
|
|||
|
|
|------|------|
|
|||
|
|
| Agent prompt 注入要求 dump 全库 | 按条 resolve;list 无密;rate limit;审计 |
|
|||
|
|
| Token 文件被同机其他用户读 | `0600` + UDS peer cred |
|
|||
|
|
| Token 被复制到另一台机器 | `aud=local-vaultd` + 可选绑定 machine-id;无 hmac key 则签失败 |
|
|||
|
|
| 磁盘被盗 | P0:OS 磁盘加密依赖;P2:vault at-rest |
|
|||
|
|
| 恶意进程连 sock | 无有效 token 拒绝;sock 权限 |
|
|||
|
|
| 日志泄漏 | audit 不写 value;CLI 默认 JSON 管道、skill 禁回显 |
|
|||
|
|
| mnote-web RCE | 读密不依赖 web 后,攻击面与 key 分离(P2 更明显) |
|
|||
|
|
| 用户把 vault 目录加进 agent 工作区 | 策略 + Pi allowlist deny;文档披露(12-1 已有) |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 9. 验收标准(设计完成 → 实现门闩)
|
|||
|
|
|
|||
|
|
### 9.1 P0 必须
|
|||
|
|
|
|||
|
|
- [x] **mnote-web 未运行**时,持有效 token 可 `list` + `resolve` 成功(AI 本已有条目)。
|
|||
|
|
- [x] 无 token / 坏 token → 明确错误码,不回退匿名读文件。
|
|||
|
|
- [x] resolve 响应含 value;audit 无 value(沿用 store audit)。
|
|||
|
|
- [x] CLI 稳态文档与 skill:**无** `auth-e2e` 作为读密前置。
|
|||
|
|
- [ ] 通用 file 工具读 vault 路径仍 deny(web 与 Pi 侧回归,既有策略)。
|
|||
|
|
- [x] 单元测试:token 校验、scope;store 原有 20 测。
|
|||
|
|
- [x] 集成 smoke:`cargo run -p mnote-vault -- …` 不启 3000(2026-07-23 本机绿)。
|
|||
|
|
|
|||
|
|
### 9.2 P1
|
|||
|
|
|
|||
|
|
- [x] login/session 不依赖 web(core + CLI + UDS;外站 HTTP 仅 api_first 出站,resolve 仍本地)。
|
|||
|
|
- [x] mnote-web AI list/get/resolve/login/session thin-wrap 同一 core(2026-07-23)。
|
|||
|
|
- [ ] policy / skill / Paseo appendSystemPrompt 全文切换(skill 已更新 login/session 本地路径;Paseo 段可再对齐)。
|
|||
|
|
|
|||
|
|
### 9.3 P2(L-Crypto)
|
|||
|
|
|
|||
|
|
- [ ] unlock 前 resolve → `vault_locked`。
|
|||
|
|
- [ ] master key 仅内存;lock 后不可 resolve。
|
|||
|
|
- [ ] token 无法离线解密 credential 文件。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 10. 实现 Checklist(批准设计后执行;本文件阶段只列不写代码)
|
|||
|
|
|
|||
|
|
### PR-1 — core 抽出
|
|||
|
|
|
|||
|
|
- [x] 新建 `mnote-vault-core`,从 `vault_store` 搬迁:load index、load credential、cipher expand、`resolve_record_secret_field`、AI actor root 解析。
|
|||
|
|
- [x] mnote-web AI 路径 thin-wrap core(list/get/resolve/login/session);CRUD/workbench 仍可双路径。
|
|||
|
|
|
|||
|
|
### PR-2 — vaultd + token
|
|||
|
|
|
|||
|
|
- [x] token issue/verify(HMAC + 文件格式 `mnv1.*`)。
|
|||
|
|
- [x] UDS server:health/list/get/resolve/**login/session**(`mnote-vault serve`)。
|
|||
|
|
- [x] audit 写入(resolve/login/session 经 store)。
|
|||
|
|
- [x] CLI 默认 local-core + token(`mnote-vault` bin;sock 优先 fallback 内嵌)。
|
|||
|
|
|
|||
|
|
### PR-3 — agent 面
|
|||
|
|
|
|||
|
|
- [x] 更新 `vault-policy.md`、`$mnote-vault`(读密去 auth-e2e;login/session 本地 CLI)。
|
|||
|
|
- [ ] Pi tool 仍进程内 thin-wrap core(不强制走 sock;可后置切 UDS)。
|
|||
|
|
- [x] smoke:不启 3000 → resolve / session+login reuse。
|
|||
|
|
- [x] TESTING_REFERENCE 增补 vault-local 段落(含 session/login)。
|
|||
|
|
|
|||
|
|
### PR-4 — login 迁出
|
|||
|
|
|
|||
|
|
- [x] login/session 进 core + CLI + UDS(api_first 出站 HTTP 在 core;human_required 仍人 + session 回写)。
|
|||
|
|
- [x] skill 表述:login/session 可本地、不依赖 mnote-web。
|
|||
|
|
|
|||
|
|
### PR-5 — L-Crypto(另设计修订)
|
|||
|
|
|
|||
|
|
- [ ] 密文格式、unlock UI、迁移工具。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 11. 待决问题(实现前钉死;默认推荐已标)
|
|||
|
|
|
|||
|
|
| # | 问题 | 推荐默认 |
|
|||
|
|
|---|------|----------|
|
|||
|
|
| D1 | UDS vs TCP | **UDS 默认**;TCP 显式开 |
|
|||
|
|
| D2 | Token 算法 | **HMAC-SHA256** 本机 secret |
|
|||
|
|
| D3 | 无 daemon 时 CLI 内嵌 | **允许**,同 token 校验 |
|
|||
|
|
| D4 | login 是否进 P0 vaultd | **P0 不含**;P0 只 resolve 闭环 |
|
|||
|
|
| D5 | web 是否立刻代理 vaultd | **P1**;P0 双路径并行 |
|
|||
|
|
| D6 | AI root 与多 workspace | P0 单默认 workspace + env 覆盖 |
|
|||
|
|
| D7 | L-Crypto 时间表 | **不进 P0**;扩展点保留 |
|
|||
|
|
| D8 | token TTL | 默认 90d;可 issue 无 exp 仅 dev |
|
|||
|
|
|
|||
|
|
若用户否定推荐,在本文修订表追加一行后再开 PR-1。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 12. 修订记录
|
|||
|
|
|
|||
|
|
| 日期 | 说明 |
|
|||
|
|
|------|------|
|
|||
|
|
| 2026-07-23 | v1 初稿:本地文件 SSOT + vaultd + agent token;与 12-1 AI 策略对齐;L-Access P0 / L-Crypto P2;验收与 PR 切片 |
|
|||
|
|
| 2026-07-23 | P0 落地:`mnote-vault-core` + `mnote-vault` CLI(issue-token/list/get/resolve);无 web smoke 绿;UDS vaultd / web 共 core 留 P1 |
|
|||
|
|
| 2026-07-23 | P1d:login/session → core + CLI/UDS;web thin-wrap;session 回写 + login reuse 不依赖 mnote-web |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 13. 批准栏(实现启动条件)
|
|||
|
|
|
|||
|
|
- [x] 用户确认 §2 Goals / Non-Goals(2026-07-23「先按12-2实现」)
|
|||
|
|
- [x] 用户确认 §11 默认决策(含 D3 内嵌 CLI)
|
|||
|
|
- [x] P0:**core + CLI 内嵌 resolve**;login / UDS / web thin-wrap 后置
|
|||
|
|
|
|||
|
|
P0 交付物:`rust/crates/mnote-vault-core`、`rust/crates/mnote-vault`(bin `mnote-vault`)。
|