diff --git a/skills/app-dev/SKILL.md b/skills/app-dev/SKILL.md index d6e1db1..2158fd1 100644 --- a/skills/app-dev/SKILL.md +++ b/skills/app-dev/SKILL.md @@ -113,7 +113,7 @@ aigrego-release publish --manifest app.manifest.json [--image ] [--store] [ ``` - **manifest 进平台是双通道、同一份文件**:CLI `publish --manifest`(上)或平台侧 console「应用中心」按向导导入——同一条 submit 管道(同一套校验、治理字段变更同样 202 进审核队列)。不管走哪条,仓库里的 `app.manifest.json` 都必须最新且合法;走手动通道时把这份文件交付给平台管理员。 -- **大产物分流(先量再发)**:dist tgz ≤64 MiB → 照旧 `publish --dist`;超限(已压缩 wasm/`.data` 几乎压不动)→ 核心放对象存储 `apps///`、dist 只留壳、manifest 按指令声明 `embedCsp`(connect/script/worker/img/media,只能是 `blob:` 或 `scheme://host[:port]`)。平台基线固定 `script-src 'self' 'wasm-unsafe-eval'`(wasm 编译必需);外链 stylesheet 仍未放开。桶必须配 CORS(含 `Allow-Headers: Range`)。细节见 `references/contract.md §7.1`。 +- **大产物分流(先量再发)**:dist tgz ≤64 MiB → 照旧 `publish --dist`;超限(已压缩 wasm/`.data` 几乎压不动)→ 核心放对象存储 `apps///`、dist 只留壳、manifest 声明 `embedCsp`(`connectSrc` + `wasmUnsafeEval` + `blob`,三项默认关闭、都进审核)。核心 JS 用 `fetch` 下载后 `URL.createObjectURL` 成 Blob 执行;跨域直载 script/Worker 不支持。桶必须配 CORS(含 `Allow-Headers: Range`)。细节见 `references/contract.md §7.1`。 - 治理字段(`scopes`/`aclManifest`/`exchangeTargets`/`dependencies`/`mounts`/`embedCsp`)变更 → 202 进审核队列(exit 0 但**不生效**),批准前不影响已安装租户;首个版本直接生效。 - 商店上架/授权/安装/启停/卸载是平台侧 console 动作;镜像 host 必须在 registries 白名单(空表=全拒)。 - 输出「待平台侧操作」清单:auto_publish 开关、registries 登记、治理审核批准、授权安装——这些 Agent 做不到,不绕道不假装完成。 diff --git a/skills/app-dev/references/checklist.md b/skills/app-dev/references/checklist.md index 45c4e54..b9473d9 100644 --- a/skills/app-dev/references/checklist.md +++ b/skills/app-dev/references/checklist.md @@ -115,10 +115,10 @@ | I1 | dist 打包成 tgz 后 ≤64 MiB(平台请求体硬上限);未压缩体积超限但实测 tgz 达标 → 仅提示 | die(tgz 超限)/ warn(压缩率依赖) | 脚本实算 `tar czf -` | | I2 | dist 内无单文件 >8 MiB 的已压缩资源(`.wasm`/`.data`/`.br`/`.gz`/`.zip`/`.7z`/`.mp4`);有则必须外置 | warn,tgz 超限时 die | 文件大小扫描 | | I3 | 需要外置时 manifest 必须声明 `embedCsp.connectSrc`(非空) | die | 脚本联动 I1/I2 | -| I4 | `embedCsp` 结构合法:仅 `type=micro`;connect/script/worker/img/media 五条指令各自 ≤8 条、合计 ≤20 条;每项只能是 `blob:` 或 `scheme://host[:port]`(可 `*.`),无路径/查询/裸 `*`/分号/空白/重复;`'self'`/`'unsafe-eval'` 等关键字拒绝(wasm 基线平台已固定) | die | 正则 + 去重 | +| I4 | `embedCsp` 结构合法:仅 `type=micro`;`connectSrc` 每项 `scheme://host[:port]`(可 `*.`,≤8 条,无路径/查询/裸 `*`/分号/空白/重复);`wasmUnsafeEval`/`blob` 必须是布尔 | die | 正则 + 类型 | | I5 | 声明与用点对得上:源码有外部 origin 的 `fetch`/`instantiateStreaming` 但 `connectSrc` 未声明 → warn;声明了但源码找不到使用点 → warn(死配置) | warn | grep 源码与构建产物 | -| I6 | 跨域加载方式已按指令声明:外链 `' >>"$D/web/index.html" -expect "外链脚本未声明拦截" "$D" 'scriptSrc 声明' 1 -set_embed_json "$D/app.manifest.json" '{"scriptSrc":["https://cdn.example.com"]}' -expect "外链脚本已声明放行" "$D" 'scriptSrc 声明' 0 +expect "跨域脚本直载拦截" "$D" '不支持跨域直载脚本' 1 D=$(fixture blob-worker) echo "const u = URL.createObjectURL(new Blob([])); new Worker(u);" >>"$D/web/src/main.tsx" -expect "blob Worker 未声明拦截" "$D" 'blob Worker' 1 -set_embed_json "$D/app.manifest.json" '{"workerSrc":["blob:"]}' -expect "blob Worker 已声明放行" "$D" 'blob Worker' 0 +expect "blob 未开启拦截" "$D" 'embedCsp.blob 未开启' 1 +set_embed_json "$D/app.manifest.json" '{"blob":true}' +expect "blob 开启放行" "$D" 'embedCsp.blob 未开启' 0 + +D=$(fixture wasm-use) +echo "WebAssembly.instantiate(bytes);" >>"$D/web/src/main.tsx" +expect "wasm 未开启拦截" "$D" 'wasmUnsafeEval 未开启' 1 +set_embed_json "$D/app.manifest.json" '{"wasmUnsafeEval":true}' +expect "wasm 开启放行" "$D" 'wasmUnsafeEval 未开启' 0 + +# 2b) 开关必须是布尔。 +D=$(fixture embed-bad-flag) +set_embed_json "$D/app.manifest.json" '{"blob":"yes"}' +expect "开关非布尔拦截" "$D" 'embedCsp 非法' 1 # 4) 合规声明 + 使用点 + 小 dist → 不误报。 D=$(fixture embed-ok)