配置治理、双人审批与业务幂等

在已认证的内建本地管理或远程管理模式启用独立配置审批:

admin:
  approvals:
    policy_changes:
      enabled: true                     # 默认 false,兼容已有部署。
      required_scopes: [mcphub:security]
      subjects: [security-reviewer-sub]  # 可选,精确 OIDC subject。
      require_step_up: true             # 需要配置 step_up_acr_values。
    notifications:
      url: https://notify.example.com/mcphub
      secret: ${MCPHUB_WEBHOOK_SECRET}   # 至少 32 字节。
    audit_archive:
      url: https://audit.example.com/mcphub
      key_id: audit-2026-01
      signing_key: ${MCPHUB_AUDIT_SIGNING_KEY}

配置管理员新增或修改后端、工具组、HTTP 工具、OpenAPI 导入时,API 和 mcpbridge admin 返回 202,包含 pending_approval、approval_id、approval_url;网页编辑器跳转到提案,配置尚未生效。另一位具有安全 scope 的用户通过“以安全管理员身份登录”(/auth/login?role=security)进入,核对脱敏前后差异后“批准并应用”。凭证变更会单独标记,但不显示凭证值。安全角色不能直接编辑配置,写操作审批角色不能批准配置。批准仍要求浏览器会话和 CSRF 验证,API Token 不可审批。删除及单纯的启用→停用立即生效;重新启用、停用同时修改其他字段均需审批。YAML、数据库和部署运维权限仍属于信任边界,静态治理配置不能通过管理 API 修改。

提案绑定目标版本;工具和导入还绑定所属工具组版本。期间发生修改时,旧提案应用失败,不会覆盖新配置。OpenAPI 提案保存具体文档和生成的工具定义,批准时不会重新下载;自动刷新发现变更也会生成提案,继续使用已批准的定义。重启使尚未执行的提案失效,中断的应用标记为结果不确定,需人工核查。失败或过期后需要重新提交。每个 issuer/subject 最多 21 个活跃请求,完整配置提案上限 32 MiB。

生产写工具可以配置:

approval:
  required_approvals: 2
  require_step_up: true
  operation_id_argument: /operation_id
  status_tool: get_operation_status
  approvers:
    - subjects: [reviewer-a-sub, reviewer-b-sub]
  # 条件只会提高审批人数或认证强度。
  # 如果仅这些业务资源需要双人审批,可将基础 required_approvals 设为 1。
  risk_rules:
    - resources:
        - argument: /project
          allowed_values: [production]
      required_approvals: 2
      require_step_up: true

审批人数默认 1,可设 1 或 2。每票必须来自不同的授权 subject;双人审批始终禁止申请人参与计票。需要加强认证时,两位审批人分别完成。第一票后仍为待审批,达到人数后才开始执行期限。待审批可被拒绝,未开始执行的批准可撤销,页面展示人数和已批准人员。风险条件使用 JSON Pointer 和精确字符串;多条件同时匹配,数组中任一值命中即视为该条件匹配,缺失、空值和错误类型会拒绝申请。多条策略取最高人数及认证强度。对删除、批量写、生产专用工具,直接配置基础双人审批;不能把 Agent 自报的 risk: low 当作可信风险边界。

operation_id_argument 指向必填业务操作 ID:1–128 个字母、数字、.、_、:、-。同一业务操作生成一次,客户端重试持续使用。MCPHub 将其绑定到 issuer、subject、来源和工具;规范化请求一致时返回原审批/状态,参数或业务 metadata 不同则拒绝复用,只有传输用 progressToken 不参与比较。已完成、已拒绝、过期、结果不确定的 ID 都不能重新创建写操作。保留期结束后删除详细结果,但保留小型哈希登记记录防止旧 ID 再用;登记记录随业务操作数增长。不同身份之间隔离。未配置 ID 时,仅合并相同的活跃申请;已结束后的相同参数可能表示新的业务操作。

业务 ID 保留在已审核参数中并发送上游。HTTP 工具可使用 Header 参数映射为 Idempotency-Key;MCP 后端需自行处理该字段。MCPHub 无法阻止绕过网关的调用或换用新 ID 的重试,业务级保证仍需要后端幂等与原子版本校验。

