Skip to content

fix(weixin): show allowed image directories - #5296

Merged
wenshao merged 1 commit into
QwenLM:mainfrom
tt-a1i:fix/weixin-image-allowlist-error
Jun 18, 2026
Merged

wenshao merged 1 commit into
QwenLM:mainfrom
tt-a1i:fix/weixin-image-allowlist-error

Conversation

@tt-a1i

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

Copy link
Copy Markdown
Contributor

Summary

  • Keep the existing Weixin image sandbox allowlist unchanged.
  • Include the allowed image directories in the "outside allowed directories" error.
  • Add regression coverage for a rejected Windows image path.

Refs #4441

Test Plan

  • npx vitest run --config vitest.config.ts src/send.test.ts (from packages/channels/weixin)
  • npx vitest run --config vitest.config.ts (from packages/channels/weixin)
  • npm run build --workspace=@qwen-code/channel-weixin
  • npx eslint packages/channels/weixin/src/send.ts packages/channels/weixin/src/send.test.ts
  • npx prettier --check packages/channels/weixin/src/send.ts packages/channels/weixin/src/send.test.ts
  • git diff --check
  • Subagent review: no blockers

AI Assistance Disclosure

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

@wenshao

wenshao commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@tt-a1i
tt-a1i force-pushed the fix/weixin-image-allowlist-error branch from 6fbe8cb to 5ea3c91 Compare June 18, 2026 17:35
@tt-a1i
tt-a1i marked this pull request as ready for review June 18, 2026 18:09
@wenshao

wenshao commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@wenshao

wenshao commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

✅ Local runtime verification (real tmux, no mocks) — PR #5296

Verdict: works as intended, no regressions — safe to merge.

I reproduced the issue #4441 rejection path against the real validateImagePath — real filesystem, real node:fs/node:os/node:path, no test doubles — running both the compiled dist/send.js (the shipped artifact) and the TypeScript source, inside an isolated tmux session.

What the PR does

When an image is rejected as outside the sandbox allowlist, the error message now also lists the allowed directories. formatAllowedImageDirs dedupes the four internal /tmp-style entries and trims trailing separators; trimDisplayDir preserves Windows drive roots (C:\). The allowlist enforcement itself is unchanged.

Evidence

1. Unit suite + build (PR head)

Test Files  2 passed (2)
     Tests  45 passed (45)     # src/send.test.ts 34 (incl. the new one) + media 11
VITEST_EXIT=0
npm run build  →  tsc --build  →  BUILD_EXIT=0
dist/send.js rebuilt 2026-06-19 02:41, contains "Allowed directories" ✓

2. Real runtime — PR head (identical result against compiled dist and source):

[A outside-allowed-dirs] THROW  -> Image path outside allowed directories: .../outside/hello.png. Allowed directories: /tmp, .../workspace
[B inside-workspace    ] OK     -> returned: .../workspace/inside.png
[C inside-/tmp         ] OK     -> returned: /tmp/realtest5296.png
HAS_ALLOWED_DIRS_HINT=true   LISTS_TMP=true   LISTS_WORKSPACE=true   NO_TRAILING_SLASH=true

Full message verbatim:

Image path outside allowed directories: /root/realtest-5296/fs/outside/hello.png. Allowed directories: /tmp, /root/realtest-5296/fs/workspace

On this host os.tmpdir() is /tmp, so all four /tmp-style allowlist entries collapse to a single /tmp via the new dedup, and the workspace is shown without a trailing slash. The happy paths (inside workspace, inside /tmp) still validate — no regression.

3. A/B against the pre-PR base commit (same harness, same filesystem):

[A outside-allowed-dirs] THROW  -> Image path outside allowed directories: .../outside/hello.png
HAS_ALLOWED_DIRS_HINT=false

