补充AIWeb工程预览方案文档

新增 /editor/agent 静态沙箱预览技术方案

新增 runner 与预览隔离威胁模型

新增 AIWeb 工程静态预览 MVP 验收清单

更新文档索引和团队决策记录
This commit is contained in:
2026-06-13 22:03:31 +08:00
parent 3f4dba97ba
commit a1b9ac8544
5 changed files with 722 additions and 0 deletions

View File

@@ -16,6 +16,14 @@
---
## 2026-06-13 `/editor/agent` AI Web 工程编辑器采用静态沙箱预览 MVP
- 背景:`/editor/agent` 需要承载浏览器内类似 IDE 的 AI Web 工程编辑和实时预览能力,但 AI 生成工程的构建和运行不能进入 Genarrative 主站 JS 上下文、当前仓库源码目录或 api-server 进程。
- 决策:第一版采用“平台编辑器壳 `/editor/agent` + api-server 控制面 + 独立 `web-project-runner` worker + 独立 preview origin”的四层结构。MVP 只支持固定 React / Vite / TypeScript 静态模板、虚拟文件系统、结构化 AI patch、平台固定构建命令、独立 runner 静态构建和独立域 iframe 预览;明确不做 HMR、终端 shell、后端服务、任意端口代理、任意 npm 安装、AI 自定义 shell script 或主站同源预览。
- 影响范围:`/editor/agent` 前端入口、api-server Web project 控制面、Web project runtime job、runner 部署、preview gateway、artifact store、安全验收和后续作品化发布链路。
- 验证方式Phase 0 必须先完成技术方案、威胁模型和验收清单Phase 1 只能在路径校验、runner 资源限制、网络隔离、preview token、iframe/CSP、失败保留上一版预览和刷新恢复验收口径明确后进入编码。
- 关联文档:`docs/technical/【技术方案】浏览器内AIWeb工程沙箱预览方案-2026-06-13.md``docs/technical/【安全模型】AIWeb工程Runner与预览隔离威胁模型-2026-06-13.md``docs/technical/【测试用例】AIWeb工程静态预览MVP验收清单-2026-06-13.md`
## 2026-06-12 外部生成 worker 扩展到跳一跳、拼消消和敲木鱼
- 背景:外部图片生成已从 HTTP 长请求迁到 `external_generation_job` 队列;跳一跳、拼消消和敲木鱼继续扩展时需要统一 job 粒度、前端等待展示和本地 / 生产验证口径。

View File

@@ -21,6 +21,8 @@
微信小程序虚拟支付接入、`wechat_mp_virtual` 渠道、`wx.requestVirtualPayment` 承接页和后端签名配置见 [【技术方案】微信虚拟支付接入-2026-05-26.md](./%E3%80%90%E6%8A%80%E6%9C%AF%E6%96%B9%E6%A1%88%E3%80%91%E5%BE%AE%E4%BF%A1%E8%99%9A%E6%8B%9F%E6%94%AF%E4%BB%98%E6%8E%A5%E5%85%A5-2026-05-26.md)。
`/editor/agent` 浏览器内 AI Web 工程编辑器的静态 SPA 沙箱预览 MVP采用“平台编辑器壳 + api-server 控制面 + 独立 runner worker + 独立预览域”四层结构;技术方案、威胁模型和验收清单见 [【技术方案】浏览器内AIWeb工程沙箱预览方案-2026-06-13.md](./technical/【技术方案】浏览器内AIWeb工程沙箱预览方案-2026-06-13.md)、[【安全模型】AIWeb工程Runner与预览隔离威胁模型-2026-06-13.md](./technical/【安全模型】AIWeb工程Runner与预览隔离威胁模型-2026-06-13.md) 和 [【测试用例】AIWeb工程静态预览MVP验收清单-2026-06-13.md](./technical/【测试用例】AIWeb工程静态预览MVP验收清单-2026-06-13.md)。
本地通过 SSH alias 管理多台服务器、查看硬件 / systemd / HTTP 健康状态并执行受控服务启停的 egui 桌面工具见 [【开发运维】本地SSH服务器管理面板技术方案-2026-06-11.md](./technical/【开发运维】本地SSH服务器管理面板技术方案-2026-06-11.md)。
生产部署切换到 systemd + Nginx + SpacetimeDB 自托管的总方案见 [PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md](./technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md),该文档也是当前生产 Jenkinsfile 的唯一入口。SpacetimeDB 表结构变更、自动迁移边界和保留旧数据的分阶段迁移流程见 [SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md](./technical/SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md)private 表迁移 JSON 导入导出、HTTP 413 分片导入和旧数据库迁移流水线经验见 [SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md](./technical/SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md) 与 [JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md](./technical/JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md);后台管理独立前端工程技术方案见 [ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md](./technical/ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md)。