客户端用明确只读的工具查询:

{"name":"mcphub_approval_status","arguments":{"approval_id":"..."}}

返回状态、人数、已批准人员、期限及可用的缓存结果,不领取执行资格、不执行写入。可选 query_upstream: true 调用同后端/工具组中明确发布且标为只读的 status_tool,传入完整已保存参数;该工具须接受业务操作 ID 等参数,并返回描述状态/回执的 structured content。仍检查 scope、资源、配置和限流,结果位于 upstream_observation,不会重置不确定状态或允许重放。来源/工具配置未变时,重启后仍可查询;配置变化则隐藏缓存结果并拒绝查询上游。基本状态只对原 issuer/subject 开放。明确准备执行批准后的写入时才调用 mcphub_resume_approval。

审批通知与独立审计归档

两项集成都为可选 HTTPS 端点,在管理 API 外配置;URL 不得包含凭证、查询参数或 fragment。审批事件与投递记录在同一 SQLite/PostgreSQL 事务提交,单实例后台顺序发送,超时 10 秒、不跟随重定向,失败按 5 秒到 1 小时退避持久化重试。接收方须按 event_id 去重,回执丢失可能重复投递;归档失败会阻塞后续归档以保持链顺序。申请、投票、决定、取消、执行和过期均产生事件;待审批/待执行请求在到期前五分钟内由每分钟维护任务提醒一次。通知仅含 event_id、approval_id、action、approval_url、expires_at,链接进入受认证的审批页,通知回调不能批准。

通知验签:X-MCPHub-Signature: sha256=<hex> 是使用共享密钥对 X-MCPHub-Timestamp + "." + 原始请求体 计算的 HMAC-SHA256。接收方检查时间新鲜度并去重 event ID;2xx 表示收到。不要将共享密钥放在 URL 或日志中。

归档密钥是 Base64 编码的 64 字节 Ed25519 私钥(seed 拼接公钥),对应 32 字节公钥应独立分发给归档校验方。每个信封包括 entry、hash(entry 原始序列化字节的 SHA-256)、signature(对 32 字节 hash 的 Ed25519 签名,Base64 编码)。entry 包含序号、前序哈希、key ID、事件和审批 ID、操作、人员、时间、审批理由/认证证据,以及绑定本地加密意图和结果的哈希。不会导出工具参数、配置密钥和 Token;审批理由中也不应填写密钥。独立接收服务验证签名与链、持久化原始 JSON 信封,然后以 2xx 返回 {"sequence":123,"hash":"对应信封哈希"};不匹配或缺少回执将重试。不要重新排版或序列化已签名的 entry。

mcphub verify-audit --file archive.jsonl --key "audit-2026-01=$AUDIT_PUBLIC_KEY"
# 密钥轮换时重复 --key ID=BASE64_PUBLIC_KEY。
# 对归档片段,传入独立保存的可信前序检查点:
mcphub verify-audit --file next.jsonl --key "audit-2026-01=$AUDIT_PUBLIC_KEY"   --after-sequence 123 --after-hash "$TRUSTED_PREVIOUS_HASH"

校验器拒绝篡改、内部记录缺失或乱序、错误公钥及断链,并输出最终序号和哈希。检查点应保存在 MCPHub 数据库之外,并与预期末尾比较以检测回滚/尾部删除;有效前缀本身不能证明完整性。使用由独立权限控制的追加式/WORM 存储,保护签名私钥。本方案不能抵御同时控制签名者和归档的运维人员,归档范围为审批事件,不是所有普通活动日志。

GET /api/v1/approvals/delivery 向配置/安全管理浏览器角色显示开关和待投递/失败数;审批页和 stderr 日志提示失败。尚未确认归档的事件会阻止清理对应审批详情,独立归档保留期由接收方控制。故障期间需监控队列和数据库增长。生产 OIDC、通知接收器和归档服务需要部署方配置,本项目不会自动开通这些外部服务。