#!/usr/bin/env python3 """Serve one Hermes tenant's generated media to the Telegram router.""" from __future__ import annotations import hmac import mimetypes import os from pathlib import Path, PurePosixPath import posixpath import shutil import stat from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from urllib.parse import parse_qs, urlsplit ALLOWED_ROOTS = (Path("/opt/data/cache/images"), Path("/opt/data/workspace")) MAX_MEDIA_BYTES = 50 << 20 class MediaPathError(ValueError): """Raised when a requested path violates the tenant media boundary.""" def read_relay_key(path: Path) -> str: """Read the shared relay key from one runtime-only secret file.""" value = path.read_text(encoding="utf-8").strip() if not value: raise RuntimeError("tenant relay key is unavailable") return value def tenant_slot(pod_name: str) -> str: """Extract the StatefulSet ordinal used to bind requests to this tenant.""" prefix, separator, ordinal = pod_name.rpartition("-") if not separator or not prefix or not ordinal.isdigit(): raise RuntimeError("tenant pod name has no ordinal") return ordinal def normalize_media_path(raw_path: str, allowed_roots: tuple[Path, ...] = ALLOWED_ROOTS) -> tuple[Path, tuple[str, ...]]: """Return an allowed root and clean relative components for an absolute path.""" value = str(raw_path or "").strip() if not value or "\x00" in value or "\\" in value or not value.startswith("/"): raise MediaPathError("invalid media path") original = PurePosixPath(value) if ".." in original.parts: raise MediaPathError("parent traversal is not allowed") cleaned = PurePosixPath(posixpath.normpath(value)) for root in allowed_roots: logical_root = PurePosixPath(root.as_posix()) try: relative = cleaned.relative_to(logical_root) except ValueError: continue components = tuple(part for part in relative.parts if part not in {"", "."}) if not components: raise MediaPathError("media path must name a file") return root, components raise MediaPathError("media path is outside allowed roots") def open_directory_without_symlinks(path: Path) -> int: """Open every component of an absolute directory path with O_NOFOLLOW.""" if not path.is_absolute() or ".." in path.parts: raise MediaPathError("invalid media root") flags = os.O_RDONLY | os.O_DIRECTORY | os.O_CLOEXEC | os.O_NOFOLLOW directory_fd = os.open("/", flags) try: for component in path.parts[1:]: next_fd = os.open(component, flags, dir_fd=directory_fd) os.close(directory_fd) directory_fd = next_fd return directory_fd except Exception: os.close(directory_fd) raise def open_media_file(raw_path: str, allowed_roots: tuple[Path, ...] = ALLOWED_ROOTS) -> tuple[int, os.stat_result, str]: """Open a regular file beneath an allowed root without following symlinks.""" root, components = normalize_media_path(raw_path, allowed_roots) directory_flags = os.O_RDONLY | os.O_DIRECTORY | os.O_CLOEXEC | os.O_NOFOLLOW file_flags = os.O_RDONLY | os.O_CLOEXEC | os.O_NOFOLLOW directory_fd = open_directory_without_symlinks(root) try: for component in components[:-1]: next_fd = os.open(component, directory_flags, dir_fd=directory_fd) os.close(directory_fd) directory_fd = next_fd file_fd = os.open(components[-1], file_flags, dir_fd=directory_fd) finally: os.close(directory_fd) metadata = os.fstat(file_fd) if not stat.S_ISREG(metadata.st_mode) or metadata.st_size > MAX_MEDIA_BYTES: os.close(file_fd) raise MediaPathError("media is not an uploadable regular file") return file_fd, metadata, components[-1] class TenantMediaServer(ThreadingHTTPServer): """HTTP server carrying immutable tenant authentication and root policy.""" daemon_threads = True def __init__( self, address: tuple[str, int], relay_key: str, slot: str, allowed_roots: tuple[Path, ...] = ALLOWED_ROOTS, ) -> None: self.relay_key = relay_key self.tenant_slot = slot self.allowed_roots = allowed_roots super().__init__(address, TenantMediaHandler) class TenantMediaHandler(BaseHTTPRequestHandler): """Authenticate the router and stream one tenant-private file descriptor.""" server: TenantMediaServer def log_message(self, _format: str, *_args: object) -> None: """Keep request paths out of logs because they contain internal names.""" def _plain_status(self, status_code: int, message: bytes) -> None: self.send_response(status_code) self.send_header("Content-Type", "text/plain; charset=utf-8") self.send_header("Content-Length", str(len(message))) self.send_header("Cache-Control", "no-store") self.end_headers() self.wfile.write(message) def _authorized(self) -> bool: expected = "Bearer " + self.server.relay_key supplied = self.headers.get("Authorization", "") slot = self.headers.get("X-Hermes-Tenant-Slot", "") return hmac.compare_digest(supplied.encode(), expected.encode()) and hmac.compare_digest( slot.encode(), self.server.tenant_slot.encode() ) def do_GET(self) -> None: # noqa: N802 - BaseHTTPRequestHandler API parsed = urlsplit(self.path) if parsed.path == "/healthz": self._plain_status(200, b"ok\n") return if parsed.path != "/media": self._plain_status(404, b"not found\n") return if not self._authorized(): self._plain_status(401, b"authentication required\n") return raw_path = parse_qs(parsed.query).get("path", [""])[0] try: file_fd, metadata, filename = open_media_file(raw_path, self.server.allowed_roots) except MediaPathError: self._plain_status(403, b"media path rejected\n") return except (FileNotFoundError, NotADirectoryError, PermissionError, OSError): self._plain_status(404, b"media unavailable\n") return content_type = mimetypes.guess_type(filename)[0] or "application/octet-stream" safe_filename = filename.replace('"', "_").replace("\r", "_").replace("\n", "_") self.send_response(200) self.send_header("Content-Type", content_type) self.send_header("Content-Length", str(metadata.st_size)) self.send_header("Content-Disposition", f'attachment; filename="{safe_filename}"') self.send_header("Cache-Control", "no-store") self.send_header("X-Content-Type-Options", "nosniff") self.end_headers() try: with os.fdopen(file_fd, "rb") as media: shutil.copyfileobj(media, self.wfile, length=64 << 10) except (BrokenPipeError, ConnectionResetError): return def main() -> None: """Start the tenant-local media handoff server.""" relay_key_path = Path( os.getenv( "HERMES_MEDIA_RELAY_KEY_FILE", "/runtime-access/chat-relay-key", ) ) relay_key = read_relay_key(relay_key_path) slot = tenant_slot(os.getenv("POD_NAME", "")) server = TenantMediaServer(("0.0.0.0", 8788), relay_key, slot) server.serve_forever() if __name__ == "__main__": main()