View File

@@ -0,0 +1,241 @@
# AI Web 工程 Runner 与预览隔离威胁模型
更新时间:`2026-06-13`
## 范围
本文约束 `/editor/agent` 浏览器内 AI Web 工程编辑器的 MVP固定 React / Vite / TypeScript 静态模板、虚拟文件系统、独立 runner 构建、独立 origin iframe 预览。
不覆盖 HMR、终端 shell、后端服务、任意依赖安装、任意端口代理和正式作品发布。这些能力进入后续阶段前必须单独补威胁模型。
## 信任边界
```text
用户浏览器主站 origin
| /editor/agent 编辑器壳
api-server 控制面
| 最小任务能力
web-project-runner 执行面
| immutable artifact
preview gateway / 独立 preview origin
```
关键原则:
- 主站不执行 AI 工程代码。
- api-server 不执行 AI 工程代码。
- runner 无平台密钥、无宿主源码挂载、无 Docker socket。
- 预览域和主站不同 origin。
- 预览页拿不到平台 cookie、access token、SpacetimeDB、OSS 写权限或 LLM provider 密钥。
## 资产与威胁
| 资产 | 主要威胁 | MVP 缓解 |
| --- | --- | --- |
| 主站 access token / cookie | 预览代码同源读取、XSS 窃取 | 独立 preview originiframe 不带主站 cookie预览页不能访问主站 storage |
| 用户 Web 工程源码 | 跨租户读取、snapshot 枚举 | project / owner 校验snapshotId 不可枚举preview token 绑定 owner / project / snapshot |
| preview artifact | 路径穿越、MIME 错误、旧 token 访问 | preview gateway 校验 token禁止 `..`;按白名单 MIME 服务;短期 token 可撤销 |
| runner 临时工作区 | 逃逸到宿主源码、读取密钥 | 独立临时目录或容器;非 root无宿主源码挂载任务结束销毁 |
| 依赖缓存 | 缓存污染、恶意 postinstall | MVP 固定依赖;禁用 scripts缓存 key 包含模板、Node 版本和 lock digest |
| api-server / SpacetimeDB | runner 横向访问内部服务 | runner 默认无内网访问;阻断 api-server 管理端口、SpacetimeDB 和生产数据库 |
| OSS / artifact store | 越权读写、签名 URL 泄露 | runner 只拿短期只读资产签名或受控写 artifact 能力;日志脱敏 |
| 构建日志 | 泄露环境变量、宿主路径、签名 URL | 日志限长、脱敏、错误摘要化;不回显平台密钥 |
| 用户浏览器 | 弹窗逃逸、下载、剪贴板、摄像头、Service Worker 常驻 | iframe sandboxCSP禁用 Service Worker不授权敏感能力 |
## Runner 限制
runner 必须 fail-closed。每个 job 至少限制:
- CPU。
- 内存。
- 磁盘。
- 进程数。
- 打开文件数。
- 任务时长。
- 日志大小。
- artifact 大小。
- 单文件大小。
执行环境要求:
- 非 root 用户。
- 只读基础镜像。
- 无 Docker socket。
- 无宿主源码目录挂载。
- 无平台 `.env`
- 无平台 token。
- 临时工作区任务结束销毁。
构建超时或资源超限时直接 killjob 进入 `failed``expired`,保留可展示错误摘要,不推进 active preview。
## 网络限制
MVP 构建期默认无外网。若模板构建确实需要网络,只允许:
- 平台受控 npm registry mirror。
- 平台资产只读签名域。
必须阻断:
- RFC1918 内网网段。
- 云 metadata 地址。
- api-server 管理端口。
- SpacetimeDB。
- 生产数据库。
- Docker daemon。
- 任意用户配置 registry。
需要覆盖 DNS rebinding 和 HTTP redirect 到内网的情况;不能只按初始 URL 字符串判断。
## 预览 token
preview token 必须满足:
- 绑定 `ownerUserId`
- 绑定 `projectId`
- 绑定 `snapshotId`
- 绑定 `artifactId`
- 短期有效。
- 可撤销。
- 不可枚举。
- 不能跨租户复用。
访问无权限 artifact 应返回 `403` 或不可区分的 `404`,不得泄露其它项目是否存在。
## Preview Gateway
gateway 只读服务 immutable artifact。
必须校验:
- token 有效且未撤销。
- artifact 属于 token 绑定 snapshot。
- 请求路径规范化后仍在 artifact 根目录。
- `index.html` fallback 只在 SPA 路由范围内生效。
- MIME 类型来自白名单映射,不信任上传文件名。
必须测试:
- path traversal。
- 错误 MIME。
- HTML 注入。
- 缓存串租户。
- 旧 token 访问。
- artifact 删除后访问。
- token 过期后访问。
## 浏览器隔离
iframe sandbox MVP 建议最小化:
```text
sandbox="allow-scripts"
```
如果后续需要表单或同源能力必须单独评审。MVP 不允许:
- `allow-same-origin`
- `allow-top-navigation`
- `allow-downloads`
- `allow-popups`
- `allow-modals`
- 摄像头。
- 麦克风。
- 剪贴板。
- 地理位置。
CSP 默认收紧:
```text
default-src 'none';
script-src 'self';
style-src 'self' 'unsafe-inline';
img-src 'self' data: blob: https://assets.genarrative.world;
font-src 'self' data:;
connect-src 'none';
frame-ancestors https://www.genarrative.world;
worker-src 'none';
```
MVP 禁用 Service Worker 和持久缓存,避免恶意预览代码在用户浏览器里长期驻留。
## Patch 校验
AI 只能提交结构化 patch
- create file
- update file
- delete file
- rename file
- package manifest request
api-server 必须拒绝:
- 绝对路径。
- `..`
- 符号链接。
- `.env``.npmrc``.git``.ssh` 等隐藏敏感文件。
- 超深目录。
- 超大文件。
- 超大总 snapshot。
- 二进制膨胀。
- 大 Data URL。
- 可执行权限。
前端编辑器可以显示校验错误,但正式准入以 api-server 为准。
## 依赖供应链
MVP 固定模板依赖,不开放任意 npm。即便用户或 AI 修改 `package.json`,也必须拒绝或忽略:
- `preinstall`
- `install`
- `postinstall`
- `prepare`
- `git:` 依赖。
- `file:` 依赖。
- `http:` / `https:` tarball 依赖。
- 私有 registry。
- lockfile 篡改。
- native build。
- 二进制下载型包。
后续开放白名单依赖时,必须加入依赖 resolver、registry mirror、封禁列表、许可证 / 安全扫描和缓存污染防护。
## 审计与熔断
必须记录:
- `ownerUserId`
- `projectId`
- `snapshotId`
- `jobId`
- `artifactId`
- `templateKey`
- 依赖 lock digest
- 构建耗时
- 资源用量
- 失败原因摘要
- runner id
- preview token 签发和撤销事件
必须提供运维开关:
- kill job。
- 禁用项目。
- 禁用 owner。
- 禁用模板。
- 禁用依赖。
- 清理 artifact。
- 暂停 runner。
- 全局关闭 `/editor/agent` preview build。
## 发布门禁
临时 preview artifact 不能直接升为线上作品。作品化发布必须:
- 重新构建。
- 重新校验 snapshot。
- 重新签发发布 artifact。
- 使用 immutable artifact。
- 走平台作品身份、公开详情、统计和权限链路。

