Skip to content

fix(cli): parse sandbox image registry ports#5325

Merged
wenshao merged 1 commit into
QwenLM:mainfrom
tt-a1i:fix/sandbox-image-registry-port
Jun 18, 2026
Merged

fix(cli): parse sandbox image registry ports#5325
wenshao merged 1 commit into
QwenLM:mainfrom
tt-a1i:fix/sandbox-image-registry-port

Conversation

@tt-a1i

@tt-a1i tt-a1i commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

What this PR does

Moves the sandbox image-name parsing out of sandbox.ts into a small, dedicated and unit-tested helper (parseSandboxImageName in sandboxImageName.ts), and fixes how the image reference is split into a Docker container-name prefix:

  • The tag separator is now resolved as the last : that appears after the final /, so a registry port such as localhost:5000 is correctly treated as part of the registry path rather than as an image tag.
  • The container-name prefix is still derived from the image basename plus its tag (e.g. ghcr.io/qwenlm/qwen-code:0.18.3qwen-code-0.18.3).
  • Image digests (@sha256:...) are stripped before parsing, so they no longer leak into the generated name, while any preceding tag is preserved (e.g. …/qwen-code-sandbox:dev@sha256:…qwen-code-sandbox-dev).

The previous implementation used image.split(':'), which broke on registry ports. Behavior is otherwise unchanged.

Why it's needed

Fixes #5324. Sandbox container names are derived from the configured image name, but the old parser split on the first :. For common private-registry images that include a port, e.g. localhost:5000/team/qwen-code:dev, this collapsed the name down to localhost-5000, losing the real image basename and tag. After this change the registry port stays part of the registry path and the container name is correctly based on the image basename (qwen-code-dev).

Reviewer Test Plan

How to verify

Repro: configure a sandbox image with a registry port, e.g. localhost:5000/team/qwen-code:dev.

  • Expected (old, buggy): container-name prefix localhost-5000.
  • Expected (new, fixed): container-name prefix qwen-code-dev.

The new unit tests cover this repro plus untagged ports, digest stripping, and tag+digest combinations. Verification commands from the PR:

  • npx vitest run src/utils/sandbox.test.ts from packages/cli
  • npm run typecheck --workspace=packages/cli
  • npm run build --workspace=packages/cli
  • npm run lint
  • npx prettier --experimental-cli --check packages/cli/src/utils/sandbox.ts packages/cli/src/utils/sandboxImageName.ts packages/cli/src/utils/sandbox.test.ts
  • git diff --check

Evidence (Before & After)

N/A — non-visible logic fix (internal container-name derivation); covered by the unit tests above.

Tested on

OS Status
🍏 macOS ✅ CI
🪟 Windows ✅ CI
🐧 Linux ✅ CI

✅ tested · ⚠️ not tested · N/A

Environment (optional)

Unit tests only (npm workspaces).

Risk & Scope

  • Main risk or tradeoff: Low; scoped to sandbox container-name derivation in packages/cli. Behavior change is limited to how the image reference is parsed into a name prefix.
  • Not validated / out of scope: No unrelated refactors, public API changes, or UI changes.
  • Breaking changes / migration notes: None.

Linked Issues

Fixes #5324

中文说明

这个 PR 做了什么

将 sandbox 镜像名解析逻辑从 sandbox.ts 抽取到一个独立、带单元测试的小helper(sandboxImageName.ts 中的 parseSandboxImageName),并修复了将镜像引用切分为 Docker 容器名前缀的方式:

  • 标签(tag)分隔符现在被解析为最后一个 / 之后 出现的最后一个 :,因此像 localhost:5000 这样的 registry 端口会被正确当作 registry 路径的一部分,而不是被误认为镜像标签。
  • 容器名前缀仍然由镜像 basename 加上其标签派生而来(例如 ghcr.io/qwenlm/qwen-code:0.18.3qwen-code-0.18.3)。
  • 镜像 digest@sha256:...)在解析前会被剥离,因此不再混入生成的名字中,同时其前面的标签会被保留(例如 …/qwen-code-sandbox:dev@sha256:…qwen-code-sandbox-dev)。

