From c387a7a365ccf534b8bd781510b988881e44e600 Mon Sep 17 00:00:00 2001 From: Jeena Date: Wed, 21 Jan 2026 23:58:15 +0900 Subject: [PATCH 1/3] Fix container username and home mount --- .gitignore | 2 -- README.md | 12 ++++++++---- container-home/.gitkeep | 0 opencode-container.py | 32 +++++++++++++++++++++++++++----- 4 files changed, 35 insertions(+), 11 deletions(-) delete mode 100644 container-home/.gitkeep diff --git a/.gitignore b/.gitignore index 5781c7c..e69de29 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +0,0 @@ -container-home/* -!container-home/.gitkeep diff --git a/README.md b/README.md index 8983696..d1ca75f 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ the host. - Arch Linux–based image - Runs as the host user (same username, UID, GID) - 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` - 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 (`.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 -presists the whole $HOME from inside the container so everything opencode -writes into config files, etc. presists there. +persists the whole $HOME from inside the container so everything OpenCode +writes into config files, etc. persists there. + +## Environment Variables + +- `XDG_DATA_HOME`: Override default data directory (default: ~/.local/share) ## Usage diff --git a/container-home/.gitkeep b/container-home/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/opencode-container.py b/opencode-container.py index 6f95659..d4dcb96 100755 --- a/opencode-container.py +++ b/opencode-container.py @@ -16,14 +16,35 @@ class OpenCodeContainer: def __init__(self): self.project_path = Path.cwd().resolve() 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.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 # ========================= 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(): self.build_image() @@ -54,9 +75,12 @@ class OpenCodeContainer: ).returncode == 0 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([ "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, str(self.docker_context_dir), ]) @@ -66,16 +90,14 @@ class OpenCodeContainer: # ========================= def create_container(self) -> None: - uid = os.getuid() - gid = os.getgid() - print(f"Creating container '{self.container_name}'") self._run([ "docker", "create", "--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.container_home_path}:/home/{self.host_username}", self.IMAGE, "sh", "-c", "sleep infinity", ]) From 81717608073ccf0a2d1e647d4737492e6a9cfaa4 Mon Sep 17 00:00:00 2001 From: Jeena Date: Thu, 22 Jan 2026 00:29:20 +0900 Subject: [PATCH 2/3] Add cleanup script --- force-cleanup.sh | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100755 force-cleanup.sh diff --git a/force-cleanup.sh b/force-cleanup.sh new file mode 100755 index 0000000..1a0d9a5 --- /dev/null +++ b/force-cleanup.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# opencode-container-cleanup.sh - Complete cleanup script for OpenCode container + +set -e + +# Stop and remove all opencode containers +echo "Stopping and removing opencode containers..." +docker ps -q --filter "name=oc-" | xargs -r docker stop +docker ps -a -q --filter "name=oc-" | xargs -r docker rm -f + +# Remove the Docker image +echo "Removing opencode-container image..." +docker rmi opencode-container:latest 2>/dev/null || true + +# Remove entire opencode-container directory +CONTAINER_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/opencode-container" +if [ -d "$CONTAINER_DIR" ]; then + echo "Removing ~/.local/share/opencode-container directory..." + rm -rf "$CONTAINER_DIR" +fi + +echo "Complete cleanup finished!" From a56da84b7a3d58cc0587cd567eb10cb3191a3f33 Mon Sep 17 00:00:00 2001 From: Jeena Date: Thu, 22 Jan 2026 01:08:18 +0900 Subject: [PATCH 3/3] Prepopulate container-home with project dirs This is to fix the problem with docker creating those directories to mount it inside of the container-home. This only happens when the project path is inside of $HOME which is mounted to the .local/share/opencode-container/cantainer-home With it like this, the empty directories are owned by the local user and not root and it's easier to clean up in the future. --- opencode-container.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/opencode-container.py b/opencode-container.py index d4dcb96..84a7919 100755 --- a/opencode-container.py +++ b/opencode-container.py @@ -45,6 +45,14 @@ class OpenCodeContainer: # Ensure container home directory exists self.container_home_path.mkdir(parents=True, exist_ok=True) + # Pre-create project directory structure to prevent root-owned directories + try: + relative_path = self.project_path.relative_to(Path.home()) + (self.container_home_path / relative_path).mkdir(parents=True, exist_ok=True) + except ValueError: + # Project is outside home directory - no action needed + pass + if not self.image_exists(): self.build_image()