Skip to content

fix(cli): shorten sandbox hostname for image-ID container names - #10624

Merged
yiliang114 merged 2 commits into
QwenLM:mainfrom
yiliang114:fix/sandbox-hostname-10605
Aug 31, 2026
Merged

fix(cli): shorten sandbox hostname for image-ID container names#10624
yiliang114 merged 2 commits into
QwenLM:mainfrom
yiliang114:fix/sandbox-hostname-10605

Conversation

@yiliang114

Copy link
Copy Markdown
Collaborator

What this PR does

In start_sandbox, the regular container name is derived from the image name. When QWEN_SANDBOX_IMAGE is an image ID, parseSandboxImageName produces sha256-<64hex>, and the -<8hex> suffix brings the full container name to 80 characters. That name was passed to docker run as both --name and --hostname. Since Linux HOST_NAME_MAX is 64, the hostname is invalid and the container fails to start with sethostname: invalid argument (exit 125).

This PR keeps the full name for --name, and only when the container name exceeds 64 characters, derives --hostname from a short hash (qwen-sandbox-<12hex>, 25 chars). Short names — including the integration-test container names — keep the previous behavior unchanged.

Why it's needed

Follow-up to F1 in the #10605 verification report: after #10605 made image IDs a documented shape for QWEN_SANDBOX_IMAGE, a regular (non-integration-test) sandbox launch with an image-ID image always failed, while CI stayed green because integration tests use a short generated name.

Reviewer Test Plan

How to verify

Run the new unit test:

cd packages/cli && npx vitest run src/serve/sandbox.test.ts

The new case feeds sha256:<64hex> as the image and asserts the resulting --name is longer than 64 chars while --hostname is within HOST_NAME_MAX. Full suite output: Test Files 1 passed (1), Tests 30 passed (30).

Evidence (Before & After)

N/A (non-user-visible; unit-test covered). Before: docker run --hostname <80-char-name> exits 125 with sethostname: invalid argument. After: --hostname is qwen-sandbox-<12hex> and the container starts normally.

Tested on

OS Status
🍏 macOS ⚠️
🪟 Windows ⚠️
🐧 Linux

Environment (optional)

Unit tests only (vitest); no Docker runtime exercised locally.

Risk & Scope

  • Main risk or tradeoff: hostname no longer equals the container name when the name exceeds 64 chars; this only affects the image-ID case that previously failed outright.
  • Not validated / out of scope: F2 from the same verification report (one-line contract test in scripts/tests/e2e-workflow.test.js) — separate follow-up.
  • Breaking changes / migration notes: none.

Linked Issues

Follow-up to F1 in the #10605 verification report.

中文说明

这个 PR 做了什么

start_sandbox 中的普通容器名由镜像名派生。当 QWEN_SANDBOX_IMAGE 是镜像 ID 时,parseSandboxImageName 得到 sha256-<64hex>,再加 -<8hex> 后缀,完整容器名达到 80 个字符。此前这个名字同时作为 --name--hostname 传给 docker run。由于 Linux 的 HOST_NAME_MAX 是 64,hostname 非法,容器启动直接失败:sethostname: invalid argument(exit 125)。

本 PR 保持 --name 使用完整名字;仅当容器名超过 64 字符时,--hostname 改为由短哈希派生(qwen-sandbox-<12hex>,25 字符)。短名字(包括集成测试的容器名)行为完全不变。

为什么需要

这是 #10605 验证报告中 F1 的 follow-up:#10605 之后镜像 ID 成为 QWEN_SANDBOX_IMAGE 的合法形态,但常规(非集成测试)沙箱在镜像 ID 形态下必然启动失败;CI 之所以没发现,是因为集成测试用的是较短的生成名。

审阅者验证方式

如何验证

