Skip to content

fix(mobile): 校验区域清单构建配置并隔离转换缓存 - #4013

Open
elfcv wants to merge 1 commit into
makecindy:mainfrom
elfcv:fix/3861-mobile-manifest-build-guard
Open

fix(mobile): 校验区域清单构建配置并隔离转换缓存#4013
elfcv wants to merge 1 commit into
makecindy:mainfrom
elfcv:fix/3861-mobile-manifest-build-guard

Conversation

@elfcv

@elfcv elfcv commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

这次改了什么

摘要

为移动端 CN / Global 的清单自举配置增加构建期防错检查,防止“本区和对端都指向同一区域”或残留环境变量被打进生产 bundle。

同时补上转换缓存边界:仅检查最终环境仍可能复用旧的 Babel 内联结果,因此 Metro 缓存按构建区域及两个清单地址的原始值摘要隔离。相同配置仍可复用缓存;生产构建初始化后配置发生变化则要求重启 Metro,避免主进程、缓存与工作进程使用不同值。

变更类型

  • fix 缺陷修复
  • docs / test / chore 文档、测试或工程维护

范围

  • 关联 Issue:Refs bug: [mobile] 国际版构建产物未烘焙国内区清单自举地址,企业 SSO 双区探测失效,国内区组织报「未找到该企业」 #3861仅覆盖建议独立提交的构建门禁,不自动关闭原 Issue。
  • 本 PR 包含:
    • 共享校验器:非空、无凭据 HTTPS URL,规范化后本区与对端不能相同,并须匹配所选区域的仓内清单。
    • Android / iOS 构建使用的 mobileClientBundleProcessEnv 在生成子进程环境后校验;Metro 在实际生产转换请求(dev: false)处再次校验,不依赖 runner 的 NODE_ENV
    • 保留原 Metro cacheVersion,追加区域/两区原始地址的 SHA-256 摘要;检查初始化后的环境漂移,且不能通过切为 CindyDev 绕过。
    • 回归测试与开发文档;错误消息不回显环境变量值。
  • 明确不包含:运行期登录/区域路由修改、生产发布环境清理、重发安装包/OTA、线上及真机 SSO 修复验收。
  • 用户可见变化:无 UI 变化。构建者会在错配时提前收到错误;开发 Metro 与稳定 CindyDev 的覆盖行为保留。
  • 是否存在 breaking change:无运行期或协议变更。构建契约收紧:CN / Global 生产包不再接受与仓内清单不一致的 shell / .env 地址覆盖;自建地址应调整 config/endpoint*.json 正本。

UI 变化

不涉及。引用的设计规范:不涉及。

怎么验证的

环境:macOS arm64,Node 22.23.1;本地 checkout 分支 fix/3861-mobile-manifest-build-guard,基线 e9c3729a1。未启动开发 Metro 实例或安装运行客户端;以下 Metro 验证为测试进程/一次性 CLI 导出,故无真机 __DEV__ build label。

自动验证

命令 结果
pnpm test:unit:related 通过;runner 509 passed / 1 skipped,mobile 相关测试通过
pnpm --filter mobile exec vitest run --pool=threads --maxWorkers=4 373 个测试文件、4,676 项测试全部通过
pnpm --filter mobile run --if-present typecheck 通过
pnpm check:i18n-glossary 通过;18 处已有 proposed 术语告警,不阻断
node --test scripts/__tests__/client-endpoint-build-env.test.mjs 12 项通过
pnpm check:dco / git diff --check 通过

缓存回归不是只检查 hash:测试使用真实 Metro Transformer / Expo Babel 与共享内存缓存,检查 CN → Global → Global → CN → Global(等价 URL 增加尾斜杠)的实际内联代码,并确认同配置有 2 次缓存命中。修复前可复现旧区域地址被复用,修复后测试通过。测试仅传 Buffer,不写探针源文件、不使用开发者磁盘缓存。

指纹:改动前后运行 node apps/mobile/scripts/ci-fingerprint.mjs compute --output <report>,再用 compare --base <before> --current <after> 比对,两平台均不变:

  • iOS:96e76c9f4cb4fd4c990fb09e631e8ab42d61583e
  • Android:20a7dee6fb588f451c59b37deec3faf7e37a8b41

手工验证

  • 在 Global 环境故意令本区/对端地址相同,运行 pnpm --filter mobile exec expo export --platform android --max-workers 1 --output-dir <temp-dir>:实际 Android bundling 立即被新校验器阻止。
  • 正确地址配置通过新检查并进入正常转换;但完整导出随后因本地缺少 config/endpoint.dev.json 失败。用基线 Metro 配置的内存加载对照运行同一导出,也得到相同缺文件错误;未修改开发者配置来掩盖此限制。

未执行的验证

  • 完整成功的安装包 / bundle 产物验收:本地缺少上述开发清单,正常导出未完成。
  • Android / iOS 真机同区及跨区 SSO、实际 EAS 云构建、生产 release/beta OTA 发布。
  • 全仓完整 unit 未重跑;已跑仓库要求的 related 门禁及额外 mobile 全量。GitHub CI 仍需独立完成。

风险

风险分类

  • 原生层 / fingerprint / OTA:涉及 bundle 构建边界,未改变原生指纹
  • 其他:构建环境校验 / Metro 转换缓存