View File

@@ -0,0 +1,266 @@
# 浏览器内 AI Web 工程沙箱预览方案
更新时间:`2026-06-13`
## 背景
`/editor/agent` 需要承载一个类似 IDE 的 AI Web 工程编辑器用户在浏览器里看到文件树、代码编辑、AI 指令输入、构建日志和实时预览AI 生成的是一个完整 Web 工程。这个工程的构建、依赖安装和运行必须与 Genarrative 主站、当前仓库源码目录、平台密钥和正式业务数据隔离。
第一版不追求“浏览器里完整云 IDE + 任意 npm + HMR + 后端服务”。目标是先跑通一个安全、可恢复、可验收的静态 SPA 预览闭环。
## 结论
MVP 采用四层结构:
```text
平台编辑器壳 /editor/agent
-> api-server 控制面
-> 独立 web-project-runner worker
-> 独立 preview origin / preview gateway
```
第一版只支持固定 React / Vite / TypeScript 静态模板、虚拟文件系统、结构化 AI patch、平台固定构建命令、独立 runner 静态构建和独立域 iframe 预览。
MVP 明确不做:
- 终端 shell。
- 任意后端服务。
- 任意端口代理。
- HMR / 长驻 dev server。
- 任意 npm 依赖安装。
- AI 自定义 build shell script。
- 与主站同源的预览 iframe。
- 将 AI 生成工程写入当前 Genarrative 仓库源码目录。
## 分层职责
### 平台编辑器壳
入口路由固定为 `/editor/agent`。这一层只负责前端体验:
- 文件树、代码编辑器、AI 指令输入。
- 当前项目版本、diff、构建日志和预览 iframe。
- 保存用户编辑和 AI patch。
- 订阅构建 job SSE 状态。
- 在构建成功后切换 iframe 的 `previewUrl`
- 构建失败时保留上一版可用预览。
平台编辑器壳不得直接执行用户工程代码,不持有 runner 临时工作区路径,不把平台 access token、用户 cookie、SpacetimeDB 连接信息或 OSS 写权限暴露给预览页。
如果后续接入现有创作链路,入口仍应走 `play_flow` 主干和 `shared-contracts` DTO不在前端壳或 `app.rs` 中新建平行业务流程。
### api-server 控制面
控制面只管理权限、快照、任务和状态,不执行 AI 工程代码:
- 鉴权和项目归属校验。
- 校验 AI patch 和用户编辑。
- 保存虚拟文件系统 snapshot。
- 创建 preview build job。
- 给 runner 发放最小任务能力。
- 输出构建日志和状态 SSE。
- 签发短期 preview URL。
- 将业务状态通过受控 procedure 或 BFF 更新到正式数据层。
api-server 不把 SpacetimeDB、OSS 写权限、LLM provider、支付、用户 cookie 或平台内部 token 传给 runner。runner 需要读取资产时,只拿只读短期签名 URL 或受控 fixture。
### web-project-runner worker
新增独立进程角色,例如 `web-project-runner`。它可以复用外部生成 worker 的“任务表 + lease + controller + worker”模式但不应把 Web 工程执行塞进 `external_generation_job`,避免语义污染。更合适的落点是新增 `web_project_runtime_job` 或抽象出通用 job 模块。
runner 只做执行面:
- 拉取指定 snapshot。
- 展开到独立临时工作区或容器。
- 使用平台白名单模板依赖。
- 执行平台固定构建命令。
- 采集构建日志、资源用量和结果。
- 上传静态 artifact。
runner 不能反向写平台业务表。业务状态回写必须经过 api-server / SpacetimeDB 的受控入口。
### preview gateway 与独立预览域
预览页使用独立 origin例如
```text
https://preview-<token>.sandbox.genarrative.world
```
或者统一域名加不可枚举 token path
```text
https://sandbox.genarrative.world/p/<previewToken>/
```
预览域不得与主站同源,不带平台 cookie不共享主站 `localStorage` / `sessionStorage`。主站只通过 sandbox iframe 嵌入预览。
MVP 只服务静态构建产物。HMR、WebSocket 代理和长驻 dev server 后置到单独阶段评审。
## MVP 流程
```text
用户在 /editor/agent 输入需求或编辑文件
-> AI 返回结构化 patch
-> api-server 校验 patch
-> 生成 workspace snapshot
-> 前端 debounce 后创建 preview build job
-> runner claim job 并构建静态 dist
-> artifact 上传 artifact store
-> preview gateway 只读服务 artifact
-> 前端 SSE 收到 succeeded 后 iframe reload
```
失败链路:
```text
构建失败 / 超时 / runner 崩溃
-> job failed / expired
-> 前端展示错误日志摘要
-> active preview 保持上一版 succeeded artifact
```
## 接口草案
接口归属分成项目控制面和运行时控制面。
```text
POST /api/creation/web-project/projects
GET /api/creation/web-project/projects/{projectId}/snapshot
PATCH /api/creation/web-project/projects/{projectId}/files
POST /api/runtime/web-project/projects/{projectId}/preview-builds
GET /api/runtime/web-project/preview-builds/{jobId}
GET /api/runtime/web-project/preview-builds/{jobId}/events
```
`/events` 复用现有 `src/services/sseStream.ts` 的 SSE 传输层口径。事件类型建议包括:
- `queued`
- `running`
- `log`
- `succeeded`
- `failed`
- `cancelled`
- `expired`
- `stale`
前端刷新恢复时,先读取项目 active snapshot 和 active preview再按未终态 job 继续订阅 SSE。
## 虚拟文件系统
平台内的“文件系统”是虚拟工作区,不是真实目录长期挂载。
snapshot manifest 建议包含:
- `projectId`
- `snapshotId`
- `parentSnapshotId`
- `ownerUserId`
- `templateKey`
- `files[]`
- `createdAt`
- `createdBy`
- `patchSummary`
文件项建议包含:
- `path`
- `contentDigest`
- `sizeBytes`
- `mediaType`
- `encoding`
- `executable=false`
路径必须 fail-closed
- 只允许相对路径。
- 拒绝绝对路径。
- 拒绝 `..`
- 拒绝符号链接。
- 拒绝超深目录。
- 拒绝超大文件。
- 拒绝隐藏敏感文件名,例如 `.env``.npmrc``.ssh``.git`
- MVP 只支持文本源码和少量静态资源。
文件内容小文本可以按 digest 存对象;大一点的 snapshot 可打包成 tar / zip artifact 放受控 artifact store。图片、音频等大资产继续走现有资产链路不让 AI 工程随意内嵌大 Data URL。
## 依赖和构建
MVP 只支持平台预置模板依赖:
- React
- Vite
- TypeScript
- 平台已审核的 UI / 工具依赖子集
`package.json` 在 MVP 中不是事实源。AI 可以提出 manifest patch但 api-server 会重写或忽略危险字段。构建命令由平台固定,例如:
```text
npm ci --ignore-scripts
npm exec vite build
```
第一版应禁止:
- `preinstall` / `install` / `postinstall`
- `git:` / `file:` / `http:` 依赖。
- 私有 registry。
- native build。
- 二进制下载型包。
- AI 自定义 shell script。
后续若要开放依赖,必须进入“受控依赖白名单”和“隔离依赖解析服务”阶段,不混入 MVP。
## 预览状态机
```text
draft snapshot
-> build queued
-> build running
-> build succeeded
-> build failed
-> build cancelled
-> build expired
-> build stale
```
状态规则:
- 新 snapshot 触发新 build 时,旧 running build 应取消或标记 stale。
- 只有当前 active snapshot 的 `succeeded` job 可以成为 active preview。
- failed / cancelled / expired / stale 不能覆盖 active preview。
- 回滚是切回历史 snapshot 并复用对应 immutable artifact或重新构建该 snapshot。
- 不允许复用 runner 临时目录作为回滚来源。
## 后续阶段
### Phase 0文档和威胁模型
补齐技术方案、威胁模型和验收清单,明确 MVP 不可做能力、安全门禁、状态机和 QA 口径。
### Phase 1静态模板预览纵切
完成 `/editor/agent` 编辑器壳、固定模板、虚拟文件系统、AI patch 保存、runner 静态构建、artifact 服务和 iframe reload。
### Phase 2持久任务和恢复
引入 `web_project_runtime_job`,按 lease / controller / worker 模式实现任务队列、取消、stale、刷新恢复和日志 SSE。
### Phase 3受控依赖安装
支持白名单依赖、lockfile 固化、依赖层缓存、安装失败可读错误、依赖封禁和审计。
### Phase 4实时体验增强
在安全评审后再做长驻 dev server、HMR、WebSocket 代理、端口租约和空闲回收。
### Phase 5作品化发布
将通过安全门禁的 Web project 接入平台作品类型。发布必须重新构建 immutable artifact不直接提升临时预览 artifact。
## 与现有系统的关系
- 前端 SSE 读取复用 `src/services/sseStream.ts`
- 后端 job 模式参考外部生成 worker 的 lease / controller 经验,但使用新的 Web 工程 runtime 语义。
- `/editor/agent` 是第一版用户入口,不新增重复 IDE 页面。
- 业务真相仍通过 server-rs + SpacetimeDB 受控写入,前端和 runner 都不能绕过控制面。

