fix: restore RFC SSH defaults for dockerized dev sessions
linuztx committed
Mar 8, 2026 at 19:28 UTC
7da508d1cd74a8930b73925bc390e4b32c9df1f9
3 files changed
+62
-25
plugins/code_execution/default_config.yaml
+8
-5
@@ -1,10 +1,13 @@
1
-# Shell interface: false = local TTY, true = SSH
2
-ssh_enabled: false
1
+# Shell interface: auto = auto-detect (SSH when non-dockerized, local when dockerized),
2
+# true = always SSH, false = always local TTY
3
+ssh_enabled: auto
4
4
-# SSH credentials (used when ssh_enabled is true)
5
-ssh_addr: localhost
6
-ssh_port: 22
5
+# SSH credentials (used when ssh_enabled is true or auto-detected)
6
+# ssh_addr: derived from rfc_url setting when empty
7
+ssh_addr: ""
8
+ssh_port: 55022
9
ssh_user: root
10
+# ssh_pass: uses root_password from RFC exchange when empty
11
ssh_pass: ""
12
13
# Timeouts for python/nodejs/terminal runtimes (seconds)
plugins/code_execution/tools/code_execution_tool.py
+39
-7
@@ -5,7 +5,7 @@ import shlex
5
import time
6
7
from helpers.tool import Tool, Response
8
-from helpers import files, projects, runtime, settings
8
+from helpers import files, rfc_exchange, projects, runtime, settings
9
from helpers.print_style import PrintStyle
10
from helpers.strings import truncate_text as truncate_text_string
11
from helpers.messages import truncate_text as truncate_text_agent
@@ -15,15 +15,46 @@ from plugins.code_execution.helpers.shell_local import LocalInteractiveSession
15
from plugins.code_execution.helpers.shell_ssh import SSHInteractiveSession
16
17
18
+def _resolve_ssh_enabled(raw_value) -> bool:
19
+ """Resolve ssh_enabled: 'auto' detects based on dockerized state."""
20
+ val = str(raw_value).strip().lower()
21
+ if val == "auto":
22
+ return not runtime.is_dockerized()
23
+ return val in ("true", "1", "yes", "on")
24
+
25
+
26
+def _resolve_ssh_addr(cfg_addr: str) -> str:
27
+ """Resolve SSH address: fall back to rfc_url from settings when empty."""
28
+ if cfg_addr:
29
+ return cfg_addr
30
+ set = settings.get_settings()
31
+ host = set.get("rfc_url", "localhost")
32
+ # Strip protocol and port from URL
33
+ if "//" in host:
34
+ host = host.split("//")[1]
35
+ if ":" in host:
36
+ host = host.split(":")[0]
37
+ if host.endswith("/"):
38
+ host = host.rstrip("/")
39
+ return host or "localhost"
40
+
41
+
42
+async def _resolve_ssh_pass(cfg_pass: str) -> str:
43
+ """Resolve SSH password: fall back to root_password via RFC when empty."""
44
+ if cfg_pass:
45
+ return cfg_pass
46
+ return await rfc_exchange.get_root_password()
47
+
48
+
49
def _get_config(agent) -> dict:
50
cfg = plugins.get_plugin_config("code_execution", agent=agent) or {}
51
21
- # SSH / TTY switch
22
- ssh_enabled = bool(cfg.get("ssh_enabled", False))
52
+ # SSH / TTY switch (supports auto/true/false)
53
+ ssh_enabled = _resolve_ssh_enabled(cfg.get("ssh_enabled", "auto"))
54
24
- # SSH credentials
25
- ssh_addr = str(cfg.get("ssh_addr", "localhost"))
26
- ssh_port = int(cfg.get("ssh_port", 22))
55
+ # SSH credentials (with RFC fallbacks)
56
+ ssh_addr = _resolve_ssh_addr(str(cfg.get("ssh_addr", "")))
57
+ ssh_port = int(cfg.get("ssh_port", 55022))
58
ssh_user = str(cfg.get("ssh_user", "root"))
59
ssh_pass = str(cfg.get("ssh_pass", ""))
60
@@ -186,12 +217,13 @@ class CodeExecution(Tool):
217
if session is not None and session not in shells:
218
cwd = await self.ensure_cwd()
219
if ssh_enabled:
220
+ ssh_pass = await _resolve_ssh_pass(cfg["ssh_pass"])
221
shell = SSHInteractiveSession(
222
self.agent.context.log,
223
cfg["ssh_addr"],
224
cfg["ssh_port"],
225
cfg["ssh_user"],
194
- cfg["ssh_pass"],
226
+ ssh_pass,
227
cwd=cwd,
228
)
229
else:
plugins/code_execution/webui/config.html
+15
-13
@@ -15,36 +15,38 @@
15
<!-- Shell Interface -->
16
<div class="field">
17
<div class="field-label">
18
- <div class="field-title">Use SSH</div>
18
+ <div class="field-title">Shell Interface</div>
19
<div class="field-description">
20
- When enabled, code execution connects via SSH using the credentials below. When disabled, a local Python TTY is used.
20
+ <b>Auto</b>: SSH when running outside Docker, local TTY when dockerized.
21
+ <b>SSH</b>: always connect via SSH. <b>Local</b>: always use local PTY.
22
</div>
23
</div>
24
<div class="field-control">
24
- <label class="toggle">
25
- <input type="checkbox" x-model="$store.pluginSettings.settings.ssh_enabled" />
26
- <span class="toggler"></span>
27
- </label>
25
+ <select x-model="$store.pluginSettings.settings.ssh_enabled">
26
+ <option value="auto">Auto</option>
27
+ <option value="true">SSH</option>
28
+ <option value="false">Local TTY</option>
29
+ </select>
30
</div>
31
</div>
32
31
- <!-- SSH credentials (shown only when SSH is enabled) -->
32
- <template x-if="$store.pluginSettings.settings.ssh_enabled">
33
+ <!-- SSH credentials (shown when SSH or Auto) -->
34
+ <template x-if="$store.pluginSettings.settings.ssh_enabled !== 'false'">
35
<div>
36
<div class="field">
37
<div class="field-label">
38
<div class="field-title">SSH Address</div>
37
- <div class="field-description">Hostname or IP of the SSH target.</div>
39
+ <div class="field-description">Hostname or IP of the SSH target. Leave empty to use the RFC URL from settings.</div>
40
</div>
41
<div class="field-control">
40
- <input type="text" x-model="$store.pluginSettings.settings.ssh_addr" placeholder="localhost" />
42
+ <input type="text" x-model="$store.pluginSettings.settings.ssh_addr" placeholder="(from RFC URL)" />
43
</div>
44
</div>
45
46
<div class="field">
47
<div class="field-label">
48
<div class="field-title">SSH Port</div>
47
- <div class="field-description">SSH port on the target host.</div>
49
+ <div class="field-description">SSH port on the target host (default: 55022 for Docker RFC).</div>
50
</div>
51
<div class="field-control">
52
<input type="number" min="1" max="65535" x-model.number="$store.pluginSettings.settings.ssh_port" />
@@ -64,10 +66,10 @@
66
<div class="field">
67
<div class="field-label">
68
<div class="field-title">SSH Password</div>
67
- <div class="field-description">Password for SSH login.</div>
69
+ <div class="field-description">Password for SSH login. Leave empty to use the dev root password (via RFC).</div>
70
</div>
71
<div class="field-control">
70
- <input type="password" autocomplete="off" x-model="$store.pluginSettings.settings.ssh_pass" />
72
+ <input type="password" autocomplete="off" x-model="$store.pluginSettings.settings.ssh_pass" placeholder="(from RFC)" />
73
</div>
74
</div>
75
</div>