from __future__ import annotations import hashlib import hmac import json import os import re import time from collections.abc import Mapping from pathlib import Path from typing import Any from urllib.parse import quote_plus from uuid import NAMESPACE_URL, UUID, uuid5 from packages.connector_kit import ConnectorContext from packages.hub_runtime import read_secret_file ENVIRONMENTS = frozenset({"dev", "test", "staging", "prod"}) PROJECT_SLUG = re.compile(r"^[a-z0-9][a-z0-9-]{0,62}$") IDENTITY_ASSERTION = re.compile(r"^v1:([0-9]{10}):([0-9a-f]{64})$") TRACE_ID = re.compile(r"^[A-Za-z0-9._:-]{1,128}$") def deterministic_id(kind: str, value: str) -> UUID: return uuid5(NAMESPACE_URL, f"https://hub.example.com/{kind}/{value}") def load_connector_identity_key() -> bytes: path = Path( os.environ.get("CONNECTOR_IDENTITY_KEY_FILE", "/run/secrets/connector_identity_signing_key") ) key = read_secret_file(path).encode("utf-8") if len(key) < 32: raise ValueError("connector identity signing key must contain at least 32 bytes") return key def identity_assertion( key: bytes, *, project: str, environment: str, client_id: str, trace_id: str, now: int | None = None, ) -> str: timestamp = int(time.time()) if now is None else now message = f"v1\n{timestamp}\n{project}\n{environment}\n{client_id}\n{trace_id}".encode() signature = hmac.new(key, message, hashlib.sha256).hexdigest() return f"v1:{timestamp}:{signature}" def connector_context( headers: Mapping[str, str], projects: set[str], *, signing_key: bytes, now: int | None = None, ) -> ConnectorContext: project = headers.get("x-itworx-project", "").strip().lower() environment = headers.get("x-itworx-environment", "").strip().lower() client_id = headers.get("x-itworx-client-id", "").strip().lower() trace_id = headers.get("x-itworx-trace-id", "").strip() if project not in projects or not PROJECT_SLUG.fullmatch(project): raise PermissionError("connector project context is not registered") if environment not in ENVIRONMENTS: raise PermissionError("connector environment context is not registered") try: UUID(client_id) except ValueError as exc: raise PermissionError("connector client context is invalid") from exc assertion = headers.get("x-itworx-identity-assertion", "").strip().lower() match = IDENTITY_ASSERTION.fullmatch(assertion) reference = int(time.time()) if now is None else now if match is None or abs(reference - int(match.group(1))) > 60: raise PermissionError("connector identity assertion is invalid or expired") expected = identity_assertion( signing_key, project=project, environment=environment, client_id=client_id, trace_id=trace_id, now=int(match.group(1)), ) if not hmac.compare_digest(assertion, expected): raise PermissionError("connector identity assertion is invalid or expired") return ConnectorContext( workspace_id=deterministic_id("workspace", "itworx"), project_id=deterministic_id("project", project), project_slug=project, environment=environment, client_id=UUID(client_id), # The trace id is already covered by the identity assertion above, so it is # authenticated Hub input; the pattern check only keeps it a safe header value. correlation_id=trace_id if TRACE_ID.fullmatch(trace_id) else None, ) def request_headers(context: Any) -> Mapping[str, str]: request = context.request_context.request headers = getattr(request, "headers", None) if headers is None: raise PermissionError("connector transport context is unavailable") return {str(key).lower(): str(value) for key, value in headers.items()} def run_asgi(application: Any) -> None: import uvicorn uvicorn.run( application, host="0.0.0.0", # noqa: S104 - container network binding is intentional. port=int(os.environ.get("PORT", "8080")), access_log=False, proxy_headers=False, server_header=False, ) def load_json_environment(name: str, expected: type[list[Any]] | type[dict[str, Any]]) -> Any: raw = os.environ.get(name, "") try: value = json.loads(raw) except (TypeError, ValueError) as exc: raise ValueError(f"{name} is invalid") from exc if not isinstance(value, expected): raise ValueError(f"{name} has an invalid shape") return value def read_regular_json(path: Path) -> dict[str, Any]: if not path.is_file() or path.is_symlink(): raise ValueError("registered configuration file is unavailable") value = json.loads(path.read_text(encoding="utf-8")) if not isinstance(value, dict): raise ValueError("registered configuration file is invalid") return value def hub_database_url() -> str: password = read_secret_file( Path(os.environ.get("HUB_DATABASE_PASSWORD_FILE", "/run/secrets/hub_database_password")) ) host = os.environ.get("HUB_DATABASE_HOST", "postgres") database = os.environ.get("HUB_DATABASE_NAME", "itworx_mcp_hub") user = os.environ.get("HUB_DATABASE_USER", "itworx_mcp_hub") return f"postgresql+psycopg://{quote_plus(user)}:{quote_plus(password)}@{host}:5432/{database}"