mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-07-24 05:16:09 +00:00
feat(tenancy): harden shared cloud runtime boundaries
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
# Cloud v2 多租户架构决策与待决策项
|
||||
|
||||
状态:`PARTIALLY_DECIDED — MVP target confirmed, implementation pending`
|
||||
状态:`DECIDED — Core isolation kernel implemented; SaaS activation gates remain`
|
||||
创建日期:2026-07-19
|
||||
最近更新:2026-07-19
|
||||
最近更新:2026-07-20
|
||||
|
||||
本文记录 Cloud v2 多租户架构中已经确认的首期决策、明确淘汰的方案和仍需在后续阶段决定的扩展项。
|
||||
“已决定”表示实现目标已经确定,不表示代码已经完成。正式实现时还需要把结论同步到
|
||||
[implementation-decisions.md](./implementation-decisions.md)、主架构、实施清单、配置模板和协议设计。
|
||||
本文同时记录实现状态。“实现完成”仅指开源 Core/SDK 的隔离内核和 fail-closed 门禁,
|
||||
不表示闭源 Control Plane、计费或 Cloud v2 部署已经可上线。最终实现选择同步记录在
|
||||
[implementation-decisions.md](./implementation-decisions.md),剩余发布门禁记录在实施清单和验证报告。
|
||||
|
||||
## 0. 已确认的 SaaS 拓扑前提
|
||||
|
||||
@@ -25,12 +26,12 @@
|
||||
|
||||
### 0.1 本轮确认的首期决策
|
||||
|
||||
| 编号 | 结论 | 首期状态 |
|
||||
| ----- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- |
|
||||
| D-001 | 一个共享 Plugin Runtime 控制面;每个运行中的 plugin installation 独占一个 nsjail 子进程;只有 digest 相同且已验证的代码/依赖 artifact 可以只读共享 | `DECIDED — implementation pending` |
|
||||
| D-002 | 一个共享 Box Runtime;Cloud 固定使用 nsjail;符合套餐的 Workspace 最多一个持久 `global` 逻辑 sandbox,普通执行按需启动 nsjail 进程 | `DECIDED — implementation pending` |
|
||||
| D-003 | SaaS 业务数据使用 PostgreSQL shared schema、应用层作用域和 RLS 双重隔离;pgvector 使用同一 PostgreSQL,作为 SaaS 默认向量后端 | `DECIDED — implementation pending` |
|
||||
| D-004 | stdio MCP 与 Box availability 解耦;Cloud v2 首期强制关闭 stdio MCP,避免为每个 Workspace 创建额外的 `mcp-shared` persistent sandbox | `DECIDED — implementation pending` |
|
||||
| 编号 | 结论 | 首期状态 |
|
||||
| ----- | --------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
|
||||
| D-001 | 一个共享 Plugin Runtime 控制面;每个运行中的 plugin installation 独占一个 nsjail 子进程;只有 digest 相同且已验证的代码 artifact 可以只读共享 | `IMPLEMENTED — real Linux/egress deployment gate pending` |
|
||||
| D-002 | 一个共享 Box Runtime;Cloud 固定使用 nsjail;符合套餐的 Workspace 最多一个持久 `global` 逻辑 sandbox,普通执行按需启动 nsjail 进程 | `IMPLEMENTED FAIL-CLOSED — hard filesystem quota provider pending` |
|
||||
| D-003 | SaaS 业务数据使用 PostgreSQL shared schema、应用层作用域和 RLS 双重隔离;pgvector 使用同一 PostgreSQL,作为 SaaS 默认向量后端 | `PARTIALLY IMPLEMENTED — transaction/outbox/deployment gates remain` |
|
||||
| D-004 | stdio MCP 与 Box availability 解耦;Cloud v2 首期强制关闭 stdio MCP,避免为每个 Workspace 创建额外的 `mcp-shared` persistent sandbox | `IMPLEMENTED` |
|
||||
|
||||
Workspace 的具体创建、释放、数据导出和单 Workspace 恢复机制不在本轮决定;本文只保证这些后续能力不会改变稳定的
|
||||
`workspace_uuid`,也不会要求重建租户专属部署。
|
||||
@@ -81,21 +82,18 @@ Core 不能继承 Plugin Runtime 所需的 nsjail/cgroup 权限。Box Runtime
|
||||
|
||||
## 3. D-001:Plugin Runtime 多租户控制面
|
||||
|
||||
状态:`DECIDED — MVP target confirmed, implementation pending`
|
||||
状态:`IMPLEMENTED — Cloud deployment verification pending`
|
||||
|
||||
### 3.1 当前实现事实
|
||||
### 3.1 已实现的基础
|
||||
|
||||
- SDK `RuntimeContext` 和 Core `PluginRuntimeConnector` 当前都绑定一个 Workspace,Runtime 只有一个全局 PluginManager。
|
||||
- 插件已经是直接子进程,但当前由 `asyncio.create_subprocess_exec` 启动,没有 nsjail 或同等级内核隔离。
|
||||
- 插件包目录当前按 author/name 组织,依赖安装会修改 Runtime 的全局 Python 环境,不能直接作为共享多租户写入边界。
|
||||
- 生产 `run-plugin` 路径仍会读取插件目录中的 `.env`;公开 SaaS 不能让 artifact 自行注入 Runtime secret。
|
||||
- 当前控制协议已有 `SET_RUNTIME_CONFIG`,可以由 Core 把验证后的实例级 worker policy 下发给 Runtime,
|
||||
但该控制 handler 当前仍要求单 Workspace context;目标协议必须先解除控制连接的 Workspace 绑定。
|
||||
- LangBot 的配置加载器原生支持把 `A__B__C` 环境变量映射到 `data/config.yaml` 的嵌套字段;
|
||||
数值和布尔字段必须先出现在配置模板中,才能稳定保留类型。
|
||||
- 现有镜像和 Box backend 已包含 nsjail、mount namespace、private `/proc`、rlimit 和 cgroup v2 相关实现,可复用隔离参数生成逻辑。
|
||||
- 当前 installation identity 及持久化模型还没有完整的随机 `installation_uuid`、`artifact_digest`、`runtime_revision`
|
||||
和 desired-state 字段;它们是目标模型,不是现有能力。
|
||||
- Plugin Runtime 控制连接只绑定稳定实例身份;一个 Supervisor 通过完整 installation binding 管理多个 Workspace。
|
||||
- 每个 enabled installation 使用独立 nsjail worker;代码只读,home/tmp/data 私有,shared profile 不读取 artifact `.env`。
|
||||
- 实例级 `PluginWorkerPolicy` 由 Core 的 `data/config.yaml` 下发,支持原生环境变量覆写;manifest 不能覆盖。
|
||||
- `installation_uuid`、`artifact_digest` 和 `runtime_revision` 已持久化并进入 desired-state、注册、Host API 和 generation/revision fence。
|
||||
- 已验证 `.lbpkg` 先进入 Workspace-scoped durable binary storage;Runtime 本地缓存丢失后可由 Core replay。
|
||||
- 相同 digest 的代码和 Runtime 准备的只读依赖环境可以共享,但 worker、运行时写入、配置和数据不合并;
|
||||
dependency preparation 在启动 worker 前完成,失败会进入明确的 installation failed 状态。
|
||||
- Cloud shared profile 强制 Linux nsjail;`plugin.worker.require_hard_limits=true` 时 cgroup v2 delegation 不可用会启动失败。
|
||||
|
||||
### 3.2 已确认的不变量
|
||||
|
||||
@@ -132,7 +130,7 @@ Core 不能继承 Plugin Runtime 所需的 nsjail/cgroup 权限。Box Runtime
|
||||
```text
|
||||
data/plugin-runtime/
|
||||
├── artifacts/sha256/<artifact_digest>/code/ # digest 校验后只读共享
|
||||
├── envs/<environment_digest>/ # 可选,只读共享依赖环境
|
||||
├── environments/sha256/<environment_digest>/ # 原子发布、只读共享依赖环境
|
||||
└── installations/<installation_uuid>/
|
||||
├── home/ # 私有可写
|
||||
├── tmp/ # 私有可写、可清理
|
||||
@@ -140,8 +138,10 @@ data/plugin-runtime/
|
||||
```
|
||||
|
||||
- artifact 只有在内容摘要和完整性校验一致时才允许共享,不能只凭 author/name/version 复用目录;
|
||||
cache 接受哪些签名/来源以及如何撤销和 GC,仍是实现前需要补充的供应链规则。
|
||||
- artifact 与共享依赖环境以只读 mount 进入 nsjail;installation 的 home/tmp/data 使用独立可写 mount。
|
||||
cache 可接受的签名/来源、撤销和 GC 规范属于后续发布规则,不改变本轮基于已验证 digest 的只读共享边界。
|
||||
- artifact 与按环境摘要构建的共享依赖环境以只读 mount 进入 nsjail;installation 的 home/tmp/data 使用独立可写 mount。
|
||||
环境摘要包含 artifact、requirements、Python ABI、Runtime 版本和 installer schema。依赖只能从已验证 artifact 的 PEP 508 声明构建,
|
||||
index/trusted-host 只由实例配置控制;构建在独立 nsjail 的临时路径中完成并在成功后原子发布,失败或并发安装不能留下可见半成品。
|
||||
- 插件 cwd 可以是其私有 mount namespace 内的只读 `/plugin`,不要求为每个 installation 复制代码;
|
||||
必须私有的是 home/tmp/data 等所有可写路径。
|
||||
- nsjail 必须启用 mount、PID、IPC、UTS 和 private `/proc` 等必要 namespace,插件不能枚举或 signal 其他插件及 Runtime 进程,
|
||||
@@ -164,6 +164,7 @@ plugin:
|
||||
max_pids: 128
|
||||
max_open_files: 256
|
||||
max_file_size_mb: 512
|
||||
require_hard_limits: true # Cloud; OSS defaults false
|
||||
```
|
||||
|
||||
配置文件路径为 `data/config.yaml`,沿用现有原生环境变量覆写:
|
||||
@@ -173,6 +174,7 @@ plugin:
|
||||
- `PLUGIN__WORKER__MAX_PIDS`
|
||||
- `PLUGIN__WORKER__MAX_OPEN_FILES`
|
||||
- `PLUGIN__WORKER__MAX_FILE_SIZE_MB`
|
||||
- `PLUGIN__WORKER__REQUIRE_HARD_LIMITS`
|
||||
|
||||
Core 启动时校验配置并通过现有 `SET_RUNTIME_CONFIG` 下发不可变 `PluginWorkerPolicy`。
|
||||
Runtime 不读取另一份环境变量配置,避免两个配置源不一致。CPU、内存和 PID 使用 cgroup 硬限制,
|
||||
@@ -203,22 +205,23 @@ installation data 的总空间硬配额需要 filesystem project quota 或独立
|
||||
- 修改 manifest 不能改变任何资源上限。
|
||||
- 旧 generation/revision 的回调、消息、副作用和存储访问全部失败关闭。
|
||||
- Runtime 重启能从业务 desired state 恢复,不依赖本地进程表作为权威真相。
|
||||
- requirements 中存在 Runtime 基础镜像未预装的包时,Supervisor 仍能先完成共享依赖环境准备再启动 worker;
|
||||
安装失败不会留下持续重启的半启动进程,也不会影响同 digest 已就绪环境的其他 installation。
|
||||
|
||||
## 4. D-002:Box 多租户控制面和套餐边界
|
||||
|
||||
状态:`DECIDED — MVP target confirmed, implementation pending`
|
||||
状态:`IMPLEMENTED FAIL-CLOSED — production quota provider pending`
|
||||
|
||||
### 4.1 当前实现事实
|
||||
### 4.1 已实现的基础
|
||||
|
||||
- Box 已经按 `instance_uuid + workspace_uuid` 派生持久 namespace,并按 generation 派生运行 namespace;
|
||||
单个 server/control connection 已有服务多个 Workspace 的数据结构基础。
|
||||
- 当前 nsjail backend 的 session 是“逻辑 session + 共享 host workspace 目录”。每次普通 `exec` 都启动一个 one-shot nsjail 进程,
|
||||
命令结束后进程退出;managed process 才会保持对应 nsjail 进程运行。
|
||||
- `persistent=True` 会让 session 跳过 300 秒 TTL reaper 和普通 shutdown 清理,但 Runtime 重启不会恢复内存中的 session 或运行进程。
|
||||
- 现有 `{global}` 强制 session ID 只覆盖部分 Agent 执行入口,不能单独保证所有入口最多一个 session,也不会自动设置 `persistent=True`。
|
||||
- 当前没有 `max_sessions_per_workspace`,调用其他入口仍可能使用不同逻辑 session ID,必须在 Box admission 层补最终门禁。
|
||||
- nsjail 文件机制不是对象存储同步算法,而是把 Box Runtime 容器中的 Workspace host path bind mount 到 sandbox 的 `/workspace`。
|
||||
- 当前 nsjail 在不可写/不可用的 cgroup v2 环境会降级并告警,无法保证共享 SaaS 的硬内存隔离。
|
||||
- 共享 Box 控制连接可服务多个 Workspace;所有操作绑定 instance、Workspace 和 generation,Runtime namespace 由可信 context 派生。
|
||||
- 短期 `SandboxAdmissionGrant`、revision tombstone 和原子 session admission 强制每个合资格 Workspace 最多一个 `global` persistent session,managed process 固定为零。
|
||||
- Core 与 Runtime 使用认证 host-control challenge 校验同一个 durable volume,而不是比较路径字符串;不一致时启动和重连失败。
|
||||
- Cloud skill 只传逻辑名称;Runtime 从 Workspace-scoped store 解析只读包路径,Python env/cache 写入租户自己的 `/workspace/.skill-envs`。
|
||||
- ZIP 安装限制压缩输入、条目、单项、总解压量和压缩比,采用流式解压并拒绝 link、非普通文件、重复项和路径逃逸。
|
||||
- 附件 host path 使用 query UUID 和 dirfd/openat/O_NOFOLLOW;Cloud replica 启动不再全局清理其他请求目录,遍历和删除有 inode 预算。
|
||||
- grant-enforced readiness 强制 cgroup、namespace、mount、共享卷、Workspace hard quota、Skill hard quota、ephemeral storage 和 inode quota 全部被证明。
|
||||
普通 nsjail backend 对尚未实现的硬磁盘能力明确返回 false,因此当前 Cloud Box 会按设计拒绝启动,直到新部署提供真实 quota provider。
|
||||
|
||||
### 4.2 首期套餐与 entitlement 模型
|
||||
|
||||
@@ -307,23 +310,50 @@ installation data 的总空间硬配额需要 filesystem project quota 或独立
|
||||
- 非 Pro、entitlement 缺失/过期及伪造 plan 的 API 直调全部失败关闭。
|
||||
- TTL 不回收 persistent session;Runtime 重启后进程和临时目录失效,但 `/workspace` 保留并能在下一次使用时安全重建。
|
||||
- 两个 Workspace 的文件、进程、session、attach token 和 generation 完全隔离;network/managed-process 请求在首期失败关闭。
|
||||
- Core 与 Box Runtime 使用同一路径的共享持久卷;filesystem quota 在 Box Runtime 写入点真实生效,现有目录扫描不被当作硬配额。
|
||||
- cgroup hard limit 不可用时 Cloud Box Runtime readiness 失败。
|
||||
- Core 与 Box Runtime 通过随机 marker challenge 证明同一共享持久卷;只配置相同路径字符串不算通过。
|
||||
- Workspace、Skill store、ephemeral root/tmp/home 的 byte quota 与 inode quota 在写入点真实生效;现有目录扫描不被当作硬配额。
|
||||
- cgroup 或任一硬存储能力不可用时 Cloud Box Runtime readiness 失败;普通 nsjail 因此不会被误当成 production-ready provider。
|
||||
|
||||
## 5. D-003:SaaS PostgreSQL 与 pgvector
|
||||
|
||||
状态:`DECIDED — MVP target confirmed, implementation pending`
|
||||
状态:`PARTIALLY IMPLEMENTED — shared schema/pgvector complete; SaaS transaction and deployment gates remain`
|
||||
|
||||
当前实现仍有明确差距:Cloud 模板默认 Chroma;pgvector adapter 使用独立 engine、全局 `id` 和固定 `vector(1536)`,
|
||||
没有持久化 `workspace_uuid/knowledge_base_uuid`,并会在应用启动时执行 `CREATE EXTENSION/create_all`;
|
||||
当前 persistence helper 也不能保证 `SET LOCAL` 与业务查询处于同一 transaction。以下均是目标约束,不是现状描述。
|
||||
当前分支已实现 PostgreSQL shared schema、transaction-local scope、FORCE RLS、Cloud runtime 非 DDL 模式、
|
||||
同业务数据库 pgvector、显式向量维度和 tenant-scoped vector 主键。一次性 migrator 使用独立凭据、advisory lock,
|
||||
负责建立并校验 runtime role 的最小权限,并完成全量 schema 验证;
|
||||
普通业务写入贯穿 commit 的 generation-aware fence、与外部副作用同事务的 outbox,以及 generation cutover 后稳定的 durable object 引用尚未实现。
|
||||
这些 Core 事务原语与生产 Job、凭据发放、备份和回滚流程,以及 runtime credential 的跨 database 连接隔离证明一起,
|
||||
都是 Cloud v2 的 SaaS activation gate。
|
||||
|
||||
### 5.1 已确认的数据库边界
|
||||
|
||||
- PostgreSQL 是 SaaS 的业务数据库,不把它扩展成通用 Runtime coordinator、Box session directory 或新控制面数据库。
|
||||
- M0 使用一个 PostgreSQL business database/shared schema 承载全部 Workspace。创建 Workspace 不创建 database、schema、role 或专属连接池。
|
||||
- 首版 migrator URL 和 runtime URL 必须归一化到同一 host、port 和 database,但必须使用不同 role。
|
||||
未来如果 migrator 使用 direct endpoint、runtime 使用 pooler endpoint,只能在两个端点都验证同一个数据库内部 cluster identity 后放宽 host/port 相等。
|
||||
该 identity 由 migrator 所有并固定,runtime role 只能读取,不能创建、修改或伪造。
|
||||
- 首版唯一业务 schema 固定为 `public`。migrator 和 runtime 连接都必须满足
|
||||
`current_schema() = 'public'` 且 `current_schemas(false) = ARRAY['public']`;禁止 runtime role 级和 business database 级 `search_path` 覆写。
|
||||
- migrator 和 runtime session 的安全值固定为 `session_replication_role=origin`、`row_security=on`、
|
||||
`lo_compat_privileges=off`。runtime role 或当前 business database 作用域内只要存在任意 `pg_db_role_setting` 持久化设置就失败关闭,
|
||||
即使该设置当前看似等于安全值也不接受;tenant context 只能通过事务内 `SET LOCAL` 建立。
|
||||
- 业务行显式携带 `workspace_uuid`;Repository/Service 的应用层 scope 是第一道边界,PostgreSQL RLS 是第二道边界。
|
||||
- 应用角色不得拥有 `BYPASSRLS`,关键租户表使用 `FORCE ROW LEVEL SECURITY`;migration/repair/audit 使用独立受控角色。
|
||||
- runtime role 的直接 ACL 固定为:business database 的 `CONNECT`、`public` 的 `USAGE`、全部 allowlisted business table 的
|
||||
`SELECT/INSERT/UPDATE/DELETE`、`alembic_version` 的只读 `SELECT`,以及业务表自有 sequence 的 `USAGE/SELECT`。
|
||||
不授予 database/schema `CREATE`、table `TRUNCATE/REFERENCES/TRIGGER`、sequence `UPDATE`、其他对象权限或任何 `WITH GRANT OPTION`。
|
||||
- runtime role 必须是 `LOGIN`,但不得具有 superuser、`BYPASSRLS`、`CREATEDB`、`CREATEROLE` 或 replication 属性;
|
||||
不得在 role membership 中以 granted role、member 或 grantor 任一方向出现;不得拥有 database、schema、table、view、sequence、routine 或 extension,
|
||||
不得持有 column ACL,也不得使用、创建或拥有其他非系统 schema。
|
||||
- business database 必须安装 `vector`,且 extension catalog 只允许 `plpgsql` 和 `vector`;不得存在 FDW、foreign server 或 user mapping。
|
||||
runtime role 和 `PUBLIC` 都不得有显式 routine ACL 或 parameter `SET/ALTER SYSTEM` ACL;runtime role 不得有效执行任何
|
||||
`SECURITY DEFINER` routine,包括被 allowlisted extension 收编的 routine。普通非 `SECURITY DEFINER` 内建函数的隐式执行权限不在此禁令内。
|
||||
- PostgreSQL 新 database 默认向 `PUBLIC` 提供的 `TEMP` 是首版在专用业务 database 上明确接受的兼容性决定,
|
||||
不是 migrator 对 runtime role 的直接 grant;首版不得据此把业务 database 与不受信任工作负载混用。
|
||||
migrator 在释放 advisory lock 前建立并校验上述精确 allowlist;Cloud runtime 每次启动都必须重新完成 schema、身份、有效权限和 catalog 负向校验,发现 drift 立即失败关闭。
|
||||
- PostgreSQL role 是 cluster-wide identity,当前 database 内的 catalog audit 不能证明同一 credential 无法连接 cluster 中的其他 database。
|
||||
SaaS 生产环境必须使用仅向该 credential 暴露目标 business database 的专用 PostgreSQL cluster/endpoint,
|
||||
或通过已验证的 HBA/proxy policy 证明该 credential 只能连接目标 business database;这项部署隔离仍是未完成的 activation gate。
|
||||
- 关键租户表使用 `FORCE ROW LEVEL SECURITY`;migration/repair/audit 使用独立受控 migrator role。
|
||||
- 每个租户事务通过 `SET LOCAL` 设置 tenant context,并由统一 `TenantUnitOfWork` 保证设置 context 和业务查询使用同一事务/连接。
|
||||
禁止使用连接级 session variable 或 `search_path`,避免连接池、PgBouncer、异常回滚和后台任务串租户。
|
||||
- 一个 `TenantUnitOfWork` 只能访问一个 Workspace。业务写入与对应 business outbox 在同一事务中提交;
|
||||
@@ -344,6 +374,9 @@ installation data 的总空间硬配额需要 filesystem project quota 或独立
|
||||
以 `CHECK (vector_dims(embedding) = embedding_dimension)` 校验;release migration 为允许的维度创建带 dimension predicate 的 expression/partial ANN index。
|
||||
知识库/model 元数据必须选择已启用维度,写入和查询 mismatch 或未启用维度时失败关闭,不能截断、补齐、退化为无界扫描或换后端。
|
||||
- `vector` extension、表、索引和 RLS 由 release migration 创建。应用进程不在启动时执行 DDL。
|
||||
- 0013 如需搬迁 legacy pgvector 数据,migrator 作为源表 owner 先记录每个受保护源表的 `ENABLE/FORCE RLS` 状态,
|
||||
仅在同一 migration transaction 内临时暂停 RLS,并在 `finally` 中精确恢复各表原状态。
|
||||
该流程不依赖 superuser 或 `BYPASSRLS`,也不允许在迁移事务外留下已禁用的 RLS。
|
||||
|
||||
### 5.3 候选拓扑与未来演进
|
||||
|
||||
@@ -357,6 +390,7 @@ installation data 的总空间硬配额需要 filesystem project quota 或独立
|
||||
|
||||
M0 不提前增加始终返回 `primary` 的 resolver、shard router 或 shard binding。
|
||||
P1 的 resolver、映射、在线迁移、连接池预算、shard-affine replica 和 dedicated shard 细节等到出现容量、地域或合规需求时再设计。
|
||||
在此之前,direct endpoint 与 pooler endpoint 分离只能通过数据库内部、runtime 不可伪造的 cluster identity 开启,不使用 DNS 名、数据库名或配置声明代替。
|
||||
|
||||
### 5.4 备份与生命周期边界
|
||||
|
||||
@@ -373,6 +407,15 @@ P1 的 resolver、映射、在线迁移、连接池预算、shard-affine replica
|
||||
- 故意遗漏应用层 Workspace filter 时,RLS 仍阻止跨租户读写。
|
||||
- 连接池/事务池复用、异常回滚、并发请求和后台任务不会残留 tenant context;如部署 PgBouncer,也必须覆盖 transaction pooling。
|
||||
- migration 对 shared schema 只执行一次,不产生 Workspace 级 schema drift;应用启动角色不能执行 DDL。
|
||||
- 首版拒绝 host、port 或 database 不同的 migrator/runtime URL,并拒绝相同 role;migrator/runtime 都只解析到 `public`,
|
||||
migrator 在迁移后完成精确 table/sequence/`alembic_version` ACL grant 和正反向 role 校验,runtime 每次启动重新校验。
|
||||
- runtime role 没有任一方向的 role membership、`WITH GRANT OPTION`、`search_path` 覆写、对象所有权、其他 schema 访问或非业务对象权限;
|
||||
专用业务 database 上可继承 PostgreSQL 默认 `PUBLIC TEMP`,但 runtime role 没有直接 `TEMP` ACL。
|
||||
- migrator/runtime session GUC 保持 `session_replication_role=origin`、`row_security=on`、`lo_compat_privileges=off`,
|
||||
runtime role/当前 database 没有任何 `pg_db_role_setting`;extension 仅为 `plpgsql/vector` 且 runtime 不拥有 extension,
|
||||
database 中没有 FDW/server/user mapping、runtime 或 `PUBLIC` 显式 routine/parameter ACL、runtime-owned routine 或 runtime 可执行的 `SECURITY DEFINER` routine。
|
||||
- 生产 deployment 证明 cluster-wide runtime credential 只能连接目标 business database;专用 cluster/endpoint 或 HBA/proxy 隔离未经验证前不得启用 SaaS。
|
||||
- legacy pgvector 搬迁在非 superuser、非 `BYPASSRLS` 的 table-owner migrator 下可成功,成功、异常和重试路径都精确恢复所有源表的 RLS/FORCE 状态。
|
||||
- 业务写入和对应 business outbox 在同一事务内具备可证明的提交顺序;外部 generation/fencing token 校验失败时不产生写入。
|
||||
- pgvector 使用真实 PostgreSQL 集成测试覆盖:两个 Workspace 使用相同 `vector_id`、猜测其他 Workspace ID、
|
||||
故意遗漏 scope、连接复用、CRUD 和后台任务,全部不能越权。
|
||||
@@ -381,13 +424,13 @@ P1 的 resolver、映射、在线迁移、连接池预算、shard-affine replica
|
||||
|
||||
## 6. D-004:stdio MCP 独立开关
|
||||
|
||||
状态:`DECIDED — MVP target confirmed, implementation pending`
|
||||
状态:`IMPLEMENTED`
|
||||
|
||||
### 6.1 当前问题
|
||||
### 6.1 已修复的原问题
|
||||
|
||||
- 当前 stdio MCP 的启用条件只检查 transport 为 `stdio` 且 Box available,没有独立 feature gate。
|
||||
- 所有 stdio MCP 当前使用固定的 `mcp-shared` 逻辑 session,并强制 `persistent=True`。
|
||||
- 如果多租户 Cloud 仅通过 `box.enabled` 开放能力,每个配置 stdio MCP 的 Workspace 都会额外保留一个 persistent sandbox,
|
||||
- 修复前,stdio MCP 的启用条件只检查 transport 为 `stdio` 且 Box available,没有独立 feature gate。
|
||||
- 修复前,所有 stdio MCP 使用固定的 `mcp-shared` 逻辑 session,并强制 `persistent=True`。
|
||||
- 在该旧逻辑下,如果多租户 Cloud 只通过 `box.enabled` 开放能力,每个配置 stdio MCP 的 Workspace 都会额外保留一个 persistent sandbox,
|
||||
绕过“每 Workspace 最多一个 managed `global` sandbox”的成本和套餐边界。
|
||||
|
||||
### 6.2 首期决定
|
||||
|
||||
Reference in New Issue
Block a user