旧实现使用 image.split(':'),在遇到 registry 端口时会出错。除此之外行为保持不变。

为什么需要它

修复 #5324。Sandbox 容器名是从配置的镜像名派生的,但旧解析器在第一个 : 处切分。对于包含端口的常见私有 registry 镜像,例如 localhost:5000/team/qwen-code:dev,这会把名字压缩成 localhost-5000,丢失了真正的镜像 basename 和标签。改动之后,registry 端口会保留为 registry 路径的一部分,容器名正确地基于镜像 basename(qwen-code-dev)。

Reviewer 测试计划

如何验证

复现:配置一个带 registry 端口的 sandbox 镜像,例如 localhost:5000/team/qwen-code:dev

  • 预期(旧的、有 bug 的):容器名前缀 localhost-5000
  • 预期(新的、已修复的):容器名前缀 qwen-code-dev

新增的单元测试覆盖了该复现,以及不带标签的端口、digest 剥离、标签 + digest 组合等场景。PR 中的验证命令:

  • packages/clinpx vitest run src/utils/sandbox.test.ts
  • npm run typecheck --workspace=packages/cli
  • npm run build --workspace=packages/cli
  • npm run lint
  • npx prettier --experimental-cli --check packages/cli/src/utils/sandbox.ts packages/cli/src/utils/sandboxImageName.ts packages/cli/src/utils/sandbox.test.ts
  • git diff --check

证据(前后对比)

N/A —— 非可见的逻辑修复(内部容器名派生);已由上述单元测试覆盖。

测试平台

OS 状态
🍏 macOS ✅ CI
🪟 Windows ✅ CI
🐧 Linux ✅ CI

✅ 已测试 · ⚠️ 未测试 · N/A

环境(可选)

仅单元测试(npm workspaces)。

风险与范围

  • 主要风险或权衡:低;范围限定在 packages/cli 的 sandbox 容器名派生。行为变化仅限于如何将镜像引用解析为名字前缀。
  • 未验证 / 超出范围:没有无关的重构、公共 API 变更或 UI 变更。
  • 破坏性变更 / 迁移说明:无。

关联 Issue

修复 #5324

AI Assistance Disclosure

I used Codex to review the changes, sanity-check the implementation against existing patterns, and help spot potential edge cases.

@tt-a1i
tt-a1i marked this pull request as ready for review June 18, 2026 17:00
@wenshao

wenshao commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@qwen-code-ci-bot qwen-code-ci-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.

Hi @tt-a1i — thanks for the fix! The actual code change (moving the image-name parser into a small tested helper that handles registry ports and digests) looks focused and correct. The bug in #5324 is real and the approach is clean.

However, this PR's description doesn't follow the PR template. The template is mandatory for all PRs because it gives reviewers the information they need to verify the change without having to read the diff in detail.

The current body uses ## Summary / ## Test plan / ## AI Assistance Disclosure. Please reformat it to match the template:

  • ## What this PR does and ## Why it's needed — describe the change in prose and the motivation (you can largely reuse your Summary text).
  • ## Reviewer Test Plan — this is the main thing that's missing:
    • ### How to verify — the commands you already listed fit here.
    • ### Evidence (Before & After) — since this is non-user-visible, N/A is fine, or paste the failing vs passing container-name output.
    • ### Tested on — fill in the OS table (Linux at minimum, since sandbox is Docker/Linux).
  • ## Risk & Scope — one line each for main risk, what's out of scope, and whether there are breaking changes.
  • ## Linked Issues — use Fixes #5324 (or Closes #5324) so the issue auto-closes on merge. Your current body says "Fixes #5324" inline but it needs to be in this section.
  • <details><summary>中文说明</summary> — full Chinese translation of the English body.

