Skip to content

Instantly share code, notes, and snippets.

@rhuss
Created May 20, 2026 08:31
Show Gist options
  • Select an option

  • Save rhuss/0321c36106c10430c84a301c264b6510 to your computer and use it in GitHub Desktop.

Select an option

Save rhuss/0321c36106c10430c84a301c264b6510 to your computer and use it in GitHub Desktop.
OpenShell sandbox Containerfile for Claude Code (cc-deck) - reproduces getifaddrs issue with Vertex AI auth
# GENERATED BY cc-deck.build --target openshell - DO NOT EDIT MANUALLY
# Regenerate with: claude /cc-deck.build --target openshell
FROM ghcr.io/nvidia/openshell-community/sandboxes/base:latest
ARG TARGETARCH
# Layer: System packages (Ubuntu 24.04, apt-get)
# Pre-installed: git, node v22, npm, python3, curl, make, claude, gh, uv
USER root
RUN apt-get update && apt-get install -y --no-install-recommends \
zsh \
jq \
ripgrep \
bat \
binaryen \
fzf \
unzip \
xz-utils \
&& ln -sf /usr/bin/batcat /usr/bin/bat \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# Layer: Rust (via rustup, for sandbox user)
USER sandbox
ENV RUSTUP_HOME=/sandbox/.rustup CARGO_HOME=/sandbox/.cargo
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable \
&& . /sandbox/.cargo/env \
&& rustup target add wasm32-wasip1
ENV PATH="/sandbox/.cargo/bin:${PATH}"
USER root
# Layer: Go (official tarball)
RUN GOARCH=$([ "$(uname -m)" = "aarch64" ] && echo arm64 || echo amd64) && \
curl -fsSL "https://go.dev/dl/go1.25.3.linux-${GOARCH}.tar.gz" | tar -C /usr/local -xzf -
ENV PATH="/usr/local/go/bin:${PATH}"
# Layer: Developer tools from GitHub releases
RUN ARCH=$(uname -m) && \
GOARCH=$([ "$ARCH" = "aarch64" ] && echo arm64 || echo amd64) && \
# starship prompt
curl -fsSL https://starship.rs/install.sh | sh -s -- -y && \
# zoxide
curl -fsSL https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | sh && \
mv /root/.local/bin/zoxide /usr/local/bin/zoxide && \
# lsd
LSD_VER=$(curl -fsSL https://api.github.com/repos/lsd-rs/lsd/releases/latest | jq -r '.tag_name' | sed 's/^v//') && \
curl -fsSL "https://github.com/lsd-rs/lsd/releases/download/v${LSD_VER}/lsd-v${LSD_VER}-${ARCH}-unknown-linux-gnu.tar.gz" \
| tar xz -C /tmp && mv /tmp/lsd-v${LSD_VER}-${ARCH}-unknown-linux-gnu/lsd /usr/local/bin/lsd && \
# helix editor
HX_VER=$(curl -fsSL https://api.github.com/repos/helix-editor/helix/releases/latest | jq -r '.tag_name') && \
curl -fsSL "https://github.com/helix-editor/helix/releases/download/${HX_VER}/helix-${HX_VER}-${ARCH}-linux.tar.xz" \
| tar xJ -C /opt && ln -sf /opt/helix-${HX_VER}-${ARCH}-linux/hx /usr/local/bin/hx && \
# rtk (tar.gz, not tar.xz)
curl -fsSL "https://github.com/rtk-ai/rtk/releases/latest/download/rtk-${ARCH}-unknown-linux-gnu.tar.gz" \
| tar xz -C /usr/local/bin rtk && chmod +x /usr/local/bin/rtk && \
# abtop (nested in directory inside archive)
curl -fsSL "https://github.com/graykode/abtop/releases/latest/download/abtop-${ARCH}-unknown-linux-gnu.tar.xz" \
| tar xJ -C /tmp && mv /tmp/abtop-${ARCH}-unknown-linux-gnu/abtop /usr/local/bin/abtop && chmod +x /usr/local/bin/abtop && \
rm -rf /tmp/abtop-* && \
rm -rf /tmp/lsd-*
# ============================================================
# MANDATORY: cc-deck + Zellij + cc-session + cc-setup (DO NOT OMIT)
# ============================================================
# MANDATORY Layer: cc-session (nested archive)
RUN ARCH=$(uname -m) && \
curl -fsSL "https://github.com/cc-deck/cc-session/releases/latest/download/cc-session-${ARCH}-unknown-linux-gnu.tar.xz" \
| tar xJ -C /tmp && \
mv /tmp/cc-session-${ARCH}-unknown-linux-gnu/cc-session /usr/local/bin/cc-session && \
chmod +x /usr/local/bin/cc-session && \
rm -rf /tmp/cc-session-*
# MANDATORY Layer: cc-setup (Go-style naming: version-os-goarch.tar.gz)
RUN GOARCH=$([ "$(uname -m)" = "aarch64" ] && echo arm64 || echo amd64) && \
VERSION=$(curl -fsSL https://api.github.com/repos/cc-deck/cc-setup/releases/latest | jq -r '.tag_name' | sed 's/^v//') && \
curl -fsSL "https://github.com/cc-deck/cc-setup/releases/download/v${VERSION}/cc-setup-${VERSION}-linux-${GOARCH}.tar.gz" \
| tar xz -C /usr/local/bin cc-setup && \
chmod +x /usr/local/bin/cc-setup
# MANDATORY Layer: cc-deck self-install (Zellij + plugin + layouts + hooks)
COPY openshell/context/cc-deck-linux-${TARGETARCH} /usr/local/bin/cc-deck
RUN chmod +x /usr/local/bin/cc-deck && \
mkdir -p /sandbox/.claude /sandbox/.cache/zellij && \
HOME=/sandbox \
ZELLIJ_CONFIG_DIR=/sandbox/.config/zellij \
cc-deck config plugin install --install-zellij --force --skip-backup && \
chown -R sandbox:sandbox /sandbox/.config/zellij /sandbox/.cache/zellij /sandbox/.claude && \
rm -rf /root/.claude /root/.cache/zellij
# MANDATORY Layer: Claude Code (upgrade existing installation)
RUN mkdir -p /sandbox/.cache && chown sandbox:sandbox /sandbox/.cache
USER sandbox
RUN curl -fsSL https://claude.ai/install.sh | bash
USER root
ENV PATH="/sandbox/.local/bin:${PATH}"
# ============================================================
# Layer: Claude Code plugins
USER sandbox
RUN claude plugins marketplace add anthropics/claude-plugins-official && \
claude plugins marketplace add kepano/obsidian-skills && \
claude plugins install superpowers@claude-plugins-official && \
claude plugins install gopls-lsp@claude-plugins-official && \
claude plugins install rust-analyzer-lsp@claude-plugins-official && \
claude plugins install obsidian@obsidian-skills
USER root
# Layer: Skills directories
RUN mkdir -p /sandbox/.agents/skills/ /sandbox/.claude/skills/ && \
chown -R sandbox:sandbox /sandbox/.agents /sandbox/.claude
# Layer: OpenShell policy
RUN mkdir -p /etc/openshell
COPY openshell/policy.yaml /etc/openshell/policy.yaml
# Layer: Shell environment
ENV SHELL="/bin/zsh"
# Layer: User configuration
# Git identity
USER sandbox
RUN git config --global user.name "Roland Huß" && \
git config --global user.email "rhuss@redhat.com"
USER root
# Shell: set zsh as default, append custom config
RUN chsh -s /bin/zsh sandbox 2>/dev/null || usermod -s /bin/zsh sandbox
COPY --chown=sandbox:sandbox openshell/context/zshrc /sandbox/.zshrc.custom
RUN touch /sandbox/.zshrc && cat /sandbox/.zshrc.custom >> /sandbox/.zshrc && rm /sandbox/.zshrc.custom
# Zellij user config (controller block stripped, re-injected by cc-deck below)
COPY --chown=sandbox:sandbox openshell/context/zellij-config.kdl /sandbox/.config/zellij/config.kdl
COPY --chown=sandbox:sandbox openshell/context/zellij-theme-claude-dark.kdl /sandbox/.config/zellij/themes/claude-dark.kdl
RUN grep -qE '^default_shell' /sandbox/.config/zellij/config.kdl || \
echo 'default_shell "zsh"' >> /sandbox/.config/zellij/config.kdl
# Claude global instructions
COPY --chown=sandbox:sandbox openshell/context/CLAUDE.md /sandbox/.claude/CLAUDE.md
# Claude settings (merge with existing cc-deck hooks)
COPY --chown=sandbox:sandbox openshell/context/claude-settings.json /tmp/user-settings.json
RUN jq -s '.[0] * .[1]' /sandbox/.claude/settings.json /tmp/user-settings.json > /tmp/merged.json \
&& mv /tmp/merged.json /sandbox/.claude/settings.json \
&& chown sandbox:sandbox /sandbox/.claude/settings.json \
&& rm -f /tmp/user-settings.json
# cc-setup MCP cache
RUN mkdir -p /sandbox/.config/cc-setup
COPY --chown=sandbox:sandbox openshell/context/cc-setup-mcp.json /sandbox/.config/cc-setup/mcp.json
# Tool configs
COPY --chown=sandbox:sandbox openshell/context/starship.toml /sandbox/.config/starship.toml
RUN mkdir -p /sandbox/.config/helix
COPY --chown=sandbox:sandbox openshell/context/helix-config.toml /sandbox/.config/helix/config.toml
RUN mkdir -p /sandbox/.config/bat /sandbox/.config/lsd
COPY --chown=sandbox:sandbox openshell/context/bat-config /sandbox/.config/bat/config
COPY --chown=sandbox:sandbox openshell/context/lsd-config.yaml /sandbox/.config/lsd/config.yaml
# Re-inject cc-deck controller and hooks after config copies
USER sandbox
RUN cc-deck config plugin install --force --skip-backup
USER root
# RTK post-install
RUN mkdir -p /sandbox/.config/rtk && chown -R sandbox:sandbox /sandbox/.config/rtk
USER sandbox
RUN rtk init -g || true
USER root
# ============================================================
# FINAL SHELL SETUP (MUST come AFTER all user config COPY/RUN layers)
# These append to .bashrc/.zshrc and must not be overwritten by later steps.
# ============================================================
# Layer: Starship prompt init (if starship is available in the image)
RUN if command -v starship >/dev/null 2>&1; then \
for PAIR in "bash:/sandbox/.bashrc" "zsh:/sandbox/.zshrc"; do \
SHELL_NAME="${PAIR%%:*}"; RC="${PAIR#*:}"; \
if [ -f "$RC" ] && ! grep -q 'starship init' "$RC"; then \
echo 'eval "$(starship init '"$SHELL_NAME"')"' >> "$RC"; \
fi; \
done; \
fi
# Layer: Auto-start Zellij on interactive login (for cc-deck ws attach)
# This MUST be the LAST addition to shell rc files (exec replaces the shell).
RUN PREFERRED_SHELL=$(getent passwd sandbox | cut -d: -f7) && \
for RC in /sandbox/.bashrc /sandbox/.zshrc; do \
if [ -f "$RC" ] || [ "$(basename $RC)" = ".bashrc" ]; then \
printf '\n# cc-deck: auto-start Zellij with cc-deck layout on interactive login\nif [ -z "$ZELLIJ" ] && [ -t 0 ]; then\n export SHELL=%s\n exec zellij --layout cc-deck attach --create cc-deck\nfi\n' "$PREFERRED_SHELL" >> "$RC"; \
fi; \
done
# Layer: Fix ownership of all sandbox home files modified by root layers above.
RUN chown -R sandbox:sandbox /sandbox
USER sandbox
WORKDIR /sandbox
ENTRYPOINT ["/bin/bash"]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment