Remove the public allow_test_bootstrap production seam so caller-controlled flags cannot forge native mutation provenance. Bind provenance to the resolved canonical entrypoint path plus a live stdio transport bind; basename-only mcp_server.py stack frames and import-only launch no longer authorize mutations. Test-mode install_test_native_runtime is pytest-only and cannot reach production Gitea mutation endpoints. Add AC9 regressions for both reviewer-found bypasses and related spoof vectors. Refs: PR #696 REQUEST_CHANGES at 253269c; issue #695 comments 11002/11005.
104 lines
4.1 KiB
Python
104 lines
4.1 KiB
Python
"""Tests for sanctioned MCP daemon guards (#558 / #695)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import unittest
|
|
from unittest.mock import patch
|
|
|
|
import mcp_daemon_guard
|
|
import gitea_auth
|
|
|
|
|
|
class TestMcpDaemonGuard(unittest.TestCase):
|
|
def tearDown(self) -> None:
|
|
mcp_daemon_guard.clear_native_runtime_for_tests()
|
|
os.environ.pop(mcp_daemon_guard.FORCE_PROVENANCE_FAIL_ENV, None)
|
|
|
|
def test_unsanctioned_blocks_mutation_runtime(self):
|
|
env = {k: v for k, v in os.environ.items() if k not in {
|
|
mcp_daemon_guard.SANCTIONED_DAEMON_ENV,
|
|
mcp_daemon_guard.ALLOW_DIRECT_IMPORT_ENV,
|
|
"PYTEST_CURRENT_TEST",
|
|
}}
|
|
env["GITEA_TEST_FORCE_UNSANCTIONED"] = "1"
|
|
with patch.dict(os.environ, env, clear=True):
|
|
with self.assertRaises(mcp_daemon_guard.UnsanctionedRuntimeError):
|
|
mcp_daemon_guard.assert_sanctioned_mutation_runtime("test")
|
|
|
|
def test_pytest_allows_runtime(self):
|
|
# Running under pytest already sets PYTEST_CURRENT_TEST.
|
|
mcp_daemon_guard.assert_sanctioned_mutation_runtime("pytest")
|
|
|
|
def test_test_native_runtime_install_under_pytest(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())
|
|
# Hermetic unit path still passes under pytest.
|
|
mcp_daemon_guard.assert_sanctioned_mutation_runtime("daemon")
|
|
# Production mutation gate rejects test-mode records.
|
|
with self.assertRaises(mcp_daemon_guard.UnsanctionedRuntimeError) as ctx:
|
|
mcp_daemon_guard.assert_production_mutation_runtime("gitea_mutation")
|
|
self.assertIn("Test-mode", str(ctx.exception))
|
|
|
|
def test_env_alone_insufficient_when_force_unsanctioned(self):
|
|
mcp_daemon_guard.clear_native_runtime_for_tests()
|
|
env = {
|
|
k: v
|
|
for k, v in os.environ.items()
|
|
if k not in {
|
|
mcp_daemon_guard.SANCTIONED_DAEMON_ENV,
|
|
mcp_daemon_guard.ALLOW_DIRECT_IMPORT_ENV,
|
|
"PYTEST_CURRENT_TEST",
|
|
}
|
|
}
|
|
env[mcp_daemon_guard.SANCTIONED_DAEMON_ENV] = "1"
|
|
env["GITEA_TEST_FORCE_UNSANCTIONED"] = "1"
|
|
with patch.dict(os.environ, env, clear=True):
|
|
with self.assertRaises(mcp_daemon_guard.UnsanctionedRuntimeError) as ctx:
|
|
mcp_daemon_guard.assert_sanctioned_mutation_runtime("env-spoof")
|
|
self.assertIn("not sufficient", str(ctx.exception))
|
|
|
|
def test_keychain_blocked_without_sanction(self):
|
|
env = {
|
|
k: v
|
|
for k, v in os.environ.items()
|
|
if k
|
|
not in {
|
|
mcp_daemon_guard.SANCTIONED_DAEMON_ENV,
|
|
mcp_daemon_guard.ALLOW_DIRECT_IMPORT_ENV,
|
|
mcp_daemon_guard.ALLOW_KEYCHAIN_CLI_ENV,
|
|
"PYTEST_CURRENT_TEST",
|
|
}
|
|
}
|
|
env["GITEA_TEST_FORCE_UNSANCTIONED"] = "1"
|
|
with patch.dict(os.environ, env, clear=True):
|
|
with self.assertRaises(mcp_daemon_guard.UnsanctionedRuntimeError):
|
|
mcp_daemon_guard.assert_keychain_access_allowed()
|
|
|
|
def test_get_auth_header_blocked_when_unsanctioned(self):
|
|
env = {
|
|
k: v
|
|
for k, v in os.environ.items()
|
|
if k
|
|
not in {
|
|
mcp_daemon_guard.SANCTIONED_DAEMON_ENV,
|
|
mcp_daemon_guard.ALLOW_DIRECT_IMPORT_ENV,
|
|
"PYTEST_CURRENT_TEST",
|
|
}
|
|
}
|
|
env["GITEA_TEST_FORCE_UNSANCTIONED"] = "1"
|
|
with patch.dict(os.environ, env, clear=True):
|
|
with self.assertRaises(mcp_daemon_guard.UnsanctionedRuntimeError):
|
|
gitea_auth.get_auth_header("gitea.prgs.cc")
|
|
|
|
def test_no_allow_test_bootstrap_public_parameter(self):
|
|
"""Production mark must not accept allow_test_bootstrap (#695)."""
|
|
sig = __import__("inspect").signature(mcp_daemon_guard.mark_sanctioned_daemon)
|
|
self.assertNotIn("allow_test_bootstrap", sig.parameters)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|