Quick test-plan note: the npm run typecheck --workspace=packages/cli / npm run build --workspace=packages/cli / npm run lint lines in your Test plan are good; they will be re-run by CI, but listing them under ### How to verify makes the reviewer flow explicit.

Once the template is filled in, I'll re-run triage and move to code review. Happy to answer questions here.

中文说明

@tt-a1i 你好 — 感谢提交修复!代码改动本身(把镜像名解析挪到一个有测试的小 helper 里,并正确处理 registry 端口和 digest)聚焦且正确,#5324 描述的 bug 确实存在,方案也很干净。

不过这个 PR 的描述没有遵循 PR 模板。模板对所有 PR 都是强制的,因为它能让 reviewer 在不细看 diff 的情况下也能完成验证。

当前正文使用的是 ## Summary / ## Test plan / ## AI Assistance Disclosure,请按模板改成以下结构:

  • ## What this PR does## Why it's needed —— 用自然语言描述改动和动机(基本可以复用你的 Summary)。
  • ## Reviewer Test Plan —— 这是目前缺失最多的部分:
    • ### How to verify —— 你已经列出的命令放在这里。
    • ### Evidence (Before & After) —— 非用户可见改动写 N/A 即可,也可以贴修复前后容器名的对比。
    • ### Tested on —— 填写 OS 表格(至少填 Linux,因为 sandbox 是 Docker/Linux)。
  • ## Risk & Scope —— 用一行分别说明主要风险、不在范围内的事项、是否有破坏性变更。
  • ## Linked Issues —— 使用 Fixes #5324(或 Closes #5324),让 issue 在合并时自动关闭。你正文里写了 "Fixes #5324",但需要放在这个章节下。
  • <details><summary>中文说明</summary> —— 英文正文的完整中文翻译。

小提示:Test plan 里的 npm run typecheck --workspace=packages/cli / npm run build --workspace=packages/cli / npm run lint 这些命令没问题;CI 会重跑,但把它们写在 ### How to verify 下能让 reviewer 的流程更清楚。

模板补齐之后我会重新跑一次 triage 并进入代码评审。有问题随时在这里沟通。

Qwen Code · qwen3.7-max

@wenshao

wenshao commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks @tt-a1i for the fix!

Template looks good ✓ — all required sections are filled in, including the bilingual Chinese translation. The prior Stage 1 gate flagged the old template format; the updated body addresses every point.

On direction: this is a straightforward bug fix for #5324. The sandbox image-name parser breaks on registry ports (localhost:5000/…localhost-5000 instead of the image basename). Clearly within scope — sandbox configuration is a core CLI feature, and this is a P3 bug. No CHANGELOG reference needed for a targeted fix like this.

On approach: the scope is tight and appropriate. Three files, all related to the fix:

  • Extract the private parseImageName into a testable parseSandboxImageName helper — justified because the old function was untestable inside sandbox.ts.
  • Fix the parsing logic (last : after last / instead of naive split(':')).
  • Add digest stripping as a bonus correctness improvement.
  • Five unit tests covering the key cases.

No scope creep, no drive-by refactors. This is what a focused bugfix PR should look like.

Moving on to code review. 🔍

中文说明

感谢 @tt-a1i 的修复!

模板完整 ✓ —— 所有章节已填写,包括中英双语翻译。之前 Stage 1 指出的模板问题已全部解决。

方向:这是对 #5324 的直接 bug 修复。sandbox 镜像名解析在遇到 registry 端口时出错(localhost:5000/…localhost-5000 而非镜像 basename),属于 CLI 核心功能范围,P3 优先级。这类针对性修复不需要 CHANGELOG 引用。

方案:范围紧凑合理。三个文件全部与修复相关:

  • 将私有 parseImageName 提取为可测试的 parseSandboxImageName helper —— 合理,因为旧函数在 sandbox.ts 内无法单独测试。
  • 修复解析逻辑(取最后一个 / 之后的最后一个 :,而非简单 split(':'))。
  • 额外增加了 digest 剥离,提升了正确性。
  • 五个单元测试覆盖关键场景。

