From 04d5633745e99ee8c50961c1a30fca3cf8b93b52 Mon Sep 17 00:00:00 2001 From: dev-lead Date: Fri, 8 May 2026 14:08:59 -0700 Subject: [PATCH] test(kanban-ws-auth): patch hermes_cli.web_server attribute alongside sys.modules entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `monkeypatch.setitem(sys.modules, "hermes_cli.web_server", stub)` alone is not enough when another test in the same xdist worker has already imported `hermes_cli.web_server`: the parent package `hermes_cli` then has the real submodule bound as an attribute, and `from hermes_cli import web_server` resolves through the attribute path, not through sys.modules. Result: `_check_ws_token` reads the REAL `_SESSION_TOKEN` (a fresh random value), the test's "secret-xyz" never matches, and the third with-block (correct token → accepted) hits a 1008 disconnect instead of a clean handshake. Test was order-dependent — passed in isolation, failed in full-suite runs where another test loaded the real web_server first. Per `feedback_no_such_thing_as_flakes`, this is a real test-isolation bug, not a flake. Fix: also `monkeypatch.setattr(hermes_cli, "web_server", stub, raising=False)` so both lookup paths see the stub. Inline comment documents the gotcha for the next reader. Co-Authored-By: Claude Opus 4.7 (1M context) --- tests/plugins/test_kanban_dashboard_plugin.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/plugins/test_kanban_dashboard_plugin.py b/tests/plugins/test_kanban_dashboard_plugin.py index 4bbc621f..08452265 100644 --- a/tests/plugins/test_kanban_dashboard_plugin.py +++ b/tests/plugins/test_kanban_dashboard_plugin.py @@ -478,9 +478,19 @@ def test_ws_events_rejects_when_token_required(tmp_path, monkeypatch): kb.init_db() # Stub web_server so _check_ws_token has a token to compare against. + # NOTE: monkeypatch.setitem(sys.modules, ...) alone is not enough. + # If another test in the same xdist worker has already imported + # hermes_cli.web_server, the parent package `hermes_cli` has the real + # module bound as an attribute. `from hermes_cli import web_server` + # then resolves via the attribute, NOT sys.modules — so the stub is + # bypassed and _check_ws_token compares against the real (random) + # _SESSION_TOKEN, rejecting our "secret-xyz" branch with 1008. + # Patching the parent package attribute keeps both lookup paths in sync. import types + import hermes_cli stub = types.SimpleNamespace(_SESSION_TOKEN="secret-xyz") monkeypatch.setitem(sys.modules, "hermes_cli.web_server", stub) + monkeypatch.setattr(hermes_cli, "web_server", stub, raising=False) app = FastAPI() app.include_router(_load_plugin_router(), prefix="/api/plugins/kanban")