"""Production application launcher for multi-namespace MCP fleets (#978 B1). One real LLM application launch mints exactly one trusted ``client_instance_id`` and propagates it to every Gitea MCP namespace worker started for that launch. Workers never invent a trusted instance identity from PID proximity, timestamps, or ordinary untrusted environment values. This module is the production serve-path authority for instance identity. Tests and fixtures may call the same functions, but production registration receives the identity from the env this launcher builds — not from a hand-set test-only helper that bypasses it. """ from __future__ import annotations import os import secrets from typing import Any, Mapping import mcp_fleet_snapshot as fleet import mcp_worker_identity as mwi #: Canonical MCP server names for the five role namespaces. NAMESPACE_SERVER_NAMES: tuple[str, ...] = ( "gitea-author", "gitea-reviewer", "gitea-merger", "gitea-controller", "gitea-reconciler", ) #: Map MCP server name → role/namespace kind. SERVER_TO_NAMESPACE: dict[str, str] = { "gitea-author": "author", "gitea-reviewer": "reviewer", "gitea-merger": "merger", "gitea-controller": "controller", "gitea-reconciler": "reconciler", } SANCTIONED_NAMESPACES: tuple[str, ...] = ( "author", "reviewer", "merger", "controller", "reconciler", ) # Env the launcher may set on every worker of one application launch. CLIENT_NAME_ENV = "GITEA_MCP_CLIENT" CLIENT_INSTANCE_ENV = fleet.CLIENT_INSTANCE_ENV FLEET_RUN_ENV = fleet.FLEET_RUN_ENV CLIENT_SESSION_ENV = "GITEA_MCP_CLIENT_SESSION" CLIENT_MANAGED_ENV = "GITEA_CLIENT_MANAGED" PROFILE_ENV = "GITEA_MCP_PROFILE" CONFIG_ENV = "GITEA_MCP_CONFIG" INSTANCE_PROVENANCE_ENV = "GITEA_MCP_INSTANCE_PROVENANCE" WORKER_IDENTITY_ENV = "GITEA_MCP_WORKER_IDENTITY" GENERATION_ID_ENV = "GITEA_MCP_GENERATION_ID" # Marker the trusted launcher alone writes; ordinary user env without this # marker is never classified as launcher-trusted provenance. LAUNCHER_PROVENANCE_VALUE = fleet.INSTANCE_ID_PROVENANCE_TRUSTED def mint_application_launch( client_type: str | None, *, launch_nonce: str | None = None, fleet_run_id: str | None = None, session_id: str | None = None, now=None, ) -> dict[str, Any]: """Mint one trusted application-instance identity for a production launch. Called exactly once per real application launch. The returned ``client_instance_id`` is injected into every namespace worker environment for that launch. A second call (separate launch) yields a different ID. """ client = mwi.normalize_client_name(client_type) instance_id = fleet.generate_client_instance_id( client, launch_nonce=launch_nonce, now=now ) assessment = fleet.assess_instance_identity(instance_id) if not assessment["trusted"]: # generate_client_instance_id always produces a trusted format; fail # closed if that invariant ever breaks rather than shipping untrusted. raise RuntimeError( f"launcher produced untrusted client_instance_id {instance_id!r}: " f"{assessment.get('reasons')}" ) session = (session_id or "").strip() or f"launch-{secrets.token_hex(12)}" return { "client_type": client, "client_instance_id": instance_id, "instance_id_provenance": LAUNCHER_PROVENANCE_VALUE, "instance_identity_trusted": True, "fleet_run_id": (fleet_run_id or "").strip() or None, "session_id": session, "namespaces": list(SANCTIONED_NAMESPACES), "namespace_server_names": list(NAMESPACE_SERVER_NAMES), } def namespace_worker_env( *, profile_name: str, client_type: str | None, client_instance_id: str, config_path: str | None = None, fleet_run_id: str | None = None, session_id: str | None = None, extra_env: Mapping[str, str] | None = None, ) -> dict[str, str]: """Build the environment for one namespace worker of a trusted launch. Never invents a client_instance_id. The caller must supply the launch-minted identity so all five workers receive the same value. """ assessment = fleet.assess_instance_identity(client_instance_id) if not assessment["trusted"]: raise ValueError( "namespace_worker_env refuses untrusted client_instance_id " f"{client_instance_id!r}: {assessment.get('reasons')}" ) client = mwi.normalize_client_name(client_type) env: dict[str, str] = { PROFILE_ENV: str(profile_name), CLIENT_MANAGED_ENV: "1", "GITEA_MCP_CLIENT": client, CLIENT_INSTANCE_ENV: assessment["client_instance_id"], INSTANCE_PROVENANCE_ENV: LAUNCHER_PROVENANCE_VALUE, } if config_path: env[CONFIG_ENV] = str(config_path) if fleet_run_id: env[FLEET_RUN_ENV] = str(fleet_run_id) if session_id: env[CLIENT_SESSION_ENV] = str(session_id) if extra_env: # Never let untrusted callers override the trusted instance keys. protected = { CLIENT_INSTANCE_ENV, INSTANCE_PROVENANCE_ENV, "GITEA_MCP_CLIENT", CLIENT_MANAGED_ENV, } for key, value in extra_env.items(): if key in protected: continue env[str(key)] = str(value) return env def build_application_mcp_servers( profile_by_namespace: Mapping[str, str], *, client_type: str | None, config_path: str | None = None, client_instance_id: str | None = None, fleet_run_id: str | None = None, session_id: str | None = None, launch_nonce: str | None = None, command: str | None = None, args: list[str] | None = None, now=None, ) -> dict[str, Any]: """Build a production ``mcpServers`` map for one application launch. Mints one ``client_instance_id`` when *client_instance_id* is omitted (fresh launch). When the caller supplies a previously minted trusted ID (resume of the same launch / config rewrite), that ID is reused so reconnect keeps attribution. A full new application restart omits the ID and receives a fresh mint. Every namespace server entry receives the **same** instance ID. Separate calls with no supplied ID receive distinct IDs. """ missing = [ ns for ns in SANCTIONED_NAMESPACES if not profile_by_namespace.get(ns) ] if missing: raise ValueError( "build_application_mcp_servers requires a profile for every " f"sanctioned namespace; missing: {missing}" ) if client_instance_id is None: launch = mint_application_launch( client_type, launch_nonce=launch_nonce, fleet_run_id=fleet_run_id, session_id=session_id, now=now, ) else: assessment = fleet.assess_instance_identity(client_instance_id) if not assessment["trusted"]: raise ValueError( "refusing to propagate untrusted client_instance_id " f"{client_instance_id!r} into production launch envs: " f"{assessment.get('reasons')}" ) launch = { "client_type": mwi.normalize_client_name(client_type), "client_instance_id": assessment["client_instance_id"], "instance_id_provenance": LAUNCHER_PROVENANCE_VALUE, "instance_identity_trusted": True, "fleet_run_id": (fleet_run_id or "").strip() or None, "session_id": (session_id or "").strip() or f"launch-{secrets.token_hex(12)}", "namespaces": list(SANCTIONED_NAMESPACES), "namespace_server_names": list(NAMESPACE_SERVER_NAMES), } # Resolve command/args from the production server entry when not provided. if command is None or args is None: import gitea_config cmd, cmd_args = gitea_config.server_command() command = command or cmd args = args if args is not None else list(cmd_args) servers: dict[str, Any] = {} shared_id = launch["client_instance_id"] for namespace in SANCTIONED_NAMESPACES: server_name = f"gitea-{namespace}" profile = profile_by_namespace[namespace] env = namespace_worker_env( profile_name=profile, client_type=launch["client_type"], client_instance_id=shared_id, config_path=config_path, fleet_run_id=launch.get("fleet_run_id"), session_id=launch.get("session_id"), ) servers[server_name] = { "command": command, "args": list(args), "env": env, } return { "mcpServers": servers, "launch": launch, "client_instance_id": shared_id, "client_type": launch["client_type"], "namespaces": list(SANCTIONED_NAMESPACES), "shared_instance_id_across_namespaces": True, "namespace_count": len(SANCTIONED_NAMESPACES), } def launcher_entry_for_profile( profile_name: str, *, client_type: str | None = None, config_path: str | None = None, client_instance_id: str | None = None, fleet_run_id: str | None = None, session_id: str | None = None, server_key: str = "gitea-tools", launch_nonce: str | None = None, now=None, ) -> dict[str, Any]: """Thin single-server production launcher entry with trusted instance ID. Used when only one namespace is being configured. Still mints (or reuses) a trusted ``client_instance_id`` so production never relies on the legacy placeholder identity for normal launches. """ import gitea_config if client_instance_id is None: launch = mint_application_launch( client_type or "unknown", launch_nonce=launch_nonce, fleet_run_id=fleet_run_id, session_id=session_id, now=now, ) client_instance_id = launch["client_instance_id"] client = launch["client_type"] fleet_run = launch.get("fleet_run_id") session = launch.get("session_id") else: assessment = fleet.assess_instance_identity(client_instance_id) if not assessment["trusted"]: raise ValueError( f"untrusted client_instance_id {client_instance_id!r}" ) client = mwi.normalize_client_name(client_type) fleet_run = (fleet_run_id or "").strip() or None session = (session_id or "").strip() or None client_instance_id = assessment["client_instance_id"] command, args = gitea_config.server_command() env = namespace_worker_env( profile_name=profile_name, client_type=client, client_instance_id=client_instance_id, config_path=config_path or gitea_config.DEFAULT_CONFIG_PATH, fleet_run_id=fleet_run, session_id=session, ) return { server_key: { "command": command, "args": args, "env": env, }, "client_instance_id": client_instance_id, "client_type": client, } def collect_instance_ids_from_mcp_servers( mcp_servers: Mapping[str, Any], ) -> dict[str, Any]: """Inspect a production mcpServers map for shared instance attribution. Returns the unique set of client_instance_id values across gitea-* servers and whether all five namespaces share exactly one trusted ID. """ ids: list[str] = [] by_server: dict[str, str | None] = {} for name in NAMESPACE_SERVER_NAMES: entry = mcp_servers.get(name) or {} env = entry.get("env") or {} raw = (env.get(CLIENT_INSTANCE_ENV) or "").strip() or None by_server[name] = raw if raw: ids.append(raw) unique = sorted(set(ids)) trusted = [ i for i in unique if fleet.assess_instance_identity(i)["trusted"] ] return { "server_instance_ids": by_server, "unique_instance_ids": unique, "trusted_instance_ids": trusted, "shared_single_trusted_id": ( len(unique) == 1 and len(trusted) == 1 and all(by_server.get(n) == unique[0] for n in NAMESPACE_SERVER_NAMES) ), "namespace_server_count": sum( 1 for n in NAMESPACE_SERVER_NAMES if n in mcp_servers ), } def inherit_or_refuse_client_instance( env: Mapping[str, str] | None = None, ) -> dict[str, Any]: """Resolve instance identity for a worker process at serve time. Production workers inherit the launcher-issued ID. They never mint a trusted ID themselves. Missing / legacy / malformed values fail soft into an untrusted assessment so registration can still record a diagnostic row without authorizing multi-instance fleet mutation. """ source = dict(env if env is not None else os.environ) raw = (source.get(CLIENT_INSTANCE_ENV) or "").strip() or None provenance_marker = (source.get(INSTANCE_PROVENANCE_ENV) or "").strip() assessment = fleet.assess_instance_identity(raw) # Ordinary user-supplied values without launcher provenance marker are # still format-checked by assess_instance_identity. When the format is # trusted but the launcher marker is absent, keep the ID but note that # provenance is not launcher-sealed (operator hand-set or legacy config). if assessment["trusted"] and provenance_marker != LAUNCHER_PROVENANCE_VALUE: assessment = dict(assessment) assessment["launcher_sealed"] = False assessment["reasons"] = list(assessment.get("reasons") or []) + [ f"{INSTANCE_PROVENANCE_ENV} is not {LAUNCHER_PROVENANCE_VALUE!r}; " "identity format is valid but not sealed by the production launcher" ] else: assessment = dict(assessment) assessment["launcher_sealed"] = bool( assessment["trusted"] and provenance_marker == LAUNCHER_PROVENANCE_VALUE ) assessment["fleet_run_id"] = (source.get(FLEET_RUN_ENV) or "").strip() or None assessment["session_id"] = ( (source.get(CLIENT_SESSION_ENV) or "").strip() or None ) assessment["client_type"] = mwi.normalize_client_name( (source.get("GITEA_MCP_CLIENT") or "").strip() or None ) return assessment