From 0d0e5780c843bdba26423f817f9eb9a22faf5898 Mon Sep 17 00:00:00 2001 From: safishamsi Date: Sat, 11 Jul 2026 16:31:10 +0100 Subject: [PATCH] test(cli): graph.json node ids are portable across checkout paths (#1789) The absolute-path-in-node-ids leak reported on 0.8.19 is already fixed on v8: detect() returns paths relative to the scan root, so the CLI-produced graph.json uses relative structural node ids (portable, no username/home leak). Lock it with a regression test that extracts the same corpus from two different absolute checkout dirs and asserts identical, leak-free node ids. Co-Authored-By: Claude Opus 4.8 (1M context) --- tests/test_cli_export.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/test_cli_export.py b/tests/test_cli_export.py index d25808205..6173a61aa 100644 --- a/tests/test_cli_export.py +++ b/tests/test_cli_export.py @@ -520,3 +520,24 @@ def test_export_html_no_community_data_at_all_still_succeeds(tmp_path): # code stays clean — same behaviour as the pre-fallback empty-communities # path, just no longer silently failing on the common case. assert r.returncode == 0, r.stderr + + +def test_graph_json_node_ids_are_portable_across_checkout_paths(tmp_path): + """#1789: the committed graph.json's node ids must be relative to the scan + root — not embed the absolute path — so the same repo yields identical ids + on any machine/checkout and leaks no local username/home.""" + def _build(root: Path): + (root / "pkg").mkdir(parents=True) + (root / "pkg" / "mod.py").write_text("def f(): return 1\n") + (root / "pkg" / "app.py").write_text("from pkg.mod import f\ndef g(): return f()\n") + r = _run(["extract", ".", "--code-only", "--no-cluster"], root) + assert r.returncode == 0, r.stderr + data = json.loads((root / "graphify-out" / "graph.json").read_text()) + return sorted(n["id"] for n in data["nodes"]) + + a = _build(tmp_path / "alice_home" / "proj") + b = _build(tmp_path / "bob_elsewhere" / "checkout" / "proj") + assert a == b, f"node ids differ across checkout paths: {a} vs {b}" + leak = {"alice_home", "bob_elsewhere", "checkout", "tmp", "private", "users", "home", "var"} + assert not any(part in leak for ident in a for part in ident.split("_")), \ + f"node id embeds an absolute-path component: {a}"