Skip to content
/ devtools Public

Containerized dev env that mirrors host paths/tools, with optional URL-allowlist proxy + secure GitHub auth injection

License

Notifications You must be signed in to change notification settings

kcosr/devtools

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

devtools

A containerized development environment with transparent URL-allowlisting proxy.

This guide assumes a Linux development environment, either local or accessed via SSH.

Why?

The goal is to provide security boundaries around file access while maintaining a mostly seamless development experience. The container should feel like a transparent pass-through of the host environment—matching paths, toolchains, and workflows—while isolating sensitive areas outside the designated workspace. This is useful for running AI coding assistants (Claude, Codex, pi, etc.) with controlled file and network access. Credentials can be kept on the host and injected via proxy, so tokens never exist inside the container.

This is an opinionated setup using host bind mounts for a pass-through experience. It can be adapted to your needs—see docs/SELF-CONTAINED.md for a traditional self-contained container approach.

Security note: The workspace directory is intended for development where content is acceptable to share with an LLM or between LLM sessions. Personal sensitive files should not be placed in the workspace directory, as it is fully accessible from within the container.

What is this?

This repo provides scripts and configuration to run your development work inside a Podman container with:

  • Minimal image - Uses host toolchains via bind mounts
  • Network control - Optional URL allowlisting via iptables and acl-proxy
  • Worktree workflow - Git worktree management with wt (worktrunk)
  • Path consistency - Same paths work on host and in container (~/worktrees/project)
  • State preservation - AI assistant configs, cargo/rustup, etc. persist between sessions

Prerequisites

  • Linux host (tested on Rocky Linux)
  • Rootless Podman (can be adapted for Docker)
  • Rust toolchain (for building acl-proxy and worktrunk)
  • sudo access (for iptables setup via nsenter)

SELinux (if enforcing)

If SELinux is in enforcing mode, containers may be blocked from reading certificate files. After starting the container and seeing permission errors, create a policy module to allow access:

# Generate and install policy from recent denials
sudo ausearch -m avc -ts recent | audit2allow -M container_certs
sudo semodule -i container_certs.pp

Install worktrunk (git worktree manager)

cargo install worktrunk

Then create the config file:

mkdir -p ~/.config/worktrunk
cat > ~/.config/worktrunk/config.toml << 'EOF'
# Worktree path template
# Creates: repo/branch as siblings
worktree-path = "../{{ branch | sanitize }}"
EOF

Quick Start

1. Clone this repo

git clone https://github.com/kcosr/devtools.git ~/devtools
cd ~/devtools

2. Build the container image

./container/build.sh

3. Create workspace and bind mount for path preservation

mkdir -p workspace/worktrees
mkdir -p ~/worktrees

# Add bind mount to /etc/fstab (requires sudo)
# Replace $USER with your actual username
echo "/home/$USER/devtools/workspace/worktrees /home/$USER/worktrees none bind 0 0" | sudo tee -a /etc/fstab

# Mount it now (mount looks up target path in fstab)
sudo mount /home/$USER/worktrees

Why bind mount instead of symlink? Git worktree stores absolute paths in .git metadata. A symlink would be resolved to the real path (e.g., ~/devtools/workspace/worktrees/...), breaking path consistency. A bind mount makes both paths identical at the kernel level, so git stores ~/worktrees/... which works in both host and container.

4. Add shell integration

# Copy completion scripts
mkdir -p ~/.bash_completion.d
cp host/bash_completion.d/*.bash ~/.bash_completion.d/

# Add devtools integration to your bashrc
cat host/bashrc.additions >> ~/.bashrc
source ~/.bashrc

Shell commands added

Command Description
c [dir] Launch container. Optional dir starts shell in that worktree.
w [dir] Navigate to workspace. w = workspace root, w myproject = worktree.
wt Worktrunk integration (alias override for wt clone around git clone). wt clone <url> creates a bare repo for worktrees.
y Copy stdin to clipboard via OSC 52. Usage: cat file | y

Tab completion works for c and w (completes worktree directories).

Tip: The w command is useful for running dev servers from the host after agents build inside the container. For example: w myproject && npm run start or w myproject/feature && cargo run. Since paths are consistent between host and container, you can build in the container and run on the host without copying files.

5. Launch a container

c                    # using the alias
# or
./container/run.sh   # directly

Usage

Basic shell

c                           # launch shell in workspace root
c myproject/main            # launch in specific worktree

Environment variables

Variable Default Description
PROXY 0 Enable transparent proxy (PROXY=1)
PERSISTENT 0 Keep container running between sessions
CONTAINER_NAME random Set a specific container name

Examples

# Ephemeral container (removed on exit)
./container/run.sh

# Persistent container
PERSISTENT=1 CONTAINER_NAME=dev ./container/run.sh

# With transparent proxy
PROXY=1 ./container/run.sh

# Run a command and exit
./container/run.sh cargo build --release

Stopping containers

Persistent containers keep running until you stop them:

podman stop devcontainer

To remove a stopped container:

podman rm devcontainer

Optional Add-ons

Transparent Proxy (URL allowlisting)

The proxy is an optional add-on for controlled environments. It runs on the host and the container routes outbound HTTP/HTTPS through it. It is experimental, but it has worked well for the current developer flows using Claude, Codex, and pi. Contributions are welcome, especially from folks with Rust and HTTP/2 expertise.

# Terminal 1: Start proxy
acl-proxy --config ~/devtools/proxy/acl-proxy.toml

# Terminal 2: Launch container with proxy
PROXY=1 c

See docs/PROXY.md for full setup (CA trust, allowlist rules, GitHub auth injection, troubleshooting).

Customization

Overlay files

Files in container/overlay/ are mounted into the container, overriding defaults:

Rename the placeholder home directory to match your username before running:

mv container/overlay/home/user container/overlay/home/$USER
  • overlay/home/<username>/.bashrc - Shell customization
  • overlay/home/<username>/.gitconfig - Set your name/email, or bind mount your existing .gitconfig in run.sh
  • overlay/home/<username>/.config/gh/ - GitHub CLI config

Adding tools

The container mounts /usr, /lib, and select /etc paths (certificates, resolv.conf, passwd, etc.) from the host. Install tools on the host and they're available in the container.

For container-specific tools, see docs/SELF-CONTAINED.md.

Directory Structure

devtools/
├── container/
│   ├── Dockerfile        # Minimal image definition
│   ├── build.sh          # Build script
│   ├── run.sh            # Container launcher
│   └── overlay/          # Config file overrides
│       └── home/user/     # User config overrides (rename to your username)
├── workspace/            # Your $HOME inside the container
│   └── worktrees/        # Git worktrees
├── proxy/
│   ├── acl-proxy.toml    # URL allowlist config
├── host/
│   ├── bashrc.additions  # Add to ~/.bashrc
│   └── bash_completion.d/
└── docs/
    ├── ARCHITECTURE.md   # How it works
    ├── PROXY.md          # Proxy details
    └── SELF-CONTAINED.md # Full Dockerfile option

Documentation

License

MIT

About

Containerized dev env that mirrors host paths/tools, with optional URL-allowlist proxy + secure GitHub auth injection

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published