From 92dece23fdddca1d447f5f9dc4370ad3842ac04a Mon Sep 17 00:00:00 2001 From: Claude CoWork Date: Mon, 22 Jun 2026 10:12:57 +0000 Subject: [PATCH] feat(code-server): add VS Code in browser image variant (WOVED-35) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds Dockerfile.code-server (extends codercom/code-server with gh CLI, tmux, ripgrep, jq, and the @openai/codex + @anthropic-ai/claude-code npm CLIs) plus a custom entrypoint that wires git identity and gh auth from environment variables on every pod start. Separate from the existing codex/claude TTY variants — code-server is a long-lived browser IDE, not a TTY-fronted agent shell. Built as a third variant of the codex-shell image registry at ghcr.io/nprodromou/codex-shell:code-server-latest Deployed on apk8s at code-server.prodromou.com via agents/code-server Kustomization (apk8s PR #165, WOVED-35). Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/build-code-server.yml | 67 +++++++++++++++++++++++++ Dockerfile.code-server | 63 +++++++++++++++++++++++ bin/code-server-entrypoint.sh | 32 ++++++++++++ 3 files changed, 162 insertions(+) create mode 100644 .github/workflows/build-code-server.yml create mode 100644 Dockerfile.code-server create mode 100644 bin/code-server-entrypoint.sh diff --git a/.github/workflows/build-code-server.yml b/.github/workflows/build-code-server.yml new file mode 100644 index 0000000..ec52a6d --- /dev/null +++ b/.github/workflows/build-code-server.yml @@ -0,0 +1,67 @@ +name: build-code-server + +on: + push: + branches: [main] + paths: + - "Dockerfile.code-server" + - "bin/code-server-entrypoint.sh" + - ".github/workflows/build-code-server.yml" + tags: ["v*"] + pull_request: + branches: [main] + paths: + - "Dockerfile.code-server" + - "bin/code-server-entrypoint.sh" + - ".github/workflows/build-code-server.yml" + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GHCR + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Compute tags + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + flavor: | + latest=false + tags: | + type=raw,value=code-server-latest,enable=${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + type=ref,event=branch,suffix=-code-server + type=ref,event=pr,suffix=-code-server + type=sha,prefix=sha-,suffix=-code-server,format=short + type=semver,pattern={{version}},suffix=-code-server + type=semver,pattern={{major}}.{{minor}},suffix=-code-server + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + file: Dockerfile.code-server + platforms: linux/amd64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha,scope=code-server + cache-to: type=gha,mode=max,scope=code-server diff --git a/Dockerfile.code-server b/Dockerfile.code-server new file mode 100644 index 0000000..c8f1a02 --- /dev/null +++ b/Dockerfile.code-server @@ -0,0 +1,63 @@ +# code-server image — VS Code in the browser for apk8s. +# Extends codercom/code-server with the agent toolchain: gh CLI, tmux, +# ripgrep, jq, and the codex + claude-code CLIs so the integrated terminal +# can run them without a separate setup step. +# +# Deployed under agents/code-server in apk8s (WOVED-35). +# Accessible at code-server.prodromou.com via CF Tunnel + Cloudflare Access. +# Identity (gh auth, git config) is wired up by the custom entrypoint from +# GH_TOKEN / GIT_USER_NAME / GIT_USER_EMAIL in the pod secret. + +FROM codercom/code-server:latest + +USER root + +# ── gh CLI ──────────────────────────────────────────────────────────────── +# renovate: datasource=github-releases depName=cli/cli +ARG GH_VERSION=v2.87.3 + +# ── Agent CLIs (npm) ────────────────────────────────────────────────────── +# renovate: datasource=npm depName=@openai/codex +ARG OPENAI_CODEX_VERSION=0.130.0 +# renovate: datasource=npm depName=@anthropic-ai/claude-code +ARG CLAUDE_CODE_VERSION=2.1.139 + +# Disable Claude Code's runtime auto-updater — version is pinned above and +# bumped by Renovate PRs, so the in-process updater would only produce a +# noisy banner and then fail (npm rename inside /usr/bin/ requires root). +ENV DISABLE_AUTOUPDATER=true + +# Install system tools, gh CLI, and npm-based agent CLIs in one layer. +RUN set -eux; \ + apt-get update; \ + apt-get install -y --no-install-recommends \ + tmux ripgrep fd-find jq unzip curl; \ + # fd is renamed fdfind on Debian; expose canonical name. + ln -sf /usr/bin/fdfind /usr/local/bin/fd; \ + \ + # gh CLI — pinned upstream binary release. + arch="$(dpkg --print-architecture)"; \ + GH_VER="${GH_VERSION#v}"; \ + curl -fsSL \ + "https://github.com/cli/cli/releases/download/${GH_VERSION}/gh_${GH_VER}_linux_${arch}.tar.gz" \ + | tar -xz -C /tmp; \ + mv "/tmp/gh_${GH_VER}_linux_${arch}/bin/gh" /usr/local/bin/gh; \ + rm -rf "/tmp/gh_${GH_VER}_linux_${arch}"; \ + gh --version; \ + \ + # Agent CLIs via npm. code-server's base image ships Node.js; we + # install these as root so they land in /usr/bin/{codex,claude}. + npm install -g \ + "@openai/codex@${OPENAI_CODEX_VERSION}" \ + "@anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}"; \ + npm cache clean --force; \ + \ + rm -rf /var/lib/apt/lists/* + +# Custom entrypoint — configures git identity + gh auth from env, then +# execs the upstream code-server binary. +COPY --chmod=0755 bin/code-server-entrypoint.sh /usr/local/bin/code-server-entrypoint.sh + +USER coder + +ENTRYPOINT ["/usr/local/bin/code-server-entrypoint.sh"] diff --git a/bin/code-server-entrypoint.sh b/bin/code-server-entrypoint.sh new file mode 100644 index 0000000..296b066 --- /dev/null +++ b/bin/code-server-entrypoint.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# code-server entrypoint. +# +# Runs as the `coder` user (uid 1000). On every pod start: +# 1. Wires git identity from GIT_USER_NAME / GIT_USER_EMAIL env vars. +# 2. Logs gh CLI in with GH_TOKEN (if present). +# 3. Execs the upstream code-server binary (reads ~/.config/code-server/ +# config.yaml — mounted from ConfigMap with auth: none). +# +# Identity env vars come from the code-server-secret ExternalSecret in apk8s +# (backed by the `agents-code-server` 1Password item). + +set -euo pipefail + +# ── Git identity ──────────────────────────────────────────────────────────── +if [[ -n "${GIT_USER_NAME:-}" ]]; then + git config --global user.name "${GIT_USER_NAME}" +fi +if [[ -n "${GIT_USER_EMAIL:-}" ]]; then + git config --global user.email "${GIT_USER_EMAIL}" +fi + +# ── gh auth ──────────────────────────────────────────────────────────────── +if [[ -n "${GH_TOKEN:-}" ]]; then + echo "${GH_TOKEN}" | gh auth login --with-token 2>/dev/null || true +fi + +# ── Start code-server ─────────────────────────────────────────────────────── +# Config is mounted at ~/.config/code-server/config.yaml (auth: none, +# bind-addr: 0.0.0.0:8080). Passing the workspace dir as the positional arg +# opens it as the default folder on first load. +exec /usr/bin/code-server /home/coder/workspace