Fix container username and home mount

This commit is contained in:
Jeena 2026-01-21 23:58:15 +09:00
parent fc2e5b1bca
commit c387a7a365
4 changed files with 35 additions and 11 deletions

2
.gitignore vendored
View file

@ -1,2 +0,0 @@
container-home/*
!container-home/.gitkeep

View file

@ -9,7 +9,7 @@ the host.
- Arch Linuxbased image - Arch Linuxbased image
- Runs as the host user (same username, UID, GID) - Runs as the host user (same username, UID, GID)
- Mounts only the current project directory (same absolute path inside container) - Mounts only the current project directory (same absolute path inside container)
- Persists OpenCode state in ./container-home directory - Persists OpenCode state in XDG_DATA_HOME/opencode-container/container-home directory
- No access to SSH keys, passwords, or full `$HOME` - No access to SSH keys, passwords, or full `$HOME`
- Simple shell function (`opencode`) to launch interactively - Simple shell function (`opencode`) to launch interactively
@ -24,10 +24,14 @@ git clone https://git.jeena.net/jeena/opencode-container.git
Source the helper file `opencode.aliases` in your shell configuration Source the helper file `opencode.aliases` in your shell configuration
(`.bashrc` or `.zshrc`) so the `opencode` function is available in new sessions. (`.bashrc` or `.zshrc`) so the `opencode` function is available in new sessions.
We set up the ./container-home directory as a central $HOME inside of the We set up the XDG_DATA_HOME/opencode-container/container-home directory as a central $HOME inside of the
container, independent of the session or project directory we start in. This container, independent of the session or project directory we start in. This
presists the whole $HOME from inside the container so everything opencode persists the whole $HOME from inside the container so everything OpenCode
writes into config files, etc. presists there. writes into config files, etc. persists there.
## Environment Variables
- `XDG_DATA_HOME`: Override default data directory (default: ~/.local/share)
## Usage ## Usage

View file

@ -16,14 +16,35 @@ class OpenCodeContainer:
def __init__(self): def __init__(self):
self.project_path = Path.cwd().resolve() self.project_path = Path.cwd().resolve()
self.project_id = self._project_id(self.project_path) self.project_id = self._project_id(self.project_path)
# Store host user info once
self.host_username = os.environ.get('USER', 'dev')
self.host_uid = os.getuid()
self.host_gid = os.getgid()
self.container_name = f"oc-{self.project_path.name}-{self.project_id}" self.container_name = f"oc-{self.project_path.name}-{self.project_id}"
self.docker_context_dir = Path(__file__).resolve().parent self.docker_context_dir = Path(__file__).resolve().parent
def _get_xdg_data_home(self) -> Path:
"""Get XDG_DATA_HOME with fallback to ~/.local/share"""
xdg_data = os.environ.get('XDG_DATA_HOME')
if xdg_data:
return Path(xdg_data)
return Path.home() / '.local' / 'share'
@property
def container_home_path(self) -> Path:
"""Container home directory in XDG_DATA_HOME"""
return self._get_xdg_data_home() / 'opencode-container' / 'container-home'
# ========================= # =========================
# Public entrypoint # Public entrypoint
# ========================= # =========================
def run(self, args: list[str]) -> None: def run(self, args: list[str]) -> None:
# Ensure container home directory exists
self.container_home_path.mkdir(parents=True, exist_ok=True)
if not self.image_exists(): if not self.image_exists():
self.build_image() self.build_image()
@ -54,9 +75,12 @@ class OpenCodeContainer:
).returncode == 0 ).returncode == 0
def build_image(self) -> None: def build_image(self) -> None:
print(f"Building image '{self.IMAGE}'") print(f"Building image '{self.IMAGE}' with user {self.host_username} ({self.host_uid}:{self.host_gid})")
self._run([ self._run([
"docker", "build", "docker", "build",
"--build-arg", f"USERNAME={self.host_username}",
"--build-arg", f"UID={self.host_uid}",
"--build-arg", f"GID={self.host_gid}",
"-t", self.IMAGE, "-t", self.IMAGE,
str(self.docker_context_dir), str(self.docker_context_dir),
]) ])
@ -66,16 +90,14 @@ class OpenCodeContainer:
# ========================= # =========================
def create_container(self) -> None: def create_container(self) -> None:
uid = os.getuid()
gid = os.getgid()
print(f"Creating container '{self.container_name}'") print(f"Creating container '{self.container_name}'")
self._run([ self._run([
"docker", "create", "docker", "create",
"--name", self.container_name, "--name", self.container_name,
"--user", f"{uid}:{gid}", "--user", f"{self.host_uid}:{self.host_gid}",
"--volume", f"{self.project_path}:{self.project_path}", "--volume", f"{self.project_path}:{self.project_path}",
"--volume", f"{self.container_home_path}:/home/{self.host_username}",
self.IMAGE, self.IMAGE,
"sh", "-c", "sleep infinity", "sh", "-c", "sleep infinity",
]) ])