Compare commits

...

2 Commits

Author SHA1 Message Date
Jesse_Chen d3833356c7 docs: record BUG-333 fix SHA
Independent Staging Quality Gate / validate (push) Successful in 9m53s
Independent Staging Quality Gate / publish (push) Successful in 11m45s
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-20 22:44:59 +08:00
Jesse_Chen 9c4b64c952 fix(ci): pull API base image from Huawei SWR instead of DaoCloud
Staging publish failed resolving python:3.12-slim through m.daocloud.io; the web image already uses the reachable SWR docker.io/library path.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-20 22:44:20 +08:00
4 changed files with 36 additions and 3 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
FROM m.daocloud.io/docker.io/library/python:3.12-slim
FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/python:3.12-slim
ENV PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
+16
View File
@@ -5003,6 +5003,22 @@
- 复发自:BUG-307(当时把分盘句和宫位表从正文挪到界面后,入口合同锁死了那句提示词)
- 修复版本:379f0e6f
## BUG-333 | staging 发布 API 镜像时 DaoCloud TLS 握手超时
- 状态:resolved
- 首次发现:2026-08-20
- 最近更新:2026-08-20
- 影响面:Gitea `backend-quality-gate``publish` job、`deploy/railway-api.Dockerfile``xiaoxin` runner 拉官方基础镜像
- 用户现象:`validate` 通过后 `Build and publish exact-SHA ACR images` 在 API Dockerfile 第一行失败:`Head "https://m.daocloud.io/v2/docker.io/library/python/manifests/3.12-slim"` TLS handshake timeout。
- 触发条件:向 `staging` 推送后 publish 构建 `deploy/railway-api.Dockerfile`
- 根因:API 基础镜像仍走 DaoCloud 代理。同一 runner 已验证可达华为 SWR / ECR / ACRWeb 镜像早已改用 `swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/node:22-alpine`API 未跟上。
- 修复:API `FROM` 改为与 Web 相同的华为 SWR `docker.io/library` 路径,指向 `python:3.12-slim`。不改运行时端口、pip/apt 镜像或 ACR 目标仓库。
- 验证:`tests/test_railway_deployment.py``frontend/tests/staging-backend-workflows.test.ts`。远端 publish 由本提交后的 Gitea quality gate 验收。
- 防复发:API/Web 官方基础镜像必须走华为 SWR `ddn-k8s/docker.io/library`,合同禁止 `daocloud`。不要为了重试再加一套 `for attempt in 1 2 3`,workflow 里该循环次数已被合同锁死为 5。
- 相关记录:BUG-149、BUG-150、BUG-332
- 复发自:无
- 修复版本:9c4b64c9
## BUG-329 | 生时纠正 Agent 回答在结算后一次性出现,推理中无法停止
- 状态:resolved
@@ -105,6 +105,7 @@ const railwayWebDockerfile = new URL(
const nextConfig = new URL("../next.config.ts", import.meta.url);
const instrumentation = new URL("../src/instrumentation.ts", import.meta.url);
const frontendPackage = new URL("../package.json", import.meta.url);
const apiDockerfile = new URL("../../deploy/railway-api.Dockerfile", import.meta.url);
function read(url: URL): string {
return readFileSync(url, "utf8");
@@ -228,6 +229,15 @@ test("quality gate validates relevant changes once and publishes a digest manife
assert.doesNotMatch(workflow, /(?:^|:)latest$/m);
});
test("staging images pull official bases from Huawei SWR instead of DaoCloud", () => {
const api = read(apiDockerfile);
const web = read(railwayWebDockerfile);
assert.match(api, /^FROM swr\.cn-north-4\.myhuaweicloud\.com\/ddn-k8s\/docker\.io\/library\/python:3\.12-slim$/m);
assert.match(web, /^FROM swr\.cn-north-4\.myhuaweicloud\.com\/ddn-k8s\/docker\.io\/library\/node:22-alpine/m);
assert.doesNotMatch(api, /daocloud/i);
assert.doesNotMatch(web, /daocloud/i);
});
test("Gitea quality gate validates before publishing an immutable ACR manifest", () => {
const workflow = read(giteaQualityWorkflow);
@@ -237,6 +247,10 @@ test("Gitea quality gate validates before publishing an immutable ACR manifest",
assert.equal((workflow.match(/runs-on: xiaoxin/g) ?? []).length, 2);
assert.match(workflow, /validate:[\s\S]*?timeout-minutes: 45[\s\S]*?publish:[\s\S]*?timeout-minutes: 60/);
assert.match(workflow, /GITEA_SHA: \$\{\{ gitea\.sha \}\}/);
assert.match(
workflow,
/docker build -f deploy\/railway-api\.Dockerfile -t "\$IMAGE_REPOSITORY:api-\$GITEA_SHA"/,
);
assert.match(
workflow,
/docker build --build-arg NEXT_DEPLOYMENT_ID="\$GITEA_SHA" -f deploy\/railway-web\.Dockerfile/,
+5 -2
View File
@@ -9,15 +9,18 @@ def test_railway_services_use_the_product_frontend_and_dynamic_ports() -> None:
api = (ROOT / "deploy" / "railway-api.Dockerfile").read_text(encoding="utf-8")
assert "COPY frontend/package.json frontend/package-lock.json" in web
assert "--hostname 0.0.0.0" in web and "${PORT:-3000}" in web
assert "HOSTNAME=0.0.0.0" in web
assert 'CMD ["node", "server.js"]' in web
assert "next-env.d.ts" not in web
assert "FROM m.daocloud.io/docker.io/library/python:3.12-slim" in api
assert "FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/python:3.12-slim" in api
assert "daocloud" not in api.lower()
assert "COPY SKILL.md mcp_server.py" in api
assert "--host 0.0.0.0" in api and "${PORT:-5200}" in api
assert "http.server" not in api
assert "FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/node:22-alpine" in web
assert "daocloud" not in web.lower()
def test_web_image_copies_postcss_config_before_building_frontend() -> None: