validators.py file-level

at main · View file ↗ · Intel ↗

History
1 files
1 commits
0 hotspots
0 🧊 dead
0 💥 blast risk
sha256:6 fix(ISR): default require_independent_second_reviewer to require Opera… · aaronrene · Sep 2, 2026
1 """Owner/repo/path validators and allowlist helpers (§HGD.4.2, §HGD.5.3)."""
2
3 from __future__ import annotations
4
5 import re
6
7 OWNER_REPO_SEGMENT_RE = re.compile(r"^[A-Za-z0-9._-]+$")
8 ALLOWLIST_ENTRY_RE = re.compile(r"^[A-Za-z0-9._-]+(?:/[A-Za-z0-9._-]+)?$")
9
10 DEFAULT_ORG_ENUMERATION_CAP = 100
11 DEFAULT_ROADMAP_PATH = "docs/ROADMAP.md"
12 DEFAULT_HANDOVER_PATH = "docs/OVERSEER-HANDOVER.md"
13 MARKER_PATH = ".overseer/config.yaml"
14
15
16 def valid_owner_repo_segment(value: str) -> bool:
17 """Return whether ``value`` matches the frozen owner/repo segment pattern."""
18 return bool(value) and bool(OWNER_REPO_SEGMENT_RE.match(value))
19
20
21 def parse_allowlist_entry(entry: str) -> tuple[str, str | None]:
22 """Parse an allowlist entry into ``(owner, repo_or_None)``.
23
24 Raises ``ValueError`` when the entry does not match the frozen shape.
25 """
26 if not isinstance(entry, str) or not entry.strip():
27 raise ValueError("empty allowlist entry")
28 text = entry.strip()
29 if not ALLOWLIST_ENTRY_RE.match(text):
30 raise ValueError(f"invalid allowlist entry: {entry!r}")
31 if "/" in text:
32 owner, repo = text.split("/", 1)
33 return owner, repo
34 return text, None
35
36
37 def validate_allowlist(entries: list[str]) -> list[tuple[str, str | None]]:
38 """Validate and return normalized allowlist pairs."""
39 return [parse_allowlist_entry(e) for e in entries]
40
41
42 def unknown_query_keys(query: dict[str, list[str]], *, allowed: frozenset[str] = frozenset()) -> list[str]:
43 """Return query keys not in ``allowed`` (empty allowed → any key is unknown)."""
44 return sorted(k for k in query if k not in allowed)