Compare commits
2 commits
e8b007ad74
...
68bccdd1ec
| Author | SHA1 | Date | |
|---|---|---|---|
| 68bccdd1ec | |||
| 22138474b8 |
3 changed files with 29 additions and 3 deletions
|
|
@ -19,7 +19,7 @@ there is no MCP server for Codex agents.
|
|||
| Context | URL |
|
||||
|---------|-----|
|
||||
| Local workstation | `http://127.0.0.1:8000` |
|
||||
| Remote via tunnel | `http://127.0.0.1:18000` |
|
||||
| Remote (railiance01, in-cluster) | `http://10.43.68.154:8000` |
|
||||
| Optional local edge relay | http://127.0.0.1:18080 |
|
||||
|
||||
When an operator has enabled the edge relay, set API_BASE to the relay URL.
|
||||
|
|
|
|||
|
|
@ -29,7 +29,17 @@ def build_ssh_command(cfg: TunnelConfig, cert_path: Optional[Path] = None) -> Li
|
|||
"""Build the SSH tunnel command (reverse -R or local -L)."""
|
||||
key = os.path.expanduser(cfg.ssh_key)
|
||||
if cfg.direction == "local":
|
||||
forward_flag = ["-L", f"{cfg.local_port}:{cfg.remote_host}:{cfg.remote_port}"]
|
||||
# Bind the forward explicitly to 127.0.0.1. Without a bind address ssh
|
||||
# listens on every loopback family, so if another process already holds
|
||||
# the IPv4 port the IPv6 bind still succeeds and ExitOnForwardFailure
|
||||
# never fires — the tunnel comes up on [::1] and every client that
|
||||
# resolves 127.0.0.1 silently reaches the other process instead.
|
||||
# That is how a local State Hub cache impersonated the primary for
|
||||
# seven weeks (CUST-WP-0067-T02).
|
||||
forward_flag = [
|
||||
"-L",
|
||||
f"127.0.0.1:{cfg.local_port}:{cfg.remote_host}:{cfg.remote_port}",
|
||||
]
|
||||
else:
|
||||
forward_flag = ["-R", f"{cfg.remote_port}:{cfg.remote_host}:{cfg.local_port}"]
|
||||
cmd = [
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@ def tunnel_cfg():
|
|||
)
|
||||
|
||||
|
||||
def cmd_value(cmd, flag):
|
||||
"""Return the argument following ``flag`` in an argv list."""
|
||||
return cmd[cmd.index(flag) + 1]
|
||||
|
||||
@pytest.fixture
|
||||
def state_dir(tmp_path):
|
||||
return tmp_path / "bridge"
|
||||
|
|
@ -44,7 +48,19 @@ class TestBuildSshCommand:
|
|||
cfg = replace(tunnel_cfg, direction="local", remote_host="10.43.103.154")
|
||||
cmd = build_ssh_command(cfg)
|
||||
assert "-L" in cmd
|
||||
assert f"{cfg.local_port}:10.43.103.154:{cfg.remote_port}" in cmd
|
||||
assert f"127.0.0.1:{cfg.local_port}:10.43.103.154:{cfg.remote_port}" in cmd
|
||||
|
||||
def test_local_forward_pins_bind_address(self, tunnel_cfg):
|
||||
"""An unbound -L also listens on [::1], so a taken IPv4 port does not fail.
|
||||
|
||||
ExitOnForwardFailure only fires when every requested bind fails. Pinning
|
||||
127.0.0.1 makes a port collision loud instead of routing clients to
|
||||
whatever else holds the port (CUST-WP-0067-T02).
|
||||
"""
|
||||
cfg = replace(tunnel_cfg, direction="local")
|
||||
forward = cmd_value(build_ssh_command(cfg), "-L")
|
||||
assert forward.startswith("127.0.0.1:")
|
||||
assert forward.count(":") == 3
|
||||
|
||||
def test_remote_host_default_loopback(self, tunnel_cfg):
|
||||
cmd = build_ssh_command(tunnel_cfg)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue