d68d2716a7
Delegate to hermes_bootstrap.harden_import_path() instead of the inline '', '.' sys.path filter, matching entry.py/acp_adapter/entry.py after #51693. The shared helper also relocates the Hermes source root ahead of an absolute cwd path on sys.path (venv/PYTHONPATH case), which the inline filter missed. Test static check rewritten to assert the shared guard runs before import cli.
93 lines
3.8 KiB
Python
93 lines
3.8 KiB
Python
"""Regression tests for tui_gateway/slash_worker.py sys.path hardening (issue #51286).
|
|
|
|
The slash-command worker is spawned as ``-m tui_gateway.slash_worker`` and
|
|
inherits the user's CWD. A local package (e.g. ``utils/``) in that CWD shadows
|
|
the installed hermes ``utils`` module and crashes the worker on ``import cli``
|
|
(``ImportError: cannot import name 'atomic_replace' from 'utils'``).
|
|
|
|
#51693 added this guard to the sibling entrypoints ``tui_gateway/entry.py`` and
|
|
``acp_adapter/entry.py`` (via the shared ``hermes_bootstrap.harden_import_path``
|
|
helper) but missed this child, so the crash still reproduced. slash_worker.py
|
|
must run the guard before its first non-stdlib import.
|
|
"""
|
|
|
|
import ast
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
|
|
|
|
|
def test_slash_worker_imports_from_cwd_with_colliding_utils(tmp_path):
|
|
"""Importing the worker from a CWD that ships its own ``utils/`` package
|
|
must succeed — the guard strips CWD so the installed module wins."""
|
|
# Mimic the user's project (tg-ws-proxy ships utils/, proxy/, ui/).
|
|
for pkg in ("utils", "proxy", "ui"):
|
|
(tmp_path / pkg).mkdir()
|
|
(tmp_path / pkg / "__init__.py").write_text("") # no atomic_replace, etc.
|
|
|
|
env = {k: v for k, v in os.environ.items() if k != "HERMES_PYTHON_SRC_ROOT"}
|
|
# Keep the source importable via PYTHONPATH; CWD ('') still precedes it on
|
|
# sys.path for ``-c``, so the shadow (and thus the guard) is still exercised.
|
|
env["PYTHONPATH"] = str(PROJECT_ROOT)
|
|
|
|
result = subprocess.run(
|
|
[sys.executable, "-c", "import tui_gateway.slash_worker"],
|
|
cwd=tmp_path,
|
|
env=env,
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=120,
|
|
)
|
|
|
|
assert result.returncode == 0, (
|
|
"slash_worker failed to import from a CWD containing a colliding "
|
|
"utils/ package — sys.path guard regressed (issue #51286).\n"
|
|
f"stderr:\n{result.stderr}"
|
|
)
|
|
|
|
|
|
def test_sys_path_guard_runs_before_cli_import():
|
|
"""The guard must execute before ``import cli`` — reordering it below the
|
|
import would re-introduce the shadowing crash. Assert via AST that the
|
|
``hermes_bootstrap.harden_import_path()`` call precedes ``import cli``."""
|
|
src = (PROJECT_ROOT / "tui_gateway" / "slash_worker.py").read_text()
|
|
tree = ast.parse(src)
|
|
|
|
harden_call_line = None
|
|
cli_import_line = None
|
|
for node in ast.walk(tree):
|
|
if (
|
|
isinstance(node, ast.Call)
|
|
and isinstance(node.func, ast.Attribute)
|
|
and node.func.attr == "harden_import_path"
|
|
):
|
|
if harden_call_line is None:
|
|
harden_call_line = node.lineno
|
|
if isinstance(node, ast.Import) and any(a.name == "cli" for a in node.names):
|
|
if cli_import_line is None:
|
|
cli_import_line = node.lineno
|
|
|
|
assert harden_call_line is not None, (
|
|
"slash_worker.py must call hermes_bootstrap.harden_import_path()"
|
|
)
|
|
assert cli_import_line is not None, "slash_worker.py must 'import cli'"
|
|
assert harden_call_line < cli_import_line, (
|
|
"harden_import_path() must run before 'import cli' (issue #51286)"
|
|
)
|
|
|
|
|
|
def test_guard_delegates_to_shared_helper_not_inline():
|
|
"""slash_worker should delegate to the shared guard, not re-implement the
|
|
old inline ``{"", "."}`` sys.path filter that #51693 replaced."""
|
|
src = (PROJECT_ROOT / "tui_gateway" / "slash_worker.py").read_text()
|
|
assert '{"", "."}' not in src and "{'', '.'}" not in src, (
|
|
"slash_worker.py should delegate to hermes_bootstrap.harden_import_path, "
|
|
"not re-implement the guard inline"
|
|
)
|
|
assert "hermes_bootstrap.harden_import_path()" in src, (
|
|
"slash_worker.py must call the shared hermes_bootstrap.harden_import_path guard"
|
|
)
|