运行新增单测:cd packages/cli && npx vitest run src/serve/sandbox.test.ts。新用例以 sha256:<64hex> 作为镜像,断言 --name 超过 64 字符而 --hostname 不超过 64。完整输出:Test Files 1 passed (1)Tests 30 passed (30)

前后对比

不适用(非用户可见,已由单测覆盖)。修复前:docker run --hostname <80字符名> 以 125 退出并报 sethostname: invalid argument;修复后:--hostnameqwen-sandbox-<12hex>,容器正常启动。

测试平台

仅 🐧 Linux(✅);macOS / Windows 未测。

环境

仅单元测试(vitest),未在本机实际运行 Docker。

风险与范围

  • 主要风险/取舍:名字超过 64 字符时 hostname 不再等于容器名;但这只影响此前完全无法启动的镜像 ID 场景。
  • 未验证/不在范围内:同一验证报告中的 F2(scripts/tests/e2e-workflow.test.js 一行契约测试)将单独跟进。
  • 破坏性变更/迁移说明:无。

关联 Issue

#10605 验证报告 F1 的 follow-up(不自动关闭)。

A regular container name derived from an image ID (sha256-<64hex> plus the
-<8hex> suffix = 80 chars) exceeds Linux HOST_NAME_MAX (64), so `docker run`
fails with `sethostname: invalid argument` (exit 125) whenever
QWEN_SANDBOX_IMAGE is an image ID -- the documented shape after QwenLM#10605. Keep
the full name for --name and derive --hostname from a short hash when the
container name is too long. Follow-up to F1 in the QwenLM#10605 verification report.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Qwen Triage finishedview run. See the stage comments in this thread for the result.

Qwen Triage 已完成 —— 查看运行。结果见本线程中的各阶段评论。

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR, @yiliang114!

Template looks good ✓

Problem: an observed bug, not theory — verified against the base code. parseSandboxImageName('sha256:<64hex>') yields sha256-<64hex> (71 chars), the -<8hex> suffix brings the container name to 80 chars, and that name was passed to docker run as --hostname. Linux HOST_NAME_MAX is 64, so the launch fails deterministically with sethostname: invalid argument (exit 125) for every regular sandbox started from an image ID — the shape #10605 (merged this morning) made documented. CI stayed green because integration-test container names are short (35 chars).

Direction: aligned — it restores behavior that the just-merged #10605 documents. It sits inside the sandbox area, though, so per gate policy this escalates for a maintainer's sign-off instead of continuing through automated review; stopping here after the gate. Claude Code's CHANGELOG has no direct counterpart for this, but the sandbox-orchestration area is actively evolving there too, so the area is relevant.

Size: not a core-module path. 17 production lines (+15/−2 in sandbox.ts), 46 test lines.

Approach: the scope feels right — it matches what I'd have done. Keeping the full name for --name preserves the existing contract (consumers parse the ContainerName (regular): line; cleanup tooling matches on the image-name prefix), and the short fallback hostname only kicks in for the case that previously failed outright — names ≤ 64 chars keep today's behavior exactly, integration tests included. The fallback is a sha256 of the container name truncated to 12 hex: deterministic and effectively collision-free (container uniqueness is enforced by --name anyway). I checked the tree: nothing reads the container hostname expecting it to equal the container name — every other hostname in this codebase is the unrelated qwen serve bind address or gh --hostname. The alternative of shortening the container name itself would break the parse/prefix contract, so it's worse. The new test pins exactly the right invariant (--name > 64, --hostname ≤ 64).

Risk: packages/cli/src/serve/sandbox.ts matches the revert-history high-risk pattern ((^|/)sandbox\.ts$). That is a review-depth signal, not a blocker — but whoever takes this through Stage 2 should keep the full enrichments and CI evidence before approving.

⏸️ Escalating to a maintainer. Sandbox-machinery changes need a human direction sign-off before the bot takes them further. No owner resolved deterministically (the PR has no labels, and the owners map has no area covering packages/cli/src/serve/), so this is a call for whichever maintainer is watching: note this is policy, not doubt — the gate itself is clean. The problem is real and verified, the approach is minimal, and the test pins the invariant. A maintainer can re-run @qwen-code /triage to continue from Stage 2, or review directly.