没有范围蔓延,没有顺手重构。这就是一个聚焦 bugfix PR 应有的样子。

进入代码审查 🔍

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Code Review

Reviewed the diff independently. The fix is correct and clean:

  • Parsing logic — finding the last : after the last / is the right way to distinguish registry ports from tags. Verified against all five test cases including edge cases (untagged ports, digest-only, tag+digest).
  • Digest strippingimage.split('@')[0] is simple and correct. The ?? image fallback is technically unreachable (split always returns at least one element), but harmless.
  • Extraction — moving the function out of sandbox.ts into sandboxImageName.ts is justified for testability. The old parseImageName was a private function with no test coverage.
  • No regressions — the call site in sandbox.ts line 606 is the only consumer. One-line swap, no other changes to sandbox.ts.
  • Tests — five cases cover the key scenarios: standard tagged image, registry port with tag, registry port without tag, digest stripping, and tag+digest combo. All pass.

No blockers. No AGENTS.md violations. The code is minimal, focused, and does exactly what the PR says.

Test Results

Unit Tests

 ✓ src/utils/sandbox.test.ts (5 tests) 5ms

 Test Files  1 passed (1)
      Tests  5 passed (5)

Typecheck & Lint

  • npm run typecheck --workspace=packages/cli
  • npm run lint

Before/After Behavior

Ran the old parseImageName vs the new parseSandboxImageName side by side:

