b4fbd6fe9f
Deploy Site / deploy-vercel (push) Has been skipped
Deploy Site / deploy-docs (push) Has been skipped
Build Skills Index / build-index (push) Has been skipped
CI / Deny unrelated histories (push) Has been skipped
CI / Detect affected areas (push) Successful in 27m35s
CI / OSV scan (push) Failing after 4s
CI / Build&Test Docker image (push) Successful in 9s
CI / Supply-chain scan (push) Has been skipped
CI / Lint Docker scripts (push) Failing after 5m13s
CI / Check contributors (push) Failing after 12m8s
CI / Docs Site (push) Failing after 12m8s
CI / TypeScript (push) Failing after 12m8s
CI / Python lints (push) Failing after 12m9s
CI / Python tests (push) Failing after 12m9s
CI / Check uv.lock (push) Failing after 23m22s
CI / CI timing report (push) Has been cancelled
Build Skills Index / trigger-deploy (push) Has been cancelled
CI / All required checks pass (push) Has been cancelled
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"
|
|
)
|