docker mode: allow username override
This commit is contained in:
@@ -107,6 +107,15 @@ When a container starts with either label, it automatically appears in the dashb
|
|||||||
|
|
||||||
Containers that only specify `webterm-theme` are still included and use the default auto command.
|
Containers that only specify `webterm-theme` are still included and use the default auto command.
|
||||||
|
|
||||||
|
**Environment Variables:**
|
||||||
|
- `WEBTERM_DOCKER_USERNAME` - Set to run Docker exec sessions as a specific user (default: root)
|
||||||
|
- `WEBTERM_DOCKER_AUTO_COMMAND` - Override the default `auto` command (default: `tmux new-session -As webterm`)
|
||||||
|
|
||||||
|
Example: Start containers and exec into them as `developer` user:
|
||||||
|
```bash
|
||||||
|
WEBTERM_DOCKER_USERNAME=developer webterm --docker-watch
|
||||||
|
```
|
||||||
|
|
||||||
Example docker-compose.yaml:
|
Example docker-compose.yaml:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ DA_PARTIAL_PATTERN = re.compile(rb"\x1b(?:\[(?:\?[\d;]*)?)?$")
|
|||||||
class DockerExecSpec:
|
class DockerExecSpec:
|
||||||
container: str
|
container: str
|
||||||
command: list[str]
|
command: list[str]
|
||||||
|
user: str | None = None
|
||||||
|
|
||||||
|
|
||||||
class DockerExecSession(Session):
|
class DockerExecSession(Session):
|
||||||
@@ -162,6 +163,8 @@ class DockerExecSession(Session):
|
|||||||
"Tty": True,
|
"Tty": True,
|
||||||
"Cmd": self.exec_spec.command,
|
"Cmd": self.exec_spec.command,
|
||||||
}
|
}
|
||||||
|
if self.exec_spec.user:
|
||||||
|
payload["User"] = self.exec_spec.user
|
||||||
response = self._request_json(
|
response = self._request_json(
|
||||||
"POST", f"/containers/{self.exec_spec.container}/exec", payload
|
"POST", f"/containers/{self.exec_spec.container}/exec", payload
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
import shlex
|
import shlex
|
||||||
import sys
|
import sys
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
@@ -137,9 +138,11 @@ class SessionManager:
|
|||||||
log.warning("Sorry, webterm does not currently support terminals on Windows")
|
log.warning("Sorry, webterm does not currently support terminals on Windows")
|
||||||
return None
|
return None
|
||||||
if app.command == AUTO_COMMAND_SENTINEL:
|
if app.command == AUTO_COMMAND_SENTINEL:
|
||||||
|
docker_user = os.environ.get("WEBTERM_DOCKER_USERNAME")
|
||||||
exec_spec = DockerExecSpec(
|
exec_spec = DockerExecSpec(
|
||||||
container=app.name,
|
container=app.name,
|
||||||
command=shlex.split(_get_auto_command()),
|
command=shlex.split(_get_auto_command()),
|
||||||
|
user=docker_user,
|
||||||
)
|
)
|
||||||
session_process = DockerExecSession(self.poller, session_id, exec_spec)
|
session_process = DockerExecSession(self.poller, session_id, exec_spec)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -214,6 +214,32 @@ class TestSessionManager:
|
|||||||
|
|
||||||
assert result is not None
|
assert result is not None
|
||||||
assert isinstance(result, DockerExecSession)
|
assert isinstance(result, DockerExecSession)
|
||||||
|
assert result.exec_spec.user is None
|
||||||
|
|
||||||
|
async def test_new_docker_exec_session_with_user(self, mock_poller, mock_path, monkeypatch):
|
||||||
|
from webterm.docker_exec_session import DockerExecSession
|
||||||
|
|
||||||
|
monkeypatch.setenv("WEBTERM_DOCKER_USERNAME", "testuser")
|
||||||
|
|
||||||
|
app = App(
|
||||||
|
name="my-container",
|
||||||
|
slug="my-container",
|
||||||
|
path="./",
|
||||||
|
command=AUTO_COMMAND_SENTINEL,
|
||||||
|
terminal=True,
|
||||||
|
)
|
||||||
|
manager = SessionManager(mock_poller, mock_path, [app])
|
||||||
|
|
||||||
|
with patch.object(DockerExecSession, "open", new_callable=AsyncMock):
|
||||||
|
result = await manager.new_session(
|
||||||
|
"my-container",
|
||||||
|
SessionID("test-session"),
|
||||||
|
RouteKey("test-route"),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result is not None
|
||||||
|
assert isinstance(result, DockerExecSession)
|
||||||
|
assert result.exec_spec.user == "testuser"
|
||||||
|
|
||||||
|
|
||||||
class TestSessionManagerRoutes:
|
class TestSessionManagerRoutes:
|
||||||
|
|||||||
Reference in New Issue
Block a user