同步 master 基线以恢复 PR CI
Project CI / Repository checks (pull_request) Successful in 3m11s
Project CI / Frontend tests (pull_request) Successful in 5m31s
Project CI / Backend tests (pull_request) Successful in 4m54s
Project CI / Native shell tests (pull_request) Failing after 12m6s

合入最新 master 提交 1a909704
保留 PR 177 首页与原生壳门禁修复
This commit is contained in:
2026-08-23 14:53:33 +08:00
8 changed files with 108 additions and 32 deletions
@@ -14333,11 +14333,11 @@
- 依据:当前完整模块首次 publish / init 的进程 RSS 会超过 `896m`,cgroup 会直接 OOM kill `spacetimedb-standalone`,客户端表现为上传连接提前关闭,后续重试连接拒绝。提高 ping 或 publish 重试次数不能修复内存上限。
- 边界:这是本地/预发完整容器的模块实例化门槛,不修改生产服务资源合同;门禁同时锁定基础 Compose 与预览 override 均为 `2g`。
## 2026-08-22 Jenkins 预览只向 API 运行镜像内置固定 secrets
## 2026-08-22 Jenkins 预览只向 API 运行镜像内置固定运行时配置
- 决策:预览 secrets 权威源固定为 Jenkins 宿主 `/data/jenkins/preview-secrets/.env.secrets.local`;目录 / 文件由 Jenkins 运行账号所有且权限分别为 `0700` / `0600`,缺失、链接、非普通文件、owner 异常或权限过宽时构建失败关闭。
- 构建边界:只通过 BuildKit secret mount 把文件提供给 `api-runtime` stage,并安装为 `/srv/genarrative/.env.secrets.local` (`genarrative:genarrative`, `0400`)。文件不进 Git、build context、日志或 artifact,不进入 Web / Nginx、SpacetimeDB 或其它镜像。容器显式运行 env 优先覆盖内置值。
- 更新与分发:固定源文件更新后必须重建并替换镜像,只重启容器无效。镜像可读者必然可提取内置 secrets,因此只允许留在当前受信任内网 Docker 主机,禁止 push、`docker save` 或作为 artifact 导出到跨信任边界的 registry、主机或存储。
- 决策:预览 `.env.local` 与 secrets 权威源固定为 Jenkins 宿主 `/data/jenkins/preview-secrets/.env.local`、`/data/jenkins/preview-secrets/.env.secrets.local`;目录 / 文件由 Jenkins 运行账号所有且权限分别为 `0700` / `0600`,缺失、链接、非普通文件、owner 异常或权限过宽时构建失败关闭。
- 构建边界:只通过两个 BuildKit secret mount 把固定宿主副本提供给 `api-runtime` stage,并安装为 `/srv/genarrative/.env.local`、`/srv/genarrative/.env.secrets.local` (`genarrative:genarrative`, `0400`)。固定宿主副本不进 Git、build context、日志或 artifact,不进入 Web / Nginx、SpacetimeDB 或其它镜像;仓库工作区 `.env.local` 不得替代它们。容器显式运行 env 优先覆盖内置值。
- 更新与分发:任一固定源文件更新后必须重建并替换 API 与 worker 镜像,只重启容器无效。镜像可读者必然可提取内置运行时配置,因此只允许留在当前受信任内网 Docker 主机,禁止 push、`docker save` 或作为 artifact 导出到跨信任边界的 registry、主机或存储。
## 2026-08-22 AGC Tauri 命令调用可达性失败关闭
@@ -4830,8 +4830,8 @@
- 现象:构建时使用 BuildKit secret mount,日志和普通 build context 都没有出现明文,于是误以为最终镜像也能不可提取地保存 secrets,随后将镜像 push 或导出给不同信任域。
- 原因:BuildKit secret mount 只避免秘密作为 `ARG` / `COPY` 进入构建上下文和中间指令;一旦 Dockerfile 把 mount 的内容安装到最终 rootfs,任何能读取、保存或运行该镜像的主体都可以提取它。
- 处理:预览固定 secrets 只从 Jenkins 宿主受控路径读取,严格校验目录 `0700`、文件 `0600`、owner、普通文件与非链接边界;只将其安装到 `api-runtime:/srv/genarrative/.env.secrets.local` 并设为 `0400`,明确排除 Nginx、Web、artifact 和其它镜像。镜像禁止推送或导出到跨信任边界。
- 更新与验证:源文件变更不会改动已存镜像,必须重建并替换容器;不能用重启代替。验收同时扫描 transcript/context/artifact 零泄漏,检查只有 API 最终 rootfs 存在目标文件,并验证容器显式运行 env 优先覆盖内置值。
- 处理:预览固定 `.env.local` 与 secrets 只从 Jenkins 宿主受控路径读取,严格校验目录 `0700`、文件 `0600`、owner、普通文件与非链接边界;只将它们安装到 `api-runtime:/srv/genarrative/.env.local` 与 `/srv/genarrative/.env.secrets.local` 并设为 `0400`,明确排除 Nginx、Web、artifact 和其它镜像。镜像禁止推送或导出到跨信任边界。
- 更新与验证:任一源文件变更不会改动已存镜像,必须重建并替换 API 与 worker 容器;不能用重启代替。验收同时扫描 transcript/context/artifact 零泄漏,检查只有 API 与 worker 最终 rootfs 存在目标文件,并验证容器显式运行 env 优先覆盖内置值。
## SpacetimeDB ping 健康不代表完整模块能在内存上限内实例化(2026-08-22)
@@ -51,9 +51,9 @@ SpacetimeDB 2.7 CLI 发布到受控 Compose 网络地址时固定使用 `--yes=r
## 预览 secrets 内置
Jenkins 节点上的预览 secrets 权威来源固定为 `/data/jenkins/preview-secrets/.env.secrets.local`。该文件不进 Git、Docker build context、构建日志或 artifact;构建时只通过 BuildKit `secret` mount 临时提供给 `api-runtime` stage,并在该运行镜像中安装为 `/srv/genarrative/.env.secrets.local`,权限固定为 `0400`。`nginx-runtime`、Web 静态产物、SpacetimeDB 镜像及其它镜像不得包含该文件。
Jenkins 节点上的预览运行时配置权威来源固定为 `/data/jenkins/preview-secrets/.env.local` 与 `/data/jenkins/preview-secrets/.env.secrets.local`。这两个固定宿主副本不进 Git、Docker build context、构建日志或 artifact;构建时分别通过 BuildKit `secret` mount 临时提供给 `api-runtime` stage,并在该运行镜像中安装为 `/srv/genarrative/.env.local` 与 `/srv/genarrative/.env.secrets.local`,权限固定为 `0400`。`nginx-runtime`、Web 静态产物、SpacetimeDB 镜像及其它镜像不得包含这些文件。仓库工作区中的 `.env.local` 不得替代固定宿主副本作为构建输入。
宿主固定目录应由 Jenkins 运行账号所有且权限为 `0700`,源文件权限为 `0600`;缺失、不是普通文件、owner 不匹配或权限过宽时,预览构建必须失败关闭。源文件变更后必须重新构建并替换预览镜像,只重启容器不会刷新已内置的内容。容器启动时显式注入的运行环境变量优先级高于镜像内的 `.env.secrets.local`,用于按实例覆盖非通用值。
宿主固定目录应由 Jenkins 运行账号所有且权限为 `0700`,两个源文件权限均为 `0600`;缺失、不是普通文件、owner 不匹配或权限过宽时,预览构建必须失败关闭。任一源文件变更后必须重新构建并替换 API 与 worker 预览镜像,只重启容器不会刷新已内置的内容。容器启动时显式注入的运行环境变量优先级高于镜像内的 `.env.local` 与 `.env.secrets.local`,用于按实例覆盖非通用值。
这种方案只隐藏构建传输过程,不能让内置后的 secrets 对镜像持有者保密:能读取、保存或运行 `api-runtime` 镜像的人可以提取该文件。因此该镜像只能留在当前受信任内网 Docker 主机,禁止 push 到公共或跨信任边界的 registry,也禁止通过 `docker save`/构建 artifact 导出传播。需要跨边界分发时必须改用不含 secrets 的镜像与运行时密钥注入。
@@ -118,7 +118,7 @@ Jenkins 在构建完成、归档 artifact 和更新 REST 状态之间可能短
- Jenkins service account 只授予 `shared/Genarrative-Preview-Deployer` 的 `Job/Read`、`Job/Build` 和读取构建产物所需权限,不授 `Overall/Administer`、`Job/Configure` 或 `Job/Delete`。
- 后端固定 Jenkins origin、Job 路径和参数白名单;客户端不能传 URL、Job 名、Compose project、容器名、宿主端口或 Jenkins 凭据。
- Git 查询固定使用本机 Gitea SSH 地址和服务端只读凭据;客户端不能传 remote、SSH 参数或凭据。Git 缓存只写入预览控制服务的受控状态目录,搜索接口需要控制台会话且结果有数量上限。
- 预览 secrets 只从固定宿主路径读取,构建前校验 owner、类型和权限;不允许分支、Jenkins 参数或控制面请求改写 secrets 路径、BuildKit secret ID 或镜像内目标路径。
- 预览 `.env.local` 与 secrets 只从固定宿主路径读取,构建前校验目录和文件的 owner、类型和权限;不允许分支、Jenkins 参数或控制面请求改写这些路径、BuildKit secret ID 或镜像内目标路径。
- Jenkins POST 支持动态 Crumb;API Token 即使免 Crumb,也不能把 Token 放进 URL 或日志。
- API 默认只接受同源请求,写请求校验 Origin;内网本身不作为认证。
- 同一 deployment 的发布和卸载串行执行;重复请求必须幂等或明确返回冲突。