中文说明

感谢贡献,@yiliang114

模板完整 ✓

问题:是已观测到的 bug,不是理论推演——已对照基线代码验证。parseSandboxImageName('sha256:<64hex>') 得到 sha256-<64hex>(71 字符),加 -<8hex> 后缀后容器名达 80 字符,而这个名字被直接传给 docker run--hostname。Linux 的 HOST_NAME_MAX 是 64,所以凡是镜像 ID 形态启动的常规沙箱必然以 sethostname: invalid argument(exit 125)失败——而镜像 ID 正是 #10605(今晨已合并)文档化的合法形态。CI 没发现是因为集成测试的容器名只有 35 字符。

方向:对齐——恢复的是刚合并的 #10605 所承诺的行为。但改动位于 sandbox 领域,按门禁策略需升级给维护者确认方向,不再继续自动化审查;门禁之后到此为止。Claude Code 的 CHANGELOG 没有直接对应项,但那边 sandbox 编排也在持续演进,该领域是相关的。

规模:非核心模块路径。生产代码 17 行(sandbox.ts +15/−2),测试 46 行。

方案:范围合理——和我的独立方案一致。--name 保留完整名字,维持现有契约(有消费者解析 ContainerName (regular): 输出行;清理工具按镜像名前缀匹配),短 hostname 兜底只在原本必然失败的分支生效——不超过 64 字符的名字(含集成测试)行为完全不变。兜底值是容器名 sha256 截前 12 位 hex:确定性强、实际不会碰撞(容器唯一性本就由 --name 保证)。已全仓检查:没有任何代码读取容器 hostname 并假定它等于容器名——代码库里其他 hostname 都是不相关的 qwen serve 绑定地址或 gh --hostname。另一个思路——直接缩短容器名本身——会破坏解析/前缀契约,更差。新测试恰好钉住了关键不变量(--name 超 64 而 --hostname 不超)。

风险packages/cli/src/serve/sandbox.ts 命中 revert 历史的高风险路径模式((^|/)sandbox\.ts$)。这是审查深度信号,不是拦截项——但后续走 Stage 2 时应保留完整增强项和 CI 证据再批准。

⏸️ 升级给维护者。 sandbox 机制的改动在机器人继续推进前需要人工确认方向。本次未确定性地解析出归属人(PR 无标签,归属映射也没有覆盖 packages/cli/src/serve/ 的领域),请任一维护者接手:注意这是策略性升级,不是有疑点——门禁本身是干净的:问题真实且已验证、方案最小化、测试钉住了不变量。维护者可以用 @qwen-code /triage 重跑从 Stage 2 继续,也可直接审查。

Qwen Code · qwen3.8-max

Reviewed at 53f084a72ae0fdbf658919afe739ca20da2d9cf0 · re-run with @qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

🩺 serve daemon A/B

Built the PR base vs this PR head 6856215, drove a fixed endpoint set against each, and diffed the JSON responses. Only fields that changed are shown.

No response changes against the PR base across 12 scenario(s).

Qwen Code · serve A/B

@yiliang114
yiliang114 enabled auto-merge August 31, 2026 11:18
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

@chiga0 chiga0 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking findings.

Reviewed at head 685621561e (updated from the original head — the approach was simplified; re-reviewed in full).

Change summary: omit --hostname entirely when containerName.length > 64, instead of passing a hash-derived short name. Docker then defaults the hostname to the first 12 characters of the container ID, which is always a valid hostname. Simpler and strictly correct.

