Remediate review 655 blockers on PR #979 (issue #978): B1 — Production launcher (mcp_application_launcher) mints one trusted client_instance_id per application launch and propagates it to all five namespace workers via GITEA_MCP_CLIENT_INSTANCE. launcher_entry and multi_namespace_launcher_entries use that path. Workers never invent a trusted ID; missing/malformed/user-supplied values fail closed. B2 — _check_mcp_runtimes_diagnostics is instance-aware: two legitimate instances sharing a profile are allowed when each has a distinct trusted client_instance_id; duplicate workers for the same (instance, profile) still fail closed. Worker identity/generation exported for peer scans. Tests cover shared ID across five namespaces, distinct launches, multi- instance same profile, same-instance duplicates, untrusted attribution, and the production launcher path. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
394 lines
14 KiB
Python
394 lines
14 KiB
Python
"""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
|