-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcheck_hardcoded_paths.py
More file actions
110 lines (92 loc) · 3.18 KB
/
Copy pathcheck_hardcoded_paths.py
File metadata and controls
110 lines (92 loc) · 3.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#!/usr/bin/env python3
"""Fail CI when new hardcoded machine-local paths appear in portable shell entrypoints."""
from __future__ import annotations
import argparse
import fnmatch
import re
import sys
from pathlib import Path
DEFAULT_GLOBS = [
"scripts/run_*.sh",
"scripts/launch_*.sh",
"scripts/queue_*.sh",
"scripts/resume_*.sh",
"scripts/ops/*.sh",
]
PATTERNS = [
(
"hardcoded_repo_root",
re.compile(r"/home/kmccleary/network_project/(?:mamba_network_intrusion|tracer_ids)"),
),
(
"hardcoded_data_root_assignment",
re.compile(r"=\s*[\"']/mnt/drive_3/network_anomaly_datasets(?:[\"']|/)"),
),
("hardcoded_conda_source", re.compile(r"\bsource\s+/usr/bin/miniconda3/etc/profile\.d/conda\.sh\b")),
("hardcoded_conda_env", re.compile(r"\bconda\s+activate\s+NP_6\b")),
]
def _load_allowlist(path: Path) -> list[str]:
if not path.exists():
return []
items = []
for raw in path.read_text(encoding="utf-8").splitlines():
line = raw.strip()
if not line or line.startswith("#"):
continue
items.append(line)
return items
def _is_ignored(rel_path: str, allowlist: list[str]) -> bool:
return any(fnmatch.fnmatch(rel_path, pat) for pat in allowlist)
def _iter_files(repo_root: Path, globs: list[str]):
seen: set[Path] = set()
for pattern in globs:
for path in sorted(repo_root.glob(pattern)):
if not path.is_file():
continue
if path in seen:
continue
seen.add(path)
yield path
def main() -> int:
parser = argparse.ArgumentParser(description="Guard against hardcoded local paths in portable scripts.")
parser.add_argument(
"--repo-root",
default=".",
help="Repository root to scan (default: .)",
)
parser.add_argument(
"--allowlist",
default="scripts/ci/hardcoded_path_allowlist.txt",
help="Path-glob allowlist file (default: scripts/ci/hardcoded_path_allowlist.txt)",
)
parser.add_argument(
"--glob",
action="append",
default=[],
help="Additional glob(s) to scan (repeatable).",
)
args = parser.parse_args()
repo_root = Path(args.repo_root).resolve()
allowlist = _load_allowlist((repo_root / args.allowlist).resolve())
globs = list(DEFAULT_GLOBS)
if args.glob:
globs.extend(args.glob)
violations = []
for path in _iter_files(repo_root, globs):
rel = str(path.relative_to(repo_root))
if _is_ignored(rel, allowlist):
continue
text = path.read_text(encoding="utf-8", errors="replace")
for lineno, line in enumerate(text.splitlines(), start=1):
for tag, pattern in PATTERNS:
if pattern.search(line):
violations.append((rel, lineno, tag, line.strip()))
if not violations:
print("[hardcoded-path-guard] OK: no violations")
return 0
print(f"[hardcoded-path-guard] FAIL: {len(violations)} violation(s)")
for rel, lineno, tag, line in violations:
print(f" - {rel}:{lineno} [{tag}] {line}")
return 1
if __name__ == "__main__":
sys.exit(main())