diff --git a/hooks/pre-commit-path-guard.py b/hooks/pre-commit-path-guard.py new file mode 100644 index 000000000..a56eca606 --- /dev/null +++ b/hooks/pre-commit-path-guard.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +""" +Pre-commit hook: Reject hardcoded home-directory paths. + +Scans staged Python files for patterns like: + - /Users//... + - /home//... + - ~/... (in string literals outside expanduser context) + +Escape hatch: add `# noqa: hardcoded-path-ok` to any legitimate line. + +Install: + cp hooks/pre-commit-path-guard.py .git/hooks/pre-commit + chmod +x .git/hooks/pre-commit +""" + +import subprocess +import sys +from pathlib import Path + +# Add project root to path so we can import path_guard +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) +from tools.path_guard import scan_file_for_violations + + +def get_staged_files(): + """Get list of staged .py files.""" + result = subprocess.run( + ["git", "diff", "--cached", "--name-only", "--diff-filter=ACM"], + capture_output=True, text=True + ) + return [f for f in result.stdout.strip().splitlines() if f.endswith(".py")] + + +def main(): + files = get_staged_files() + if not files: + sys.exit(0) + + all_violations = [] + for filepath in files: + if not Path(filepath).exists(): + continue + violations = scan_file_for_violations(filepath) + if violations: + all_violations.append((filepath, violations)) + + if all_violations: + print("\nāŒ HARDCODED PATH DETECTED — commit rejected") + print("=" * 60) + for filepath, violations in all_violations: + print(f"\n {filepath}:") + for lineno, line, pattern, suggestion in violations: + print(f" Line {lineno}: {line[:80]}") + print(f" Pattern: {pattern}") + print(f" Fix: {suggestion}") + print("\n" + "=" * 60) + print("Options:") + print(" 1. Use get_hermes_home(), os.environ['HOME'], or relative paths") + print(" 2. Add # noqa: hardcoded-path-ok to the line for legitimate cases") + print("") + sys.exit(1) + + sys.exit(0) + + +if __name__ == "__main__": + main()