369 lines
13 KiB
Python
369 lines
13 KiB
Python
"""Prove the exact loopback API listener inherited the pinned runtime contract.
|
|
|
|
The probe first resolves the unique PID that owns the exact
|
|
``127.0.0.1:<api-port>`` listening socket. It then inspects only that PID's
|
|
argv, cwd, upload receipt environment, and a secret-free database target
|
|
fingerprint. Process-wide scans and look-alike uvicorn commands are deliberately
|
|
not accepted as runtime identity proof.
|
|
|
|
Output is privacy-safe: no full environment or arbitrary command line is
|
|
emitted.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import ntpath
|
|
import re
|
|
from typing import Any, Iterable, Mapping, Sequence
|
|
|
|
|
|
LOOPBACK_ADDRESS = "127.0.0.1"
|
|
LOWER_SHA256 = re.compile(r"^[0-9a-f]{64}$")
|
|
RUNTIME_ENVIRONMENT_NAMES = (
|
|
"USER_UPLOAD_DIR",
|
|
"USER_UPLOAD_MANIFEST_REQUIRED",
|
|
"USER_UPLOAD_MANIFEST_PATH",
|
|
"USER_UPLOAD_MANIFEST_SHA256",
|
|
"USER_UPLOAD_WRITE_FREEZE_PATH",
|
|
"PUBLIC_RUNTIME_DB_TARGET_SHA256",
|
|
)
|
|
|
|
|
|
def _normalized_windows_path(value: str) -> str:
|
|
return ntpath.normcase(ntpath.normpath(value))
|
|
|
|
|
|
def _option_value(argv: Sequence[str], option: str) -> str | None:
|
|
"""Return an option's sole split-form value, or None when ambiguous."""
|
|
|
|
indexes = [index for index, value in enumerate(argv) if value == option]
|
|
if len(indexes) != 1:
|
|
return None
|
|
index = indexes[0]
|
|
if index + 1 >= len(argv):
|
|
return None
|
|
return argv[index + 1]
|
|
|
|
|
|
def _matches_public_api(argv: Sequence[str], api_port: int) -> bool:
|
|
values = [str(value) for value in argv]
|
|
return (
|
|
values.count("uvicorn") == 1
|
|
and values.count("app.main:app") == 1
|
|
and _option_value(values, "--host") == LOOPBACK_ADDRESS
|
|
and _option_value(values, "--port") == str(api_port)
|
|
and _option_value(values, "--workers") == "1"
|
|
)
|
|
|
|
|
|
def _snapshot_environment(snapshot: Mapping[str, Any]) -> Mapping[str, Any]:
|
|
environment = snapshot.get("environment")
|
|
if isinstance(environment, Mapping):
|
|
return environment
|
|
# Compatibility with the original pure-function fixtures. The live probe
|
|
# never relies on this flattened representation.
|
|
return {"USER_UPLOAD_DIR": snapshot.get("user_upload_root")}
|
|
|
|
|
|
def evaluate_listener_binding(
|
|
listener_pids: Iterable[int],
|
|
process_snapshots: Iterable[Mapping[str, Any]],
|
|
*,
|
|
expected_root: str,
|
|
expected_api_cwd: str,
|
|
expected_manifest_path: str,
|
|
expected_manifest_sha256: str,
|
|
expected_write_freeze_path: str,
|
|
expected_database_target_sha256: str,
|
|
api_port: int,
|
|
) -> tuple[int, dict[str, Any]]:
|
|
"""Evaluate snapshots only for the unique exact loopback listener PID."""
|
|
|
|
unique_listener_pids = sorted({int(pid) for pid in listener_pids})
|
|
if len(unique_listener_pids) != 1:
|
|
return 1, {
|
|
"status": "failed",
|
|
"reason": "api_listener_count_mismatch",
|
|
"listening_processes": len(unique_listener_pids),
|
|
}
|
|
|
|
listener_pid = unique_listener_pids[0]
|
|
listener_snapshots = [
|
|
snapshot
|
|
for snapshot in process_snapshots
|
|
if int(snapshot.get("pid", -1)) == listener_pid
|
|
]
|
|
if len(listener_snapshots) != 1:
|
|
return 1, {
|
|
"status": "failed",
|
|
"reason": "listener_process_unavailable",
|
|
"pid": listener_pid,
|
|
}
|
|
|
|
snapshot = listener_snapshots[0]
|
|
if not _matches_public_api(snapshot.get("argv") or [], api_port):
|
|
return 1, {
|
|
"status": "failed",
|
|
"reason": "listener_command_mismatch",
|
|
"pid": listener_pid,
|
|
}
|
|
|
|
actual_cwd = snapshot.get("cwd")
|
|
if not isinstance(actual_cwd, str) or not actual_cwd.strip():
|
|
return 1, {
|
|
"status": "failed",
|
|
"reason": "listener_cwd_missing",
|
|
"pid": listener_pid,
|
|
}
|
|
if _normalized_windows_path(actual_cwd) != _normalized_windows_path(
|
|
expected_api_cwd
|
|
):
|
|
return 1, {
|
|
"status": "failed",
|
|
"reason": "listener_cwd_drift",
|
|
"pid": listener_pid,
|
|
"expected_api_cwd": expected_api_cwd,
|
|
"actual_api_cwd": actual_cwd,
|
|
}
|
|
|
|
environment = _snapshot_environment(snapshot)
|
|
actual_root = environment.get("USER_UPLOAD_DIR")
|
|
if not isinstance(actual_root, str) or not actual_root.strip():
|
|
return 1, {
|
|
"status": "failed",
|
|
"reason": "user_upload_dir_missing",
|
|
"pid": listener_pid,
|
|
}
|
|
if _normalized_windows_path(actual_root) != _normalized_windows_path(expected_root):
|
|
return 1, {
|
|
"status": "failed",
|
|
"reason": "user_upload_dir_drift",
|
|
"pid": listener_pid,
|
|
"expected_root": expected_root,
|
|
"actual_root": actual_root,
|
|
}
|
|
|
|
if environment.get("USER_UPLOAD_MANIFEST_REQUIRED") != "true":
|
|
return 1, {
|
|
"status": "failed",
|
|
"reason": "upload_manifest_required_mismatch",
|
|
"pid": listener_pid,
|
|
}
|
|
|
|
actual_manifest_path = environment.get("USER_UPLOAD_MANIFEST_PATH")
|
|
if not isinstance(actual_manifest_path, str) or not actual_manifest_path.strip():
|
|
return 1, {
|
|
"status": "failed",
|
|
"reason": "upload_manifest_path_missing",
|
|
"pid": listener_pid,
|
|
}
|
|
if _normalized_windows_path(actual_manifest_path) != _normalized_windows_path(
|
|
expected_manifest_path
|
|
):
|
|
return 1, {
|
|
"status": "failed",
|
|
"reason": "upload_manifest_path_drift",
|
|
"pid": listener_pid,
|
|
}
|
|
|
|
actual_manifest_sha256 = environment.get("USER_UPLOAD_MANIFEST_SHA256")
|
|
if (
|
|
not isinstance(actual_manifest_sha256, str)
|
|
or LOWER_SHA256.fullmatch(actual_manifest_sha256) is None
|
|
or LOWER_SHA256.fullmatch(expected_manifest_sha256) is None
|
|
or actual_manifest_sha256 != expected_manifest_sha256
|
|
):
|
|
return 1, {
|
|
"status": "failed",
|
|
"reason": "upload_manifest_sha256_drift",
|
|
"pid": listener_pid,
|
|
}
|
|
|
|
actual_freeze_path = environment.get("USER_UPLOAD_WRITE_FREEZE_PATH")
|
|
if not isinstance(actual_freeze_path, str) or not actual_freeze_path.strip():
|
|
return 1, {
|
|
"status": "failed",
|
|
"reason": "upload_write_freeze_path_missing",
|
|
"pid": listener_pid,
|
|
}
|
|
if _normalized_windows_path(actual_freeze_path) != _normalized_windows_path(
|
|
expected_write_freeze_path
|
|
):
|
|
return 1, {
|
|
"status": "failed",
|
|
"reason": "upload_write_freeze_path_drift",
|
|
"pid": listener_pid,
|
|
}
|
|
|
|
actual_database_target_sha256 = environment.get("PUBLIC_RUNTIME_DB_TARGET_SHA256")
|
|
if (
|
|
not isinstance(actual_database_target_sha256, str)
|
|
or LOWER_SHA256.fullmatch(actual_database_target_sha256) is None
|
|
or LOWER_SHA256.fullmatch(expected_database_target_sha256) is None
|
|
or actual_database_target_sha256 != expected_database_target_sha256
|
|
):
|
|
return 1, {
|
|
"status": "failed",
|
|
"reason": "database_target_sha256_drift",
|
|
"pid": listener_pid,
|
|
}
|
|
|
|
return 0, {
|
|
"status": "passed",
|
|
"pid": listener_pid,
|
|
"user_upload_root": actual_root,
|
|
"api_cwd": actual_cwd,
|
|
"listener": f"{LOOPBACK_ADDRESS}:{api_port}",
|
|
"manifest_sha256": actual_manifest_sha256,
|
|
"database_target_sha256": actual_database_target_sha256,
|
|
}
|
|
|
|
|
|
def evaluate_snapshots(
|
|
snapshots: Iterable[Mapping[str, Any]],
|
|
*,
|
|
expected_root: str,
|
|
api_port: int,
|
|
) -> tuple[int, dict[str, Any]]:
|
|
"""Compatibility wrapper for legacy unit fixtures.
|
|
|
|
Live execution does not call this function. It preserves the historical
|
|
argv/root-only contract so older focused tests remain useful without
|
|
weakening listener-bound production proof.
|
|
"""
|
|
|
|
matches = [
|
|
snapshot
|
|
for snapshot in snapshots
|
|
if _matches_public_api(snapshot.get("argv") or [], api_port)
|
|
]
|
|
if len(matches) != 1:
|
|
return 1, {
|
|
"status": "failed",
|
|
"reason": "api_process_count_mismatch",
|
|
"matching_processes": len(matches),
|
|
}
|
|
|
|
match = matches[0]
|
|
actual_root = _snapshot_environment(match).get("USER_UPLOAD_DIR")
|
|
if not isinstance(actual_root, str) or not actual_root.strip():
|
|
return 1, {
|
|
"status": "failed",
|
|
"reason": "user_upload_dir_missing",
|
|
"pid": int(match["pid"]),
|
|
}
|
|
if _normalized_windows_path(actual_root) != _normalized_windows_path(expected_root):
|
|
return 1, {
|
|
"status": "failed",
|
|
"reason": "user_upload_dir_drift",
|
|
"pid": int(match["pid"]),
|
|
"expected_root": expected_root,
|
|
"actual_root": actual_root,
|
|
}
|
|
return 0, {
|
|
"status": "passed",
|
|
"pid": int(match["pid"]),
|
|
"user_upload_root": actual_root,
|
|
}
|
|
|
|
|
|
def _connection_address(connection: Any) -> tuple[str, int] | None:
|
|
address = connection.laddr
|
|
if not address:
|
|
return None
|
|
try:
|
|
return str(address.ip), int(address.port)
|
|
except AttributeError:
|
|
if len(address) < 2:
|
|
return None
|
|
return str(address[0]), int(address[1])
|
|
|
|
|
|
def _collect_listener_pids(api_port: int) -> list[int]:
|
|
import psutil
|
|
|
|
listener_pids: set[int] = set()
|
|
for connection in psutil.net_connections(kind="tcp"):
|
|
if connection.status != psutil.CONN_LISTEN or connection.pid is None:
|
|
continue
|
|
address = _connection_address(connection)
|
|
if address == (LOOPBACK_ADDRESS, api_port):
|
|
listener_pids.add(int(connection.pid))
|
|
return sorted(listener_pids)
|
|
|
|
|
|
def _collect_process_snapshots(listener_pids: Iterable[int]) -> list[dict[str, Any]]:
|
|
import psutil
|
|
|
|
snapshots: list[dict[str, Any]] = []
|
|
for pid in sorted({int(value) for value in listener_pids}):
|
|
try:
|
|
process = psutil.Process(pid)
|
|
argv = list(process.cmdline())
|
|
cwd = process.cwd()
|
|
environment = process.environ()
|
|
except (psutil.AccessDenied, psutil.NoSuchProcess, psutil.ZombieProcess):
|
|
continue
|
|
snapshots.append(
|
|
{
|
|
"pid": pid,
|
|
"argv": argv,
|
|
"cwd": cwd,
|
|
# Never retain unrelated process secrets (including DATABASE_URL)
|
|
# in the snapshot or result payload.
|
|
"environment": {
|
|
name: environment.get(name) for name in RUNTIME_ENVIRONMENT_NAMES
|
|
},
|
|
}
|
|
)
|
|
return snapshots
|
|
|
|
|
|
def _failure(reason: str) -> tuple[int, dict[str, Any]]:
|
|
return 1, {"status": "failed", "reason": reason}
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--expected-root", required=True)
|
|
parser.add_argument("--expected-api-cwd", required=True)
|
|
parser.add_argument("--expected-manifest-path", required=True)
|
|
parser.add_argument("--expected-manifest-sha256", required=True)
|
|
parser.add_argument("--expected-write-freeze-path", required=True)
|
|
parser.add_argument("--expected-database-target-sha256", required=True)
|
|
parser.add_argument("--api-port", type=int, required=True)
|
|
args = parser.parse_args()
|
|
|
|
try:
|
|
listener_pids = _collect_listener_pids(args.api_port)
|
|
snapshots = _collect_process_snapshots(listener_pids)
|
|
# Close the process-exit/PID-reuse race: the same sole PID must still
|
|
# own the socket after its identity was inspected.
|
|
listener_pids_after = _collect_listener_pids(args.api_port)
|
|
if listener_pids_after != listener_pids:
|
|
exit_code, payload = _failure("api_listener_changed_during_probe")
|
|
else:
|
|
exit_code, payload = evaluate_listener_binding(
|
|
listener_pids,
|
|
snapshots,
|
|
expected_root=args.expected_root,
|
|
expected_api_cwd=args.expected_api_cwd,
|
|
expected_manifest_path=args.expected_manifest_path,
|
|
expected_manifest_sha256=args.expected_manifest_sha256,
|
|
expected_write_freeze_path=args.expected_write_freeze_path,
|
|
expected_database_target_sha256=(args.expected_database_target_sha256),
|
|
api_port=args.api_port,
|
|
)
|
|
except Exception:
|
|
# psutil permission/platform failures are proof failures. Avoid
|
|
# printing exception strings because they can contain process details.
|
|
exit_code, payload = _failure("listener_inspection_failed")
|
|
|
|
print(json.dumps(payload, ensure_ascii=True, separators=(",", ":")))
|
|
return exit_code
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|