test(gateway): cover slow health clients
This commit is contained in:
+3
-1
@@ -56,7 +56,9 @@ Restart the deployed process after editing `config.json`. Long-running processes
|
|||||||
> When the WebSocket `host` is `0.0.0.0`, the channel refuses to start unless `token` or `tokenIssueSecret` is also configured. See [`webui.md#lan-access`](./webui.md#lan-access) for details.
|
> When the WebSocket `host` is `0.0.0.0`, the channel refuses to start unless `token` or `tokenIssueSecret` is also configured. See [`webui.md#lan-access`](./webui.md#lan-access) for details.
|
||||||
> The gateway health route itself is intentionally minimal and unauthenticated. When the
|
> The gateway health route itself is intentionally minimal and unauthenticated. When the
|
||||||
> container binds it to `0.0.0.0`, publish port `18790` to host loopback only; place any
|
> container binds it to `0.0.0.0`, publish port `18790` to host loopback only; place any
|
||||||
> remotely monitored health endpoint behind a firewall or reverse proxy.
|
> remotely monitored health endpoint behind a firewall or reverse proxy. If another host
|
||||||
|
> must probe it directly, replace `127.0.0.1` in the port mapping with a trusted host
|
||||||
|
> interface and restrict inbound traffic to the monitoring system.
|
||||||
|
|
||||||
### Docker Compose
|
### Docker Compose
|
||||||
|
|
||||||
|
|||||||
@@ -1022,7 +1022,8 @@ def _print_gateway_health_endpoint(host: str, port: int) -> None:
|
|||||||
return
|
return
|
||||||
|
|
||||||
console.print(
|
console.print(
|
||||||
"[yellow]Warning: the unauthenticated health endpoint is reachable beyond this device. "
|
"[yellow]Warning: the unauthenticated health endpoint is listening beyond loopback "
|
||||||
|
"and may be reachable from other devices. "
|
||||||
f"Keep port {port} private or protect it with a firewall or reverse proxy.[/yellow]"
|
f"Keep port {port} private or protect it with a firewall or reverse proxy.[/yellow]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -2889,6 +2889,7 @@ def test_gateway_health_endpoint_binds_and_serves_expected_responses(
|
|||||||
assert captured["port"] == 18791
|
assert captured["port"] == 18791
|
||||||
assert f"Health endpoint: {display_url}" in result.stdout
|
assert f"Health endpoint: {display_url}" in result.stdout
|
||||||
assert ("unauthenticated health endpoint" in result.stdout) is warns_about_public_bind
|
assert ("unauthenticated health endpoint" in result.stdout) is warns_about_public_bind
|
||||||
|
assert ("may be reachable from other devices" in result.stdout) is warns_about_public_bind
|
||||||
assert ("listening on 0.0.0.0" in result.stdout) is warns_about_public_bind
|
assert ("listening on 0.0.0.0" in result.stdout) is warns_about_public_bind
|
||||||
|
|
||||||
health_handler = captured["handler"]
|
health_handler = captured["handler"]
|
||||||
@@ -2954,6 +2955,16 @@ def test_gateway_health_endpoint_binds_and_serves_expected_responses(
|
|||||||
|
|
||||||
asyncio.run(_exercise_connection_limit())
|
asyncio.run(_exercise_connection_limit())
|
||||||
|
|
||||||
|
class _NeverRespondingReader:
|
||||||
|
async def read(self, _size: int) -> bytes:
|
||||||
|
await asyncio.Event().wait()
|
||||||
|
|
||||||
|
monkeypatch.setattr(cli_commands, "_GATEWAY_HEALTH_READ_TIMEOUT_SECONDS", 0.01)
|
||||||
|
timed_out_writer = _FakeWriter()
|
||||||
|
asyncio.run(health_handler(_NeverRespondingReader(), timed_out_writer))
|
||||||
|
assert timed_out_writer.closed is True
|
||||||
|
assert timed_out_writer.output == b""
|
||||||
|
|
||||||
|
|
||||||
def test_gateway_shutdown_lets_agent_task_own_mcp_cleanup(
|
def test_gateway_shutdown_lets_agent_task_own_mcp_cleanup(
|
||||||
monkeypatch,
|
monkeypatch,
|
||||||
|
|||||||
Reference in New Issue
Block a user