.devcontainer 目录及相关文件your-project/├── .devcontainer/│ ├── devcontainer.json│ ├── Dockerfile│ └── init-firewall.sh└── ...
devcontainer.json 中的 features 字段添加配置:{"name": "CodeBuddy Code Sandbox","features": {"ghcr.io/devcontainers-contrib/features/codebuddy-code:1": {"version": "latest"}},// ... 其他配置}
{"features": {"ghcr.io/devcontainers-contrib/features/codebuddy-code:1": {"version": "2.16.0"}}}
{"features": {"ghcr.io/devcontainers-contrib/features/codebuddy-code:1": {}}}
{"name": "CodeBuddy Code Sandbox","build": {"dockerfile": "Dockerfile","args": {"TZ": "${localEnv:TZ:America/Los_Angeles}","GIT_DELTA_VERSION": "0.18.2","ZSH_IN_DOCKER_VERSION": "1.2.0"}},"features": {"ghcr.io/devcontainers-contrib/features/codebuddy-code:1": {"version": "latest"}},"runArgs": ["--cap-add=NET_ADMIN","--cap-add=NET_RAW"],"customizations": {"vscode": {"extensions": ["dbaeumer.vscode-eslint","esbenp.prettier-vscode","eamodio.gitlens"],"settings": {"editor.formatOnSave": true,"editor.defaultFormatter": "esbenp.prettier-vscode","editor.codeActionsOnSave": {"source.fixAll.eslint": "explicit"},"terminal.integrated.defaultProfile.linux": "zsh","terminal.integrated.profiles.linux": {"bash": {"path": "bash","icon": "terminal-bash"},"zsh": {"path": "zsh"}}}}},"remoteUser": "node","mounts": ["source=codebuddy-code-bashhistory-${devcontainerId},target=/commandhistory,type=volume","source=codebuddy-code-config-${devcontainerId},target=/home/node/.codebuddy,type=volume"],"containerEnv": {"NODE_OPTIONS": "--max-old-space-size=4096","CODEBUDDY_CONFIG_DIR": "/home/node/.codebuddy","POWERLEVEL9K_DISABLE_GITSTATUS": "true"},"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=delegated","workspaceFolder": "/workspace","postStartCommand": "sudo /usr/local/bin/init-firewall.sh","waitFor": "postStartCommand"}
features - 声明使用 CodeBuddy Code Dev Containers Feature,支持版本管理version: "latest" - 使用最新版本(可替换为具体版本号如 "2.16.0")CODEBUDDY_CODE_VERSION 参数CODEBUDDY_CODE_VERSION 参数和手动安装命令):FROM node:20ARG TZENV TZ="$TZ"# Install basic development tools and iptables/ipsetRUN apt-get update && apt-get install -y --no-install-recommends \\less \\git \\procps \\sudo \\fzf \\zsh \\man-db \\unzip \\gnupg2 \\gh \\iptables \\ipset \\iproute2 \\dnsutils \\aggregate \\jq \\nano \\vim \\&& apt-get clean && rm -rf /var/lib/apt/lists/*# Ensure default node user has access to /usr/local/shareRUN mkdir -p /usr/local/share/npm-global && \\chown -R node:node /usr/local/shareARG USERNAME=node# Persist bash history.RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \\&& mkdir /commandhistory \\&& touch /commandhistory/.bash_history \\&& chown -R $USERNAME /commandhistory# Set `DEVCONTAINER` environment variable to help with orientationENV DEVCONTAINER=true# Create workspace and config directories and set permissionsRUN mkdir -p /workspace /home/node/.codebuddy && \\chown -R node:node /workspace /home/node/.codebuddyWORKDIR /workspaceARG GIT_DELTA_VERSION=0.18.2RUN ARCH=$(dpkg --print-architecture) && \\wget "https://github.com/dandavison/delta/releases/download/${GIT_DELTA_VERSION}/git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && \\sudo dpkg -i "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && \\rm "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb"# Set up non-root userUSER node# Install global packagesENV NPM_CONFIG_PREFIX=/usr/local/share/npm-globalENV PATH=$PATH:/usr/local/share/npm-global/bin# Set the default shell to zsh rather than shENV SHELL=/bin/zsh# Set the default editor and visualENV EDITOR=nanoENV VISUAL=nano# Default powerline10k themeARG ZSH_IN_DOCKER_VERSION=1.2.0RUN sh -c "$(wget -O- https://github.com/deluan/zsh-in-docker/releases/download/v${ZSH_IN_DOCKER_VERSION}/zsh-in-docker.sh)" -- \\-p git \\-p fzf \\-a "source /usr/share/doc/fzf/examples/key-bindings.zsh" \\-a "source /usr/share/doc/fzf/examples/completion.zsh" \\-a "export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \\-x# CodeBuddy Code will be installed via Dev Containers Feature# Copy and set up firewall scriptCOPY init-firewall.sh /usr/local/bin/USER rootRUN chmod +x /usr/local/bin/init-firewall.sh && \\echo "node ALL=(root) NOPASSWD: /usr/local/bin/init-firewall.sh" > /etc/sudoers.d/node-firewall && \\chmod 0440 /etc/sudoers.d/node-firewallUSER node
FROM node:20ARG TZENV TZ="$TZ"ARG CODEBUDDY_CODE_VERSION=latest# Install basic development tools and iptables/ipsetRUN apt-get update && apt-get install -y --no-install-recommends \\less \\git \\procps \\sudo \\fzf \\zsh \\man-db \\unzip \\gnupg2 \\gh \\iptables \\ipset \\iproute2 \\dnsutils \\aggregate \\jq \\nano \\vim \\&& apt-get clean && rm -rf /var/lib/apt/lists/*# Ensure default node user has access to /usr/local/shareRUN mkdir -p /usr/local/share/npm-global && \\chown -R node:node /usr/local/shareARG USERNAME=node# Persist bash history.RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \\&& mkdir /commandhistory \\&& touch /commandhistory/.bash_history \\&& chown -R $USERNAME /commandhistory# Set `DEVCONTAINER` environment variable to help with orientationENV DEVCONTAINER=true# Create workspace and config directories and set permissionsRUN mkdir -p /workspace /home/node/.codebuddy && \\chown -R node:node /workspace /home/node/.codebuddyWORKDIR /workspaceARG GIT_DELTA_VERSION=0.18.2RUN ARCH=$(dpkg --print-architecture) && \\wget "https://github.com/dandavison/delta/releases/download/${GIT_DELTA_VERSION}/git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && \\sudo dpkg -i "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && \\rm "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb"# Set up non-root userUSER node# Install global packagesENV NPM_CONFIG_PREFIX=/usr/local/share/npm-globalENV PATH=$PATH:/usr/local/share/npm-global/bin# Set the default shell to zsh rather than shENV SHELL=/bin/zsh# Set the default editor and visualENV EDITOR=nanoENV VISUAL=nano# Default powerline10k themeARG ZSH_IN_DOCKER_VERSION=1.2.0RUN sh -c "$(wget -O- https://github.com/deluan/zsh-in-docker/releases/download/v${ZSH_IN_DOCKER_VERSION}/zsh-in-docker.sh)" -- \\-p git \\-p fzf \\-a "source /usr/share/doc/fzf/examples/key-bindings.zsh" \\-a "source /usr/share/doc/fzf/examples/completion.zsh" \\-a "export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \\-x# Install CodeBuddy Code (manual installation method - only if not using Dev Containers Feature)RUN npm install -g @tencent-ai/codebuddy-code@${CODEBUDDY_CODE_VERSION}# Copy and set up firewall scriptCOPY init-firewall.sh /usr/local/bin/USER rootRUN chmod +x /usr/local/bin/init-firewall.sh && \\echo "node ALL=(root) NOPASSWD: /usr/local/bin/init-firewall.sh" > /etc/sudoers.d/node-firewall && \\chmod 0440 /etc/sudoers.d/node-firewallUSER node
build.args 需包含 "CODEBUDDY_CODE_VERSION" 参数,且 features 字段中不应包含 CodeBuddy Code Feature。#!/bin/bashset -euo pipefail # Exit on error, undefined vars, and pipeline failuresIFS=$'\\n\\t' # Stricter word splitting# 1. Extract Docker DNS info BEFORE any flushingDOCKER_DNS_RULES=$(iptables-save -t nat | grep "127\\.0\\.0\\.11" || true)# Flush existing rules and delete existing ipsetsiptables -Fiptables -Xiptables -t nat -Fiptables -t nat -Xiptables -t mangle -Fiptables -t mangle -Xipset destroy allowed-domains 2>/dev/null || true# 2. Selectively restore ONLY internal Docker DNS resolutionif [ -n "$DOCKER_DNS_RULES" ]; thenecho "Restoring Docker DNS rules..."iptables -t nat -N DOCKER_OUTPUT 2>/dev/null || trueiptables -t nat -N DOCKER_POSTROUTING 2>/dev/null || trueecho "$DOCKER_DNS_RULES" | xargs -L 1 iptables -t natelseecho "No Docker DNS rules to restore"fi# First allow DNS and localhost before any restrictions# Allow outbound DNSiptables -A OUTPUT -p udp --dport 53 -j ACCEPT# Allow inbound DNS responsesiptables -A INPUT -p udp --sport 53 -j ACCEPT# Allow outbound SSHiptables -A OUTPUT -p tcp --dport 22 -j ACCEPT# Allow inbound SSH responsesiptables -A INPUT -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT# Allow localhostiptables -A INPUT -i lo -j ACCEPTiptables -A OUTPUT -o lo -j ACCEPT# Create ipset with CIDR supportipset create allowed-domains hash:net# Fetch GitHub meta information and aggregate + add their IP rangesecho "Fetching GitHub IP ranges..."gh_ranges=$(curl -s https://api.github.com/meta)if [ -z "$gh_ranges" ]; thenecho "ERROR: Failed to fetch GitHub IP ranges"exit 1fiif ! echo "$gh_ranges" | jq -e '.web and .api and .git' >/dev/null; thenecho "ERROR: GitHub API response missing required fields"exit 1fiecho "Processing GitHub IPs..."while read -r cidr; doif [[ ! "$cidr" =~ ^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}/[0-9]{1,2}$ ]]; thenecho "ERROR: Invalid CIDR range from GitHub meta: $cidr"exit 1fiecho "Adding GitHub range $cidr"ipset add allowed-domains "$cidr"done < <(echo "$gh_ranges" | jq -r '(.web + .api + .git)[]' | aggregate -q)# Resolve and add other allowed domainsfor domain in \\"registry.npmjs.org" \\"copilot.tencent.com" \\"sentry.io" \\"marketplace.visualstudio.com" \\"vscode.blob.core.windows.net" \\"update.code.visualstudio.com"; doecho "Resolving $domain..."ips=$(dig +noall +answer A "$domain" | awk '$4 == "A" {print $5}')if [ -z "$ips" ]; thenecho "ERROR: Failed to resolve $domain"exit 1fiwhile read -r ip; doif [[ ! "$ip" =~ ^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$ ]]; thenecho "ERROR: Invalid IP from DNS for $domain: $ip"exit 1fiecho "Adding $ip for $domain"ipset add allowed-domains "$ip"done < <(echo "$ips")done# Get host IP from default routeHOST_IP=$(ip route | grep default | cut -d" " -f3)if [ -z "$HOST_IP" ]; thenecho "ERROR: Failed to detect host IP"exit 1fiHOST_NETWORK=$(echo "$HOST_IP" | sed "s/\\.[0-9]*$/.0\\/24/")echo "Host network detected as: $HOST_NETWORK"# Set up remaining iptables rulesiptables -A INPUT -s "$HOST_NETWORK" -j ACCEPTiptables -A OUTPUT -d "$HOST_NETWORK" -j ACCEPT# Set default policies to DROP firstiptables -P INPUT DROPiptables -P FORWARD DROPiptables -P OUTPUT DROP# First allow established connections for already approved trafficiptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPTiptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT# Then allow only specific outbound traffic to allowed domainsiptables -A OUTPUT -m set --match-set allowed-domains dst -j ACCEPT# Explicitly REJECT all other outbound traffic for immediate feedbackiptables -A OUTPUT -j REJECT --reject-with icmp-admin-prohibitedecho "Firewall configuration complete"echo "Verifying firewall rules..."if curl --connect-timeout 5 https://example.com >/dev/null 2>&1; thenecho "ERROR: Firewall verification failed - was able to reach https://example.com"exit 1elseecho "Firewall verification passed - unable to reach https://example.com as expected"fi# Verify GitHub API accessif ! curl --connect-timeout 5 https://api.github.com/zen >/dev/null 2>&1; thenecho "ERROR: Firewall verification failed - unable to reach https://api.github.com"exit 1elseecho "Firewall verification passed - able to reach https://api.github.com as expected"fi
-y (或 --dangerously-skip-permissions) 执行时,开发容器无法阻止恶意项目窃取容器内可访问的任何内容,包括 CodeBuddy Code 凭证。我们建议仅在处理可信仓库时使用开发容器。 始终保持良好的安全实践并监控 CodeBuddy 的活动。codebuddy -y (或 codebuddy --dangerously-skip-permissions) 来绕过权限提示,实现无人值守操作。文档反馈