提交gitea知识库方案
This commit is contained in:
@@ -0,0 +1,558 @@
|
||||
---
|
||||
title: Gitea知识库 v1.1 技术栈与详细实施设计
|
||||
date: 2026-08-10
|
||||
type: 设计spec
|
||||
status: draft
|
||||
content_status: discussion
|
||||
owner: Verlit
|
||||
last_updated_at: 2026-08-10
|
||||
last_updated_by: Codex
|
||||
hash: sha256:943f3d865bf228e8adef23b6c9064079f0a3573ada0ff9fbae2560defc0b727b
|
||||
hash_scope: Markdown 正文(从一级标题开始至文件末尾)的 UTF-8 SHA-256
|
||||
belongs_to:
|
||||
- "[[3-业务线/Gitea知识库/_context|Gitea知识库]]"
|
||||
depends_knowledge:
|
||||
- "[[3-业务线/Gitea知识库/公司共享 Context 项目仓库发布方案 v1|公司共享 Context 项目仓库发布方案 v1]]"
|
||||
- "[[3-业务线/Gitea知识库/公司共享 Context MCP-first 身份与审计方案 v1.1|公司共享 Context MCP-first 身份与审计方案 v1.1]]"
|
||||
- "[[3-业务线/Gitea知识库/v1-工程构建规格|v1.1 工程构建规格]]"
|
||||
- "[[3-业务线/Gitea知识库/v1-开发任务分解|v1.1 开发任务分解]]"
|
||||
source_refs:
|
||||
- "https://developers.openai.com/codex/codex-manual.md"
|
||||
- "https://code.claude.com/docs/en/mcp"
|
||||
- "https://code.claude.com/docs/en/permissions"
|
||||
- "https://github.com/modelcontextprotocol/go-sdk/blob/main/docs/protocol.md"
|
||||
- "https://github.com/modelcontextprotocol/go-sdk/releases/tag/v1.7.0"
|
||||
- "https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http"
|
||||
- "https://modelcontextprotocol.io/docs/tutorials/security/authorization"
|
||||
- "https://go.dev/doc/devel/release"
|
||||
- "https://www.postgresql.org/support/versioning/"
|
||||
- "https://open.feishu.cn/document/authentication-management/access-token/get-user-access-token"
|
||||
- "https://open.feishu.cn/document/server-docs/contact-v3/user/field-overview"
|
||||
- "https://docs.gitea.com/usage/permissions"
|
||||
- "https://github.com/go-gitea/gitea/releases/tag/v1.26.2"
|
||||
---
|
||||
|
||||
# Gitea知识库 v1.1 技术栈与详细实施设计
|
||||
|
||||
## 1. 结论
|
||||
|
||||
本项目可以确定技术栈并拆解到可下发的开发与实施步骤。推荐采用“一个模块化 Go 代码库、两个运行角色、一个 PostgreSQL 控制数据底座、一个独立 Gitea、一个远程 MCP 用户入口”的方案:
|
||||
|
||||
```text
|
||||
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. 部署拓扑与进程边界
|
||||
|
||||
```mermaid
|
||||
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 只负责:
|
||||
|
||||
1. 注册远程 MCP endpoint 和支持的协议版本。
|
||||
2. 发起逐用户 OAuth,并安全保存/刷新该用户的 MCP 凭据。
|
||||
3. 将 `client_kind`、`client_version`、`adapter_version` 和本地 session 绑定到 AgentSession。
|
||||
4. 在 A3/A4 前展示固定的 project、action、candidate hash、`base_current` 和 diff 摘要。
|
||||
5. 只有真实用户完成确认后,向框架确认服务换取一次性 `confirmation_id`。
|
||||
6. 将用户明确选择的本地内容经过 Local Source Gate 后调用 MCP。
|
||||
|
||||
Codex/Claude Code 自带的 tool prompt 是第一层交互保护,但不直接成为发布授权真源;服务端只接受框架确认服务签发、与精确请求 hash 绑定的一次性凭证。
|
||||
|
||||
### 5.4 Local Source Gate:本地文件传输控制
|
||||
|
||||
```text
|
||||
用户明确选择路径/章节
|
||||
→ 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 登录流程
|
||||
|
||||
```text
|
||||
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. 双层权限算法
|
||||
|
||||
每次工具调用按固定顺序执行:
|
||||
|
||||
```text
|
||||
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_identity`
|
||||
- `list_authorized_projects`
|
||||
- `get_my_project_roles`
|
||||
- `get_current_manifest`
|
||||
- `read_artifact`
|
||||
- `search_current`
|
||||
- `verify_release_hash`
|
||||
|
||||
### 9.2 第二批:选择、构建与检查
|
||||
|
||||
- `create_selection`
|
||||
- `append_selection_content`(仅在 Host 需分块传输时)
|
||||
- `build_preview`
|
||||
- `validate_release_request`
|
||||
- `preview_release_diff`
|
||||
|
||||
Markdown 内容通过 MCP 加密传输,但不得进入访问日志和审计正文;审计仅记录内容 hash、大小、文件数和脱敏标签。首期设置单文件和 bundle 大小上限,超限时停止,不自动改走通用上传接口。
|
||||
|
||||
### 9.3 第三批:受控发布
|
||||
|
||||
- `submit_discussion_release`
|
||||
- `submit_confirmed_release`
|
||||
- `get_release_status`
|
||||
- `cancel_precommit_release`
|
||||
|
||||
A3/A4 请求必须引用一次性 `confirmation_id`,并绑定 tool、user、session、project、candidate hash、`base_current` 和过期时间。Host 不能提供可靠确认时不注册提交工具。
|
||||
|
||||
### 9.4 第四批:审计查询
|
||||
|
||||
- `list_my_actions`
|
||||
- `get_action_detail`
|
||||
- `trace_release`
|
||||
- `trace_correlation`
|
||||
- `list_project_audit_events`
|
||||
- `verify_audit_event`
|
||||
|
||||
审计生成不是 MCP tool;它由服务端中间件和业务事务自动完成。
|
||||
|
||||
## 10. 强制审计实现
|
||||
|
||||
### 10.1 每次调用顺序
|
||||
|
||||
```text
|
||||
解析 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 发布事务
|
||||
|
||||
1. worker 读取服务端 policy、validation、confirmation、幂等和 `base_current`。
|
||||
2. 使用临时 worktree 获取指定 `main`,再次校验远端 commit 与 `base_current`。
|
||||
3. 生成完整新 `current/`,不在服务目录逐文件修改。
|
||||
4. 创建单一 Git commit,记录 release ID、human、agent、service 和 manifest hash。
|
||||
5. 非 force push 到受保护 `main`;non-fast-forward 返回 `STALE_BASE`。
|
||||
6. 从该 commit 构建不可变 `releases/<release-id>/`。
|
||||
7. 校验 manifest/checksum 后原子切换唯一 current。
|
||||
8. 通过 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. 代码仓库结构
|
||||
|
||||
```text
|
||||
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/
|
||||
```
|
||||
|
||||
同一镜像通过子命令运行:
|
||||
|
||||
```text
|
||||
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:参数与责任确认
|
||||
|
||||
1. 固定 Codex、Claude Code 的受支持版本和 adapter version,并确认飞书自建应用、试点用户和管理员。
|
||||
2. 选择已有或独立部署的成熟 OAuth/OIDC Authorization Server,确认 MCP PRM、PKCE、resource/audience、客户端注册、撤销和飞书身份联邦能力。
|
||||
3. 确认目标 Linux/容器环境、域名、TLS、反向代理、PostgreSQL、存储和备份。
|
||||
4. 确认 Gitea 是新建还是复用、版本、管理员和维护窗口。
|
||||
5. 固定试点 project、成员、飞书—Gitea 预配置绑定、publisher 和安全/备份责任人。
|
||||
6. 确认 RPO/RTO、审计保留、脱敏和事故联系人。
|
||||
|
||||
### G1:测试环境基础设施
|
||||
|
||||
1. 只读盘点目标环境。
|
||||
2. 准备 PostgreSQL 数据库/角色和密钥引用。
|
||||
3. 部署固定版本 Gitea,关闭公开注册并保护 `main`。
|
||||
4. 部署 reverse proxy、`contextd serve/worker` 和 OTel 输出。
|
||||
5. 配置飞书 OAuth redirect、最小 scope 和 MCP resource metadata。
|
||||
6. 创建一个合成项目和合成用户,先运行 M01~M10。
|
||||
|
||||
### G2:身份、权限与仓库
|
||||
|
||||
1. 建立试点用户的内部、飞书和 Gitea 绑定。
|
||||
2. 建立 ProjectGrant 和 Gitea Code Read 权限。
|
||||
3. 创建项目级 reader、permission-checker 和 publish-gateway 服务身份。
|
||||
4. 验证双层权限不一致、用户停用、解绑和 Gitea 撤权。
|
||||
5. 创建试点私仓、受保护 `main` 和备份链。
|
||||
|
||||
### G3:发布闭环
|
||||
|
||||
1. 只开放身份与 current 读取工具。
|
||||
2. 读取稳定后开放 selection/build/validate/diff。
|
||||
3. Host 精确确认验证通过后再开放 discussion 发布。
|
||||
4. confirmed/恢复作为最后一批 A4 工具开放。
|
||||
5. 每次发布验证 Git/current/MCP/Agent 四段一致和三主体审计。
|
||||
|
||||
### G4:安全、备份与恢复
|
||||
|
||||
1. 完成越权、提示注入、秘密/PII、路径和审计中断测试。
|
||||
2. 轮换 Feishu app secret、MCP 签发密钥、Gitea token 和数据库凭据。
|
||||
3. 恢复 PostgreSQL、Gitea、current、audit checkpoints 和服务配置。
|
||||
4. 在隔离环境完成空环境恢复并验证撤销凭据失效。
|
||||
|
||||
### G5:真实试点
|
||||
|
||||
1. 只接一个 internal、Markdown 为主的真实项目。
|
||||
2. 完成 M01~M10 和 T01~T12。
|
||||
3. 至少两名非平台维护者完成真实读取、发布或纠错。
|
||||
4. 观察使用和维护成本,命中止损即停止扩项目。
|
||||
5. 根据证据决定保持 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 加入首期,才属于需要重新确认的版本变更。
|
||||
Reference in New Issue
Block a user