View File

@@ -0,0 +1,205 @@
# AI Web 工程静态预览 MVP 验收清单
更新时间:`2026-06-13`
## 范围
本清单用于验收 `/editor/agent` 浏览器内 AI Web 工程编辑器 MVP。
MVP 必须只支持:
- 固定 React / Vite / TypeScript 静态模板。
- 虚拟文件系统。
- 结构化 AI patch。
- 独立 runner 静态构建。
- 独立 preview origin iframe 预览。
- 失败保留上一版可用预览。
MVP 不支持:
- 终端 shell。
- 后端服务。
- HMR。
- 任意端口代理。
- 任意 npm 安装。
- AI 自定义 package scripts。
- Service Worker。
- 主站同源预览。
## Happy Path
- [ ] 用户打开 `/editor/agent` 能看到文件树、编辑器、AI 输入区、构建日志区和预览 iframe。
- [ ] 创建新 Web project 后得到固定模板文件树。
- [ ] AI patch 新增或修改一个 React 组件后api-server 生成新 snapshot。
- [ ] 前端 debounce 后创建 preview build job。
- [ ] runner 构建成功并产出 immutable artifact。
- [ ] SSE 返回 `queued -> running -> succeeded`
- [ ] iframe 切换到新 preview URL。
- [ ] 刷新 `/editor/agent` 后能恢复当前 project、active snapshot、active preview 和未完成 job 状态。
## Patch 与路径校验
- [ ] 相对路径普通源码修改通过。
- [ ] 绝对路径被拒绝。
- [ ] `..` 路径被拒绝。
- [ ] 符号链接被拒绝。
- [ ] `.env` 被拒绝。
- [ ] `.npmrc` 被拒绝。
- [ ] `.git/` 被拒绝。
- [ ] `.ssh/` 被拒绝。
- [ ] 超深目录被拒绝。
- [ ] 超大单文件被拒绝。
- [ ] 超大 snapshot 被拒绝。
- [ ] 大 Data URL 被拒绝或转资产流程。
- [ ] 二进制膨胀被拒绝。
- [ ] rename 后目标路径仍需重新校验。
## 构建与状态机
- [ ] job 状态覆盖 `queued/running/succeeded/failed/cancelled/expired/stale`
- [ ] 新 snapshot 创建后,旧 running job 被取消或标记 stale。
- [ ] 只有当前 active snapshot 的 `succeeded` job 能推进 active preview。
- [ ] failed job 不覆盖上一版 active preview。
- [ ] cancelled job 不覆盖上一版 active preview。
- [ ] expired job 不覆盖上一版 active preview。
- [ ] stale job 不覆盖上一版 active preview。
- [ ] 构建失败时展示可读错误摘要和日志片段。
- [ ] 构建超时后 runner 被 killjob 进入 failed 或 expired。
- [ ] runner 崩溃后 job 能恢复为可重领或 expired。
- [ ] 页面刷新后能通过 projectId / jobId 恢复日志和状态。
- [ ] snapshot 回滚会复用对应 immutable artifact 或重新构建,不复用临时目录。
## Runner 隔离
- [ ] runner 进程无平台密钥环境变量。
- [ ] runner 无宿主源码目录挂载。
- [ ] runner 无 Docker socket。
- [ ] runner 使用非 root 用户。
- [ ] runner 工作区为任务级临时目录。
- [ ] 任务结束后临时目录被销毁。
- [ ] CPU 限制生效。
- [ ] 内存限制生效。
- [ ] 磁盘限制生效。
- [ ] 进程数限制生效。
- [ ] 打开文件数限制生效。
- [ ] 日志大小限制生效。
- [ ] artifact 大小限制生效。
- [ ] 任务超时限制生效。
## 网络隔离
- [ ] 构建期默认不能访问公网。
- [ ] 若允许 registry mirror只能访问白名单域名。
- [ ] 不能访问 RFC1918 内网地址。
- [ ] 不能访问云 metadata 地址。
- [ ] 不能访问 api-server 管理端口。
- [ ] 不能访问 SpacetimeDB。
- [ ] 不能访问生产数据库。
- [ ] HTTP redirect 到内网时被阻断。
- [ ] DNS rebinding 到内网时被阻断。
## 依赖供应链
- [ ] AI 修改 `package.json` 新增普通依赖时MVP 拒绝或忽略。
- [ ] `preinstall` 被拒绝或忽略。
- [ ] `install` 被拒绝或忽略。
- [ ] `postinstall` 被拒绝或忽略。
- [ ] `prepare` 被拒绝或忽略。
- [ ] `git:` 依赖被拒绝。
- [ ] `file:` 依赖被拒绝。
- [ ] `http:` / `https:` tarball 依赖被拒绝。
- [ ] 私有 registry 被拒绝。
- [ ] lockfile 篡改被拒绝或重写。
- [ ] 构建命令由平台固定,不执行 AI 写入的 shell script。
## Preview Token 与 Gateway
- [ ] preview token 绑定 owner。
- [ ] preview token 绑定 project。
- [ ] preview token 绑定 snapshot。
- [ ] preview token 绑定 artifact。
- [ ] preview token 短期有效。
- [ ] preview token 可撤销。
- [ ] preview token 不可枚举。
- [ ] 跨租户访问返回 403 或 404。
- [ ] path traversal 被拒绝。
- [ ] 错误 MIME 不会按可执行脚本服务。
- [ ] SPA fallback 只在 artifact 根内生效。
- [ ] artifact 删除后旧 URL 不能继续读取。
- [ ] token 过期后旧 URL 不能继续读取。
- [ ] preview cache 不串租户。
## 浏览器隔离
- [ ] 预览 origin 与主站 origin 不同。
- [ ] 预览 iframe 不带主站 cookie。
- [ ] 预览代码不能读取主站 `localStorage`
- [ ] 预览代码不能读取主站 `sessionStorage`
- [ ] 预览代码不能调用主站认证 API。
- [ ] iframe sandbox 不允许 top navigation。
- [ ] iframe sandbox 不允许 downloads。
- [ ] iframe sandbox 不允许 popups。
- [ ] iframe sandbox 不允许 clipboard。
- [ ] iframe sandbox 不允许 camera / mic。
- [ ] CSP 禁止未白名单 `connect-src`
- [ ] Service Worker 被禁用。
## 日志与错误
- [ ] 构建日志按 jobId 分段展示。
- [ ] 日志限长。
- [ ] 错误摘要可读。
- [ ] 日志不包含平台 token。
- [ ] 日志不包含 OSS 写签名。
- [ ] 日志不包含完整宿主路径。
- [ ] 日志不包含环境变量 dump。
- [ ] SSE 断开后前端可重新拉取 job 状态。
## 取消、回滚与并发
- [ ] 用户连续编辑触发多个 snapshot 时,只保留最新 snapshot 的 active build 候选。
- [ ] 用户手动取消当前 build 后runner 停止或 job 被标记 cancelled。
- [ ] 两个标签页同时编辑同一项目时,有明确版本冲突或 last-write 策略提示。
- [ ] 回滚到历史 snapshot 后active preview 对应历史 snapshot。
- [ ] 历史 artifact 缺失时可重新构建。
- [ ] 构建队列积压时 `/editor/agent` 显示确定状态,不假装实时完成。
## Artifact GC
- [ ] 未引用的 failed artifact 会清理。
- [ ] 过期 preview artifact 会清理。
- [ ] active preview artifact 不会被误删。
- [ ] 历史 snapshot 的可回滚 artifact 按保留策略保留或可重建。
- [ ] GC 后 preview gateway 对已删除 artifact 返回确定错误。
## 最小自动化验证建议
后端 / runner
```bash
cargo test -p api-server web_project --manifest-path server-rs/Cargo.toml
cargo test -p spacetime-module web_project --manifest-path server-rs/Cargo.toml
```
前端:
```bash
npm run test -- src/services/sseStream.test.ts
npm run test -- src/components/editor/agent
npm run typecheck
npm run check:encoding
git diff --check
```
浏览器 smoke
```text
打开 /editor/agent
创建模板项目
提交一次 AI patch
等待静态构建成功
确认 iframe 展示新预览
提交一次故意破坏构建的 patch
确认错误出现且上一版预览仍保留
刷新页面确认项目、日志和 active preview 可恢复
```