What was checked:

  • parseSandboxImageName("sha256:" + 64hex)sha256-<64hex> (71 chars) → containerName = sha256-<64hex>-<8hex> = 80 chars. Trigger confirmed.
  • Threshold containerName.length <= 64: Linux sethostname(2) rejects len > 64, so exactly-64-char names pass --hostname containerName unchanged. Correct.
  • When --hostname is omitted, Docker defaults to the container's short ID (12 hex chars). Always valid.
  • import { randomBytes } from "node:crypto"createHash is NOT present (the first commit added it; the updated commit removed it, keeping the import clean).
  • Integration-test path (qwen-code-integration-test-<8hex> = 35 chars): length <= 64, behavior unchanged.
  • Proxy container (SANDBOX_PROXY_NAME = "qwen-code-sandbox-proxy", 24 chars): no --hostname arg, Docker default, unaffected.
  • Existing test now also asserts --hostname == --name for normal short names — confirms no regression on the happy path.
  • New test: asserts --name > 64 and --hostname absent from args. Would fail if the fix were reverted.

CI at head 685621561e:

  • Test (ubuntu-latest, Node 22.x)pending at review time (still running); the prior head's run of the same job passed 30/30.
  • Test (windows-latest, Node 22.x)SKIPPED (pre-existing matrix condition; no platform-specific code in this fix).
  • Test (macos-latest, Node 22.x)SKIPPED (same).
  • Integration Tests (CLI, No Sandbox)SKIPPED.
  • All other completed checks: success.

Unreviewable dimensions: Docker end-to-end not exercised; macOS/Windows unit jobs SKIPPED (pre-existing skip, not introduced by this PR).

Reviewed with AI assistance.

@yiliang114 yiliang114 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed: no findings. The 64-char bound is the POSIX hostname limit that image-ID container names (sha256-<64hex>-<8hex>) exceed, while the container --name itself may be longer — omitting only --hostname and letting the runtime pick one is the right cut. Both cases are pinned: the existing regular-image test now asserts hostname==name, and the new image-ID test asserts no --hostname flag. CI green. (Self-PR: GitHub blocks self-approval, needs another maintainer.)

@qwen-code-review-bot

Copy link
Copy Markdown
Collaborator

No blocking findings.

The conditional preserves existing hostname behavior for valid container names and lets Docker select a valid default only for oversized image-ID-derived names. The updated tests cover both paths.

@yiliang114

Copy link
Copy Markdown
Collaborator Author

@qwen-code-review-bot approve it if no blockers

@qwen-code-review-bot

Copy link
Copy Markdown
Collaborator

Approved — no blocking findings.

@qwen-code-dev-bot qwen-code-dev-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gate APPROVE at head 68562156 on the review conclusion, per maintainer instruction to decide independently of CI. Code review is complete and clean: the final approach (omit --hostname when the container name exceeds the 64-byte HOST_NAME_MAX instead of passing it) is the strictly safer shape — the ≤64 path keeps hostname==name pinned by test, and the >64 image-ID path previously died with exit 125 (sethostname invalid argument), so no existing behavior depended on the flag there; no repo consumer reads the sandbox container's hostname (token salt / writer-lease / worktree paths all run outside this comparison or were equally broken pre-fix). 0 unresolved threads. Note for the record: Test (ubuntu-latest) was still running at submission time; Serve A/B and the E2E leg passed on the prior head.

中文:按维护者指示以自身 Review 结论投票,不再等待 CI。最终方案(容器名超 64 时省略 --hostname)经独立核对无行为回归:≤64 路径保持 name==hostname 且被测试钉住,>64 路径旧行为本就是 exit 125 全坏,无既有依赖;仓内无消费方读取沙箱容器 hostname。线程零未解决。记录在案:提交时 Test (ubuntu) 仍在运行,非红。

@yiliang114
yiliang114 added this pull request to the merge queue Aug 31, 2026
Merged via the queue into QwenLM:main with commit 2e19425 Aug 31, 2026
92 of 94 checks passed
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Released in v0.23.0.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants