cmux/tests/test_sidebar_invalid_panel.py
Lawrence Chen 7e69751e1b
Sidebar metadata + tagged reload isolation (#16)
* Sidebar primitives + tagged dev isolation

* Allow wider sidebar resize

* Fix tagged socket selection + panel id errors

* Fix progress label quoting + bundle suffix sanitize

* Skip ctrl-enter keybind test when keystrokes blocked

* Fix shell nc hang + prune stale per-surface sidebar metadata
2026-02-06 18:09:56 -08:00

127 lines
4 KiB
Python

#!/usr/bin/env python3
"""
Regression: report_ports/report_pwd must validate panel IDs.
If shell-integration hooks fire late (after a split is closed) they can report
ports/cwd for a stale surface UUID. These updates should not pollute the sidebar
state (stale ports/cwd).
Run with a tagged instance to avoid unix socket conflicts:
CMUX_TAG=<tag> python3 tests/test_sidebar_invalid_panel.py
"""
from __future__ import annotations
import os
import random
import subprocess
import sys
import time
import uuid
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from cmux import cmux, cmuxError # noqa: E402
def _parse_sidebar_state(text: str) -> dict[str, str]:
data: dict[str, str] = {}
for raw in (text or "").splitlines():
line = raw.rstrip("\n")
if not line or line.startswith(" "):
continue
if "=" not in line:
continue
k, v = line.split("=", 1)
data[k.strip()] = v.strip()
return data
def _parse_ports(raw: str) -> set[int]:
raw = (raw or "").strip()
if not raw or raw == "none":
return set()
ports: set[int] = set()
for item in raw.split(","):
item = item.strip()
if not item:
continue
try:
ports.add(int(item))
except ValueError:
continue
return ports
def _pick_absent_port(exclude: set[int]) -> int:
# Pick a random port that isn't already showing and also isn't currently
# listening machine-wide (avoid false failures if something is bound).
for _ in range(200):
port = random.randint(20000, 65000)
if port in exclude:
continue
result = subprocess.run(
["lsof", "-nP", f"-iTCP:{port}", "-sTCP:LISTEN", "-t"],
capture_output=True,
text=True,
)
if result.returncode != 0 and not (result.stdout or "").strip():
return port
# Fall back to a fixed high port; still validate against exclude.
for port in (54321, 54322, 54323, 61999):
if port not in exclude:
return port
return 65000
def main() -> int:
try:
with cmux() as client:
tab_id = client.new_tab()
client.select_tab(tab_id)
time.sleep(0.8)
initial_state = client.sidebar_state(tab_id)
initial_ports = _parse_ports(_parse_sidebar_state(initial_state).get("ports", ""))
test_port = _pick_absent_port(initial_ports)
surface_ids = {surface_id for _, surface_id, _ in client.list_surfaces(tab_id)}
fake_panel = uuid.uuid4()
while str(fake_panel) in surface_ids:
fake_panel = uuid.uuid4()
# Ports: reporting against a bogus panel must not update the union.
client._send_command(f"report_ports {test_port} --tab={tab_id} --panel={fake_panel}")
time.sleep(0.3)
state = client.sidebar_state(tab_id)
ports = _parse_ports(_parse_sidebar_state(state).get("ports", ""))
if test_port in ports:
print(f"FAIL: invalid panel report_ports leaked into sidebar ports: {ports}")
return 1
# CWD: reporting against a bogus panel must not set cwd to that value.
unique_dir = f"/tmp/cmux_invalid_pwd_{os.getpid()}"
client._send_command(f"report_pwd {unique_dir} --tab={tab_id} --panel={fake_panel}")
time.sleep(0.3)
state = client.sidebar_state(tab_id)
if unique_dir in state:
print("FAIL: invalid panel report_pwd leaked into sidebar_state")
print(state)
return 1
try:
client.close_tab(tab_id)
except cmuxError:
pass
print("PASS: invalid panel reports do not pollute sidebar metadata")
return 0
except (cmuxError, RuntimeError, ValueError) as e:
print(f"FAIL: {e}")
return 1
if __name__ == "__main__":
raise SystemExit(main())