From a421d1d688f596d52081c358df4e3539168a3dab Mon Sep 17 00:00:00 2001 From: claude Date: Thu, 25 Jun 2026 01:23:10 +0000 Subject: [PATCH] Rename TOOL_ALLOW to TOOL_EGRESS_ALLOW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The constant and its MCP tool name ("allow" → "egress-allow") were the only supervise tools without an egress-scoped identifier, despite the tool being egress-only (routes.yaml payload, COMPONENT_FOR_TOOL maps it to "egress", always grouped with TOOL_EGRESS_BLOCK). The rename brings it in line with TOOL_EGRESS_BLOCK and TOOL_EGRESS_TOKEN_ALLOW, and adds TOOL_EGRESS_ALLOW and TOOL_EGRESS_BLOCK to __all__ (both were previously absent). --- bot_bottle/cli/supervise.py | 6 +++--- bot_bottle/supervise.py | 8 +++++--- bot_bottle/supervise_server.py | 8 ++++---- tests/unit/test_supervise.py | 4 ++-- tests/unit/test_supervise_cli.py | 2 +- tests/unit/test_supervise_server.py | 10 +++++----- 6 files changed, 20 insertions(+), 18 deletions(-) diff --git a/bot_bottle/cli/supervise.py b/bot_bottle/cli/supervise.py index 9db0b93..41f4a66 100644 --- a/bot_bottle/cli/supervise.py +++ b/bot_bottle/cli/supervise.py @@ -51,7 +51,7 @@ from ..supervise import ( STATUS_MODIFIED, STATUS_REJECTED, TOOL_CAPABILITY_BLOCK, - TOOL_ALLOW, + TOOL_EGRESS_ALLOW, TOOL_EGRESS_BLOCK, TOOL_GITLEAKS_ALLOW, TOOL_EGRESS_TOKEN_ALLOW, @@ -145,7 +145,7 @@ def _detail_lines( def _suffix_for_tool(tool: str) -> str: if tool == TOOL_CAPABILITY_BLOCK: return ".dockerfile" - if tool in (TOOL_ALLOW, TOOL_EGRESS_BLOCK): + if tool in (TOOL_EGRESS_ALLOW, TOOL_EGRESS_BLOCK): return ".yaml" if tool in (TOOL_GITLEAKS_ALLOW, TOOL_EGRESS_TOKEN_ALLOW): return ".txt" @@ -177,7 +177,7 @@ def approve( # diff_before, diff_after = apply_capability_change( # qp.proposal.bottle_slug, file_to_apply, # ) - if qp.proposal.tool in (TOOL_ALLOW, TOOL_EGRESS_BLOCK): + if qp.proposal.tool in (TOOL_EGRESS_ALLOW, TOOL_EGRESS_BLOCK): diff_before, diff_after = apply_routes_change( qp.proposal.bottle_slug, file_to_apply, diff --git a/bot_bottle/supervise.py b/bot_bottle/supervise.py index 7b1d56d..73ce0b2 100644 --- a/bot_bottle/supervise.py +++ b/bot_bottle/supervise.py @@ -50,14 +50,14 @@ SUPERVISE_PORT = 9100 TOOL_CAPABILITY_BLOCK = "capability-block" TOOL_EGRESS_BLOCK = "egress-block" -TOOL_ALLOW = "allow" +TOOL_EGRESS_ALLOW = "egress-allow" TOOL_GITLEAKS_ALLOW = "gitleaks-allow" # Written directly by the egress addon (not an agent-facing MCP tool) when an # outbound DLP token block is routed to the operator for override (PRD 0062). TOOL_EGRESS_TOKEN_ALLOW = "egress-token-allow" TOOL_LIST_EGRESS_ROUTES = "list-egress-routes" TOOLS: tuple[str, ...] = ( - TOOL_ALLOW, + TOOL_EGRESS_ALLOW, TOOL_CAPABILITY_BLOCK, TOOL_EGRESS_BLOCK, TOOL_GITLEAKS_ALLOW, @@ -80,7 +80,7 @@ EGRESS_INTROSPECT_URL = "http://_egress.local/allowlist" # here — those changes are captured by git history + the rebuild record # laid down in PRD 0016. COMPONENT_FOR_TOOL: dict[str, str] = { - TOOL_ALLOW: "egress", + TOOL_EGRESS_ALLOW: "egress", TOOL_EGRESS_BLOCK: "egress", } @@ -559,6 +559,8 @@ __all__ = [ "EGRESS_FORWARD_PROXY", "EGRESS_INTROSPECT_URL", "TOOL_CAPABILITY_BLOCK", + "TOOL_EGRESS_ALLOW", + "TOOL_EGRESS_BLOCK", "TOOL_GITLEAKS_ALLOW", "TOOL_EGRESS_TOKEN_ALLOW", "TOOL_LIST_EGRESS_ROUTES", diff --git a/bot_bottle/supervise_server.py b/bot_bottle/supervise_server.py index e529787..3e9ba1c 100644 --- a/bot_bottle/supervise_server.py +++ b/bot_bottle/supervise_server.py @@ -148,7 +148,7 @@ TOOL_DEFINITIONS: list[dict[str, object]] = [ "allowlist. Returns JSON with one entry per allowed host, " "each carrying its matches rules (if any) and whether " "the proxy injects Authorization for the route. Use this " - "before composing an `allow` or `egress-block` proposal so " + "before composing an `egress-allow` or `egress-block` proposal so " "the new routes file extends the live one rather than " "replacing it." ), @@ -159,7 +159,7 @@ TOOL_DEFINITIONS: list[dict[str, object]] = [ }, }, { - "name": _sv.TOOL_ALLOW, + "name": _sv.TOOL_EGRESS_ALLOW, "description": ( "Request operator approval to change the bottle's egress " "allowlist. Pass the full proposed routes.yaml content, not " @@ -276,7 +276,7 @@ TOOL_DEFINITIONS: list[dict[str, object]] = [ # Map each proposal tool to the input field that carries the agent's # payload (stored in Proposal.proposed_file). PROPOSED_FILE_FIELD: dict[str, str] = { - _sv.TOOL_ALLOW: "routes_yaml", + _sv.TOOL_EGRESS_ALLOW: "routes_yaml", _sv.TOOL_CAPABILITY_BLOCK: "dockerfile", _sv.TOOL_EGRESS_BLOCK: "routes_yaml", } @@ -295,7 +295,7 @@ def validate_proposed_file(tool: str, content: str) -> None: # Dockerfiles are too varied to validate syntactically beyond # non-empty. The operator reads the diff in the TUI. pass - elif tool in (_sv.TOOL_ALLOW, _sv.TOOL_EGRESS_BLOCK): + elif tool in (_sv.TOOL_EGRESS_ALLOW, _sv.TOOL_EGRESS_BLOCK): try: load_routes(content) except ValueError as e: diff --git a/tests/unit/test_supervise.py b/tests/unit/test_supervise.py index ed30ef2..58288e8 100644 --- a/tests/unit/test_supervise.py +++ b/tests/unit/test_supervise.py @@ -318,7 +318,7 @@ class TestToolConstants(unittest.TestCase): def test_tools_tuple_matches_individual_constants(self): self.assertEqual( ( - supervise.TOOL_ALLOW, + supervise.TOOL_EGRESS_ALLOW, TOOL_CAPABILITY_BLOCK, supervise.TOOL_EGRESS_BLOCK, TOOL_GITLEAKS_ALLOW, @@ -341,7 +341,7 @@ class TestToolConstants(unittest.TestCase): def test_component_map_has_egress_entries(self): self.assertEqual( { - supervise.TOOL_ALLOW: "egress", + supervise.TOOL_EGRESS_ALLOW: "egress", supervise.TOOL_EGRESS_BLOCK: "egress", }, supervise.COMPONENT_FOR_TOOL, diff --git a/tests/unit/test_supervise_cli.py b/tests/unit/test_supervise_cli.py index 63a7b47..43bcdd6 100644 --- a/tests/unit/test_supervise_cli.py +++ b/tests/unit/test_supervise_cli.py @@ -33,7 +33,7 @@ FIXED = datetime(2026, 5, 25, 12, 0, 0, tzinfo=timezone.utc) def _proposal(slug: str = "dev", tool: str = TOOL_CAPABILITY_BLOCK) -> Proposal: payloads = { TOOL_CAPABILITY_BLOCK: "FROM python:3.13\n", - supervise.TOOL_ALLOW: "routes:\n - host: example.com\n", + supervise.TOOL_EGRESS_ALLOW: "routes:\n - host: example.com\n", supervise.TOOL_EGRESS_BLOCK: "routes:\n - host: example.com\n", TOOL_GITLEAKS_ALLOW: "file: tests/test_fixture.py\nline: 3\n", TOOL_EGRESS_TOKEN_ALLOW: "host: api.example.com\ndetector: token\n", diff --git a/tests/unit/test_supervise_server.py b/tests/unit/test_supervise_server.py index a09a870..0535076 100644 --- a/tests/unit/test_supervise_server.py +++ b/tests/unit/test_supervise_server.py @@ -59,7 +59,7 @@ class TestValidation(unittest.TestCase): def test_egress_routes_yaml_is_validated(self): validate_proposed_file( - _sv.TOOL_ALLOW, + _sv.TOOL_EGRESS_ALLOW, "routes:\n - host: example.com\n", ) @@ -147,7 +147,7 @@ class TestHandleToolsList(unittest.TestCase): names = [t["name"] for t in result["tools"]] # type: ignore[index] self.assertEqual( sorted([ - _sv.TOOL_ALLOW, + _sv.TOOL_EGRESS_ALLOW, _sv.TOOL_CAPABILITY_BLOCK, _sv.TOOL_EGRESS_BLOCK, _sv.TOOL_LIST_EGRESS_ROUTES, @@ -181,7 +181,7 @@ class TestHandleToolsList(unittest.TestCase): self.assertNotIn("required", schema) # type: ignore[operator] def test_egress_tools_take_routes_yaml_and_justification(self): - for tool_name in (_sv.TOOL_ALLOW, _sv.TOOL_EGRESS_BLOCK): + for tool_name in (_sv.TOOL_EGRESS_ALLOW, _sv.TOOL_EGRESS_BLOCK): with self.subTest(tool_name=tool_name): tool = next(t for t in TOOL_DEFINITIONS if t["name"] == tool_name) schema = tool["inputSchema"] @@ -244,7 +244,7 @@ class TestHandleToolsCall(unittest.TestCase): try: result = handle_tools_call( { - "name": _sv.TOOL_ALLOW, + "name": _sv.TOOL_EGRESS_ALLOW, "arguments": { "routes_yaml": "routes:\n - host: example.com\n", "justification": "need example.com", @@ -451,7 +451,7 @@ class TestHttpEndToEnd(unittest.TestCase): self.assertEqual(1, result["id"]) names = [t["name"] for t in result["result"]["tools"]] # type: ignore[index] self.assertIn(_sv.TOOL_CAPABILITY_BLOCK, names) - self.assertIn(_sv.TOOL_ALLOW, names) + self.assertIn(_sv.TOOL_EGRESS_ALLOW, names) self.assertIn(_sv.TOOL_EGRESS_BLOCK, names) def test_unknown_method_returns_jsonrpc_error(self):