bind.py python
59 lines 1.8 KB
Raw
sha256:0e9549ec7b463911bc08b7d586dc320b1ac9b1f5c943ee7e3865dcc6cb0f6f83 chore(governance): sync handover+roadmap to 84db8c8 (drift:… Human 12 hours ago
1 """Bind + port policy for hosted-dashboard preview (§HGD.6.4, §HGD.10.1)."""
2
3 from __future__ import annotations
4
5 import ipaddress
6 import socket
7
8 DEFAULT_PORT = 8766
9 LOOPBACK_LITERALS = frozenset({"127.0.0.1", "localhost", "::1"})
10
11
12 def normalize_bind_address(bind: str) -> str:
13 """Normalize bind literal for ``HTTPServer``."""
14 text = bind.strip()
15 if text == "localhost":
16 return "127.0.0.1"
17 return text
18
19
20 def is_loopback_bind(bind: str) -> bool:
21 """Return whether ``bind`` is a loopback literal."""
22 return bind.strip() in LOOPBACK_LITERALS
23
24
25 def validate_bind_address(bind: str, *, allow_non_loopback: bool) -> str | None:
26 """Return normalized bind address, or ``None`` when refused.
27
28 Non-loopback binds require ``allow_non_loopback=True`` (config + auth/TLS rules).
29 """
30 text = bind.strip()
31 if text in LOOPBACK_LITERALS:
32 return normalize_bind_address(text)
33 if not allow_non_loopback:
34 return None
35 # Refuse wildcard-ish and empty; allow concrete operator hosts when opted in.
36 if not text or text in {"*", ""}:
37 return None
38 return text
39
40
41 def is_loopback_peer(host: str) -> bool:
42 """Return whether ``host`` is a loopback peer address."""
43 try:
44 return ipaddress.ip_address(host).is_loopback
45 except ValueError:
46 return False
47
48
49 def port_is_available(bind: str, port: int) -> bool:
50 """Return whether ``port`` can be bound on ``bind``."""
51 family = socket.AF_INET6 if bind == "::1" else socket.AF_INET
52 probe_host = bind if bind != "127.0.0.1" else "127.0.0.1"
53 with socket.socket(family, socket.SOCK_STREAM) as sock:
54 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
55 try:
56 sock.bind((probe_host, port))
57 except OSError:
58 return False
59 return True
File History 1 commit
sha256:6abcf1fa82a7a621ccbc945f19acdba5bc0db54569599404a1452fb4a096a199 fix(ISR): default require_independent_second_reviewer to require Human minor 11 hours ago