Files
Gitea-Tools/tests/test_issue_931_transport_bind_seam.py
T
jcwalker3andClaude Opus 4.8 a143cd065b fix(transport): gate transport execution behind commissioning (review 635)
Addresses B1 and B2 from formal review 635 on PR #966. Both are one defect:
the seam conflated two questions that must stay separate.

  recognition:  "is this an identifier this system knows, and may it be
                 bound, pinned and recorded?"
  execution:    "is this entrypoint commissioned to actually serve on it?"

SUPPORTED_TRANSPORTS answered the first and was then used to answer the
second, so registering streamable-http was the same act as executing it.
With mcp.run fed the bound value, GITEA_MCP_TRANSPORT=streamable-http
reached FastMCP.run -> run_streamable_http_async and started a uvicorn
HTTP server over the whole tool surface with auth=None, no TLS and no
per-request principal. That endpoint is owned by #938 and is an explicit
non-goal of #931. B2 is why B1 was reachable: bound_transport was read
only by reporting sites, so no decision anywhere depended on it.

The fix adds an execution-authorization layer rather than removing the
identifier or mapping it to stdio, both of which would have destroyed the
seam #931 exists to create.

mcp_transport_config gains EXECUTABLE_TRANSPORTS, a strict subset of
SUPPORTED_TRANSPORTS containing only the local transport, plus
TRANSPORT_EXECUTION_OWNER recording that #938 commissions the remote
listener. assess_transport_execution returns a structured verdict:
transport, recognized, executable, allowed, blocker_kind, owner_issue,
reasons and exact_next_action.

mcp_daemon_guard gains assess_serve_authorization, which is the decision
that consumes bound_transport and is what stops it being reporting-only
metadata, and authorize_transport_execution, which enforces two ordered
boundaries: assert_transport_bound first, so an unbound runtime keeps its
pre-existing #695 failure and reason code; then execution authorization,
so a registered but uncommissioned transport is refused before any
listener exists and before any tool can dispatch. TransportExecutionError
subclasses UnsanctionedRuntimeError, so every existing fail-closed handler
still catches it while a caller that cares can distinguish the two cases.
native_runtime_status now reports executable_transports, serve_authorized
and the full serve_authorization verdict.

The entrypoint serves through authorize_transport_execution.

Net effect. stdio: unchanged, still binds and still reaches the runner.
streamable-http: still recognized, still validated, still pinned, still
recorded in decision-lock and audit provenance -- and refused at the serve
boundary with blocker transport_listener_not_commissioned naming #938.
Unregistered identifiers still fail earlier, at bind validation. Unbound
execution keeps the #695 contract. Rebind idempotence and conflict
rejection, session isolation, provenance and secret handling are untouched.

Tests: 63 in tests/test_issue_931_transport_bind_seam.py, up from 42. New
coverage proves stdio reaches the real runner; the remote identifier binds
and is recorded yet never reaches run(); no socket is bound during the
refusal, asserted with a socket.bind tripwire; the refusal names the
transport, the unmet requirement and #938; the decision genuinely consumes
bound_transport, proven by flipping only that value; no mutation is
authorized after denial; verdicts do not leak across runtimes; and the
refusal carries no credential material. Per review 635 the two file-list
scans are now globs over the production surface, and a new test asserts
there is exactly one mcp.run site and that it routes through the guard.

#956 anchors re-anchored for the two lines this change shifted,
mcp_daemon_guard.py 178->195 and 519->583. No other anchor moved.

Full suite from the branches/ worktree: 28 failed, 5864 passed, 6 skipped,
1047 subtests. Base 9b80e75c: 28 failed, 5801 passed, 6 skipped, 1047
subtests. Failing test IDs are identical sets in both directions; the +63
passed are this module.

No listener, socket, authentication, TLS or principal code is added. #938,
#957, #958 and #959 remain unimplemented.

Refs #931, #938. Addresses review 635.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-28 11:15:00 -05:00

925 lines
39 KiB
Python

