diff --git a/docs/technical/【开发运维】Jenkins容器预览部署控制面技术方案-2026-08-15.md b/docs/technical/【开发运维】Jenkins容器预览部署控制面技术方案-2026-08-15.md index 93d5fa629..878172c07 100644 --- a/docs/technical/【开发运维】Jenkins容器预览部署控制面技术方案-2026-08-15.md +++ b/docs/technical/【开发运维】Jenkins容器预览部署控制面技术方案-2026-08-15.md @@ -47,6 +47,8 @@ SpacetimeDB 2.7 CLI 发布到受控 Compose 网络地址时固定使用 `--yes=r 预览 Compose override 将 SpacetimeDB 内存上限设为 `2g`。基础 loadtest Compose 的 `896m` 是压测采样口径,当前完整模块首次发布和实例化会超过该上限;预览环境若沿用该值,容器会被 cgroup OOM 杀死并使模块上传中断。该覆盖只作用于分支预览实例,不修改生产或压测基线。 +每个预览实例使用独立 SpacetimeDB 空库,不继承生产账号和短信凭据。Jenkins 在实例私有 `api-server.env` 中开启预览专用认证:未注册的中国大陆手机号首次使用 6 到 128 位密码时自动创建预览账号;短信入口使用 `mock` provider 与固定预览验证码 `123456`,不向真实手机发送短信。该设置不写入公共 env 示例、生产配置或镜像层;实例重建会重建独立数据库,原预览账号不保留。 + ## Jenkins 参数与产物 固定 Job:`shared/Genarrative-Preview-Deployer`。 @@ -118,4 +120,5 @@ Jenkins 在构建完成、归档 artifact 和更新 REST 状态之间可能短 - 后端:输入校验、登录会话、Origin、Crumb、Jenkins `401/403/404/5xx`、queue 到 build 状态机、artifact schema、卸载所有权和幂等测试。 - 前端:登录、分支与可选 commit、自动刷新、排队/构建/成功/失败状态、内网链接、卸载确认和刷新恢复测试。 - Jenkins:两个分支依次发布后在不同端口并存;同一分支换 commit 优先复用端口;非分支 commit 被拒绝;卸载只删除目标实例并释放端口。 +- 预览认证:新手机号可以首次密码登录并重复使用同一密码;错误密码被拒绝;获取验证码后使用 `123456` 可完成登录;容器不包含生产短信凭据。 - 通用:`npm run check:encoding`、相关 typecheck/build/test、Rust 定向测试和 `git diff --check`。 diff --git a/scripts/check-preview-deployer.mjs b/scripts/check-preview-deployer.mjs index 5cee19342..860417d07 100644 --- a/scripts/check-preview-deployer.mjs +++ b/scripts/check-preview-deployer.mjs @@ -125,6 +125,16 @@ assertIncludes( 'restart: on-failure', '预览外部生成 worker 必须在运行时身份初始化竞态后自动重启。', ); +assertIncludes( + deployer, + 'GENARRATIVE_DEV_PASSWORD_ENTRY_AUTO_REGISTER_ENABLED=true', + '预览独立空库必须允许首次密码登录自动创建预览账号。', +); +assertIncludes( + deployer, + "'SMS_AUTH_ENABLED=true',\n 'SMS_AUTH_PROVIDER=mock',\n 'SMS_AUTH_MOCK_VERIFY_CODE=123456'", + '预览短信登录必须使用固定 mock 验证码,不得继承生产短信密钥。', +); assertIncludes( deployer, '^preview-[0-9a-f]{16}$', diff --git a/scripts/jenkins-preview-deployer.sh b/scripts/jenkins-preview-deployer.sh index 0171628b8..9e61cebfc 100644 --- a/scripts/jenkins-preview-deployer.sh +++ b/scripts/jenkins-preview-deployer.sh @@ -336,6 +336,15 @@ const [file, internalSecret, jwtSecret] = process.argv.slice(2); let content = fs.readFileSync(file, 'utf8'); content = content.replace(/^GENARRATIVE_INTERNAL_API_SECRET=.*$/mu, `GENARRATIVE_INTERNAL_API_SECRET=${internalSecret}`); content = content.replace(/^GENARRATIVE_JWT_SECRET=.*$/mu, `GENARRATIVE_JWT_SECRET=${jwtSecret}`); +content += [ + '', + '# Jenkins 分支预览使用隔离数据库和预览专用认证,不继承生产账号或短信凭据。', + 'GENARRATIVE_DEV_PASSWORD_ENTRY_AUTO_REGISTER_ENABLED=true', + 'SMS_AUTH_ENABLED=true', + 'SMS_AUTH_PROVIDER=mock', + 'SMS_AUTH_MOCK_VERIFY_CODE=123456', + '', +].join('\n'); fs.writeFileSync(file, content, {encoding: 'utf8', mode: 0o600}); NODE unset internal_secret jwt_secret