yetuge 42df8f3e5f
fix(integrations): decode lark-cli and npm output as UTF-8 (#6590)
* fix(integrations): decode lark-cli and npm output as UTF-8

Every text-mode subprocess.run in lark_cli.py that captures lark-cli or npm
output omits encoding, so the bytes are decoded with the host locale. Both
write UTF-8 to a pipe: the @larksuite/cli npm package's bin is a Node wrapper
around a native binary that emits UTF-8 (lark-cli --help writes U+2014 as
E2 80 94), and npm output is UTF-8 too.

On a host whose ANSI code page is not UTF-8 (cp936, cp1252) the locale decode
silently mangles every non-ASCII field -- auth status --json returns a garbled
userName, so the status card shows mojibake -- and an undecodable byte raises
inside subprocess's reader thread, which is not re-raised: stdout comes back
as None or "", so a healthy CLI is reported as unavailable and a successful
run raises "lark-cli did not return JSON output."

Decode these captures as UTF-8, matching #5440 (PowerShell), #5904 (AIO
sandbox docker CLI) and #6548 (Git Bash output in LocalSandbox). The
whoami /user capture stays on the locale: whoami is a native tool that writes
the host code page, the same UTF-8/native split #6548 drew.

Tests drive the real functions with a stand-in CLI emitting UTF-8 CJK JSON
and pin the pre-fix decode path, so they fail on main and pass here on any
host locale.

Fixes #6589

* test(lark): isolate the paths singleton in the encoding suite

The new tests reached ensure_lark_cli_credential_tree through the global
get_paths() singleton, so every run created and hardened a real
<cwd>/.deer-flow/users/alice/integrations/lark-cli/{config,data} tree in
whatever directory pytest ran from -- the same runtime home a live deployment
keeps real per-user Lark credentials in. An autouse fixture now points the
singleton at tmp_path, matching what test_lark_cli_integration.py does.

Red/green is unchanged: reverting only lark_cli.py still fails the two
assertions that pin the decode, and the suite leaves no .deer-flow behind.

* test(lark): make the version probe pin the decode, drop the inert locale patch

Two test-rigor notes from review:

- test_probe_lark_cli_at_path only asserted available/error, and the probe
  returns available=True with any non-empty output and a zero exit code, so
  the test stayed green even with the encoding pin removed from
  _probe_lark_cli_at_path. The stand-in now answers --version with a non-ASCII
  payload and the test names the expected text, which fails on the unpinned
  call site (verified) and passes with the pin.
- The locale.getencoding patch was inert: the subprocess.run wrapper injects
  the codec for unpinned text-mode calls and lark_cli never consults the
  locale itself, so nothing reached the real locale-decode path. Dropped it,
  along with the now-unused import, rather than implying a redirection that
  does not happen.

The Windows shim forwards its arguments (%*) so the stand-in sees --version.

---------

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-10-10 14:28:10 +08:00
..