30 KiB
7-76 [process] AI 主体账号 · Web PAT · 生产级鉴权硬化 · 用户级密码箱 v1
创建时间:2026-07-26
状态:PROCESS(P0–P1b 已实现;§12 验收清单已勾选;P2 / 部分跨用户 e2e 残留见 §12.5)
执行看板:design/07-ai/process/7-76-execution-goal-v1.md
Owner:07-ai/mnote-webcontrol-plane auth /12-vault(密码箱多用户与代签面)
建议 repo 落点:design/07-ai/process/7-76-ai-principal-web-pat-and-auth-hardening-v1.md上位依据:
/mnt/Data1T/mnote/ARCHITECTURE.md/mnt/Data1T/mnote/AGENTS.md(云首发 control-plane、libsql-local、Page AI = Pi Lab)design/07-ai/process/7-71-unified-ai-management-control-plane-and-pi-lab-integration-v1.mddesign/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.mddesign/12-vault/process/12-1-password-vault-dedicated-crud-workbench-v1.mddesign/12-vault/process/12-2-vaultd-local-token-agent-read-path-v1.md/home/lix/.agent-infra/vault-policy.md+$mnote-vault触发会话:
- Paseo
28e19bd9-f091-4fa8-807b-e80b88d3aba7
主题:生产/开发分流、屏蔽测试快速登录、让外部 AI 以正式身份访问自身记录与用户笔记;密码箱按用户隔离并支持分享给 AI。用户已拍板(相对初稿的硬约束,不得回退):
- 开发态对标生产:撤下「测试账号快速登录」;开发只是在生产形态上调试,不靠 fixture 快捷入口。
- Web PAT 可复显:不做「创建后永远不可再看明文」;列表默认遮罩,需要时可 reveal;不是放弃安全,而是可审计的受控复显。
mnote.e2e定位改为系统 AI 主体账号(不是普通冒充测试人):拥有 AI 自己的知识库、笔记与记录;可查看别人分享给 AI 的密码;**仅持有该账号密码的人(一般是 admin)**可登录检查;普通用户不能访问该主体工作区。- 外部 AI 主能力 = 用户笔记的增删读写(及必要元数据),不作为再介入 Pi 内部对话的主路径。
- 密码箱跟随用户:一个用户只有一个密码箱(用户真源,而非「共享 workspace 一库混装」)。
- Admin 可代用户签发 vault token(须审计)。
1. 第一结论
本设计同时收口四件事,且它们共用同一套主体模型:
| 主题 | 结论 |
|---|---|
| 鉴权 UI | 移除 /auth 测试快速登录与 HTML 内嵌测试密码;MNOTE_WEB_ALLOW_DEV_FIXTURES 只服务 seed/smoke 机机接口,不再驱动登录页后门。 |
| AI 主体 | 保留并正式化系统账号 mnote-e2e / mnote.e2e@example.com 为 AI Principal(principal_kind=ai_service),不是普通 e2e 人设;其工作区 / 知识库 / vault 为 AI 私有面。 |
| 机机访问 | 引入 control-plane Web PAT(mnpat1.*):外部 AI / 脚本用 Bearer 调用 JSON API;浏览器人用继续 cookie session。 |
| 密码箱 | 从「workspace 级单库」演进为 每用户一库;支持 share-to-AI;vault capability token(mnv1.*)与 Web PAT 职责分离;admin 可代签 vault token。 |
一句话:
人用 cookie 登录自己的工作区;外部 AI 持 用户或 AI 主体的 PAT 做笔记 CRUD;读密另持 vault token;AI 自己的家在 AI 主体账号 下,普通用户进不去。
2. 背景与现状
§2 保留设计前痛点快照;当前实现状态以 §10 / §12 勾选为准(2026-07-26 核验)。
2.1 测试快速登录(设计前)
| 项 | 设计前 | 当前(已核验) |
|---|---|---|
| 开关 | ALLOW_DEV_FIXTURES 默认 false |
不变;seed 仍 fail-closed |
/auth |
无开关渲染快速登录 + data-test-password |
已移除按钮与测试密码 DOM |
| 测试 | 断言 HTML 含快速登录 | 断言 不含 快速登录 / data-test-password / 明文密码 |
2.2 AI 管理面(设计前 → 当前)
7-71/admin/ai、/user/ai主线仍在。- 已补:Web PAT API + Bearer 中间件 + 管理 UI「API 访问令牌 / 密码箱 AI 访问」。
- PAT 存储当前为部署侧 sealed JSON(
~/.config/mnote/api-access-tokens.json),非 control-plane 表;API 合同满足 7-76。 - Page AI = Pi Lab;外部 AI 默认走 PAT + notes/tree/tools,不含 Pi run scope。
2.3 密码箱(设计前 → 当前)
- 真源仍为 workspace 下
.mnote/vault/**;用户默认落在users/<id>/workspaces/my-space(一人一默认箱路径)。 - share-to-AI / AI vault 路径:12-x 既有能力 +
POST /api/vault/ai/tokenWeb 签发(admin 可代签)。 - 12-2 vaultd /
mnv1读密路径保留。
3. Goals / Non-Goals
3.1 Goals
- 开发 = 生产基线:登录页无快速登录、无测试密码 DOM;需要 seed 时用受控 API / CLI,不走人机后门。
- 正式 AI 主体:
mnote-e2e升级为系统 AI 账号(可配置显示名);自有笔记/知识库/vault;可接收他人 vault 分享;人登录该账号需密码(admin 持有),普通用户无入口。 - Web PAT:用户与 admin 可签发/列表/撤销/复显(受控);scope 白名单;默认服务「外部 AI 笔记 CRUD」而非 Pi 会话劫持。
- 密码箱用户真源:每用户一个 vault 命名空间;share-to-AI 显式授权;admin 可代签 vault token 并全量审计。
- 凭证分职:cookie / Web PAT / vault token / 扩展 token / 上游 provider key 互不冒充。
3.2 Non-Goals
- 不把外部 AI 做成第二套 Page AI 宿主;不替换 Pi Lab。
- 不在本阶段做 OAuth2 完整 AS / 第三方 App 商店。
- 不取消 12-2 本机 vaultd 路径;云端多用户在其之上叠加 owner 与 Web 签发。
- 不做「admin 默认可明文浏览任意用户密码」;break-glass 若需要另开 P2 且强审计。
- 不把 vault 挂进 graph/
tree.*为普通页面节点。
4. 主体与凭证模型
4.1 主体(Principal)
principal_kind |
示例 | 谁用 | 工作区 / 知识库 / vault |
|---|---|---|---|
human |
普通注册用户 | 浏览器人 | 自己的用户空间 |
ai_service |
mnote-e2e(系统 AI 主体) |
外部 AI 以 PAT 操作;人仅 admin 用密码检查 | AI 私有 空间 |
service(可选 P1) |
service:ops |
运维脚本 | 极窄 health/overview,默认无用户笔记 |
AI 主体账号规则:
- 账号标识稳定:
username=mnote-e2e(或system/ai,迁移期保留 e2e 兼容 id)。 - control-plane 标记:
principal_kind=ai_service、is_system=true、login_policy=password_holders_only。 - 禁止 对普通用户暴露「切换到 AI 账号」;禁止公开注册同名。
- 禁止 把 AI 主体密码写进前端 HTML / 文档 / smoke 默认文案(smoke 用 env 或 vault,不进 SSR)。
- 普通用户访问 AI 主体私有资源 →
403 principal_forbidden。 - Admin 检查:用密码登录该账号(或未来 break-glass 代登,P2);UI 上可在
/admin/ai显示「AI 主体状态」,不自动注入密码。 - 禁止 将
mnote-e2e列入MNOTE_ADMIN_USER_IDS或access-policy.json的admins(历史 e2e 方便已废止)。
4.1.1 账户分离(方案 A · 2026-07-26 已落地)
| 账号 | principal / role | admin 能力 | 用途 |
|---|---|---|---|
mnote-admin |
human / admin |
是 | ops:/admin/*、access-policy、代签 PAT/vault、全局 AI policy |
liaibo 等真人 |
human / user |
否 | 个人笔记 / vault / 分享给 AI |
mnote-e2e |
ai_service |
否 | AI 私有工作区与知识库;外部 AI 以 PAT 操作 |
Admin 判定真源(保持兼容):users.role=admin 或 access-policy.admins 或 MNOTE_ADMIN_USER_IDS。
云首发基线:admins=["mnote-admin"] 且 MNOTE_ADMIN_USER_IDS=mnote-admin。
本地 insecure 默认口令仅用于 dev(见 TESTING_REFERENCE);生产 init 必须显式 --password。
4.2 五种凭证(禁止混用)
| 凭证 | 前缀 | 作用 | 持有方 |
|---|---|---|---|
| Session cookie | (httpOnly cookie) | 人用浏览器全站 | 浏览器 |
| Web PAT | mnpat1. |
机机调 mnote-web JSON API | 外部 AI / 脚本 env 或 0600 文件 |
| Vault token | mnv1. |
仅 vault list/get/resolve/login | agent 本地 token 文件 / skill |
| Extension token | mnext1. |
Chrome 扩展写 vault | 扩展;禁止给 agent |
| Provider API Key | 厂商格式 | 调 OpenAI 等 | admin provider 配置;不是登录 MNote |
原则:一种凭证一种职责。
Web PAT 不等于 登录 vault;vault token 不等于 登录 Web;AI 主体密码 不等于 分发给所有用户的万能 key。
5. 生产级鉴权:撤快速登录
5.1 产品行为
| 环境 | 登录页 | 标准邮箱/用户名密码 | /api/dev/seed |
AI 主体密码登录 |
|---|---|---|---|---|
| 生产 | 无快速登录 | 开 | 关 | 仅知密者(admin) |
| 开发(对标生产) | 同样无快速登录 | 开 | 仅当 ALLOW_DEV_FIXTURES=1 的机机 seed |
同生产;本地 admin 自持密码 |
开发调试方式:
- 使用真实注册/登录流程,或本地已知 admin/测试人账号密码(存在密码箱或本地 secret,不进 HTML)。
- 自动化:优先 PAT;次选 control-plane seed API(fixtures 开时);禁止依赖「快速登录」按钮选择器作为唯一 smoke。
5.2 实现落点(P0)
- 删除
AuthPage中测试快速登录按钮、TEST_ACCOUNT_*常量注入 DOM、data-test-password等。 - 清理
AUTH_SCRIPT中 quick-login 分支;表单脚本不得依赖quickLogin节点(避免if (!quickLogin) return整页失效)。 - 更新
gateway.rs/ 相关 SSR 测试:断言 不包含「测试账号快速登录」与测试密码属性。 scripts/TESTING_REFERENCE.md、AGENTS smoke 文案:改为「开发用标准登录或 PAT;fixtures 仅 seed」。- 可选 harden:对
principal_kind=ai_service的密码登录增加审计日志auth.ai_principal.login;rate limit 加强。
5.3 明确不做
- 不把快速登录藏到「连点 logo 十次」之类隐藏手势。
- 不在生产 HTML 注释里保留 e2e 密码。
6. Web PAT(外部 AI 访问合同)
6.1 产品 IA
/user/ai → 导航 「API 访问令牌」(#ai-api-tokens)
用户只管理 自己的 PAT:
- 创建:名称、过期、scope 勾选(白名单)。
- 列表:前缀
mnpat_****abcd、创建/最后使用/过期、状态。 - Reveal(可复显):默认遮罩;用户点击「显示」→ 二次确认(或短时 re-auth)→ 展示明文;操作写审计。
- 撤销 / 改名 / 旋转(rotate = 废旧发新,旧 jti 立即失效)。
- 文案:用于外部 AI、脚本访问 你的 笔记与授权 API;不是 vault 读密 token;不是 Pi 内部会话钥匙。
/admin/ai → 「API 访问令牌」
- 平台级
servicePAT(可选,窄 scope)。 - 代签:选择主体(普通用户 或 AI 主体)→ 生成该
sub的 PAT + 审计。 - 强制撤销任意 PAT、查看元数据与审计。
- 为 AI 主体 预置/轮转「给外部 AI 用的主 PAT」的运营入口(仍走同一表结构)。
6.2 可复显的安全模型(相对「只显示一次」)
用户明确要求 可再显示,因此采用:
创建时:
raw = 高熵随机 或 mnpat1.<payload>.<sig>
token_hash = SHA-256(raw) // 鉴权比对
token_sealed = Seal(server_key, raw) // 可恢复密封(AEAD)
token_prefix = raw 前后缀展示位
明文不进日志
Reveal:
校验 session 为 owner 或 admin 代操作权限
解封 token_sealed → 返回明文一次响应
写 audit: api_token.reveal
鉴权请求:
只比对 token_hash,不走 sealed 热路径
约束:
server_key来自部署密钥(env / 文件 0600),不进库、不进前端。- Reveal 限流(按 user / token_id);列表默认永不自动展开。
- 若部署选择更高安全档(
PAT_REVEAL_MODE=create_only),可编译/配置为创建后清空 sealed —— 默认产品档为 reveal_allowed(符合本拍板)。 - 泄露响应:revoke + 轮转;审计含
jti不含 raw。
6.3 Token 形态与存储
mnpat1.<base64url(payload)>.<base64url(sig)>
# 或 mnpat1_ + 高熵 random(服务端只存 hash + sealed)
Claims(逻辑字段,无论 JWT 形还是 opaque):
{
"v": 1,
"iss": "mnote-web",
"aud": "mnote-api",
"sub": "user:<user_id>",
"principal_kind": "human | ai_service | service",
"scope": ["notes.read", "notes.write", "tree.read", "tree.write"],
"workspace_ids": ["*"],
"jti": "...",
"iat": 0,
"exp": 0
}
control-plane 表 api_access_tokens:
id, jti,
subject_user_id, -- 权限主体
created_by_user_id, -- 签发者(admin 代签可不同于 subject)
name,
token_prefix,
token_hash, -- 鉴权
token_sealed, -- 可复显密封;create_only 模式可空
scopes_json,
workspace_ids_json,
expires_at, revoked_at,
last_used_at, last_reveal_at,
created_at, updated_at
6.4 Scope 白名单(对齐「外部 AI = 笔记 CRUD」)
P0 默认推荐(创建向导默认勾选):
| Scope | 含义 | 外部 AI 默认 |
|---|---|---|
notes.read |
读页面/文件正文与元数据(授权工作区内) | ✓ |
notes.write |
创建/更新/删除笔记正文(授权范围内) | ✓ |
tree.read |
读树/目录投影 | ✓ |
tree.write |
新建/重命名/移动/归档(tree.*) |
✓(可默认关,产品可选) |
ai.settings.read |
读自己的 effective AI 设置 | 可选 |
ai.usage.read |
读用量 | 可选 |
默认不开放(Non-Goals / 需显式高危勾选):
| Scope | 说明 |
|---|---|
ai.sessions.write / pi.run |
不作为外部 AI 主路径;避免外部 agent 驱动内部 Pi |
ai.admin.* |
仅 admin session 或 admin 级 service PAT |
vault.resolve |
不塞进 Web PAT 默认;读密用 mnv1 |
provider.keys.read |
禁止;上游 key 永不经 PAT 下发明文 |
映射实现:
- 优先复用现有
/api/mnote/tools/*与 local-folder / page / tree 路由的 统一鉴权中间件。 - 每个 handler 声明 required scopes;缺 scope → 403,不静默放大。
directory_grants/ membership 仍然生效:PAT 不能绕过文件夹授权。- 写入走既有版本/冲突/watcher 纪律(对齐 7-18);外部 AI 写文件 = 授权 roots 内 patch/write,不是第二套真相。
6.5 鉴权中间件规则
- 请求带
Authorization: Bearer mnpat1…→ 走 PAT;忽略 cookie 叠加(避免权限并集歧义)。 - 仅 cookie → 人用 session(现有行为)。
- 绑定
RequestContext.user_id = subject_user_id,auth_method = pat,附带 scopes。 - AI 主体 PAT:
subject为 AI 用户 id,只能访问 AI 私有空间 + 显式 share 给 AI 的资源。 - 人用户 PAT:只能访问该用户被授权的 workspace 资源。
- HTML SSR 管理页:不以长期 PAT 当 cookie 渲染全站;机机走 JSON。P2 才考虑 exchange code → 短会话。
6.6 调用示例
# 外部 AI:以某用户 PAT 列树 / 读写笔记
curl -H "Authorization: Bearer mnpat1.…" \
https://<host>/api/… # 具体 path 以 tools/tree/page 现网为准
# 外部 AI:以 AI 主体 PAT 写 AI 自己的知识库笔记
curl -H "Authorization: Bearer mnpat1.…" \
https://<host>/api/…
Agent 持有方式:环境变量或 0600 文件(对齐 vault token 习惯);禁止默认写入前端 localStorage。
7. AI 主体:自己的知识库、记录与「被分享的密码」
7.1 AI 私有面
AI 主体拥有与普通用户同构的能力边界,但 默认不对普通用户可见:
| 能力 | 说明 |
|---|---|
| 笔记 / 树 | AI 自己的 workspace(或 system workspace 绑定 AI 主体) |
| 知识库 | LightRAG 命名空间绑定 AI 主体;索引 AI 私有笔记与授权语料 |
| 设置 | /user/ai 在 AI 主体 session 下的 effective 配置;admin 可在 /admin/ai 看全局 |
| Vault | AI 自己的一箱 + 他人 share-to-AI 的只读投影 |
普通用户 不能:
- 打开 AI 主体的 FileTree / 笔记(无 membership)。
- 列出 AI 主体 vault 私有条目。
- 使用 AI 主体密码(除非 admin 运营持有)。
Admin 可以:
- 密码登录 AI 主体做检查(审计)。
- 代签 / 撤销 AI 主体的 Web PAT 与 vault token。
- 在管理面查看 AI 主体健康、用量、token 元数据(默认无 vault 明文)。
7.2 分享密码给 AI(share-to-AI)
用户 U 的 vault 条目 C
→ 用户标记 share_to_ai = true
或 创建 share grant: (item_id, grantee=ai_principal, perms=resolve|list)
→ AI 主体的 vault token / AI 读密路径可见 C
→ 用户 U 的其他条目默认不可见
→ 其他用户 V 不可见 C(除非另有 grant)
隔离验收:
- 用户 A token 不能 resolve 用户 B 私有条目。
- AI token 只能 resolve:AI 自有条目 ∪ 有效 share-to-AI 条目。
- 用户 A 的 Web PAT 默认 不能 resolve 密码;除非错误地签发了 vault scope(产品向导应拆分两步,默认不勾)。
- 撤销 share 或 revoke token 后立即失效。
7.3 与 Page AI(Pi)的边界
| 角色 | 职责 |
|---|---|
| Pi Lab(内部) | 浏览器内 Page AI;cookie + directory_grants;不依赖外部 PAT |
| 外部 AI(Paseo/Codex/…) | 持用户或 AI 主体 PAT,做 笔记/树 CRUD;可选另持 vault token 读密 |
| 禁止默认 | 外部 AI 用 PAT 驱动 /api/page-ai/pi/* 代聊、劫持内部 session |
若未来需要「外部系统触发一次 Pi run」,单独立项高危 scope,不进 7-76 P0 默认。
8. 密码箱:一人一箱 + 代签
8.1 真源模型(升级 12-1)
产品口径(冻结):密码箱跟随用户,一个用户只有一个密码箱。
推荐存储解析:
# 逻辑
VaultRoot(user_id) → 用户私有系统目录
# 物理(云 / 多用户服务器,推荐)
{control_or_data_root}/users/<user_id>/vault/**
# 物理(单机 local-first 兼容)
若部署仅有单用户绑定默认 workspace:
可仍落在该用户默认 workspace 的 .mnote/vault/**
但元数据必须带 owner_user_id,且 API 按 user_id 解析,禁止「同事共享 workspace 就共享密码箱」
禁止:
- 多个 human 共用一个无 owner 的 workspace vault 当默认。
- Agent 用通用 file 工具扫任意 vault 路径。
- 默认 actor 写死所有人共用
mnote-e2e而不校验 owner(开发本机单用户过渡期除外,须文档标明)。
条目 frontmatter / index 强制:
ownerUserId: <user_id>
shareToAi: bool | grant refs
旧数据迁移:
- 缺
ownerUserId→ 归属「当前 workspace 的 owner 用户」或部署配置的MNOTE_VAULT_LEGACY_OWNER;迁移完成前,非 owner deny。
8.2 Vault token claims 升级
在 12-2 VaultTokenClaims 上强制:
{
"v": 1,
"iss": "mnote-vault",
"aud": "mnote-vault",
"sub": "user:<user_id>",
"actor": "user:<user_id>",
"principal_kind": "human | ai_service",
"scope": ["vault.list", "vault.get", "vault.resolve"],
"item_ids": [],
"include_shared_to_ai": true,
"workspace": null,
"iat": 0,
"exp": 0,
"jti": "..."
}
item_ids非空 = 白名单;空 = 该主体命名空间内策略允许的全部(仍受 share 与总闸)。- AI 主体 token:
include_shared_to_ai=true时合并分享投影。 - Admin 代签:
created_by记 admin;sub仍是目标用户或 AI 主体;必须审计vault_token.issue.delegated。
8.3 签发入口(同一后端)
| 入口 | 谁 | 能力 |
|---|---|---|
/vault →「AI 访问」 |
用户 | 管自己的条目可见性、签发/撤销自己的 vault token |
/user/ai →「密码箱 AI 访问」 |
用户 | 总闸、复制 token、测 doctor;深链避免双真源 |
/admin/ai →「密码箱治理」 |
Admin | 代签、强制撤销、元数据与审计;默认不 reveal 用户密码明文 |
总闸:
user.settings.vault_ai_access = off | resolve_only | resolve_and_login
总闸 off → 既有 token verify 失败或签发拒绝。
8.4 与 Web PAT 的关系(再强调)
| 需求 | 钥匙 |
|---|---|
| 外部 AI 增删读写用户笔记 | Web PAT(用户 sub) |
| 外部 AI 写 AI 自己的笔记/知识库 | Web PAT(AI 主体 sub) |
| 外部 AI / skill 读密 | Vault token mnv1(对应用户或 AI 主体) |
人打开 /vault 编辑 |
Session cookie |
| 扩展保存密码 | mnext1 |
创建向导默认 两步拆分:「笔记 API 令牌」与「密码箱令牌」,禁止一键「全能钥匙」无 scope 确认。
9. 信息架构汇总
/user/ai 侧栏
- Overview(已有)
- Models / Tools / Skills(effective)
- 目录权限(directory_grants,唯一授权真源)
- API 访问令牌(Web PAT,可复显)
- 密码箱 AI 访问(vault token + 总闸 + share 摘要)
- Sessions / Usage(人用 Pi;外部 AI 不依赖此写路径)
/admin/ai 侧栏
- 全局 provider / model / policy(7-71)
- API 访问令牌(平台 + 代签 + AI 主体 PAT)
- 密码箱治理(代签 vault token / 强制撤销 / 审计)
- AI 主体(状态、是否可登录、最近登录审计、知识库/工作区绑定)
- 环境健康只读:快速登录已移除、fixtures 开关状态、PAT reveal 模式
/auth
- 仅标准登录/注册。
- 无测试快速登录、无测试密码 DOM。
/vault
- 按 当前登录用户 的唯一密码箱工作。
- 条目:允许 AI 使用 / 分享给 AI。
- AI 访问令牌入口深链到
/user/ai#vault-ai-access。
10. 分阶段落地
| 阶段 | 内容 | 验收要点 | 状态(2026-07-26 核验) |
|---|---|---|---|
| P0 | 删除快速登录 + 修脚本/测试/文档;AI 主体字段标记最小落库 | 任意环境 HTML 无测试密码;标准登录可用 | done |
| P0.5 | PAT API + Bearer 中间件 + /user/ai·/admin/ai PAT UI(sealed 复显) |
外部 AI 用 PAT 完成 notes/tree 读写 | done(代码+单测;端到端 smoke 建议补) |
| P1 | 用户级 vault 路径 + share-to-AI + vault 区 | A 不能读 B;AI 能读 share | done(主路径):复用 users/<id>/… + 12-x share-to-AI;Web 签发 vault token |
| P1b | Admin 代签 PAT/vault token、撤销、审计;AI 主体运营 | 代签有 created_by 审计 |
done |
| P2 | PAT exchange 短会话、break-glass、service 细粒度、PAT_REVEAL_MODE=create_only |
高级场景 | deferred |
实现顺序回顾: P0 → P0.5 → P1/P1b 已合入主工作区;P2 不阻塞产品主路径。
11. 安全边界清单
- 凭证分职,禁止用 vault token 调笔记 API 或用 PAT 当 master key。
- PAT 与 cookie 不同时并权。
- Scope 白名单 + handler 强制;默认不含 Pi 写入。
- directory_grants / membership 不可绕过。
- PAT reveal 可审计、限流;日志无 raw token。
- AI 主体私有资源对普通用户 403。
- share-to-AI 显式;撤销即时。
- Admin 代签全审计;默认不 reveal 他人 vault 明文。
- 扩展 token 禁止进 agent。
- 开发对标生产:无登录页后门。
12. 测试与验收
勾选口径:[x] = 代码已实现且本轮有单测/静态核验证据;未勾选 = 未做独立 e2e 或仅结构依赖、需后续补测。
核验日:2026-07-26。证据:auth.rs/api_access_token.rs/middleware/request_context.rs/ai_adminUI /cargo test -p mnote-web --lib定向套件。
12.1 P0 鉴权
/authHTML 不含「测试账号快速登录」、data-test-password、硬编码 e2e 密码属性。- 标准注册/登录仍可用(
auth_api_*单测通过)。 ALLOW_DEV_FIXTURES=0时/api/dev/seed403(既有 fail-closed 保留)。- 相关单元/SSR 测试已改断言(
auth_entry_uses_mnote_web_login_ui_when_compat_enabled)。
12.2 Web PAT
- 用户可创建/列表/撤销/复显自己的 PAT(
/api/ai-tokens*+ UI)。 - Bearer 可
notes.read/write(及 tree scope):middleware + documents/tree/toolsensure_scope。 - 缺 scope 403(
ensure_scope_session_passes_pat_requires单测)。 - 用户 A 的 PAT 不能写用户 B 的私有笔记(结构上仍受 directory_grants/membership;无独立 PAT 跨用户 e2e)。
- AI 主体 PAT 不能读普通用户未授权笔记(同上,依赖 grants,无独立 e2e)。
- 默认不能调用 Pi run API(PAT scope 白名单不含 Pi;无
pi.run)。 - reveal 产生审计(
api_token.reveal)+ 30s 限流生效(代码路径)。
12.3 Vault 多用户
- 每用户一箱路径解析:
users/<id>/workspaces/my-space+ AI vault 路径(12-x / vault-core)。 - owner mismatch → deny(share 模型与路径隔离已有;全量 owner 字段强制校验未单独立项闭环)。
- share-to-AI 后 AI resolve / 取消分享:12-x vault-core share/unshare 能力与单测保留。
- Admin 代签 vault token 有审计(
POST /api/vault/ai/token+vault_token.issue(.delegated))。 - 通用 file/RAG 仍排除 vault(12-1 既有门闩,本轮未回退)。
12.4 AI 主体
mnote-e2e注册标记role=ai_service;/api/ai-admin/users返回principalKind。- 普通用户 session 无法打开 AI 主体工作区(依赖 membership/默认私有 workspace;无专用 403 e2e)。
- Admin 密码登录 AI 主体成功且有专用审计事件(通用登录可用;未单独埋
auth.ai_principal.logine2e)。 - AI 知识库命名空间隔离冒烟(未做本轮专项 smoke)。
12.5 残留 / 下一步(不回退已勾选)
- 补 PAT 跨用户拒绝 e2e(A token → B 笔记 403)。
- 补 AI 主体工作区拒绝 / 知识库隔离浏览器 smoke。
- 可选:PAT 迁 control-plane 表;AI 主体专用登录审计。
- P2 整包延后。
- 零散脚本:
scripts/test-handle-qa.js已改为标准登录(本轮核验时修正)。
13. 与现有设计的衔接 / 覆盖关系
| 文档 | 关系 |
|---|---|
| 7-71 | 在 effective AI 配置之上增加 Token / AI 主体运营区段;不另起第二套 provider 真相。 |
| 7-18 | 外部 AI 写笔记仍受 AiAccessScope / allowed roots / 冲突模型约束;本设计补 谁持何种凭证进入。 |
| 12-1 | 工作台 UI 保留;存储归属从 workspace 单库升级为 用户一箱(本文 §8 为增量合同)。 |
| 12-2 | vaultd + mnv1 路径保留;claims 强制 user/AI owner;Web 代签与多用户 verify 为增量。 |
| 12-3 | mnext1 仍仅扩展;不与 PAT/mnv1 合并。 |
| AGENTS / TESTING_REFERENCE | 删除「优先测试账号快速登录」作为生产或默认真路径的表述。 |
后续若 vault 用户根路径实现细节膨胀,可再拆 12-4-user-scoped-vault-and-share-to-ai-v1.md,但 产品口径以本文为 SSOT,避免双源。
14. 开放实现细节(不阻塞 P0)
- AI 主体 username 是否长期保留
mnote-e2e字符串,或迁移为system-ai(兼容 id 映射)。 VaultRoot物理根:control-plane data dir vs 用户私有默认 workspace —— 实现选一种并写迁移脚本。- Web PAT 用 opaque+hash 还是可验证 signed payload —— 两者均可,表结构已支持。
- 外部笔记 CRUD 优先挂现有
mnote_agent_tools还是一组更窄的 REST 资源路由 —— 建议 先中间件 + 现有 tools/tree/page,少造表面。
15. 建议 PR 切片
| PR | 内容 | 风险 |
|---|---|---|
| PR-A | 删除快速登录 + 测试/文档 | 低;立刻降公网面 |
| PR-B | api_access_tokens schema + middleware + 单测 |
中 |
| PR-C | /user/ai PAT UI(创建/列表/撤销/reveal) |
中 |
| PR-D | notes/tree 路由 scope 接线 + 外部 AI smoke | 中 |
| PR-E | 用户级 vault root + owner + share-to-AI | 高(数据迁移) |
| PR-F | admin 代签 + AI 主体运营 + 审计 | 中 |
16. 完成定义(Definition of Done)
当下列全部成立时,本稿可迁 done/:
| # | 条件 | 状态 |
|---|---|---|
| 1 | 登录页无快速登录后门,开发/生产行为一致 | 满足(P0) |
| 2 | 外部 AI 可仅凭 Web PAT 在授权范围内笔记 CRUD,无需 cookie/Pi | 代码满足;建议补浏览器/API smoke |
| 3 | AI 主体隔离笔记/知识库,仅密码持有者可人登检查 | 部分满足(角色标记+默认 workspace;缺专用 e2e) |
| 4 | 密码箱用户隔离 + share-to-AI;vault token 与 PAT 分职 | 主路径满足 |
| 5 | Admin 代签与 reveal/revoke 有审计;文档与 smoke 一致 | 满足(残留见 §12.5) |
结论: 不迁 done/ 直至 §12 未勾选项(跨用户 e2e / AI 主体工作区 / KB 隔离 smoke)补齐或明确降级为 follow-up。P0–P1b 产品主路径可按 PROCESS 继续使用。
17. 变更记录
| 日期 | 说明 |
|---|---|
| 2026-07-26 | 初版:吸收 Paseo 28e19bd9-… 讨论与用户六条拍板;落盘 7-76。 |
| 2026-07-26 | 执行:P0–P1b 落地(见 7-76-execution-goal-v1.md);P2 延后。 |
| 2026-07-26 | 核验并勾选 §10/§12 已完成项;修正 test-handle-qa.js 残留快速登录;§12.5 记录残留。 |