=== Sandbox Image Name Parser: Before vs After (PR #5325) ===

Input:  ghcr.io/qwenlm/qwen-code:0.18.3
Before: qwen-code-0.18.3
After:  qwen-code-0.18.3  [SAME]

Input:  localhost:5000/team/qwen-code:dev
Before: localhost-5000/team/qwen-code
After:  qwen-code-dev  [FIXED]

Input:  localhost:5000/team/qwen-code-sandbox
Before: localhost-5000/team/qwen-code-sandbox
After:  qwen-code-sandbox  [FIXED]

Input:  registry.example.com/team/qwen-code-sandbox@sha256:abcdef
Before: qwen-code-sandbox@sha256-abcdef
After:  qwen-code-sandbox  [FIXED]

Input:  registry.example.com/team/qwen-code-sandbox:dev@sha256:abcdef
Before: qwen-code-sandbox-dev@sha256
After:  qwen-code-sandbox-dev  [FIXED]

The old parser was even worse than the issue described — it didn't just lose the tag on localhost:5000/…:dev, it produced localhost-5000/team/qwen-code (with slashes, which Docker rejects in container names). The fix resolves all of these correctly.

Note: full E2E sandbox testing (actual Docker container creation) requires a Docker daemon and sandbox configuration, which isn't available in this CI environment. The function is only called during container creation, so the unit tests + behavioral demo above cover the logic completely.

中文说明

代码审查

独立审查了 diff。修复正确且干净:

  • 解析逻辑 —— 取最后一个 / 之后的最后一个 : 是区分 registry 端口和标签的正确方法。已验证全部五个测试用例,包括边界场景(无标签端口、仅 digest、标签+digest)。
  • Digest 剥离 —— image.split('@')[0] 简单正确。?? image 后备实际上不会触发(split 至少返回一个元素),但无害。
  • 提取 —— 将函数从 sandbox.ts 移到 sandboxImageName.ts 有充分理由:旧的 parseImageName 是私有函数,没有测试覆盖。
  • 无回归 —— sandbox.ts 第 606 行是唯一调用点。一行替换,sandbox.ts 无其他改动。
  • 测试 —— 五个用例覆盖关键场景:标准标签镜像、带标签的 registry 端口、无标签的 registry 端口、digest 剥离、标签+digest 组合。全部通过。

无阻塞问题,无 AGENTS.md 违规。代码最小化、聚焦,完全实现了 PR 描述的功能。

测试结果

单元测试

5/5 通过 ✅

Typecheck 和 Lint

全部通过 ✅

前后对比

旧解析器比 issue 描述的更糟糕 —— 对 localhost:5000/…:dev 不仅丢失了标签,还生成了 localhost-5000/team/qwen-code(包含斜杠,Docker 会拒绝这种容器名)。修复后所有场景都正确处理。

注:完整 E2E sandbox 测试(实际 Docker 容器创建)需要 Docker daemon 和 sandbox 配置,当前 CI 环境不可用。该函数仅在容器创建时调用,单元测试 + 行为对比 demo 已完整覆盖逻辑。

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Reflection

Stepping back to look at the whole picture:

This PR fixes a genuine bug (#5324) that breaks sandbox container creation for anyone using a private registry with a port — a common setup in enterprise environments. The old parser was even more broken than the issue described: it produced container names with slashes (Docker-invalid) in addition to losing the tag.

My independent proposal before reading the diff was the same approach: find the last : after the last /, extract the basename, handle digests. The PR matches this exactly — no extra abstraction, no scope creep, no unnecessary files.

The code is 21 lines of logic plus 44 lines of tests. Three files changed, all necessary. If I had to maintain this in six months, I'd thank the author for making it trivially readable and well-tested.

Everything checks out:

  • Template ✅
  • Direction ✅
  • Scope ✅ (minimal and focused)
  • Code review ✅ (correct, no blockers)
  • Unit tests ✅ (5/5 pass)
  • Typecheck ✅
  • Lint ✅
  • Before/after behavior ✅ (verified via demo)

Approving. ✅

中文说明

总结

这个 PR 修复了 #5324 中的一个真实 bug —— 对使用带端口的私有 registry 的用户(企业环境中很常见),sandbox 容器创建会失败。旧解析器比 issue 描述的更严重:它生成的容器名包含斜杠(Docker 不允许),并且丢失了标签。

我在看 diff 之前的独立方案与 PR 的做法完全一致:取最后一个 / 之后的最后一个 :,提取 basename,处理 digest。PR 精确匹配了这个方案 —— 没有多余抽象,没有范围蔓延,没有不必要的文件。

逻辑 21 行,测试 44 行。改了三个文件,全部必要。如果六个月后要维护这段代码,我会感谢作者让它如此易读且有测试覆盖。

全部检查通过,批准合并。✅

Qwen Code · qwen3.7-max

@qwen-code-ci-bot qwen-code-ci-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.

LGTM, looks ready to ship. ✅

@wenshao

wenshao commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

✅ Maintainer verification — real sandbox-launch test under tmux

Verified this PR locally by driving the actual qwen sandbox launch with a private-registry image and observing the real derived container name (tmux + a fake docker shim, since this host has no Docker), plus the unit suite. Verdict: a correct fix that turns a hard failure into working behavior — good to merge. I add a 🐧 Linux runtime check on top of the PR's CI coverage.

Environment

  • Isolated git worktree at the PR head (a8382207, on current upstream main), fresh npm ci (no symlinked node_modules), real esbuild bundle.
  • Linux · Node v22.22.2 · bundled qwen 0.18.3.
  • Scope is clean: exactly 3 files, +67 / −9, single commit (the env-var/comment changes visible in a 3-dot diff are unrelated upstream commits, not this PR).

1. Static checks (reproducing the PR test plan)

Check Command Result
Unit tests vitest run src/utils/sandbox.test.ts 5/5 (basename+tag, port tagged/untagged, digest drop, tag+digest)
Lint eslint sandbox.ts sandboxImageName.ts sandbox.test.ts ✅ clean
Format prettier --check (3 files) ✅ clean
Whitespace git diff --check ✅ clean
Typecheck npm run typecheck -w packages/cli exit 0, 0 errors

2. Why this matters (the bug)

Sandbox container names are derived from the image reference. The old image.split(':') treats the first : as the tag separator — but a private registry host like localhost:5000 contains a : for its port. So the derived name keeps the port and the registry path including /. Docker container names may only contain [a-zA-Z0-9][a-zA-Z0-9_.-]+, so the old name is rejected by Docker — i.e. the sandbox fails to start for any port-qualified registry image (not just a cosmetic naming issue).

3. Real sandbox-launch A/B in tmux

Ran the real qwen -p hi with QWEN_SANDBOX=docker and QWEN_SANDBOX_IMAGE=localhost:5000/team/qwen-code:dev. A fake docker on PATH satisfies the image/network preflight so the real start_sandbox reaches its container-naming step and emits the real docker run --name … — no container is actually run.

OLD (pre-PR):  ContainerName (regular): localhost-5000/team/qwen-code-0   <- port kept + contains '/'  => Docker would REJECT
               docker run … --name localhost-5000/team/qwen-code-0

NEW (this PR): ContainerName (regular): qwen-code-dev-0                   <- clean, valid container name
               docker run … --name qwen-code-dev-0

The name appears both on stderr and in the actual docker run --name argument. (Note: the real localhost:5000/team/qwen-code:dev resolves to localhost-5000/team/qwen-code under the old parser — even worse than the localhost-5000 cited in the description, because it also keeps the /team/qwen-code path.)

4. Function-level A/B (real parseSandboxImageName vs the pre-PR split(':'))

image OLD NEW (PR)
localhost:5000/team/qwen-code:dev localhost-5000/team/qwen-code qwen-code-dev
localhost:5000/team/qwen-code (no tag) localhost-5000/team/qwen-code qwen-code
registry.example.com:8443/a/b/c:1.2.3 registry.example.com-8443/a/b/c c-1.2.3
…/qwen-code-sandbox:dev@sha256:… qwen-code-sandbox-dev@sha256 ❌ (digest leaks) qwen-code-sandbox-dev
qwen-code-sandbox@sha256:… qwen-code-sandbox@sha256-… qwen-code-sandbox
ghcr.io/qwenlm/qwen-code:0.18.3 qwen-code-0.18.3 qwen-code-0.18.3 (unchanged)
qwen-code:0.18.3 qwen-code-0.18.3 qwen-code-0.18.3 (unchanged)

Every previously-correct case is unchanged (no regression); only the broken port/digest cases change — and they change from Docker-invalid names to valid ones.

Observations (non-blocking)

  1. Real-world severity: because the old names contained / (and @ for digests), Docker would reject them — so this is a hard "sandbox won't start" bug for port-qualified private-registry images, not just an ugly name. The fix restores functionality.
  2. Good refactor: the logic is now a small, pure, exported function with direct unit coverage; only the parser changed, and start_sandbox is otherwise untouched.
  3. Cross-platform: pure string logic, platform-agnostic. PR is CI-green on macOS/Windows/Linux; I additionally exercised the real Linux sandbox flow end-to-end.

🇨🇳 中文版(点击展开)

✅ 维护者验证 —— 在 tmux 中进行真实的 sandbox 启动测试

我在本地通过驱动真实的 qwen sandbox 启动(用一个私有 registry 镜像,并观察真实派生出来的容器名;因本机没有 Docker,用了一个 fake docker 垫片)外加单测进行了验证。结论:这是一个把「硬失败」修成「可用」的正确修复,建议合并。 在 PR 的 CI 覆盖之上,我补了一次 🐧 Linux 运行时验证。

环境

  • 在 PR head(a8382207,基于当前上游 main)上独立 git worktree,全新 npm ci(绝不软链 node_modules),真实 esbuild 打包。
  • Linux · Node v22.22.2 · 打包后的 qwen 0.18.3
  • 改动范围干净:恰好 3 个文件,+67 / −9,单个提交(3-dot diff 里看到的 env-var/注释改动是无关的上游提交,不属于本 PR)。

1. 静态检查(复现 PR 测试计划)

检查项 命令 结果
单元测试 vitest run src/utils/sandbox.test.ts 5/5(basename+tag、带/不带 tag 的端口、剥离 digest、tag+digest)
Lint eslint sandbox.ts sandboxImageName.ts sandbox.test.ts ✅ 干净
格式 prettier --check(3 个文件) ✅ 干净
空白字符 git diff --check ✅ 干净
类型检查 npm run typecheck -w packages/cli 退出码 0,0 错误

2. 为什么重要(这个 bug)

Sandbox 容器名是从镜像引用派生的。旧的 image.split(':')第一个 : 当作 tag 分隔符——但像 localhost:5000 这样的私有 registry 主机名里的 : 是端口。于是派生出的名字保留了端口和带 / 的 registry 路径。而 Docker 容器名只允许 [a-zA-Z0-9][a-zA-Z0-9_.-]+,所以旧名字会被 Docker 拒绝——也就是说,对任何带端口的 registry 镜像,sandbox 根本起不来(不只是名字难看的问题)。

3. tmux 中真实 sandbox 启动的 A/B

QWEN_SANDBOX=dockerQWEN_SANDBOX_IMAGE=localhost:5000/team/qwen-code:dev 跑真实的 qwen -p hi。PATH 上的 fake docker 满足镜像/网络的前置检查,使真实的 start_sandbox 走到容器命名那一步并产出真实的 docker run --name …——不会真正运行容器。

旧版(PR 前): ContainerName (regular): localhost-5000/team/qwen-code-0   <- 保留端口且含 '/' => Docker 会拒绝
              docker run … --name localhost-5000/team/qwen-code-0

新版(本 PR): ContainerName (regular): qwen-code-dev-0                   <- 干净、合法的容器名
              docker run … --name qwen-code-dev-0

该名字同时出现在 stderr 和真实的 docker run --name 参数里。(注:真实的 localhost:5000/team/qwen-code:dev 在旧解析器下得到 localhost-5000/team/qwen-code——比描述里写的 localhost-5000 还要糟,因为它还保留了 /team/qwen-code 路径。)

4. 函数级 A/B(真实的 parseSandboxImageName vs 旧的 split(':')

镜像 旧版 新版(PR)
localhost:5000/team/qwen-code:dev localhost-5000/team/qwen-code qwen-code-dev
localhost:5000/team/qwen-code(无 tag) localhost-5000/team/qwen-code qwen-code
registry.example.com:8443/a/b/c:1.2.3 registry.example.com-8443/a/b/c c-1.2.3
…/qwen-code-sandbox:dev@sha256:… qwen-code-sandbox-dev@sha256 ❌(digest 泄漏) qwen-code-sandbox-dev
qwen-code-sandbox@sha256:… qwen-code-sandbox@sha256-… qwen-code-sandbox
ghcr.io/qwenlm/qwen-code:0.18.3 qwen-code-0.18.3 qwen-code-0.18.3(不变)
qwen-code:0.18.3 qwen-code-0.18.3 qwen-code-0.18.3(不变)

所有原本正确的情形都保持不变(无回归);只有原本损坏的端口/digest 情形发生变化——而且是从 Docker 非法名变成合法名。

观察项(非阻断)

  1. 真实严重性: 因为旧名字含 /(digest 情形还含 @),Docker 会直接拒绝——所以对带端口的私有 registry 镜像,这是「sandbox 起不来」的硬 bug,不只是名字难看。修复后恢复了可用性。
  2. 不错的重构: 逻辑现在是一个小巧、纯粹、可导出的函数,有直接单测覆盖;只改了解析器,start_sandbox 其余部分未动。
  3. 跨平台: 纯字符串逻辑,与平台无关。PR 在 macOS/Windows/Linux 的 CI 全绿;我额外端到端验证了真实的 Linux sandbox 流程。

@wenshao
wenshao merged commit f75ca03 into QwenLM:main Jun 18, 2026
36 checks passed
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.

bug(cli): sandbox image name parser mishandles registry ports

3 participants