feat(egress-proxy): retarget remediation flow (PRD 0017 chunk 3) #30
@@ -278,7 +278,7 @@ def _run_agent_container(plan: DockerBottlePlan, internal_network: str) -> str:
|
||||
docker_args.extend(["-e", name])
|
||||
|
||||
# PRD 0013: read-only current-config mount so the agent can read
|
||||
# routes.json / allowlist / Dockerfile before composing a
|
||||
# routes.yaml / allowlist / Dockerfile before composing a
|
||||
# supervise tool-call proposal. Mounted from the per-bottle
|
||||
# stage_dir/current-config/ populated at prepare time.
|
||||
if plan.supervise_plan is not None:
|
||||
|
||||
@@ -425,7 +425,13 @@ def sha256_hex(content: str) -> str:
|
||||
# Filenames inside the per-bottle current-config dir. The agent reads
|
||||
# these (read-only) from CURRENT_CONFIG_DIR_IN_AGENT and proposes
|
||||
# modified versions back via the three MCP tools.
|
||||
CURRENT_CONFIG_ROUTES = "routes.json"
|
||||
# Filename of the staged egress-proxy routes file inside the agent's
|
||||
# read-only current-config mount. JSON content under a `.yaml`
|
||||
# extension to match the live file the egress-proxy sidecar reads
|
||||
# (`/etc/egress-proxy/routes.yaml`) — the egress-proxy-block tool
|
||||
# description points at this exact path, and the apply step writes
|
||||
# the new content to the matching live path.
|
||||
CURRENT_CONFIG_ROUTES = "routes.yaml"
|
||||
CURRENT_CONFIG_ALLOWLIST = "allowlist"
|
||||
CURRENT_CONFIG_DOCKERFILE = "Dockerfile"
|
||||
|
||||
@@ -437,7 +443,7 @@ class SupervisePlan:
|
||||
`queue_dir` is the host directory bind-mounted into the sidecar
|
||||
at /run/supervise/queue. `current_config_dir` is the host
|
||||
directory bind-mounted (read-only) into the *agent* container at
|
||||
/etc/claude-bottle/current-config, holding routes.json + allowlist
|
||||
/etc/claude-bottle/current-config, holding routes.yaml + allowlist
|
||||
+ Dockerfile so the agent can read them before composing a
|
||||
proposal. `internal_network` is empty at prepare time; the
|
||||
backend's launch step fills it via dataclasses.replace before
|
||||
|
||||
@@ -38,7 +38,7 @@ FIXED = datetime(2026, 5, 25, 12, 0, 0, tzinfo=timezone.utc)
|
||||
|
||||
|
||||
def _proposal(slug: str = "dev", tool: str = TOOL_EGRESS_PROXY_BLOCK) -> Proposal:
|
||||
# Per-tool payload shape: cred-proxy gets routes.json, pipelock
|
||||
# Per-tool payload shape: cred-proxy gets routes.yaml, pipelock
|
||||
# gets a failed URL (PR #25 follow-up), capability gets a
|
||||
# Dockerfile-ish blob. Match the production dispatch in
|
||||
# PROPOSED_FILE_FIELD.
|
||||
|
||||
@@ -297,9 +297,9 @@ class TestDiffAndHash(unittest.TestCase):
|
||||
self.assertEqual("", render_diff("a\nb\n", "a\nb\n"))
|
||||
|
||||
def test_render_diff_shows_changes(self):
|
||||
diff = render_diff("a\nb\nc\n", "a\nB\nc\n", label="routes.json")
|
||||
self.assertIn("routes.json (current)", diff)
|
||||
self.assertIn("routes.json (proposed)", diff)
|
||||
diff = render_diff("a\nb\nc\n", "a\nB\nc\n", label="routes.yaml")
|
||||
self.assertIn("routes.yaml (current)", diff)
|
||||
self.assertIn("routes.yaml (proposed)", diff)
|
||||
self.assertIn("-b", diff)
|
||||
self.assertIn("+B", diff)
|
||||
|
||||
@@ -365,7 +365,7 @@ class TestSupervisePrepare(unittest.TestCase):
|
||||
self.assertTrue(plan.current_config_dir.is_dir())
|
||||
self.assertEqual(
|
||||
'{"routes": [{"path": "/x/"}]}\n',
|
||||
(plan.current_config_dir / "routes.json").read_text(),
|
||||
(plan.current_config_dir / "routes.yaml").read_text(),
|
||||
)
|
||||
self.assertEqual(
|
||||
"example.com\n",
|
||||
@@ -382,7 +382,7 @@ class TestSupervisePrepare(unittest.TestCase):
|
||||
plan = _StubSupervise().prepare("dev", self.stage_dir)
|
||||
self.assertEqual(
|
||||
'{"routes": []}\n',
|
||||
(plan.current_config_dir / "routes.json").read_text(),
|
||||
(plan.current_config_dir / "routes.yaml").read_text(),
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user