33 KiB
title, date, type, status, content_status, owner, last_updated_at, last_updated_by, hash, hash_scope, belongs_to, depends_knowledge, source_refs
Gitea知识库 v1.1 技术栈与详细实施设计
1. 结论
本项目可以确定技术栈并拆解到可下发的开发与实施步骤。推荐采用“一个模块化 Go 代码库、两个运行角色、一个 PostgreSQL 控制数据底座、一个独立 Gitea、一个远程 MCP 用户入口”的方案:
Agent Host
→ 飞书 OAuth 登录
→ 远程 MCP Gateway
→ Identity/AuthZ/Audit 中间件
→ Read / Build / Validate / Release 业务模块
→ Gitea 私有项目仓库
→ 不可变 release + 唯一 current
本方案不建设自定义业务 Web 页面。HTTP 仅用于 MCP transport、OAuth 协议回调、健康检查和内部运维端点,不提供发布驾驶舱、权限后台或审计后台。
Agent 产品不进入业务核心。Codex、Claude Code(本文把用户所称 CC 按 Claude Code 记录)和后续 Agent 都通过统一兼容层调用同一个远程 MCP;服务端只信任标准 OAuth、框架确认凭证和受控 Selection Manifest,不信任具体 Agent 的品牌或模型声明。若 CC 实际指其他客户端,只新增适配器,不改变核心方案。
2. 推荐技术栈
| 层 | 确定方案 | 当前基线 | 选择理由 | 明确不采用 |
|---|---|---|---|---|
| 服务端语言 | Go | Go 1.26.x,构建时固定最新安全补丁 | 官方 MCP SDK、标准库 HTTP、单二进制、并发和部署边界清晰 | 首期不做多语言服务 |
| MCP SDK | 官方 Go SDK | modelcontextprotocol/go-sdk v1.7.x,依赖锁定 |
已覆盖 Streamable HTTP、Bearer auth 和 2026-07-28 协议 | 不使用非官方协议实现 |
| MCP 协议 | 当前协议+兼容协商 | 目标 2026-07-28,兼容 2025-11-25 |
当前协议已无服务端会话,便于多实例;兼容尚未升级的 Agent Host | 不新增旧 HTTP+SSE 实现 |
| OAuth 授权服务器 | 成熟 OAuth/OIDC Authorization Server+飞书身份联邦 | 产品在 C1-04 前锁定;必须支持 PKCE、PRM、resource/audience、撤销和逐请求校验 | 飞书完成员工认证,授权服务器完成 MCP 客户端协议与令牌生命周期 | 不在 contextd 内从零自研密码学、客户端注册和令牌签发体系 |
| HTTP 层 | Go net/http |
标准库 ServeMux 和中间件 |
只需协议端点,无业务页面,无须 Web 框架 | 不引入前端、SSR、模板和 Web 管理系统 |
| 主数据存储 | PostgreSQL | PostgreSQL 18.x,部署时锁定最新小版本 | 同时支撑身份、权限、release、幂等、outbox、审计和全文索引 | 首期不引入 MySQL、MongoDB |
| SQL 访问 | pgx/v5+sqlc |
锁定版本 | 显式 SQL、类型生成、事务边界可审查 | 不用隐藏 SQL/权限条件的重型 ORM |
| 数据迁移 | goose |
锁定版本,迁移只走运维身份 | 简单、可版本化、可回滚说明 | 不允许 Agent/MCP 执行迁移 |
| Gitea | 自建 Gitea | 1.26.x 支持分支,G0 时复核最新安全补丁 | 项目权限、私仓、分支保护和 Git 历史真源 | 不把 Gitea Admin 暴露给 Agent |
| Git 写入 | 系统 Git CLI | 固定最低版本,临时 worktree+HTTPS | 多文件单 commit 和标准 non-fast-forward/CAS 语义成熟 | 不开放通用 Git tool;不把 token 放命令行或日志 |
| Markdown | Go AST 解析器 | goldmark+自有规范化层 |
可确定性解析标题、链接和正文 | 不用 LLM 生成确定性发布物 |
| Schema | JSON Schema 2020-12 | schema+合法/非法样例 | 与 v1/v1.1 契约包一致 | 不用仅靠 Go struct 代替外部契约 |
| 搜索 | PostgreSQL pg_trgm+元数据过滤 |
规范化正文、标题、标签、路径;只索引授权项目的 current | 中文不依赖空格分词,首期可获得可预测的子串/相似度检索并保持项目隔离 | 首期不把原生英文 FTS 当中文主检索,也不引入 Elasticsearch/向量数据库 |
| 异步任务 | PostgreSQL outbox worker | 同一代码库、独立 worker 运行角色 | 保证业务状态与事件一致,减少基础设施 | 首期不引入 Kafka/RabbitMQ |
| 审计 | PostgreSQL 独立 schema/角色 | append-only、事件 hash、每日签名 checkpoint | 查询和完整性验证可落地 | 不把普通日志当审计真源 |
| 可观测 | OpenTelemetry | OTLP 输出到公司既有监控 | 不绑定具体监控产品 | 审计正文和 token 不进入 telemetry |
| 测试 | go test+Testcontainers |
fake Feishu/Gitea+临时 PostgreSQL | 默认离线、可重复、正反用例统一 | 普通 CI 不连接生产环境 |
| 打包 | OCI 镜像 | 多阶段构建、固定 digest、SBOM | 可复现、便于测试环境部署 | 首期不要求 Kubernetes |
2.1 为什么选择 Go 而不是 Web 技术栈
- 当前产品没有自定义页面,主要工作是协议接入、身份、权限、事务、文件构建、Git 和审计。
- 官方 Go MCP SDK 可以直接挂在
net/http,不需要业务 Web 框架。 - 一个代码库可编译成同一镜像的
serve和worker两个运行角色,减少微服务和跨语言维护成本。 - Go 的标准库、显式错误和静态类型适合安全门、状态机和可审查中间件。
若现有开发团队不能维护 Go,TypeScript 可以作为替代语言,但必须重新确认 SDK 版本、运行时、依赖供应链和部署基线;不能在编码中途混用两套主栈。
3. 部署拓扑与进程边界
flowchart LR
U[飞书用户] --> C[Codex / Claude Code / Other Agent]
C --> H[Agent Compatibility Layer]
H --> A[OAuth Authorization Server]
A -->|Feishu federation| F[飞书 OAuth]
A -->|Per-user OAuth bearer| P[Reverse Proxy]
P --> M[contextd serve]
M --> DB[(PostgreSQL)]
M --> R[Current Reader]
M --> O[Outbox]
O --> W[contextd worker]
W --> G[Gitea 1.26.x]
W --> FS[Immutable Releases/current]
W --> DB
M --> OT[OTel Collector]
W --> OT
| 运行角色 | 面向谁 | 允许能力 | 禁止能力 |
|---|---|---|---|
contextd serve |
Agent Host | OAuth/MCP、身份、授权、读取、构建请求、发布请求、审计查询 | 不持有 Gitea 写 token,不执行部署/备份/迁移 |
contextd worker |
内部 outbox | 构建、检查、Git commit/push、导出、读回、审计完成事件 | 不接受用户网络请求,不具有 Gitea Admin |
migrator |
受控运维任务 | 数据库迁移 | 不作为常驻服务,不可由 MCP 调用 |
audit-reader |
授权审计查询 | 脱敏 select/view | 无 insert/update/delete |
backup/restore |
受控运维任务 | 备份和隔离恢复 | 不作为普通 Agent 工具 |
首期采用模块化单体代码库,不拆成身份、权限、发布和审计微服务。serve/worker 的运行身份和凭据分离,但共享领域契约和代码版本。
4. 协议端点而非 Web 页面
| 路径/能力 | 用途 | 可见范围 |
|---|---|---|
POST /mcp |
远程 Streamable HTTP MCP | Agent Host |
/.well-known/oauth-protected-resource |
MCP Protected Resource Metadata | Agent Host |
| OAuth metadata/authorize/token/revoke | MCP 客户端授权与撤销 | Agent Host/OAuth Authorization Server |
/oauth/feishu/callback |
飞书授权码回调 | 飞书 OAuth 浏览器跳转 |
/health/live、/health/ready |
存活与依赖健康 | 内部探针 |
/metrics 或 OTLP |
指标/trace 输出 | 内网监控 |
这些均是机器协议端点。项目不实现 HTML 页面、导航、表单、角色后台和审计后台。
2026-07-28 连接使用 stateless Streamable HTTP;内部 AgentSession 是应用身份对象,不是 MCP transport session。/mcp 必须验证 Origin/Host、协议 header 与 body 一致性、Content-Type、请求大小、超时和 bearer resource;旧协议兼容只通过官方 SDK 协商,不自行维护两套业务逻辑。
5. Agent 无关的兼容层契约
5.1 架构判断
Agent 品牌与模型能力不是业务权限依据,因此不需要把 Codex、Claude Code 或其他 Agent 写进发布、权限和审计核心。Agent 的差异只影响:MCP 配置方式、OAuth callback、工具确认事件和本地文件读取适配。
当前官方能力证明 Codex 和 Claude Code 都能连接远程 Streamable HTTP MCP 并完成 OAuth。Codex 还提供 MCP server/tool approval 配置,Claude Code 提供 MCP permission ask/allow/deny 和企业 managed MCP 配置。这些客户端能力用于交互和部署,但服务端仍必须逐次验证 token、权限和确认。
5.2 Verlit 已确认的接入条件
| 条件 | 当前结论 | 设计处理 |
|---|---|---|
| Agent 选择 | 框架自行兼容,优先 Codex、Claude Code | Agent adapter 可插拔,业务工具 schema 保持一致 |
| MCP 连接 | 每位用户独立连接同一远程 MCP | 每人独立 OAuth token、AgentSession 和审计主体 |
| OAuth | 必须完成 OAuth | MCP resource server+成熟授权服务器+飞书 Authorization Code/PKCE 身份联邦 |
| 人类确认 | 框架支持 | A3/A4 使用框架签发的一次性 confirmation_id |
| 本地文件 | 可以读取并传输,但必须受控 | 采用下述 Local Source Gate,不允许 Agent 自由扫描或上传 |
这四项已经从“待提供信息”转为“已确认架构约束”。C1-00 仍需对 Codex、Claude Code 的实际版本做契约测试,但它是适配验收,不再决定核心架构是否成立。
5.3 兼容层最小接口
每个 Agent adapter 只负责:
- 注册远程 MCP endpoint 和支持的协议版本。
- 发起逐用户 OAuth,并安全保存/刷新该用户的 MCP 凭据。
- 将
client_kind、client_version、adapter_version和本地 session 绑定到 AgentSession。 - 在 A3/A4 前展示固定的 project、action、candidate hash、
base_current和 diff 摘要。 - 只有真实用户完成确认后,向框架确认服务换取一次性
confirmation_id。 - 将用户明确选择的本地内容经过 Local Source Gate 后调用 MCP。
Codex/Claude Code 自带的 tool prompt 是第一层交互保护,但不直接成为发布授权真源;服务端只接受框架确认服务签发、与精确请求 hash 绑定的一次性凭证。
5.4 Local Source Gate:本地文件传输控制
用户明确选择路径/章节
→ adapter 解析真实路径
→ 允许根、类型、大小、隐藏/控制文件检查
→ 本地 secret/PII/路径预检查
→ 展示文件数、相对路径、大小和 hash 供用户确认
→ 生成不可变 Selection Manifest
→ 通过 MCP 分块传输选中内容
→ 服务端复算 hash、再做完整 validation
强制规则:
- 允许根由框架/企业配置确定,Agent 和正文不能修改。
- 不递归扫描未选择目录;不允许工作区外路径、符号链接逃逸、
.git、凭据目录、隐藏控制文件和未允许二进制。 - 只传相对 source label、内容、大小和 hash,不传个人绝对路径。
- 默认只允许 Markdown;附件使用类型 allowlist、单文件上限和 bundle 总上限。
- 工具参数和传输正文不进入普通日志;审计只保存 selection ID、文件数、字节数、规则结果和 hash。
- 客户端预检查不是最终放行依据;服务端必须重新执行路径语义、secret/PII、链接和内容策略检查。
- 任何分块缺失、hash 不一致、用户取消、会话变化或超时都废弃整个 selection,不做部分发布。
- 临时缓冲区使用独立目录、最小权限和完成后清理;不得成为 Agent 后续默认检索面。
Local Source Gate 可以由 Verlit 的兼容框架统一实现,Codex 和 Claude Code 只提供文件读取能力。这样 Agent 可替换,而本地数据控制保持一致。
6. 飞书登录与 MCP 会话
6.1 推荐身份模型
- 内部
user_id是唯一长期主体,不直接采用邮箱、手机号、姓名或 Gitea username 作为主键。 FeishuBinding保存tenant_key、当前应用的open_id,在权限允许时同时保存租户内user_id;外部 ID 变化或应用迁移通过绑定版本处理。GiteaBinding保存 Gitea 数字用户 ID、username 和绑定状态。- 飞书 user token 只用于登录时取得身份,不作为 MCP token,不透传给 Gitea。
6.2 登录流程
Agent Host 请求 /mcp
→ 401 + Protected Resource Metadata
→ Host 进入 OAuth Authorization Code + PKCE
→ OAuth Authorization Server 重定向飞书授权页
→ 飞书 callback 返回一次性 code
→ 身份联邦适配器换取 user_access_token 并读取稳定用户 ID
→ 查找内部 UserIdentity、FeishuBinding 和预配置 GiteaBinding
→ 校验用户/绑定状态
→ 授权服务器签发短期 MCP access token
→ Host 携带 token 调用 /mcp
6.3 Token 规则
- access token 由成熟授权服务器签发;可采用短期签名 JWT 或可内省的 opaque token,但必须校验 issuer、audience/resource、scope、client、expiry 和撤销状态。
- 若采用 opaque token,随机强度至少 256 bit,业务数据库只保存不可逆 hash;若采用 JWT,业务数据库不落原始 token,撤权仍通过会话和权限版本即时生效。
- 建议 access token 15 分钟、refresh/session 8 小时;最终值在 C1 安全评审确认。
- token 绑定
user_id、Agent Host client、MCP resource、scope、permission version 和 expiry。 - 每次工具调用重新检查用户、绑定、AgentSession 和权限版本;撤权不等待 token 自然到期。
- Feishu、MCP 和 Gitea token 三者永不复用或互相透传。
6.4 首次登录与飞书—Gitea 绑定
- 首次飞书登录只证明“这个人是谁”,不会根据用户输入的 Gitea username 自动授予项目权限。
- v1.1 试点采用受控预配置:治理人员把
tenant_key+飞书稳定 ID与 Gitea 数字用户 ID 建立待激活映射,并同时配置 ProjectGrant;该动作走迁移/受控运维流程,不暴露为普通 MCP tool。 - 用户首次登录时只激活已存在且唯一匹配的映射;未配置、重复、停用或不一致时进入
binding_pending/denied,只允许读取本人身份与处理提示,不能列出或读取项目。 - Gitea 绑定必须以 Gitea 数字用户 ID 为真源,username 只用于展示;后续若建设自助绑定,必须通过 Gitea OAuth/一次性所有权验证另行评审,不能用“用户自行填写账号名”替代。
- 项目授权和解绑同样不暴露为普通 MCP 写工具。撤销 FeishuBinding、GiteaBinding、ProjectGrant 或 AgentSession 任一项,下一次调用立即拒绝并写审计事件。
7. PostgreSQL 数据模型
7.1 身份与授权
| 表 | 核心字段 | 约束 |
|---|---|---|
user_identities |
internal user ID、status、display name | 显示名变化不改主键 |
feishu_bindings |
tenant、open/user ID、user ID、status、version | tenant+外部 ID 唯一;不保存明文 token |
gitea_bindings |
Gitea numeric ID、username、user ID、status | Gitea numeric ID 唯一 |
projects |
project ID、repo mapping、sensitivity、status | repo mapping 受保护 |
project_grants |
user、project、role、actions、expiry、version | 第一层权限真源 |
agent_sessions |
session、user、agent/client、scope、expiry | 短期,可撤销 |
mcp_tokens |
token hash、session、resource、scope、expiry | 不保存明文 bearer token |
confirmations |
user/session、tool、project、request hash、expiry | 一次性,不能跨 hash 复用 |
7.2 发布与读取
| 表 | 作用 |
|---|---|
selections |
不可变选择范围、来源 revision 和 hash |
artifacts |
artifact manifest、bundle hash、builder version |
validation_reports |
policy version、finding、结果和例外引用 |
release_records |
release 状态、幂等键、base_current、commit/readback |
current_versions |
每项目唯一有效 current 和版本引用 |
current_search_documents |
仅 current 的 project-scoped 规范化检索文档与 trigram 索引 |
7.3 审计与可靠任务
| 表 | 作用与权限 |
|---|---|
outbox_events |
业务事务内写入待执行/待投递事件;worker claim |
audit_events |
追加写三主体事件;运行角色无 update/delete |
audit_checkpoints |
按日/分区保存事件链摘要和签名引用 |
数据库至少使用 runtime、worker、audit_writer、audit_reader、migrator、backup 六类角色。运行时不得拥有迁移、审计删除或任意 schema 权限。
当前版本不创建 skills、skill_reviews 或 skill_registry 表;它们属于独立后续版本。
8. 双层权限算法
每次工具调用按固定顺序执行:
Bearer token 有效
∩ UserIdentity active
∩ FeishuBinding active
∩ AgentSession active and bound to client
∩ ProjectGrant allows action/resource
∩ Project/sensitivity/policy allows
∩ GiteaBinding active
∩ Gitea confirms current project permission
∩ exact Confirmation valid when A3/A4
- 服务端不读取工具参数中的
user_id、role、grant、session 作为权威数据。 - 首期每次项目访问实时查询 Gitea 权限,不使用允许结果的长期缓存;Gitea 不可用时 fail closed。
- 后续只有在撤权失效机制验证后,才可增加短 TTL 缓存。
- Gitea 权限查询使用独立 read-scoped 服务凭据;发布写入使用独立 project-scoped 网关凭据。
- 用户本人不需要向 Agent 提供 Gitea token。
9. MCP 工具实现分组
9.1 第一批:身份与只读
get_my_identitylist_authorized_projectsget_my_project_rolesget_current_manifestread_artifactsearch_currentverify_release_hash
9.2 第二批:选择、构建与检查
create_selectionappend_selection_content(仅在 Host 需分块传输时)build_previewvalidate_release_requestpreview_release_diff
Markdown 内容通过 MCP 加密传输,但不得进入访问日志和审计正文;审计仅记录内容 hash、大小、文件数和脱敏标签。首期设置单文件和 bundle 大小上限,超限时停止,不自动改走通用上传接口。
9.3 第三批:受控发布
submit_discussion_releasesubmit_confirmed_releaseget_release_statuscancel_precommit_release
A3/A4 请求必须引用一次性 confirmation_id,并绑定 tool、user、session、project、candidate hash、base_current 和过期时间。Host 不能提供可靠确认时不注册提交工具。
9.4 第四批:审计查询
list_my_actionsget_action_detailtrace_releasetrace_correlationlist_project_audit_eventsverify_audit_event
审计生成不是 MCP tool;它由服务端中间件和业务事务自动完成。
10. 强制审计实现
10.1 每次调用顺序
解析 bearer/token context
→ 持久化 request_received
→ 身份、双层权限、策略和确认判断
→ 持久化 allowed/denied
→ 执行业务逻辑或 outbox 任务
→ postcheck/readback
→ 持久化 completed/failed
→ 返回 MCP 结果
10.2 可靠性
request_received无法持久化时拒绝工具调用。- 发布等写动作与 outbox 在同一个 PostgreSQL 事务提交。
- worker 使用
FOR UPDATE SKIP LOCKED/等价机制 claim 任务,按幂等键重复安全执行。 - completed 只有在 Git、current、MCP readback 和审计结果均落盘后产生。
- 每个事件记录 human、agent、service、session、tool、action、project、request hash、policy、authorization、confirmation、result 和 correlation。
audit_events使用 canonical JSON hash;每日产生签名 checkpoint 并进入备份,便于发现离线篡改。
11. Gitea 发布与 current
11.1 Gitea 权限
- 每个项目一个私有 Context 仓库。
- 普通成员按项目获得 Code Read;无需 Write。
- 只有
publish-gateway:<project>可写受保护main。 - Gitea Admin、组织 Owner 和仓库 Settings 权限不进入 MCP 工具。
11.2 发布事务
- worker 读取服务端 policy、validation、confirmation、幂等和
base_current。 - 使用临时 worktree 获取指定
main,再次校验远端 commit 与base_current。 - 生成完整新
current/,不在服务目录逐文件修改。 - 创建单一 Git commit,记录 release ID、human、agent、service 和 manifest hash。
- 非 force push 到受保护
main;non-fast-forward 返回STALE_BASE。 - 从该 commit 构建不可变
releases/<release-id>/。 - 校验 manifest/checksum 后原子切换唯一 current。
- 通过 MCP 内部读取路径执行 readback;一致后才 completed。
11.3 Search 索引
current 切换时为新 release 生成规范化检索文档和 PostgreSQL pg_trgm GIN/GiST 索引,以 project_id+release_id 为版本键;标题、标签、相对路径和正文分别保留权重字段。切换 current 与索引激活必须保持同一版本。查询先鉴权、再限定 project、最后执行精确匹配、前缀/子串与 trigram 相似度排序,不跨项目检索后在模型端过滤。
原生 PostgreSQL FTS 可作为英文或明确分词语料的补充,但不作为 v1.1 中文主检索。只有基准测试证明 pg_trgm 无法满足真实规模和相关性时,才评审中文分词扩展或外部检索服务。
12. 代码仓库结构
context-platform/
├─ cmd/contextd/
├─ contracts/
│ ├─ v1/
│ └─ v1.1/
├─ internal/
│ ├─ domain/
│ ├─ identity/
│ ├─ authorization/
│ ├─ mcpserver/
│ ├─ selection/
│ ├─ builder/
│ ├─ validation/
│ ├─ release/
│ ├─ gitea/
│ ├─ current/
│ ├─ search/
│ ├─ audit/
│ └─ observability/
├─ migrations/
├─ config/
├─ tests/
│ ├─ contract/
│ ├─ integration/
│ ├─ security/
│ └─ fixtures/
├─ deploy/
└─ docs/
同一镜像通过子命令运行:
contextd serve
contextd worker
contextd migrate # 仅运维任务
contextd verify # 离线配置/契约自检
13. C1 代码开发执行顺序
| WP | 工作包 | 主要动作 | 交付物 | 通过门 |
|---|---|---|---|---|
| C1-00 | Agent adapter 契约测试 | 分别用 Codex、Claude Code adapter+fake OAuth/MCP 验证逐用户 token、协议、框架确认和 Local Source Gate | 通用 adapter contract、两份兼容性报告 | 两个客户端通过同一 schema;不接真实业务数据 |
| C1-01 | 工程基线 | 创建代码仓库、Go module、依赖锁、CI、秘密扫描、制品规则 | 仓库骨架、构建命令 | 离线 build/test 通过,无真实配置 |
| C1-02 | 契约与领域 | 落地 v1/v1.1 schema、状态机、ID、错误和样例 | contracts、domain tests | CT/UT 通过,未知 major/状态拒绝 |
| C1-03 | PostgreSQL 与迁移 | 表、索引、约束、DB roles、迁移和测试库 | migration、sqlc、repository ports | 回滚说明、最小权限和并发测试通过 |
| C1-04 | 身份与 OAuth | 选定成熟授权服务器,接入 fake Feishu、binding、token/session、PRM/auth metadata | identity federation adapter、auth middleware | 参数冒充、未预配绑定和撤权后访问均拒绝 |
| C1-05 | 双层授权 | ProjectGrant、Gitea permission port、policy 和确认 | authorization engine、fake Gitea | M01~M04、M07 通过 |
| C1-06 | MCP 与审计骨架 | Streamable HTTP、工具 registry、三主体中间件、outbox | serve/worker、audit events | M05、M08~M10 通过 |
| C1-07 | current 读取与搜索 | manifest/read/search/hash verify、project filter | 第一批 MCP 工具 | 未授权、跨项目和历史读取均失败 |
| C1-08 | Selection/Build/Validate | 实现 Local Source Gate、分块传输、规范化、附件/链接、扫描和 diff | 第二批 MCP 工具 | 未选内容不读取;确定性 hash、安全阻断和大小限制通过 |
| C1-09 | Release/Export/Readback | 幂等、CAS、fake Git/Gitea、原子 current、readback | 第三批 MCP 工具 | 并发、失败状态、恢复发布通过 |
| C1-10 | 审计查询与观测 | 查询工具、event verify、指标/trace、脱敏 | 第四批工具、OTel | 三主体链完整,日志无正文/秘密 |
| C1-11 | 安全与恢复测试 | 冒充、越权、注入、审计中断、DB/Git/current 恢复 | 测试报告 | M01~M10 和开发态 T 用例通过 |
| C1-12 | 打包交接 | OCI、SBOM、checksum、配置样例、运行手册 | 不连接环境的制品 | 可复现、无秘密、不会自动部署 |
C1-00 某个客户端未通过时,只阻断该客户端 adapter,不阻断核心和已通过客户端;不得为兼容单个 Agent 降级 OAuth、确认、Local Source Gate 或审计语义。
14. G0~G5 真实实施顺序
G0:参数与责任确认
- 固定 Codex、Claude Code 的受支持版本和 adapter version,并确认飞书自建应用、试点用户和管理员。
- 选择已有或独立部署的成熟 OAuth/OIDC Authorization Server,确认 MCP PRM、PKCE、resource/audience、客户端注册、撤销和飞书身份联邦能力。
- 确认目标 Linux/容器环境、域名、TLS、反向代理、PostgreSQL、存储和备份。
- 确认 Gitea 是新建还是复用、版本、管理员和维护窗口。
- 固定试点 project、成员、飞书—Gitea 预配置绑定、publisher 和安全/备份责任人。
- 确认 RPO/RTO、审计保留、脱敏和事故联系人。
G1:测试环境基础设施
- 只读盘点目标环境。
- 准备 PostgreSQL 数据库/角色和密钥引用。
- 部署固定版本 Gitea,关闭公开注册并保护
main。 - 部署 reverse proxy、
contextd serve/worker和 OTel 输出。 - 配置飞书 OAuth redirect、最小 scope 和 MCP resource metadata。
- 创建一个合成项目和合成用户,先运行 M01~M10。
G2:身份、权限与仓库
- 建立试点用户的内部、飞书和 Gitea 绑定。
- 建立 ProjectGrant 和 Gitea Code Read 权限。
- 创建项目级 reader、permission-checker 和 publish-gateway 服务身份。
- 验证双层权限不一致、用户停用、解绑和 Gitea 撤权。
- 创建试点私仓、受保护
main和备份链。
G3:发布闭环
- 只开放身份与 current 读取工具。
- 读取稳定后开放 selection/build/validate/diff。
- Host 精确确认验证通过后再开放 discussion 发布。
- confirmed/恢复作为最后一批 A4 工具开放。
- 每次发布验证 Git/current/MCP/Agent 四段一致和三主体审计。
G4:安全、备份与恢复
- 完成越权、提示注入、秘密/PII、路径和审计中断测试。
- 轮换 Feishu app secret、MCP 签发密钥、Gitea token 和数据库凭据。
- 恢复 PostgreSQL、Gitea、current、audit checkpoints 和服务配置。
- 在隔离环境完成空环境恢复并验证撤销凭据失效。
G5:真实试点
- 只接一个 internal、Markdown 为主的真实项目。
- 完成 M01~M10 和 T01~T12。
- 至少两名非平台维护者完成真实读取、发布或纠错。
- 观察使用和维护成本,命中止损即停止扩项目。
- 根据证据决定保持 v1.1,还是单独立项 Skill Registry、飞书内容来源或其他版本。
15. 默认不引入的复杂度
- 不建设自定义 Web/移动端页面。
- 不使用 Kubernetes 作为首期前置。
- 不拆身份、权限、发布、审计为多个代码仓库或微服务。
- 不引入 Redis、Kafka、RabbitMQ、Elasticsearch 或向量数据库。
- 不让 LLM 决定权限、审核策略、Git commit 或 current 切换。
- 不让 MCP 工具执行部署、迁移、备份、恢复、密钥和 Gitea Admin。
- 不创建 Skill Registry 数据表或发布链。
只有真实负载、可靠性或检索效果证明 PostgreSQL/模块化单体不足时,才为后续版本增加基础设施。
16. 工作量量级
在一名熟悉 Go/安全后端的主开发+一名测试/平台协作者条件下,C1 代码与测试基线约为 45~70 人日;G0~G4 环境接入、加固和恢复验证约为 15~30 人日,真实试点观察另计。
该估算包含 Codex、Claude Code 两个 adapter 的契约适配和 Local Source Gate 基础实现,但不包括:第三种 Agent 的特殊兼容、公司没有可用飞书自建应用权限、目标服务器需要重新采购、历史 Gitea 迁移或 Skill Registry 扩展。若某客户端违反统一契约,只重新评估该 adapter,不扩大核心权限。
17. 已确认条件与后续实施参数
| 优先级 | 信息 | 当前状态 | 后续处理 |
|---|---|---|---|
| P0 | Agent 架构 | confirmed:框架兼容,优先 Codex、Claude Code | C1-00 固定受支持版本和 adapter contract |
| P0 | 每人独立远程 MCP | confirmed:必须支持 | C1-00 测试两名用户 token/subject 隔离 |
| P0 | OAuth | confirmed:必须完成 | C1-04 集成成熟 OAuth AS+飞书身份联邦 |
| P0 | A3/A4 人类确认 | confirmed:框架支持 | C1-00/05 验证一次性 confirmation 不可伪造/复用 |
| P0 | 本地文件 | confirmed:可读可传但必须控制 | C1-08 实现并验收 Local Source Gate |
| P1 | 团队能否维护 Go;如不能,主要语言是什么 | open | C1-01 前决定是否接受默认 Go 栈 |
| P1 | 可复用的 OAuth/OIDC Authorization Server;如无,批准独立部署哪一成熟产品 | open | C1-04 前锁定;不得在业务服务内临时自研完整授权服务器 |
| P1 | 是否已有飞书自建应用、App 管理员和可用 OAuth redirect 域名 | open | G0 前确认真实 OAuth 参数和 scope |
| P1 | Gitea 是新建还是复用,当前版本和管理员 | open | G0 盘点、升级和权限 API 兼容性 |
| P1 | 目标服务器是否允许 Linux 容器、PostgreSQL 18 和反向代理 | open | 决定部署配置,不影响领域设计 |
| P1 | 飞书—Gitea 绑定和 ProjectGrant 的首批预配置名单与治理责任人 | open | G2 前导入;未预配置用户 fail closed |
| P1 | Local Source Gate 的允许根、类型、单文件/bundle 上限、secret/PII 规则和临时保留期 | open | C1-08 前按 PRD 默认值评审并配置化 |
| P2 | 既有秘密、日志、指标、备份产品 | open | 优先复用,避免重复建设 |
Agent 相关架构信息已经足以关闭概念设计缺口。尚未提供的 P1/P2 信息不阻断当前文档设计,只在对应 C1/G0 任务开始前阻断具体代码栈确认或部署命令。
18. 与 v1/v1.1 的一致性
| 原则 | 本方案实现方式 | 是否偏移 |
|---|---|---|
| 一项目一私仓 | Gitea private repository+ProjectGrant | 否 |
发布网关唯一写 main |
只有 worker 的 project-scoped gateway credential | 否 |
唯一 main/current |
不可变 release+原子 current 指针 | 否 |
| 内容/事务状态分离 | v1 状态机原样落地 | 否 |
| MCP 唯一用户入口 | 仅 /mcp 暴露业务工具 |
否 |
| Agent 可替换 | Codex/Claude Code 通过统一 adapter contract,服务端不信任 Agent 自报身份 | 否 |
| 飞书绑定内部主体 | 成熟授权服务器完成 MCP OAuth,飞书联邦到内部 UserIdentity | 否 |
| 飞书—Gitea 绑定 | Gitea 数字 ID 受控预配置;未绑定、冲突或停用即拒绝 | 否,补齐安全落地方式 |
| 双层权限 | ProjectGrant+实时 Gitea 权限复核 | 否 |
| 三主体强制审计 | MCP 中间件+业务 outbox+append-only store | 否 |
| 无自建 Web | 只有协议和内部健康端点 | 否 |
| 私人来源明确选择 | Local Source Gate 只传用户明确选择的文件/章节 | 否 |
| 搜索只暴露 current | PostgreSQL project-scoped pg_trgm+元数据过滤 |
否,补齐中文检索基线 |
| Skill Registry 后置 | 当前无 skill 表、工具和流程 | 否 |
因此,本技术栈是 v1.1 的实现选择,不构成新的业务版本。只有改成共享用户身份、取消 Gitea 二次复核、绕过强制审计、开放 Web 旁路或把 Skill Registry 加入首期,才属于需要重新确认的版本变更。