message / docs /cloud-contract.md
dot
Add Supabase administrator sessions and profile client key management
9b403c4
|
Raw History Blame Contribute Delete
5.82 kB

云端原生市场 V1 契约

目标:单运营者自托管可信 DSH bundle 市场。所有核心操作均有 Web 入口;不包含计费、公共社区、多租户或不可信插件沙箱。旧 Python 市场单独启动,新部署默认不加载它。

运行与认证

入口为 app.cloud_main:app,独立于旧 app.main。MESSAGE_DATA_DIR 为仓库外可写根,保存 catalog 与 profiles;同一实例只运行一个 API worker,负责子进程。每个 profile 独立 Node 进程、安装状态和 MCP 会话。

管理API默认使用Supabase管理员账号与HttpOnly/Secure/SameSite cookie、精确Origin和CSRF。无项目配置时可启动锁定引导,不能注册首位管理员。MCP使用页面创建的profile scoped API key,每次请求查Supabase哈希/撤销/过期。详细Auth接口与SQL约束见 supabase-auth.md;不需要service_role。插件秘密仍只允许精确{$env:变量名}引用,值仅注入目标worker。

MESSAGE_ALLOWED_HOSTS 与 MESSAGE_ALLOWED_ORIGINS 明确配置,拒绝不匹配 Host/Origin;无 Origin 的原生客户端可用。反向代理终止 TLS,只有经过此鉴权网关才可远程访问;内部 DSH HTTP 仅 loopback。

API(统一 JSON;错误为 detail 文本)

  • GET /api/native/health:免认证仅 {status:'healthy'}
  • GET /api/native/catalog:{items:[{id,name,version,description,sha256,bytes}]};id 为 SHA256
  • POST /api/native/catalog:multipart file 上传独立 tgz;检查归档路径、元数据、bundle 声明、依赖来源和大小;重复相同内容幂等,同名同版本不同内容拒绝;返回 artifact
  • GET /api/native/catalog/{id}/download:鉴权下载归档
  • GET /api/native/profiles:{items:[{id,status,generation,restart_required,last_error}]}
  • POST /api/native/profiles:{id} 创建空 profile,返回状态;id 仅小写字母/数字/短横线
  • GET /api/native/profiles/{id}:{id,status,generation,restart_required,last_error,bundles,plugins,configured_tools,active_tools}
  • POST /api/native/profiles/{id}/install:{artifact_id};同名新版本是升级,返回 {operation,profile},标记待重启
  • POST /api/native/profiles/{id}/enable、/disable:{name},返回 {operation,profile},标记待重启
  • POST /api/native/profiles/{id}/restart、/stop:无body,返回状态;restart关闭旧worker和会话,启动新generation,失败可诊断/恢复
  • POST /api/native/profiles/{id}/call:{name,arguments:{}};只调用正在运行worker的真实MCP,不用临时CLI假装活跃工具
  • /mcp/{id}:鉴权Streamable HTTP代理,正确转发POST/GET/DELETE、MCP会话/协议头与SSE;隔离profile token和后端会话

Web登录会话使用HttpOnly cookie,刷新页面可恢复,不在localStorage保存token。默认页为原生市场,可选择profile、查看目录与安装版本、上传/下载、安装/升级/启停、看到待重启状态、重启/停止、调用工具、查看可复制的MCP配置。旧页面标记legacy并保持兼容路由。

交付验收

真实浏览器与真实SDK覆盖:未登录拒绝、上传/目录、profile创建、安装、待重启、重启后工具可用、调用、禁用与重启后拒绝、升级新值、两profile状态与令牌隔离、同profile多MCP会话、错误恢复、API进程关闭回收workers、冷启动持久状态恢复。消费者源码/lock哈希不因安装/升级变化。

部署包提供轻量Python依赖锁、Node lock、前端构建、非root容器、健康检查、数据卷和反向代理TLS示例;不执行实际发布。所有用户文档为Markdown。

操作与恢复补充

安装/升级/启停/配置/卸载/重启/停止为异步操作,接受 Idempotency-Key,返回 HTTP 202 {operation_id, status}。GET /api/native/operations?profile_id= 返回 {items:[{id,profile_id,kind,status,result,error,created_at,updated_at}]},GET /api/native/operations/{id} 读取单项;status 为 queued/running/succeeded/failed/cancelled。同 key 重复请求返回同一操作,不重复执行;不同payload同key拒绝。POST /api/native/operations/{id}/cancel 申请取消,终态可持续查询;已不可取消则409。页面刷新后可重新读取任务。启动时未完成操作标为 interrupted/failed,不能报告成功。

新增 POST /api/native/profiles/{id}/remove:{name}。卸载先停止使用该包的worker,再执行离线包移除,不假装全量事务;失败保留诊断与明确的实际状态。操作返回中区分期望安装/启用状态、正在运行的generation与待重启状态。

配置接口:POST /api/native/profiles/{id}/configure,body {entry_id, config:{}},同一异步操作契约。plugins条目提供entryId/entry_id、patchId/row_id、raw config和readOnlyReason;管理读取不挂载第三方apply。安装/升级前停止worker,完成后待人工重启;普通配置和启停可保留旧worker直到重启。

存活GET /api/native/health 与就绪GET /api/native/readiness 分开;后者在应运行profile未就绪时503。每次请求在读取body之前鉴权。

Auth接口

GET /api/native/auth/status 返回配置/登录/CSRF/存储状态;POST /auth/login 输入email/password;POST /auth/logout撤销当前Supabase会话;POST /auth/recover发默认PKCE邮件;GET /auth/recovery/callback消费一次code;POST /auth/password仅允许独立恢复cookie。以上路径省略共同 /api/native 前缀。

GET/POST /api/native/profiles/{id}/keys 列表/创建(name、expires_in_days),DELETE /{key_id}撤销,GET /api/native/auth/audit查固定事件。密钥只创建响应有明文,其他响应无哈希或secret。session绑定key ID,撤销中断本进程现有流。