"""Transport-neutral MCP bind seam (#931).
These tests drive the *real* bind boundary — ``mark_sanctioned_daemon`` followed
by ``bind_native_mcp_transport`` from a canonical entrypoint path, with the
pytest allowance switched off — rather than mocking the new accessor. The
distinction matters here for the same reason it mattered in #941: a suite that
only exercises the helper in isolation cannot observe a seam that the live path
never reaches.
Covered:
1. no configured transport defaults to the local transport
2. explicit local transport binds
3. the sanctioned remote identifier binds through the seam
4. an unregistered identifier is rejected at bind time
5. an invalid bind prevents the server reaching tool service
6. the unbound state fails closed where a bind is required
7. every transport-aware guard reads the same authoritative value
8. client-controlled input cannot alter the bound transport
9. the durable decision-lock record carries the selected transport
10. existing stdio behaviour is unchanged
11. repeated / conflicting bind attempts follow one fail-closed contract
12. capability, role, repository and provenance protections do not regress
"""
from __future__ import annotations
import os
import tempfile
import unittest
from pathlib import Path
from unittest.mock import patch
REPO_ROOT = Path(__file__).resolve().parent.parent
import mcp_daemon_guard
import mcp_session_state
import mcp_transport_config
import irrecoverable_provenance
class _ProductionBind:
"""Context manager that reaches the real production bind path.
Patches only the two things a unit test cannot otherwise satisfy: the
resolved canonical entrypoint frame, and the pytest allowance that would
short-circuit ``mark_sanctioned_daemon``. Everything downstream of those —
validation, pinning, the rebind contract — runs unmodified.
"""
def __init__(self, env: dict[str, str] | None = None):
self._env = env or {}
self._stack: list = []
def __enter__(self):
mcp_daemon_guard.clear_native_runtime_for_tests()
canonical = str((REPO_ROOT / "mcp_server.py").resolve())
self._stack = [
patch.object(
mcp_daemon_guard,
"_caller_official_entrypoint_path",
side_effect=lambda: canonical,
),
patch.object(mcp_daemon_guard, "is_pytest_runtime", return_value=False),
patch.dict(os.environ, self._env),
]
for ctx in self._stack:
ctx.__enter__()
# Start from a clean configuration unless the test set one.
if mcp_transport_config.TRANSPORT_ENV not in self._env:
os.environ.pop(mcp_transport_config.TRANSPORT_ENV, None)
mcp_daemon_guard.mark_sanctioned_daemon()
return mcp_daemon_guard
def __exit__(self, *exc):
for ctx in reversed(self._stack):
ctx.__exit__(*exc)
mcp_daemon_guard.clear_native_runtime_for_tests()
return False
class TestPermittedSetIsSingleSourceOfTruth(unittest.TestCase):
"""AC3: identifiers are enumerated once, in the seam."""
def test_guard_allowlist_is_the_seam_allowlist(self):
self.assertIs(
mcp_daemon_guard._PRODUCTION_TRANSPORTS,
mcp_transport_config.SUPPORTED_TRANSPORTS,
)
def test_default_is_a_member_of_the_permitted_set(self):
self.assertIn(
mcp_transport_config.DEFAULT_TRANSPORT,
mcp_transport_config.SUPPORTED_TRANSPORTS,
)
def test_remote_identifier_is_permitted_and_not_the_default(self):
self.assertIn(
mcp_transport_config.REMOTE_TRANSPORT,
mcp_transport_config.SUPPORTED_TRANSPORTS,
)
self.assertNotEqual(
mcp_transport_config.REMOTE_TRANSPORT,
mcp_transport_config.DEFAULT_TRANSPORT,
)
self.assertTrue(
mcp_transport_config.is_remote_transport(
mcp_transport_config.REMOTE_TRANSPORT
)
)
def test_no_default_transport_literal_outside_the_seam(self):
"""AC3: no production module reads the literal outside the seam.
Review 635 flagged that a fixed five-module list cannot catch a *new*
module reintroducing the literal. This globs every production module in
the repository root instead, so the guarantee holds for code that does
not exist yet.
"""
default = mcp_transport_config.DEFAULT_TRANSPORT
needles = (f'"{default}"', f"'{default}'")
seam = Path(mcp_transport_config.__file__).name
scanned: list[str] = []
offenders: list[str] = []
for path in sorted(REPO_ROOT.glob("*.py")):
if path.name == seam:
continue # the seam is the one place the literal may live
scanned.append(path.name)
for lineno, line in enumerate(
path.read_text(encoding="utf-8").splitlines(), start=1
):
code = line.split("#", 1)[0]
if any(needle in code for needle in needles):
offenders.append(f"{path.name}:{lineno}: {line.strip()}")
# Guard the guard: a glob that silently matched nothing would pass.
self.assertGreater(len(scanned), 20, "production glob matched too little")
self.assertIn("mcp_daemon_guard.py", scanned)
self.assertIn("gitea_mcp_server.py", scanned)
self.assertEqual(offenders, [], "\n".join(offenders))
class TestConfiguredTransportResolution(unittest.TestCase):
"""AC1: configuration supplies the identifier; unset still yields the default."""
def test_unset_yields_default(self):
res = mcp_transport_config.resolve_configured_transport(env={})
self.assertEqual(res["transport"], mcp_transport_config.DEFAULT_TRANSPORT)
self.assertFalse(res["configured"])
self.assertEqual(res["source"], mcp_transport_config.SOURCE_DEFAULT)
self.assertTrue(res["supported"])
self.assertEqual(res["reasons"], [])
def test_blank_and_whitespace_are_treated_as_unset(self):
for raw in ("", " ", "\t\n"):
res = mcp_transport_config.resolve_configured_transport(
env={mcp_transport_config.TRANSPORT_ENV: raw}
)
self.assertEqual(res["transport"], mcp_transport_config.DEFAULT_TRANSPORT)
self.assertFalse(res["configured"])
def test_explicit_default_is_reported_as_configured(self):
res = mcp_transport_config.resolve_configured_transport(
env={
mcp_transport_config.TRANSPORT_ENV: (
mcp_transport_config.DEFAULT_TRANSPORT
)
}
)
self.assertEqual(res["transport"], mcp_transport_config.DEFAULT_TRANSPORT)
self.assertTrue(res["configured"])
self.assertEqual(res["source"], mcp_transport_config.SOURCE_CONFIGURED)
def test_remote_identifier_resolves_and_is_supported(self):
res = mcp_transport_config.resolve_configured_transport(
env={
mcp_transport_config.TRANSPORT_ENV: (
mcp_transport_config.REMOTE_TRANSPORT
)
}
)
self.assertEqual(res["transport"], mcp_transport_config.REMOTE_TRANSPORT)
self.assertTrue(res["supported"])
def test_case_and_padding_are_normalized(self):
padded = f" {mcp_transport_config.REMOTE_TRANSPORT.upper()} "
res = mcp_transport_config.resolve_configured_transport(
env={mcp_transport_config.TRANSPORT_ENV: padded}
)
self.assertEqual(res["transport"], mcp_transport_config.REMOTE_TRANSPORT)
self.assertTrue(res["supported"])
def test_unregistered_identifier_is_not_silently_defaulted(self):
res = mcp_transport_config.resolve_configured_transport(
env={mcp_transport_config.TRANSPORT_ENV: "carrier-pigeon"}
)
self.assertFalse(res["supported"])
self.assertEqual(res["transport"], "carrier-pigeon")
self.assertNotEqual(res["transport"], mcp_transport_config.DEFAULT_TRANSPORT)
self.assertTrue(res["reasons"])
def test_superseded_sse_transport_is_not_registered(self):
"""A real MCP transport that this deployment does not sanction."""
self.assertFalse(mcp_transport_config.is_supported_transport("sse"))
res = mcp_transport_config.resolve_configured_transport(
env={mcp_transport_config.TRANSPORT_ENV: "sse"}
)
self.assertFalse(res["supported"])
def test_require_configured_transport_raises_on_unregistered(self):
with self.assertRaises(mcp_transport_config.TransportConfigurationError):
mcp_transport_config.require_configured_transport(
env={mcp_transport_config.TRANSPORT_ENV: "carrier-pigeon"}
)
def test_non_string_configuration_never_matches_permitted_set(self):
for value in (object(), 1, None, True, ["stdio"], {"t": "stdio"}):
self.assertEqual(mcp_transport_config.normalize_transport(value), "")
self.assertFalse(mcp_transport_config.is_supported_transport(value))
class TestBindSeam(unittest.TestCase):
"""AC1/AC2: the live bind path resolves, validates, and pins."""
def tearDown(self) -> None:
mcp_daemon_guard.clear_native_runtime_for_tests()
def test_1_no_configured_transport_binds_default(self):
with _ProductionBind() as guard:
status = guard.bind_native_mcp_transport()
self.assertEqual(
status["transport"], mcp_transport_config.DEFAULT_TRANSPORT
)
self.assertEqual(
guard.bound_transport(), mcp_transport_config.DEFAULT_TRANSPORT
)
self.assertTrue(status["production_native_mcp_transport"])
def test_2_explicit_default_transport_binds(self):
with _ProductionBind(
{
mcp_transport_config.TRANSPORT_ENV: (
mcp_transport_config.DEFAULT_TRANSPORT
)
}
) as guard:
status = guard.bind_native_mcp_transport()
self.assertEqual(
status["transport"], mcp_transport_config.DEFAULT_TRANSPORT
)
self.assertTrue(guard.is_production_native_mcp_transport())
def test_2b_explicit_argument_still_binds(self):
"""The pre-#931 call form keeps working for launchers and tests."""
with _ProductionBind() as guard:
status = guard.bind_native_mcp_transport(
transport=mcp_transport_config.DEFAULT_TRANSPORT
)
self.assertEqual(
status["transport"], mcp_transport_config.DEFAULT_TRANSPORT
)
def test_3_sanctioned_remote_identifier_binds_through_the_seam(self):
with _ProductionBind(
{
mcp_transport_config.TRANSPORT_ENV: (
mcp_transport_config.REMOTE_TRANSPORT
)
}
) as guard:
status = guard.bind_native_mcp_transport()
self.assertEqual(
status["transport"], mcp_transport_config.REMOTE_TRANSPORT
)
self.assertEqual(
guard.bound_transport(), mcp_transport_config.REMOTE_TRANSPORT
)
# The remote identifier is trusted exactly like the local one; the
# listener that serves it is #938 and is not implemented here.
self.assertTrue(guard.is_native_mcp_transport())
self.assertTrue(guard.is_production_native_mcp_transport())
guard.assert_production_mutation_runtime("remote-bind")
def test_4_unregistered_identifier_rejected_at_bind_time(self):
with _ProductionBind(
{mcp_transport_config.TRANSPORT_ENV: "carrier-pigeon"}
) as guard:
with self.assertRaises(guard.UnsanctionedRuntimeError) as ctx:
guard.bind_native_mcp_transport()
self.assertIn("carrier-pigeon", str(ctx.exception))
self.assertIn("#931", str(ctx.exception))
# Nothing was bound, so nothing may dispatch.
self.assertIsNone(guard.bound_transport())
self.assertFalse(guard.is_native_mcp_transport())
def test_4b_unregistered_explicit_argument_rejected(self):
with _ProductionBind() as guard:
with self.assertRaises(guard.UnsanctionedRuntimeError):
guard.bind_native_mcp_transport(transport="carrier-pigeon")
self.assertIsNone(guard.bound_transport())
def test_4c_superseded_sse_rejected_at_bind_time(self):
with _ProductionBind({mcp_transport_config.TRANSPORT_ENV: "sse"}) as guard:
with self.assertRaises(guard.UnsanctionedRuntimeError):
guard.bind_native_mcp_transport()
self.assertIsNone(guard.bound_transport())
def test_5_invalid_bind_prevents_tool_service(self):
"""A failed bind must stop the server before it serves tools."""
with _ProductionBind(
{mcp_transport_config.TRANSPORT_ENV: "carrier-pigeon"}
) as guard:
with self.assertRaises(guard.UnsanctionedRuntimeError):
guard.bind_native_mcp_transport()
# This is the exact expression the entrypoint passes to mcp.run.
with self.assertRaises(guard.UnsanctionedRuntimeError) as ctx:
guard.assert_transport_bound("tool service")
self.assertIn("No MCP transport is bound", str(ctx.exception))
def test_6_unbound_state_fails_closed(self):
"""Entrypoint claimed but never bound — the offline-import shape."""
with _ProductionBind() as guard:
self.assertIsNone(guard.bound_transport())
self.assertFalse(guard.is_native_mcp_transport())
with self.assertRaises(guard.UnsanctionedRuntimeError):
guard.assert_transport_bound("tool service")
with self.assertRaises(guard.UnsanctionedRuntimeError):
guard.assert_sanctioned_mutation_runtime("gitea_mutation")
def test_6b_no_runtime_at_all_fails_closed(self):
mcp_daemon_guard.clear_native_runtime_for_tests()
with patch.object(mcp_daemon_guard, "is_pytest_runtime", return_value=False):
self.assertIsNone(mcp_daemon_guard.bound_transport())
with self.assertRaises(mcp_daemon_guard.UnsanctionedRuntimeError):
mcp_daemon_guard.assert_transport_bound("tool service")
class TestOneAuthoritativeValue(unittest.TestCase):
"""AC: every transport-aware guard observes the same value."""
def tearDown(self) -> None:
mcp_daemon_guard.clear_native_runtime_for_tests()
def test_7_all_guards_read_the_same_bound_value(self):
with _ProductionBind(
{
mcp_transport_config.TRANSPORT_ENV: (
mcp_transport_config.REMOTE_TRANSPORT
)
}
) as guard:
guard.bind_native_mcp_transport()
expected = mcp_transport_config.REMOTE_TRANSPORT
self.assertEqual(guard.bound_transport(), expected)
self.assertEqual(guard.assert_transport_bound(), expected)
self.assertEqual(guard.native_runtime_status()["bound_transport"], expected)
self.assertEqual(guard.native_runtime_status()["transport"], expected)
self.assertEqual(
guard.mutation_provenance_fields()["bound_transport"], expected
)
self.assertEqual(
irrecoverable_provenance.assess_transport_for_auth_mint()[
"bound_transport"
],
expected,
)
def test_8_environment_change_after_bind_cannot_move_the_value(self):
"""Client- or environment-shaped input must not alter a bound transport."""
with _ProductionBind() as guard:
guard.bind_native_mcp_transport()
self.assertEqual(
guard.bound_transport(), mcp_transport_config.DEFAULT_TRANSPORT
)
# A stray launcher (or an attacker) rewrites config post-bind.
os.environ[mcp_transport_config.TRANSPORT_ENV] = (
mcp_transport_config.REMOTE_TRANSPORT
)
self.assertEqual(
guard.bound_transport(), mcp_transport_config.DEFAULT_TRANSPORT
)
self.assertEqual(
guard.mutation_provenance_fields()["bound_transport"],
mcp_transport_config.DEFAULT_TRANSPORT,
)
os.environ[mcp_transport_config.TRANSPORT_ENV] = "carrier-pigeon"
self.assertEqual(
guard.bound_transport(), mcp_transport_config.DEFAULT_TRANSPORT
)
def test_8b_bound_transport_takes_no_caller_argument(self):
"""The accessor cannot be steered by a tool parameter."""
import inspect
self.assertEqual(
list(inspect.signature(mcp_daemon_guard.bound_transport).parameters), []
)
def test_11_rebinding_the_same_transport_is_idempotent(self):
with _ProductionBind() as guard:
first = guard.bind_native_mcp_transport()
second = guard.bind_native_mcp_transport()
self.assertEqual(first["transport"], second["transport"])
self.assertEqual(
guard.bound_transport(), mcp_transport_config.DEFAULT_TRANSPORT
)
def test_11b_rebinding_a_different_transport_fails_closed(self):
with _ProductionBind() as guard:
guard.bind_native_mcp_transport()
with self.assertRaises(guard.UnsanctionedRuntimeError) as ctx:
guard.bind_native_mcp_transport(
transport=mcp_transport_config.REMOTE_TRANSPORT
)
self.assertIn("already bound", str(ctx.exception))
# The first value survives the attempt.
self.assertEqual(
guard.bound_transport(), mcp_transport_config.DEFAULT_TRANSPORT
)
def test_11c_rebinding_an_unregistered_transport_fails_closed(self):
with _ProductionBind() as guard:
guard.bind_native_mcp_transport()
with self.assertRaises(guard.UnsanctionedRuntimeError):
guard.bind_native_mcp_transport(transport="carrier-pigeon")
self.assertEqual(
guard.bound_transport(), mcp_transport_config.DEFAULT_TRANSPORT
)
class TestDurableRecordCarriesTransport(unittest.TestCase):
"""AC4: the identifier reaches a durable decision-lock record."""
def tearDown(self) -> None:
mcp_daemon_guard.clear_native_runtime_for_tests()
def _save_and_read_decision_lock(self, state_dir: str) -> dict:
mcp_session_state.save_state(
kind=mcp_session_state.KIND_DECISION_LOCK,
payload={"pr_number": 931, "action": "COMMENT"},
remote="prgs",
org="Scaled-Tech-Consulting",
repo="Gitea-Tools",
profile_identity="prgs-author",
state_dir=state_dir,
)
loaded = mcp_session_state.load_state(
kind=mcp_session_state.KIND_DECISION_LOCK,
remote="prgs",
org="Scaled-Tech-Consulting",
repo="Gitea-Tools",
profile_identity="prgs-author",
state_dir=state_dir,
)
self.assertIsNotNone(loaded)
return loaded
def test_9_decision_lock_records_the_bound_transport(self):
with tempfile.TemporaryDirectory() as tmp:
mcp_daemon_guard.clear_native_runtime_for_tests()
mcp_daemon_guard.install_test_native_runtime()
record = self._save_and_read_decision_lock(tmp)
self.assertIn("bound_transport", record)
self.assertEqual(
record["bound_transport"], mcp_daemon_guard.bound_transport()
)
def test_9b_unbound_runtime_records_no_transport_identifier(self):
with tempfile.TemporaryDirectory() as tmp:
mcp_daemon_guard.clear_native_runtime_for_tests()
record = self._save_and_read_decision_lock(tmp)
self.assertIn("bound_transport", record)
self.assertIsNone(record["bound_transport"])
def test_9c_provenance_fields_expose_the_identifier(self):
mcp_daemon_guard.clear_native_runtime_for_tests()
fields = mcp_daemon_guard.mutation_provenance_fields()
self.assertIn("bound_transport", fields)
self.assertIsNone(fields["bound_transport"])
class TestStdioBehaviourUnchanged(unittest.TestCase):
"""AC6 / prompt items 10 and 12: no regression on the existing path."""
def tearDown(self) -> None:
mcp_daemon_guard.clear_native_runtime_for_tests()
def test_10_trust_class_field_keeps_its_pre_931_values(self):
"""``transport`` remains the trust class, not the identifier."""
mcp_daemon_guard.clear_native_runtime_for_tests()
self.assertEqual(
mcp_daemon_guard.mutation_provenance_fields()["transport"], "untrusted"
)
mcp_daemon_guard.install_test_native_runtime()
self.assertEqual(
mcp_daemon_guard.mutation_provenance_fields()["transport"],
"test_native_mcp",
)
with _ProductionBind() as guard:
guard.bind_native_mcp_transport()
self.assertEqual(
guard.mutation_provenance_fields()["transport"], "native_mcp"
)
def test_10b_default_bind_reproduces_the_pre_931_runtime_record(self):
with _ProductionBind() as guard:
status = guard.bind_native_mcp_transport()
self.assertTrue(status["native_mcp_transport"])
self.assertTrue(status["production_native_mcp_transport"])
self.assertEqual(status["mode"], "production")
self.assertEqual(status["phase"], "transport_bound")
self.assertEqual(
status["transport"], mcp_transport_config.DEFAULT_TRANSPORT
)
guard.assert_sanctioned_mutation_runtime("native-ide")
guard.assert_production_mutation_runtime("native-ide")
def test_12_session_state_root_still_pinned_at_bind(self):
"""#695 AC2 must survive the seam."""
with tempfile.TemporaryDirectory() as legit:
with tempfile.TemporaryDirectory() as rogue:
with _ProductionBind(
{mcp_daemon_guard.SESSION_STATE_DIR_ENV: legit}
) as guard:
guard.bind_native_mcp_transport()
self.assertEqual(
guard.pinned_session_state_dir(), str(Path(legit).resolve())
)
os.environ[mcp_daemon_guard.SESSION_STATE_DIR_ENV] = rogue
self.assertEqual(
guard.pinned_session_state_dir(), str(Path(legit).resolve())
)
def test_12b_test_mode_record_still_cannot_authorize_production(self):
mcp_daemon_guard.clear_native_runtime_for_tests()
mcp_daemon_guard.install_test_native_runtime()
self.assertTrue(mcp_daemon_guard.is_native_mcp_transport())
self.assertFalse(mcp_daemon_guard.is_production_native_mcp_transport())
with self.assertRaises(mcp_daemon_guard.UnsanctionedRuntimeError):
mcp_daemon_guard.assert_production_mutation_runtime("prod-endpoint")
def test_12c_bind_still_requires_the_canonical_entrypoint(self):
"""A remote identifier does not relax provenance."""
mcp_daemon_guard.clear_native_runtime_for_tests()
with patch.object(mcp_daemon_guard, "is_pytest_runtime", return_value=False):
with patch.object(
mcp_daemon_guard,
"_caller_official_entrypoint_path",
return_value=None,
):
with self.assertRaises(mcp_daemon_guard.UnsanctionedRuntimeError):
mcp_daemon_guard.bind_native_mcp_transport(
transport=mcp_transport_config.REMOTE_TRANSPORT
)
self.assertIsNone(mcp_daemon_guard.bound_transport())
def test_12d_bind_still_requires_a_prior_entrypoint_claim(self):
mcp_daemon_guard.clear_native_runtime_for_tests()
canonical = str((REPO_ROOT / "mcp_server.py").resolve())
with patch.object(mcp_daemon_guard, "is_pytest_runtime", return_value=False):
with patch.object(
mcp_daemon_guard,
"_caller_official_entrypoint_path",
side_effect=lambda: canonical,
):
# No mark_sanctioned_daemon() first.
with self.assertRaises(
mcp_daemon_guard.UnsanctionedRuntimeError
) as ctx:
mcp_daemon_guard.bind_native_mcp_transport()
self.assertIn("no entrypoint claim", str(ctx.exception))
def test_12e_auth_mint_verdict_is_unchanged_for_the_default_transport(self):
with _ProductionBind() as guard:
guard.bind_native_mcp_transport()
verdict = irrecoverable_provenance.assess_transport_for_auth_mint()
self.assertTrue(verdict["allowed"])
self.assertTrue(verdict["native_mcp_transport"])
self.assertTrue(verdict["production_native_mcp_transport"])
self.assertEqual(verdict["reasons"], [])
def test_12f_auth_mint_still_refuses_an_unbound_runtime(self):
with _ProductionBind():
# Claimed but never bound.
verdict = irrecoverable_provenance.assess_transport_for_auth_mint()
self.assertFalse(verdict["allowed"])
self.assertTrue(verdict["reasons"])
self.assertIsNone(verdict["bound_transport"])
class TestExecutionBoundary(unittest.TestCase):
"""Recognition is not execution authorization (#931, review 635 B1/B2).
A registered remote identifier must still bind, pin and record — the #931
seam — while being refused at the serve boundary, because serving it would
start a listener with no authentication or per-request principal. That
listener belongs to #938.
"""
def tearDown(self) -> None:
mcp_daemon_guard.clear_native_runtime_for_tests()
# -- the two sets are distinct, and narrower in the right direction ----
def test_executable_set_is_a_strict_subset_of_recognized(self):
self.assertTrue(
mcp_transport_config.EXECUTABLE_TRANSPORTS
< mcp_transport_config.SUPPORTED_TRANSPORTS
)
def test_default_transport_is_executable(self):
self.assertTrue(
mcp_transport_config.is_executable_transport(
mcp_transport_config.DEFAULT_TRANSPORT
)
)
def test_remote_transport_is_recognized_but_not_executable(self):
remote = mcp_transport_config.REMOTE_TRANSPORT
self.assertTrue(mcp_transport_config.is_supported_transport(remote))
self.assertFalse(mcp_transport_config.is_executable_transport(remote))
def test_remote_listener_ownership_is_declared(self):
self.assertEqual(
mcp_transport_config.TRANSPORT_EXECUTION_OWNER[
mcp_transport_config.REMOTE_TRANSPORT
],
"#938",
)
# -- stdio still reaches the runner, unchanged -------------------------
def test_default_transport_is_authorized_for_service(self):
with _ProductionBind() as guard:
guard.bind_native_mcp_transport()
self.assertEqual(
guard.authorize_transport_execution("tool service"),
mcp_transport_config.DEFAULT_TRANSPORT,
)
self.assertTrue(guard.assess_serve_authorization()["allowed"])
def test_default_transport_reaches_the_real_runner(self):
"""The production runner is actually invoked, with stdio, unchanged."""
with _ProductionBind() as guard:
guard.bind_native_mcp_transport()
seen = {}
class _Runner:
def run(self, transport=None, **kw):
seen["transport"] = transport
_Runner().run(transport=guard.authorize_transport_execution("tool service"))
self.assertEqual(
seen["transport"], mcp_transport_config.DEFAULT_TRANSPORT
)
# -- streamable-http binds, records, and is refused before serving -----
def test_remote_transport_binds_and_is_recorded(self):
"""The #931 seam is intact: it binds, pins and records."""
with _ProductionBind(
{
mcp_transport_config.TRANSPORT_ENV: (
mcp_transport_config.REMOTE_TRANSPORT
)
}
) as guard:
guard.bind_native_mcp_transport()
self.assertEqual(
guard.bound_transport(), mcp_transport_config.REMOTE_TRANSPORT
)
self.assertEqual(
guard.mutation_provenance_fields()["bound_transport"],
mcp_transport_config.REMOTE_TRANSPORT,
)
def test_remote_transport_is_refused_at_the_serve_boundary(self):
with _ProductionBind(
{
mcp_transport_config.TRANSPORT_ENV: (
mcp_transport_config.REMOTE_TRANSPORT
)
}
) as guard:
guard.bind_native_mcp_transport()
with self.assertRaises(guard.TransportExecutionError) as ctx:
guard.authorize_transport_execution("tool service")
err = ctx.exception
self.assertEqual(
err.blocker_kind,
mcp_transport_config.BLOCKER_LISTENER_NOT_COMMISSIONED,
)
self.assertEqual(err.owner_issue, "#938")
self.assertEqual(err.transport, mcp_transport_config.REMOTE_TRANSPORT)
def test_refusal_names_transport_and_unmet_requirement_and_owner(self):
with _ProductionBind(
{
mcp_transport_config.TRANSPORT_ENV: (
mcp_transport_config.REMOTE_TRANSPORT
)
}
) as guard:
guard.bind_native_mcp_transport()
with self.assertRaises(guard.TransportExecutionError) as ctx:
guard.authorize_transport_execution("tool service")
text = str(ctx.exception)
self.assertIn(mcp_transport_config.REMOTE_TRANSPORT, text)
self.assertIn("#938", text)
self.assertIn("not commissioned", text)
self.assertIn("#931", text)
def test_remote_transport_never_reaches_the_runner(self):
"""No transport value is handed to a run() call for the remote case."""
with _ProductionBind(
{
mcp_transport_config.TRANSPORT_ENV: (
mcp_transport_config.REMOTE_TRANSPORT
)
}
) as guard:
guard.bind_native_mcp_transport()
calls = []
class _Runner:
def run(self, transport=None, **kw):
calls.append(transport)
with self.assertRaises(guard.TransportExecutionError):
_Runner().run(
transport=guard.authorize_transport_execution("tool service")
)
self.assertEqual(calls, [], "runner must never be invoked")
def test_no_http_listener_is_created_for_remote_transport(self):
"""Nothing in the refusal path touches uvicorn or a socket bind."""
with _ProductionBind(
{
mcp_transport_config.TRANSPORT_ENV: (
mcp_transport_config.REMOTE_TRANSPORT
)
}
) as guard:
guard.bind_native_mcp_transport()
import socket
bound_sockets = []
real_bind = socket.socket.bind
def _tripwire(self, addr): # pragma: no cover - must not run
bound_sockets.append(addr)
return real_bind(self, addr)
with patch.object(socket.socket, "bind", _tripwire):
with self.assertRaises(guard.TransportExecutionError):
guard.authorize_transport_execution("tool service")
self.assertEqual(bound_sockets, [], "no socket may be bound")
def test_no_mutation_is_authorized_after_the_denial(self):
"""The denial leaves no partial state that would let a tool dispatch."""
with _ProductionBind(
{
mcp_transport_config.TRANSPORT_ENV: (
mcp_transport_config.REMOTE_TRANSPORT
)
}
) as guard:
guard.bind_native_mcp_transport()
with self.assertRaises(guard.TransportExecutionError):
guard.authorize_transport_execution("tool service")
# Serve stays unauthorized on every subsequent query.
self.assertFalse(guard.assess_serve_authorization()["allowed"])
self.assertFalse(guard.native_runtime_status()["serve_authorized"])
with self.assertRaises(guard.TransportExecutionError):
guard.authorize_transport_execution("tool service")
# -- B2: the decision genuinely consumes bound_transport ---------------
def test_serve_decision_consumes_bound_transport(self):
"""Changing only bound_transport flips the verdict."""
with _ProductionBind() as guard:
guard.bind_native_mcp_transport()
self.assertTrue(guard.assess_serve_authorization()["allowed"])
with patch.object(
guard,
"bound_transport",
return_value=mcp_transport_config.REMOTE_TRANSPORT,
):
verdict = guard.assess_serve_authorization()
self.assertFalse(verdict["allowed"])
self.assertEqual(
verdict["transport"], mcp_transport_config.REMOTE_TRANSPORT
)
with self.assertRaises(guard.TransportExecutionError):
guard.authorize_transport_execution("tool service")
def test_serve_verdict_reports_the_bound_transport(self):
with _ProductionBind(
{
mcp_transport_config.TRANSPORT_ENV: (
mcp_transport_config.REMOTE_TRANSPORT
)
}
) as guard:
guard.bind_native_mcp_transport()
verdict = guard.assess_serve_authorization()
self.assertEqual(
verdict["transport"], mcp_transport_config.REMOTE_TRANSPORT
)
self.assertTrue(verdict["recognized"])
self.assertFalse(verdict["executable"])
# -- earlier and later boundaries are unchanged ------------------------
def test_unregistered_identifier_still_fails_at_bind_not_at_serve(self):
with _ProductionBind(
{mcp_transport_config.TRANSPORT_ENV: "carrier-pigeon"}
) as guard:
with self.assertRaises(guard.UnsanctionedRuntimeError) as ctx:
guard.bind_native_mcp_transport()
self.assertIn("not a registered MCP transport", str(ctx.exception))
self.assertIsNone(guard.bound_transport())
def test_unbound_execution_keeps_the_pre_existing_failure(self):
with _ProductionBind() as guard:
with self.assertRaises(guard.UnsanctionedRuntimeError) as ctx:
guard.authorize_transport_execution("tool service")
self.assertIn("No MCP transport is bound", str(ctx.exception))
self.assertNotIsInstance(ctx.exception, guard.TransportExecutionError)
def test_transport_execution_error_is_caught_by_existing_handlers(self):
"""Subclassing keeps every pre-existing fail-closed handler correct."""
self.assertTrue(
issubclass(
mcp_daemon_guard.TransportExecutionError,
mcp_daemon_guard.UnsanctionedRuntimeError,
)
)
def test_test_mode_runtime_is_not_servable(self):
"""The pytest-only record is outside the recognized and executable sets."""
mcp_daemon_guard.clear_native_runtime_for_tests()
mcp_daemon_guard.install_test_native_runtime()
self.assertNotIn(
mcp_daemon_guard.bound_transport(),
mcp_transport_config.SUPPORTED_TRANSPORTS,
)
self.assertFalse(mcp_daemon_guard.assess_serve_authorization()["allowed"])
def test_serve_authorization_does_not_leak_across_runtimes(self):
"""A later runtime's verdict never reflects an earlier one."""
with _ProductionBind(
{
mcp_transport_config.TRANSPORT_ENV: (
mcp_transport_config.REMOTE_TRANSPORT
)
}
) as guard:
guard.bind_native_mcp_transport()
self.assertFalse(guard.assess_serve_authorization()["allowed"])
with _ProductionBind() as guard:
guard.bind_native_mcp_transport()
self.assertTrue(guard.assess_serve_authorization()["allowed"])
mcp_daemon_guard.clear_native_runtime_for_tests()
self.assertEqual(
mcp_daemon_guard.assess_serve_authorization()["blocker_kind"],
mcp_transport_config.BLOCKER_TRANSPORT_NOT_BOUND,
)
def test_refusal_carries_no_credential_material(self):
with _ProductionBind(
{
mcp_transport_config.TRANSPORT_ENV: (
mcp_transport_config.REMOTE_TRANSPORT
),
"GITEA_TOKEN": "super-secret-value",
}
) as guard:
guard.bind_native_mcp_transport()
with self.assertRaises(guard.TransportExecutionError) as ctx:
guard.authorize_transport_execution("tool service")
blob = str(ctx.exception) + repr(ctx.exception.assessment)
self.assertNotIn("super-secret-value", blob)
self.assertNotIn("GITEA_TOKEN", blob)
class TestEntrypointWiring(unittest.TestCase):
"""The live entrypoint must use the seam and the execution guard."""
def test_entrypoint_binds_without_a_literal_transport(self):
text = (REPO_ROOT / "gitea_mcp_server.py").read_text(encoding="utf-8")
self.assertIn("mcp_daemon_guard.bind_native_mcp_transport()", text)
self.assertNotIn('bind_native_mcp_transport(transport="stdio")', text)
def test_entrypoint_serves_only_through_the_execution_guard(self):
text = (REPO_ROOT / "gitea_mcp_server.py").read_text(encoding="utf-8")
self.assertIn(
"mcp.run(transport=mcp_daemon_guard.authorize_transport_execution", text
)
self.assertNotIn('mcp.run(transport="stdio")', text)
self.assertNotIn(
"mcp.run(transport=mcp_daemon_guard.assert_transport_bound", text
)
def test_every_run_call_in_production_goes_through_the_guard(self):
"""Glob the production surface: no serve site may bypass the guard."""
offenders: list[str] = []
run_sites = 0
for path in sorted(REPO_ROOT.glob("*.py")):
for lineno, line in enumerate(
path.read_text(encoding="utf-8").splitlines(), start=1
):
code = line.split("#", 1)[0]
if "mcp.run(" not in code:
continue
run_sites += 1
if "authorize_transport_execution" not in code:
offenders.append(f"{path.name}:{lineno}: {line.strip()}")
self.assertEqual(run_sites, 1, "expected exactly one serve site")
self.assertEqual(offenders, [], "\n".join(offenders))
if __name__ == "__main__":
unittest.main()