mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-25 17:18:11 +00:00
Hermes-sweeper review on #60741 flagged that _op_version (the paired op probe used by the same setup/status CLI flow at lines 127 and 205) still ran text=True without explicit encoding/errors. Add encoding='utf-8', errors='replace' to match _op_whoami and the production op read path at agent/secret_sources/onepassword.py:271-278. Also extend the regression test to cover _op_version alongside _op_whoami, and update the module docstring to reflect the widened scope. Test sensitivity verified: reverting the source change makes test_op_version_passes_utf8_encoding fail with encoding=None.
68 lines
2.8 KiB
Python
68 lines
2.8 KiB
Python
"""Regression test for issue #53428 — subprocess.run(text=True) without
|
|
explicit ``encoding=`` triggers ``UnicodeDecodeError`` on Chinese Windows
|
|
(cp936/GBK default encoding).
|
|
|
|
PR #55339 covers 21 call sites in ``agent/``, ``gateway/``, ``cli.py``,
|
|
``cron/``, plus 5 more in ``tools/`` and ``hermes_cli/`` (main.py,
|
|
setup.py, tts_tool.py, transcription_tools.py). The two call sites it
|
|
misses — ``hermes_cli/onepassword_secrets_cli.py::_op_whoami`` and
|
|
``_op_version`` — are guarded here.
|
|
|
|
Without ``encoding=``, ``text=True`` decodes child output with
|
|
``locale.getpreferredencoding(False)`` — cp936 on Chinese Windows —
|
|
which crashes on non-GBK bytes (issues #47939, #53428, #57238).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
|
|
def _assert_utf8_kwargs(mock_run):
|
|
"""Lift the encoding/errors kwargs out of the mock and assert them."""
|
|
assert mock_run.called, "subprocess.run was not called"
|
|
kwargs = mock_run.call_args.kwargs
|
|
assert kwargs.get("encoding") == "utf-8", (
|
|
f"subprocess.run called without encoding='utf-8' "
|
|
f"(got encoding={kwargs.get('encoding')!r}). "
|
|
f"On Chinese Windows (cp936), text=True without explicit encoding "
|
|
f"crashes with UnicodeDecodeError on non-GBK bytes. See #53428."
|
|
)
|
|
assert kwargs.get("errors") == "replace", (
|
|
f"subprocess.run called without errors='replace' "
|
|
f"(got errors={kwargs.get('errors')!r}). encoding='utf-8' alone "
|
|
f"still raises UnicodeDecodeError on non-UTF-8 bytes emitted by "
|
|
f"Windows-native CLIs. See #53428."
|
|
)
|
|
|
|
|
|
def test_op_whoami_passes_utf8_encoding(tmp_path):
|
|
"""_op_whoami must pass encoding='utf-8', errors='replace' so op CLI
|
|
output containing non-ASCII account names doesn't crash on cp936."""
|
|
from hermes_cli import onepassword_secrets_cli as op_cli
|
|
|
|
fake_binary = tmp_path / "op"
|
|
fake_binary.write_bytes(b"")
|
|
with patch.object(op_cli.subprocess, "run") as mock_run:
|
|
mock_run.return_value = MagicMock(
|
|
returncode=0, stdout="user@example.com", stderr=""
|
|
)
|
|
op_cli._op_whoami(fake_binary, account="")
|
|
_assert_utf8_kwargs(mock_run)
|
|
|
|
|
|
def test_op_version_passes_utf8_encoding(tmp_path):
|
|
"""_op_version must pass encoding='utf-8', errors='replace' so op CLI
|
|
output containing non-ASCII bytes doesn't crash on cp936. Pairs with
|
|
_op_whoami — both run in the same setup/status CLI flow."""
|
|
from hermes_cli import onepassword_secrets_cli as op_cli
|
|
|
|
fake_binary = tmp_path / "op"
|
|
fake_binary.write_bytes(b"")
|
|
with patch.object(op_cli.subprocess, "run") as mock_run:
|
|
mock_run.return_value = MagicMock(
|
|
returncode=0, stdout="2.24.0", stderr=""
|
|
)
|
|
op_cli._op_version(fake_binary)
|
|
_assert_utf8_kwargs(mock_run)
|