update
This commit is contained in:
1 parent
444f20c319
commit
ff503b0b76
12 files changed
+54
-18
No files matched your search
@@ -132,7 +132,7 @@ aigrego-release publish --manifest app.manifest.json [--image <ref>] [--store] [
|
||||
- ⑤ **应用 API 路径禁用 `/api`、`/auth`、`/svc` 前缀**(含自定义域名下),用 `/v1/` 之类。为什么:这三个前缀是平台保留通道,网关静态转发/验签规则会截胡或放行错流量。
|
||||
- ⑥ **密钥/令牌不进日志、不落配置文件、不进 argv**。为什么:`@aigrego/logger` 的字段名自动脱敏只是兜底;CI 里命令行参数会进 `ps` 和构建日志。凭证走 env 注入。
|
||||
- ⑦ **manifest 不携带 `deployDescriptor`**。为什么:它仅平台管理员可写;自注册时会被剥离(记 warn+审计),submit 携带非管理员直接 403——带了也没用,还制造「以为生效」的错觉。
|
||||
- ⑧ **micro 前端:portal-sdk 用 vendor 版(`<script src="/apps/<key>/_/vendor/portal-sdk.js">`)不打进 bundle;JS 全部外置,禁内联 `<script>`**。为什么:vendor 保证桥协议版本与宿主同源(BUG-44 版本闸门);PROD CSP 是严格 `default-src 'self'`,内联脚本直接白屏。
|
||||
- ⑧ **micro 前端:portal-sdk 用 vendor 版(`<script src="/apps/<key>/vendor/portal-sdk.js">`)不打进 bundle;JS 全部外置,禁内联 `<script>`**。为什么:vendor 保证桥协议版本与宿主同源(BUG-44 版本闸门);PROD CSP 是严格 `default-src 'self'`,内联脚本直接白屏。托管路径 2026-10 起拍平为 `/apps/<key>/*`,残留旧 `/_/` 前缀的产物传上去资产全 404。
|
||||
- ⑨ **改治理字段要有审核预期**:提交返回 202 = 进了平台管理员审核队列,批准前旧 manifest 继续生效。为什么:scopes/acl 是租户安全边界,平台不允许应用单方面扩权。
|
||||
- ⑩ **容器规格红线**:商店安装只收 `{image, port, env}`;禁挂 docker.sock/宿主路径;资源限额默认 512Mi/1核/256pids 只可收窄;保留 env(`APP_KEY/APP_SECRET/PORTAL_API_URL/PORT`)禁覆盖。为什么:docker.sock 是宿主 root 等价物,信任不向下传递(平台安全模型 §7)。
|
||||
|
||||
|
||||
@@ -57,8 +57,8 @@
|
||||
|
||||
| # | 项 | 档 | 验证方法 |
|
||||
|---|---|---|---|
|
||||
| E1 | portal-sdk 用 vendor 版 `<script src="/apps/<key>/_/vendor/portal-sdk.js">`,源码不 `import '@aigrego/portal-sdk'` | die `[S]` | grep |
|
||||
| E2 | index.html 资源引用全部绝对路径 `/apps/<key>/_/...` | die `[S]` | 读 html |
|
||||
| E1 | portal-sdk 用 vendor 版 `<script src="/apps/<key>/vendor/portal-sdk.js">`,源码不 `import '@aigrego/portal-sdk'` | die `[S]` | grep |
|
||||
| E2 | index.html 资源引用全部绝对路径 `/apps/<key>/...`(严禁旧 `/_/` 子路径) | die `[S]` | 读 html |
|
||||
| E3 | 无内联 `<script>` 代码块(PROD CSP 严格 default-src 'self') | die `[S]` | grep html |
|
||||
| E4 | `sdk.ready()` 握手 + 非 iframe 环境降级友好页 | die | 读 sdk 封装 |
|
||||
| E5 | 后端调用一律 `sdk.callService(appKey, ...)`,不直接 fetch `/svc/...` | warn | grep fetch |
|
||||
|
||||
@@ -150,8 +150,8 @@ logger.info('request', { method, path, status, ms }); // 每请求一行
|
||||
|
||||
## 7. micro 前端接入(portal-sdk 宿主桥)
|
||||
|
||||
- 前端产物由 Portal 同源托管 `/apps/<key>/_/*`(未登录 302、深链 index.html 兜底);iframe sandbox 固定属性;**PROD CSP `default-src 'self'` 无 unsafe-inline——JS 必须外置文件**
|
||||
- **SDK 不打进 bundle**:`<script src="/apps/<key>/_/vendor/portal-sdk.js">` 注入全局 `createPortalClient`;vendor 文件 = 平台 `portal-sdk` 的 dist/browser.js 拷贝
|
||||
- 前端产物由 Portal 同源托管 `/apps/<key>/*`(2026-10 拍平,旧 `/_/` 子路径下线;静态层闸 = published ∧ 当前租户已授权,否则一律 404;顶层导航直达 301 回壳路由,深链走 `?r=` query);iframe sandbox 固定属性;**PROD CSP `default-src 'self'` 无 unsafe-inline——JS 必须外置文件**
|
||||
- **SDK 不打进 bundle**:`<script src="/apps/<key>/vendor/portal-sdk.js">` 注入全局 `createPortalClient`;vendor 文件 = 平台 `portal-sdk` 的 dist/browser.js 拷贝
|
||||
- 接入序列:`sdk.ready()` 握手 → `InitPayload{appKey,host,theme,locale,user,tenant,route,fullscreen,acl}`;不在 iframe 内运行会抛错 → 降级友好页
|
||||
- **后端调用一律 `sdk.callService(appKey, path, init)`**(宿主铸 `aud=<key>` 用户态 TDT 代发 `/svc/<key><path>`,零跨域);业务错误约定 `200+{ok:false,error:{code,message}}` 信封,闸口错误走传输层状态码
|
||||
- `sdk.getToken(scopes?)` 宿主缓存续期(窄令牌不复用为宽)
|
||||
@@ -159,7 +159,7 @@ logger.info('request', { method, path, status, ms }); // 每请求一行
|
||||
- **ACL 前端收口**:握手 `init.acl`(admin → `bypass:true`;member → 仅 `defaultForMember` 页 PID 列表)驱动页面显隐与前端路由守卫——**只是 UX 闸,真闸是后端四道闸**
|
||||
- i18n:只读宿主 `localStorage['ts-lang']`(zh-CN/en-US)+ 监听 storage 事件实时切换,不反写;zh-CN 字典为唯一事实来源
|
||||
- 皮肤令牌 `--sk-*` 属门户自身,不辐射 iframe 内应用;micro 应用样式自管
|
||||
- 产物发布:`aigrego-release publish --dist <dir>`,包根必须直接含 `index.html`(≤64MB,原子替换);index.html 用**绝对路径** `/apps/<key>/_/...` 引用资源
|
||||
- 产物发布:`aigrego-release publish --dist <dir>`,包根必须直接含 `index.html`(≤64MB,原子替换);index.html 用**绝对路径** `/apps/<key>/...` 引用资源
|
||||
|
||||
## 8. 令牌(TDT)与跨应用交换
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ curl -sSL https://code.innev.cn/images/tickshield-dist/raw/branch/main/cli/aigre
|
||||
`publish` 子动作:
|
||||
|
||||
1. `--manifest app.manifest.json` → `POST /api/apps/submit`。治理字段有 diff ⇒ **202 进审核队列,批准前不影响已安装租户**;无 diff ⇒ 200 当场生效;**首个版本直接生效**。版本号以 manifest.version 为准(semver)。
|
||||
2. `--dist <dir|tgz>` → `POST /api/apps/:key/artifacts`。产物目录根的 `index.html` 必须存在(`tar czf -C <dir> .`,套一层目录会被拒);≤64MB、路径穿越/symlink 被拒、同卷 rename 原子替换;上传后 `/apps/<key>/_/*` 托管立即可读。
|
||||
2. `--dist <dir|tgz>` → `POST /api/apps/:key/artifacts`。产物目录根的 `index.html` 必须存在(`tar czf -C <dir> .`,套一层目录会被拒);≤64MB、路径穿越/symlink 被拒、同卷 rename 原子替换;上传后 `/apps/<key>/*` 托管立即可读(2026-10 起拍平,旧 `/_/` 子路径产物必须重新构建上传)。
|
||||
3. `--image <ref>` → `POST /api/apps/:key/deploy`。只写 `deployDescriptor.image` 并滚动重启;**镜像必须先由应用方自己 push 到平台白名单 registry**;docker.sock 不可用时降级为仅记录。
|
||||
4. `--store` → `POST /api/apps/:key/publish` 自行上架。**前置:平台已给该应用开 `auto_publish`**,否则 403;已上架返回 409 视为跳过。
|
||||
|
||||
|
||||
@@ -15,4 +15,4 @@ RUN ln -s /opt/xgent/runtime/node_modules /app/node_modules
|
||||
ENV APP_ENTRY=/app/server.js MANIFEST_PATH=/app/app.manifest.json
|
||||
|
||||
# micro 型前端产物不进镜像:CI 里 bun 构建 web/ 后经 aigrego-release publish --dist 上传,
|
||||
# 由 Portal 同源托管 /apps/<key>/_/*。
|
||||
# 由 Portal 同源托管 /apps/<key>/*。
|
||||
@@ -1,5 +1,6 @@
|
||||
<!doctype html>
|
||||
<!-- micro 应用托管页:资源一律绝对路径 /apps/<key>/_/ 引用(门户同源托管 /apps/<key>/_/*)。
|
||||
<!-- micro 应用托管页:资源一律绝对路径 /apps/<key>/ 引用(门户同源托管 /apps/<key>/*,
|
||||
2026-10 拍平——严禁残留旧 /_/ 子路径,否则上传后资产全 404)。
|
||||
PROD CSP 严格 default-src 'self'——禁止内联脚本,JS 必须外置文件。
|
||||
portal-sdk 用 vendor 版全局注入(不打进 bundle,桥协议版本与宿主同源)。
|
||||
占位:全局替换 my-app → 你的 listingKey。 -->
|
||||
@@ -11,7 +12,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script src="/apps/my-app/_/vendor/portal-sdk.js"></script>
|
||||
<script src="/apps/my-app/_/app.bundle.js"></script>
|
||||
<script src="/apps/my-app/vendor/portal-sdk.js"></script>
|
||||
<script src="/apps/my-app/app.bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -29,7 +29,7 @@ export interface PortalClientLike {
|
||||
|
||||
const factory = (globalThis as { createPortalClient?: () => PortalClientLike }).createPortalClient;
|
||||
|
||||
// 直接以顶层页面打开(/apps/<key>/_/ 静态托管路径)时 createPortalClient 抛
|
||||
// 直接以顶层页面打开(/apps/<key>/ 静态托管路径)时 createPortalClient 抛
|
||||
//「must run inside the portal host iframe」——降级为 sdk=null,由 UI 给友好提示。
|
||||
function createClient(): PortalClientLike | null {
|
||||
if (!factory) return null;
|
||||
|
||||
@@ -65,7 +65,8 @@ die 消息统一三段式:是什么 + 为什么(后果) + 怎么办/绕过
|
||||
| 症状 | 原因 | 怎么办 |
|
||||
|---|---|---|
|
||||
| PROD 白屏,Console 报 CSP 违例 | 内联 `<script>`(严格 `default-src 'self'`) | JS 全部外置文件 |
|
||||
| 直开 `/apps/<key>/_/` 抛「must run inside the portal host iframe」 | 正常——桥只在 iframe 内可用 | 降级友好页(照 sdk.ts 范式 catch) |
|
||||
| 宿主报「应用加载失败」,网络面板 `/apps/<key>/_/…` 全 404 | 产物按旧 `/_/` base 构建,平台托管路径已拍平为 `/apps/<key>/*` | 以拍平 base 重新构建并 `publish --dist` |
|
||||
| 直开 `/apps/<key>/` 被 301 回壳路由;iframe 内抛「must run inside the portal host iframe」 | 正常——顶层导航一律回壳,桥只在 iframe 内可用 | 降级友好页(照 sdk.ts 范式 catch) |
|
||||
| 页面显隐不对 | acl 没接(旧宿主无 acl 字段时不设防) | 握手取 init.acl 驱动路由守卫;真闸在后端四道闸 |
|
||||
| 调后端跨域报错 | 直接 fetch `/svc/...` | 一律 `sdk.callService(appKey, path)` 走宿主代发 |
|
||||
| 刷新丢路由 | 没接 `?r=` 深链 | initialRoute() 恢复 + routeSync 上报 |
|
||||
|
||||
@@ -196,8 +196,10 @@ if [ "$IS_MICRO" = 1 ]; then
|
||||
INLINE=$(grep -oE '<script>' web/index.html | wc -l | tr -d ' ')
|
||||
fi
|
||||
[ "$INLINE" -gt 0 ] && die "index.html 有 $INLINE 个无 src 的 <script> 块(PROD CSP 严格 default-src 'self',JS 必须外置)"
|
||||
grep -q "<script src=\"/apps/${LISTING_KEY:-my-app}/_/vendor/portal-sdk.js\"" web/index.html \
|
||||
|| die "index.html 未以绝对路径引 vendor 版 portal-sdk:/apps/<key>/_/vendor/portal-sdk.js"
|
||||
grep -q "/apps/${LISTING_KEY:-my-app}/_/" web/index.html \
|
||||
&& die "index.html 残留 /apps/<key>/_/ 旧托管路径——平台已拍平为 /apps/<key>/*,旧形态上传后资产全 404(应用加载失败)"
|
||||
grep -q "<script src=\"/apps/${LISTING_KEY:-my-app}/vendor/portal-sdk.js\"" web/index.html \
|
||||
|| die "index.html 未以绝对路径引 vendor 版 portal-sdk:/apps/<key>/vendor/portal-sdk.js"
|
||||
fi
|
||||
if [ -d web/src ]; then
|
||||
grep -rq "@aigrego/portal-sdk" web/src --include='*.ts' --include='*.tsx' --include='*.js' 2>/dev/null \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: app-publish
|
||||
description: 改造目标项目 Gitea Actions CI/CD 工作流的应用部署 job,按 TickShield(刻盾云)平台契约改用 aigrego-release(release-cli)发布上架:submit app.manifest.json + 记录镜像/上传 dist 产物 + --store 自动上架 + --wait 等治理审核,推 v 开头 tag 即发布到应用市场;项目没有工作流时新建完整发布工作流。凡用户要求「把部署 job 改成发布到应用市场 / 这个项目上架到 TickShield 商店 / CI 里自动发布应用 / 推 tag 自动上架 / 给 workflow 加应用市场发布 / 把这个 app 挂到门户商店 / 上线到刻盾云市场」,或带着 流水线绿了但商店没上架没生效 / 发布了但商店搜不到我的应用 / 403 auto_publish is off for this app / 401 凭证无效 / 403 listingKey mismatch / 400 index.html missing at archive root / 409 submit a manifest first 等症状,或提到 aigrego-release / release-cli / publish --store / --wait / AIGREGO_PORTAL_URL / APP_KEY / APP_SECRET / auto_publish / 应用市场发布模板 时,务必使用本 skill——即使用户没说「应用市场」四个字。Use whenever the user wants to convert or add a Gitea Actions deploy job that publishes a TickShield app to the platform marketplace via aigrego-release. 边界:应用开发/审查/手工发布指引用 app-dev;通用构建部署工作流规范(本机重建容器部署)用 gitea-actions;Dockerfile 选型评审用 runtime-image;git 提交推送日报用 push-and-report。
|
||||
description: 改造目标项目 Gitea Actions CI/CD 工作流的应用部署 job,按 TickShield(刻盾云)平台契约改用 aigrego-release(release-cli)发布上架:submit app.manifest.json + 记录镜像/上传 dist 产物 + --store 自动上架 + --wait 等治理审核,推 v 开头 tag 即发布到应用市场;项目没有工作流时新建完整发布工作流。凡用户要求「把部署 job 改成发布到应用市场 / 这个项目上架到 TickShield 商店 / CI 里自动发布应用 / 推 tag 自动上架 / 给 workflow 加应用市场发布 / 把这个 app 挂到门户商店 / 上线到刻盾云市场」,或带着 流水线绿了但商店没上架没生效 / 发布了但商店搜不到我的应用 / 应用打开报「应用加载失败」、网络面板 /apps/<key> 静态资源全 404 / 产物路径还带 /_/ 旧前缀 / 403 auto_publish is off for this app / 401 凭证无效 / 403 listingKey mismatch / 400 index.html missing at archive root / 409 submit a manifest first 等症状,或提到 aigrego-release / release-cli / publish --store / --wait / AIGREGO_PORTAL_URL / APP_KEY / APP_SECRET / auto_publish / 应用市场发布模板 时,务必使用本 skill——即使用户没说「应用市场」四个字。Use whenever the user wants to convert or add a Gitea Actions deploy job that publishes a TickShield app to the platform marketplace via aigrego-release. 边界:应用开发/审查/手工发布指引用 app-dev;通用构建部署工作流规范(本机重建容器部署)用 gitea-actions;Dockerfile 选型评审用 runtime-image;git 提交推送日报用 push-and-report。
|
||||
---
|
||||
|
||||
# app-publish — 把 CI 部署环节改造为发布上架到 TickShield 应用市场
|
||||
@@ -10,7 +10,7 @@ description: 改造目标项目 Gitea Actions CI/CD 工作流的应用部署 job
|
||||
- **改造模式**:项目已有 `.gitea/workflows/` 工作流 —— 保留构建推镜像段与不冲突的定制,把「本机 docker 重建容器」部署 job 替换为发布 job(部署权责移交平台编排)
|
||||
- **新建模式**:项目没有工作流 —— 照 `references/app-release-template.yaml` 生成完整发布工作流
|
||||
|
||||
契约锚点:本 skill 基线 = TickShield 平台 **Go 版 release-cli**(`packages/release-cli/`,自 commit `75cbae6` 起)与服务端 `ValidateManifest` 校验代码(2026-10)。**旧 .mjs 已删除,minIO 上的 `cli/aigrego-release.mjs` 也被平台发版时显式清除**——任何对 .mjs 的引用必 404 或拿到不再更新的旧版。子命令/flag/env/配置文件/退出码与旧版逐一对齐,唯一新增 `version` 子命令。与平台行为冲突时以平台仓代码为准,并回本仓库更新本 skill。`docs/reference/App出仓与集成指引.md` 主体是**已废弃的 @xgent 旧体系**(xrel_ 令牌、register-app --prod 均已失效),仅开头「现行口径」一节有效,禁止照搬。
|
||||
契约锚点:本 skill 基线 = TickShield 平台 **Go 版 release-cli**(`packages/release-cli/`,自 commit `75cbae6` 起)与服务端 `ValidateManifest` 校验代码(2026-10)。托管侧基线 = **2026-10-20 拍平版**(平台仓 commit `baa7a94`):micro 静态托管 `/apps/<key>/*`——**旧 `/_/` 子路径下线,`/_/` 不再被路由消费、会被当普通目录查盘**;`/host` 宿主页移除(桥由门户 SPA `appBridge.ts` 直挂,iframe sandbox 保留);静态层新增授权闸(published ∧ 当前租户已授权,否则一律 404);顶层导航直达 `/apps/<key>/` 301 回壳路由。**平台与产物版本强耦合**:旧 `/_/` base 构建的产物传到新平台 = index.html 200、资产全 404(宿主报「应用加载失败」),重跑旧 CI 不会自愈,必须以新 base 重新构建发布。**旧 .mjs 已删除,minIO 上的 `cli/aigrego-release.mjs` 也被平台发版时显式清除**——任何对 .mjs 的引用必 404 或拿到不再更新的旧版。子命令/flag/env/配置文件/退出码与旧版逐一对齐,唯一新增 `version` 子命令。与平台行为冲突时以平台仓代码为准,并回本仓库更新本 skill。`docs/reference/App出仓与集成指引.md` 主体是**已废弃的 @xgent 旧体系**(xrel_ 令牌、register-app --prod 均已失效),仅开头「现行口径」一节有效,禁止照搬。
|
||||
|
||||
**调用形态分流(硬规则)**:裸调用(无任务输入)= **只读评估态**——只出「现状差距报告 + 改造/新建方案」,**永不主动改文件**;报告交付即停,等用户确认后才动手。带任务输入(如「把这个项目的部署改成发布到商店」)= 任务即授权按流程走,但写文件仍需过第 2 步确认闸。
|
||||
|
||||
@@ -47,6 +47,7 @@ description: 改造目标项目 Gitea Actions CI/CD 工作流的应用部署 job
|
||||
| 现有构建段镜像 ref(改造模式) | 读现有 workflow 的 build/push 步骤 | 发布 job 用同一表达式重算镜像 ref,保证与构建产物一致 |
|
||||
| 「本机重建容器」部署段(改造模式) | grep `docker run -d` / `docker rm -f` / `compose up` / 健康检查步 | 定位待替换的部署 job;连同其健康检查/.env 检查块一并识别 |
|
||||
| micro 的 dist 构建方式 | 读 `web/package.json` build 脚本、产物目录(dist/build/out) | 生成前端构建步与 `--dist` 参数 |
|
||||
| micro 前端托管 base | grep 构建步 `VITE_BASE`/`--base`/`PUBLIC_PATH` 与前端入口 html 的 `/apps/` 绝对引用 | 残留 `/_/` 旧子路径形态 → die 级差距:先改拍平 base `/apps/<key>/` 再谈发布,否则传上去资产全 404(约束⑨) |
|
||||
| 本地 CLI | `bash <本skill目录>/scripts/ensure-cli.sh`(PATH → /usr/local/bin → ~/.local/bin → minIO 按架构下载) | 第 3 步本地 dry-run 用;CI 里按 runner 架构下载,不依赖本机 |
|
||||
|
||||
→ 验收:模式(改造/新建)有 glob 结论背书;每个探测项有文件证据(路径);缺料停在补料指引。
|
||||
@@ -57,6 +58,7 @@ description: 改造目标项目 Gitea Actions CI/CD 工作流的应用部署 job
|
||||
|---|---|---|
|
||||
| 镜像 ref | 改造模式沿用现有构建段表达式;新建模式 `${{ vars.APP_IMAGE_PREFIX \|\| 'livebook:8418/projects' }}/<项目名>` | tag 取 `GITHUB_REF_NAME` 去 v |
|
||||
| `--dist` 目录(micro) | 第 0 步探测的构建产物目录 | 包根必须直接含 index.html(约束⑤) |
|
||||
| dist 构建 base(micro) | 第 0 步探测 | `./` 相对或 `/apps/<key>/` 绝对皆可,严禁 `/apps/<key>/_/`(约束⑨) |
|
||||
| `--wait` 秒数 | 默认 600 | 治理审核等待上限;驳回/超时 = 流水线红(这正是门禁语义) |
|
||||
| `TICKSHIELD_RAW_BASE` | Variable,默认 `http://livebook:9000/tickshield`(minIO 公共桶) | 二进制路径 = `$RAW_BASE/cli/aigrego-release-<os>-<arch>` + `sha256sums.txt` 校验;禁用旧地址与 .mjs(约束③) |
|
||||
| `TICKSHIELD_PORTAL_URL` | Variable,默认 `http://gateway:8080` | 随环境变,用户确认 |
|
||||
@@ -110,8 +112,9 @@ description: 改造目标项目 Gitea Actions CI/CD 工作流的应用部署 job
|
||||
- ⑥ **listingKey/版本号以 app.manifest.json 为单一事实源;workflow 不另配 listingKey(CLI 缺省从 manifest 取),镜像 tag 取 git tag**。为什么:listingKey 四位一体(== TDT aud == 容器名 == 网络别名 == scope 命名空间)不可变,另配易产生 403 listingKey mismatch;版本与 tag 不对齐则商店版本无法回溯。
|
||||
- ⑦ **改造模式不静默丢弃**:旧「本机重建容器」部署段替换为发布 job,删除内容逐项列进汇报;与发布不冲突的项目定制保留。为什么:部署权责移交平台编排(`--image` 写 deployDescriptor + 重启契约容器),旧段留着会双轨部署;静默删定制是事故。
|
||||
- ⑧ **新建模式触发 = 推 `v*` tag(+ workflow_dispatch 兜底);改造模式不动原触发**。为什么:版本号即镜像 tag 的发布模型——推 main 不发版,否则 Packages 堆满无版本意义的镜像且无法回溯。
|
||||
- ⑨ **micro 产物必须是拍平托管形态:构建 base(`VITE_BASE`/`--base`/`PUBLIC_PATH` 等)与 index.html 里的绝对引用一律 `/apps/<key>/`,严禁残留 `/_/` 子路径**。为什么:平台 2026-10-20 起托管 URL 从 `/apps/<key>/_/*` 拍平为 `/apps/<key>/*`(`/_/` 不再被路由消费,会被当普通目录查盘)——旧形态产物传上去 index.html 能 200、资产全 404,宿主报「应用加载失败」,**重跑旧 CI 不会自愈**。平台升到拍平版后,存量 micro 应用必须以新 base 重新构建并 `publish --dist`;CI 构建步应带 dist index.html 的 `/_/` 防线(模板已内置)。
|
||||
|
||||
fail-fast 分级:无 manifest / 无 Dockerfile / manifest 含 deployDescriptor / 生成的 workflow 缺 --wait / 密钥明文 / CLI 旧地址 / dist 包根缺 index.html = **die**(拦死,无绕过口);镜像 host 未确认在 registries 白名单 / auto_publish 状态未知 / 镜像未覆盖多架构 = **warn**(平台侧事项,CI 管不了,列待人工清单);首提直接生效 / 重复 --store 409 跳过 / docker.sock 不可用时 --image 降级仅记录 = **log**(平台行为背景,不挂常驻警告)。
|
||||
fail-fast 分级:无 manifest / 无 Dockerfile / manifest 含 deployDescriptor / 生成的 workflow 缺 --wait / 密钥明文 / CLI 旧地址 / dist 包根缺 index.html / workflow 构建 base 或 dist 产物残留 `/_/` 旧托管路径 = **die**(拦死,无绕过口);镜像 host 未确认在 registries 白名单 / auto_publish 状态未知 / 镜像未覆盖多架构 = **warn**(平台侧事项,CI 管不了,列待人工清单);首提直接生效 / 重复 --store 409 跳过 / docker.sock 不可用时 --image 降级仅记录 = **log**(平台行为背景,不挂常驻警告)。
|
||||
|
||||
## 凭证与配置
|
||||
|
||||
@@ -141,6 +144,9 @@ fail-fast 分级:无 manifest / 无 Dockerfile / manifest 含 deployDescriptor
|
||||
| 403 `deployDescriptor is platform-admin only` | manifest 携带 deployDescriptor | 从 manifest 删除该字段(自检脚本 die 拦) |
|
||||
| 400 manifest 校验失败(版本非 semver、scope 格式等) | 不符 ValidateManifest | 对照错误文案逐条修;可先跑 `app-dev` 的 check-app.sh 预检 |
|
||||
| 400 `index.html missing at archive root` | `--dist` 套了目录,包根无 index.html | 传构建产物目录本身(约束⑤) |
|
||||
| 宿主报「应用加载失败」,网络面板 `/apps/<key>/_/…` 全部 404 | dist 按旧 `/_/` base 构建;平台已拍平,`/_/` 被当普通目录查盘 | 构建 base 改 `/apps/<key>/`、修 index.html 硬编码引用,重新 `publish --dist`(约束⑨);旧 CI 原样重跑无用 |
|
||||
| `/apps/<key>/…` 静态资源 404(路径无 `/_/`) | 静态层授权闸:应用未 published 或当前租户未授权(与侧边栏菜单同口径) | 平台侧核对上架状态与租户授权(tenant_app_grants);授权即恢复 |
|
||||
| 手动敲 `/apps/<key>/` 被 301 到 `/apps/<key>` | 正常——顶层文档导航一律回壳路由,不落裸应用 | 无需处理;iframe 入口与 `?r=` 深链不受影响 |
|
||||
| 413 | 产物包超 64MB | 精简产物/排查打包内容 |
|
||||
| 409 `submit a manifest first` | 无生效版本就单独 `--image` | manifest 与 image 同一条 publish 命令(约束④) |
|
||||
| 400 `invalid image reference` | 镜像引用含非法字符 | 字符集 `^[A-Za-z0-9][A-Za-z0-9._/:@+-]{0,255}$` |
|
||||
|
||||
@@ -63,7 +63,10 @@ jobs:
|
||||
run: |
|
||||
docker run --rm -v "$PWD/src:/src" -w "/src/{{WEB_DIR}}" node:20-alpine \
|
||||
sh -c 'npm ci && npm run build'
|
||||
# 前端若需绝对托管 base(monaco/worker 等运行期路径),构建 env 设 /apps/<key>/
|
||||
# (如 VITE_BASE=/apps/<key>/)——拍平形态,严禁 /_/ 旧子路径(约束⑨)
|
||||
test -f "{{DIST_DIR}}/index.html" || { echo "::error::dist 包根缺 index.html(约束⑤:--dist 必须传产物目录本身)"; exit 1; }
|
||||
! grep -Eq '/apps/[a-z0-9-]+/_/' "{{DIST_DIR}}/index.html" || { echo "::error::dist index.html 残留 /_/ 旧托管路径(约束⑨)——以拍平 base /apps/<key>/ 重新构建"; exit 1; }
|
||||
# [/OPTIONAL:DIST_BUILD]
|
||||
|
||||
- name: Fetch aigrego-release CLI
|
||||
|
||||
@@ -137,5 +137,28 @@ else
|
||||
ok "⑫ 无未渲染的 {{SLOT}} 残留"
|
||||
fi
|
||||
|
||||
# ⑬ micro 托管 base 拍平闸(2026-10 平台下线 /_/ 子路径,/_/ 被当普通目录查盘):
|
||||
# workflow 构建参数与本地可及的 dist index.html 双查;旧形态产物上传后 index.html 200、资产全 404
|
||||
if grep -q -- '--dist' "$CODE"; then
|
||||
if grep -Eq '(VITE_BASE|PUBLIC_PATH|BASE_URL|--base)[= ][^ ]*/_/' "$CODE"; then
|
||||
die "⑬ 构建 base 仍是 /apps/<key>/_/ 旧形态 ——托管 URL 已拍平为 /apps/<key>/*,旧 base 产物传上去资产全 404(应用加载失败),改 /apps/<key>/ 重新构建"
|
||||
elif grep -Eq '/apps/[a-z0-9][a-z0-9-]*/_/' "$CODE"; then
|
||||
die "⑬ workflow 残留 /apps/<key>/_/ 旧托管路径引用 ——托管 URL 已拍平为 /apps/<key>/*"
|
||||
else
|
||||
D="$(grep -oE -- '--dist[ =]"[^"]+"|--dist[ =][^ ]+' "$CODE" | head -1 | sed -E 's/^--dist[ =]//; s/^"//; s/"$//; s|^src/||')"
|
||||
if [ -n "$D" ] && [ -f "$ROOT/$D/index.html" ]; then
|
||||
if grep -Eq '/apps/[a-z0-9][a-z0-9-]*/_/' "$ROOT/$D/index.html"; then
|
||||
die "⑬ $D/index.html 引用 /apps/<key>/_/ 旧托管路径 ——以拍平 base /apps/<key>/ 重新构建再 publish --dist"
|
||||
else
|
||||
ok "⑬ dist index.html 无 /_/ 旧路径(本地实证)"
|
||||
fi
|
||||
else
|
||||
ok "⑬ workflow 无 /_/ 旧 base(本地 dist 不可及,产物形态由 CI 内 grep 防线兜底)"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
skp "⑬ 无 --dist(非 micro 或未上传产物)"
|
||||
fi
|
||||
|
||||
echo "== done =="
|
||||
exit "$FAIL"
|
||||
Reference in new issue
Block a user