Direct before/after: base emits the bare message (exactly the #4441 complaint); head appends the directory list.

4. The new test has teeth — running the PR's regression test against the base code fails as expected:

× validateImagePath > reports the allowed directories when a Windows image path is rejected
  Expected: "...hello.png. Allowed directories: /tmp, D:\OtherProject"
  Received: "...hello.png"
TEETH_VITEST_EXIT=1

Edge cases checked (against the exact helper logic)

input output
/tmp/, /tmp//, /tmp /tmp dedup ✓
.../workspace/ .../workspace trailing separator trimmed ✓
C:\, C:/ preserved Windows drive root kept ✓
D:\OtherProject\ D:\OtherProject ✓
/ / not emptied ✓

Minor / non-blocking nit: a workspace that is literally a drive root is built internally as C:\/ and then displays as C: (cosmetic only; unreachable in normal use because tmpdir()/cwd are never bare drive roots).

Notes

  • True Windows path semantics are exercised only via mocked realpathSync in the unit test — expected on a Linux host. The win32 branch is unit-covered and the new test pins the exact string /tmp, D:\OtherProject.
  • After the A/B swap, the working tree was restored to head and verified clean (RESTORE_CLEAN=yes).
🇨🇳 中文版(点击展开)

✅ 本地真实运行验证(真实 tmux,无 mock)— PR #5296

结论:行为符合预期,无回归,可以合并。

我在隔离的 tmux 会话中,针对真实的 validateImagePath 复现了 issue #4441 的拒绝路径——使用真实文件系统、真实的 node:fs/node:os/node:path,完全不使用任何 mock——并且同时跑了编译产物 dist/send.js(实际发布的文件)和 TypeScript 源码两种形态。

这个 PR 做了什么

当图片因不在沙箱白名单内而被拒绝时,错误信息现在会额外列出允许的目录。formatAllowedImageDirs 会对四个内部的 /tmp 类条目去重并裁掉末尾分隔符;trimDisplayDir 会保留 Windows 盘符根(C:\)。白名单本身的校验逻辑没有改变。

证据

1. 单元测试 + 构建(PR head)

Test Files  2 passed (2)
     Tests  45 passed (45)     # send.test.ts 34 个(含新增用例)+ media 11 个
VITEST_EXIT=0
npm run build  →  tsc --build  →  BUILD_EXIT=0
dist/send.js 于 2026-06-19 02:41 重新生成,包含 "Allowed directories" ✓

2. 真实运行 — PR head(编译产物 dist 与源码结果一致):

[A outside-allowed-dirs] THROW  -> Image path outside allowed directories: .../outside/hello.png. Allowed directories: /tmp, .../workspace
[B inside-workspace    ] OK     -> returned: .../workspace/inside.png
[C inside-/tmp         ] OK     -> returned: /tmp/realtest5296.png
HAS_ALLOWED_DIRS_HINT=true   LISTS_TMP=true   LISTS_WORKSPACE=true   NO_TRAILING_SLASH=true

完整信息原文:

Image path outside allowed directories: /root/realtest-5296/fs/outside/hello.png. Allowed directories: /tmp, /root/realtest-5296/fs/workspace

本机 os.tmpdir() 为 /tmp,因此四个 /tmp 类白名单条目经新增的去重逻辑后合并为一个 /tmp,工作区目录也不带末尾斜杠。两个正常路径(工作区内、/tmp 内)仍能通过校验——无回归。

3. 与 PR 之前的 base 提交做 A/B 对比(同一套脚本、同一文件系统):

[A outside-allowed-dirs] THROW  -> Image path outside allowed directories: .../outside/hello.png
HAS_ALLOWED_DIRS_HINT=false

直接的前后对比:base 只给出干巴巴的信息(正是 #4441 的抱怨点);head 追加了目录列表。

4. 新增测试是有效的(有“牙齿”)——把 PR 的回归测试跑在 base 代码上会按预期失败:

× validateImagePath > reports the allowed directories when a Windows image path is rejected
  Expected: "...hello.png. Allowed directories: /tmp, D:\OtherProject"
  Received: "...hello.png"
TEETH_VITEST_EXIT=1

边界情况核对(针对两个 helper 的精确逻辑)

输入 输出
/tmp/、/tmp//、/tmp /tmp 去重 ✓
.../workspace/ .../workspace 末尾分隔符被裁掉 ✓
C:\、C:/ 原样保留 保留 Windows 盘符根 ✓
D:\OtherProject\ D:\OtherProject ✓
/ / 不会被裁成空 ✓

非阻塞的小提示:如果工作区本身就是盘符根,内部会拼成 C:\/,显示时会变成 C:(仅影响显示;正常使用中不可能触发,因为 tmpdir()/cwd 不会是裸盘符根)。

说明

  • 真正的 Windows 路径语义只能通过单元测试里 mock 的 realpathSync 来覆盖——在 Linux 主机上属正常情况。win32 分支已有单元测试覆盖,且新增用例钉住了精确字符串 /tmp, D:\OtherProject。
  • A/B 替换文件之后,工作区已恢复到 head 并验证干净(RESTORE_CLEAN=yes)。

@wenshao
wenshao merged commit 0a0fedf into QwenLM:main Jun 18, 2026
30 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.

2 participants