影响与回滚

  • 影响范围:经过本地构建 helper 或 Metro 生成的 CN / Global 生产 bundle。第一次使用新缓存命名空间会重新转换;同配置后续仍可命中缓存。生产进程中途修改区域/清单值时需要重启 Metro。
  • app.config.js、其 CJS loader、Expo extra、原生身份与依赖均未改;本地指纹对比一致,不引入冷更要求。最终仍以 PR CI 的 base/head 指纹比较为准。
  • 开发模式与稳定 CindyDev 的显式覆盖不被生产校验收紧。没有 UI、数据库迁移、运行期协议或用户持久数据变化。
  • 本补丁不会修复已经发布或直接复制复用的成品 bundle;bug: [mobile] 国际版构建产物未烘焙国内区清单自举地址,企业 SSO 双区探测失效,国内区组织报「未找到该企业」 #3861 仍需发布链路及最终产物/真机证据,不能仅凭本 PR 认定线上恢复。
  • 回滚:回退本 PR 即撤销新增门禁及缓存命名空间扩展,无数据迁移;旧转换缓存无需手动删除。

提交前检查

  • 已 review 完整 diff
  • 每个 commit 都带 DCO 签名(git commit -s
  • UI 变化与设计依据已注明不涉及
  • 未提交凭证、令牌或授权文件
  • 已补充必要文档
  • 已确认测试结果或说明未执行原因

Signed-off-by: cnxpfcv-oss <270533111+cnxpfcv-oss@users.noreply.github.com>
@elfcv
elfcv requested a review from a team as a code owner September 6, 2026 14:31
@greptile-apps

greptile-apps Bot commented Sep 6, 2026

Copy link
Copy Markdown

Greptile Summary

本 PR 为移动端 CN / Global 正式 bundle 增加区域清单构建校验,并通过环境摘要隔离 Metro 转换缓存。

  • 校验区域、本区及对端清单 URL,拒绝空值、凭据、非 HTTPS、重复或与仓内配置不一致的地址。
  • 在 Metro 生产转换边界复核最终环境,并检测初始化后的配置漂移。
  • 将区域与两个清单地址的摘要加入现有 Metro 缓存版本。
  • 增加 helper、Metro 真实转换缓存回归测试,并补充移动端开发文档。

Confidence Score: 5/5

该 PR 未发现需要阻止合并的具体问题,现有实现与回归测试能够支持所声明的构建门禁和缓存隔离行为。

生产转换会根据实际 dev 标志校验最终环境,缓存键包含所有会被 Babel 内联的区域清单值,且测试覆盖跨区域缓存复用、配置漂移、错误脱敏和开发模式兼容性。

Important Files Changed

Filename Overview
apps/mobile/metro.config.js 在 Metro 初始化和生产转换边界加入环境快照、最终配置校验及缓存命名空间隔离。
scripts/shared/mobile-manifest-build-guard.cjs 新增共享 URL/区域校验器和不泄露原始环境值的 SHA-256 构建快照。
scripts/shared/client-endpoint-build-env.mjs 在移动端 bundle 子进程环境生成后调用共享清单校验器。
apps/mobile/src/tests/mobileManifestBuildGuard.test.ts 覆盖正式转换门禁、环境漂移、开发模式兼容性及真实 Metro 转换缓存隔离。
scripts/tests/client-endpoint-build-env.test.mjs 覆盖 URL 规范化、错配拒绝、敏感值不回显和快照身份稳定性。
docs/dev-rules/mobile-development.md 记录正式打包清单约束、缓存隔离、重启要求及开发模式例外。

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[构建入口] --> B[从仓内 endpoint 配置派生环境]
  B --> C[校验区域与清单地址]
  C -->|无效| X[中止构建]
  C -->|有效| D[加载 Metro 配置]
  D --> E[生成区域与地址摘要]
  E --> F[扩展 Metro cacheVersion]
  F --> G{生产转换 dev=false?}
  G -->|否| H[保留开发端点覆盖]
  G -->|是| I[复核最终环境]
  I -->|环境漂移| Y[要求重启 Metro]
  I -->|一致| J[执行默认转换并使用隔离缓存]
Loading

Reviews (1): Last reviewed commit: "fix(mobile): guard manifest build env an..." | Re-trigger Greptile

@MagicLizi MagicLizi added touches:product-ui 改动碰到产品 / UI 面(review-pr 自动维护,仅展示) touches:rules 改动碰到规则 / 规范文档(review-pr 自动维护,仅展示) touches:security 改动碰到安全边界(review-pr 自动维护,仅展示) labels Sep 6, 2026
@MagicLizi

Copy link
Copy Markdown
Contributor

这条 PR 命中了维护者确认门(当前在拦:product;同时还有 security、rules),需要维护者确认后才能合并。

讨论 issue:#4015

请维护者直接在本 PR 上 Approve;如果需要修改,请 Request Changes,作者改完后再 Approve 即可放行。在此之前自动流程不会合并。

@MagicLizi

Copy link
Copy Markdown
Contributor

命中 UI 路径(apps/mobile/metro.config.js)但 description 未附界面效果证据——建议补充改动后效果:截图/录屏,或改动后界面的 HTML 页面(```html 代码块、.html 附件或在线预览链接),便于确认界面符合 DESIGN.md 设计规范

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting-discussion 等待维护者讨论(review-pr) touches:product-ui 改动碰到产品 / UI 面(review-pr 自动维护,仅展示) touches:rules 改动碰到规则 / 规范文档(review-pr 自动维护,仅展示) touches:security 改动碰到安全边界(review-pr 自动维护,仅展示)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants