Merge pull request #14 from o3LL/fix/proc-guard-private-browser

fix(browser): skip the Chrome sweep when the host has no procfs
This commit is contained in:
Alexandre Teixeira
2026-09-29 14:54:00 +01:00
committed by GitHub
2 changed files with 57 additions and 1 deletions
+13 -1
View File
@@ -119,6 +119,12 @@ def _browser_pid_file_candidates(
)
return list(dict.fromkeys(candidates))
# Linux exposes one command line per pid under /proc; macOS and Windows do not.
# Kept as a module attribute so the procfs-dependent paths stay testable on a
# host that has no procfs, and on one that does.
_PROC_ROOT = Path("/proc")
_SCHOLARLY_METADATA_CUE_RE = re.compile(
r"\b(?:accept(?:ed|ance)?|publish(?:ed|ing|cation)?|venue|conference|"
r"journal|proceedings|doi)\b",
@@ -2316,8 +2322,14 @@ class PrivateBrowserTool:
except OSError:
return
profile_prefix = str(tmpdir / "agent-browser-chrome-")
if not _PROC_ROOT.is_dir():
# Without procfs there is no way to match a reparented Chrome by
# its command line, and the sweep is an optimisation rather than a
# correctness requirement. Leave those trees to the daemon's own
# lifecycle instead of failing the whole shutdown path.
return
pids: list[int] = []
for entry in Path("/proc").iterdir():
for entry in _PROC_ROOT.iterdir():
if not entry.name.isdigit():
continue
try:
+44
View File
@@ -1801,3 +1801,47 @@ def test_generic_go_to_phrase_is_browser_interaction() -> None:
assert not _looks_like_explicit_browser_interaction(
"Find rules for getting rid of garbage in Setagaya-ku."
)
def test_terminate_owned_chrome_skips_the_sweep_without_procfs(
monkeypatch, tmp_path
) -> None:
"""macOS and Windows have no /proc; shutdown must degrade, not raise."""
missing = tmp_path / "no-procfs"
monkeypatch.setattr(web_tools, "_PROC_ROOT", missing)
def _unexpected_iterdir(*args, **kwargs):
raise AssertionError("the pid sweep must not run without procfs")
monkeypatch.setattr(Path, "iterdir", _unexpected_iterdir)
PrivateBrowserTool._terminate_owned_chrome({"TMPDIR": str(tmp_path)})
def test_terminate_owned_chrome_kills_only_this_runtimes_profile(
monkeypatch, tmp_path
) -> None:
"""With procfs present, match on the runtime-owned profile prefix alone."""
proc = tmp_path / "proc"
tmpdir = tmp_path / "runtime-tmp"
tmpdir.mkdir()
profile_prefix = str(tmpdir.resolve() / "agent-browser-chrome-")
def _write_pid(pid: str, cmdline: str) -> None:
entry = proc / pid
entry.mkdir(parents=True)
(entry / "cmdline").write_bytes(cmdline.replace(" ", "\0").encode())
_write_pid("101", f"chrome --user-data-dir={profile_prefix}abc")
_write_pid("202", "chrome --user-data-dir=/Users/someone/Library/Chrome")
(proc / "self").mkdir()
monkeypatch.setattr(web_tools, "_PROC_ROOT", proc)
killed: list[int] = []
monkeypatch.setattr(web_tools.os, "kill", lambda pid, sig: killed.append(pid))
PrivateBrowserTool._terminate_owned_chrome({"TMPDIR": str(tmpdir)})
assert killed == [101]