From 6175e0a8ea614f21597f1f4c9955c223c9ce31af Mon Sep 17 00:00:00 2001 From: Safi Date: Mon, 27 Apr 2026 21:27:26 +0100 Subject: [PATCH] fix #547 #559 #570: expand ~ in hooksPath, fix gitignore inline comments, nosec on write sinks --- README.md | 12 +++++++++--- graphify/export.py | 14 +++++++------- graphify/hooks.py | 2 +- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 22601278..3f966368 100644 --- a/README.md +++ b/README.md @@ -176,9 +176,15 @@ Think of it this way: the always-on hook gives your assistant a map. The `/graph **Recommended `.gitignore` additions:** ``` # keep graph outputs, skip heavy/local-only files -graphify-out/cache/ # optional: commit for shared extraction speed, skip to keep repo small -graphify-out/manifest.json # mtime-based, invalid after git clone — always gitignore this -graphify-out/cost.json # local token tracking, not useful to share + +# optional: commit for shared extraction speed, skip to keep repo small +graphify-out/cache/ + +# mtime-based, invalid after git clone - always gitignore this +graphify-out/manifest.json + +# local token tracking, not useful to share +graphify-out/cost.json ``` **Shared setup:** diff --git a/graphify/export.py b/graphify/export.py index 6eb4e0d5..1decae29 100644 --- a/graphify/export.py +++ b/graphify/export.py @@ -313,7 +313,7 @@ def to_json(G: nx.Graph, communities: dict[int, list[str]], output_path: str, *, conf = link.get("confidence", "EXTRACTED") link["confidence_score"] = _CONFIDENCE_SCORE_DEFAULTS.get(conf, 1.0) data["hyperedges"] = getattr(G, "graph", {}).get("hyperedges", []) - with open(output_path, "w", encoding="utf-8") as f: + with open(output_path, "w", encoding="utf-8") as f: # nosec json.dump(data, f, indent=2) @@ -355,7 +355,7 @@ def to_cypher(G: nx.Graph, output_path: str) -> None: f"MATCH (a {{id: '{u_esc}'}}), (b {{id: '{v_esc}'}}) " f"MERGE (a)-[:{rel} {{confidence: '{conf}'}}]->(b);" ) - with open(output_path, "w", encoding="utf-8") as f: + with open(output_path, "w", encoding="utf-8") as f: # nosec f.write("\n".join(lines)) @@ -480,7 +480,7 @@ def to_html( """ - Path(output_path).write_text(html, encoding="utf-8") + Path(output_path).write_text(html, encoding="utf-8") # nosec # Keep backward-compatible alias - skill.md calls generate_html @@ -595,7 +595,7 @@ def to_obsidian( lines.append(inline_tags) fname = node_filename[node_id] + ".md" - (out / fname).write_text("\n".join(lines), encoding="utf-8") + (out / fname).write_text("\n".join(lines), encoding="utf-8") # nosec # Write one _COMMUNITY_name.md overview note per community # Build inter-community edge counts for "Connections to other communities" @@ -712,7 +712,7 @@ def to_obsidian( community_safe = safe_name(community_name) fname = f"_COMMUNITY_{community_safe}.md" - (out / fname).write_text("\n".join(lines), encoding="utf-8") + (out / fname).write_text("\n".join(lines), encoding="utf-8") # nosec community_notes_written += 1 # Improvement 4: write .obsidian/graph.json to color nodes by community in graph view @@ -727,7 +727,7 @@ def to_obsidian( for cid, label in sorted((community_labels or {}).items()) ] } - (obsidian_dir / "graph.json").write_text(json.dumps(graph_config, indent=2), encoding="utf-8") + (obsidian_dir / "graph.json").write_text(json.dumps(graph_config, indent=2), encoding="utf-8") # nosec return G.number_of_nodes() + community_notes_written @@ -888,7 +888,7 @@ def to_canvas( }) canvas_data = {"nodes": canvas_nodes, "edges": canvas_edges} - Path(output_path).write_text(json.dumps(canvas_data, indent=2), encoding="utf-8") + Path(output_path).write_text(json.dumps(canvas_data, indent=2), encoding="utf-8") # nosec def push_to_neo4j( diff --git a/graphify/hooks.py b/graphify/hooks.py index 3fa7d2e5..e921155b 100644 --- a/graphify/hooks.py +++ b/graphify/hooks.py @@ -145,7 +145,7 @@ def _hooks_dir(root: Path) -> Path: if result.returncode == 0: custom = result.stdout.strip() if custom: - p = Path(custom) + p = Path(custom).expanduser() if not p.is_absolute(): p = root / p p.mkdir(parents=True, exist_ok=True)