From a2919d0852b0e25d39a4e56f91d009c44095fc27 Mon Sep 17 00:00:00 2001 From: Claude CoWork Date: Mon, 22 Jun 2026 10:29:25 +0000 Subject: [PATCH] feat(code-server): add Dockerfile + CI for VS Code in browser image (WOVED-35) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Builds ghcr.io/nprodromou/code-server — upstream codercom/code-server with gh CLI, tmux, Node.js on PATH, and codex/claude agent CLIs for the integrated terminal. Deployed to apk8s via apk8s PR #165 (agents/code-server HelmRelease). Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/build-code-server.yml | 66 ++++++++++++++++++++++ Dockerfile.code-server | 74 +++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 .github/workflows/build-code-server.yml create mode 100644 Dockerfile.code-server diff --git a/.github/workflows/build-code-server.yml b/.github/workflows/build-code-server.yml new file mode 100644 index 0000000..79366e6 --- /dev/null +++ b/.github/workflows/build-code-server.yml @@ -0,0 +1,66 @@ +name: build-code-server + +on: + push: + branches: [main] + tags: ["v*"] + paths: + - "Dockerfile.code-server" + - ".github/workflows/build-code-server.yml" + pull_request: + branches: [main] + paths: + - "Dockerfile.code-server" + - ".github/workflows/build-code-server.yml" + +env: + # Image lives at ghcr.io/nprodromou/code-server regardless of which + # repo hosts the Dockerfile — GHCR allows cross-repo pushes. + IMAGE: ghcr.io/nprodromou/code-server + +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: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Compute tags + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.IMAGE }} + flavor: | + latest=false + tags: | + type=raw,value=latest,enable=${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + type=ref,event=branch + type=ref,event=pr + type=sha,prefix=sha-,format=short + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + + - 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 + cache-to: type=gha,mode=max diff --git a/Dockerfile.code-server b/Dockerfile.code-server new file mode 100644 index 0000000..02a5d18 --- /dev/null +++ b/Dockerfile.code-server @@ -0,0 +1,74 @@ +# code-server — VS Code in the browser for apk8s. +# +# Thin overlay on upstream codercom/code-server that adds gh (GitHub CLI), +# tmux, Node.js on the system PATH, and the codex/claude agent CLIs so they +# are available in the integrated terminal. +# +# Authentication is delegated to Cloudflare Access (WARP). code-server itself +# runs with auth: none (config.yaml mounted from the k8s ConfigMap). The only +# network path in is through the CF tunnel. +# +# The upstream image runs as uid/gid 1000 (user: coder). Keep that — the data +# and workspace PVCs must not change ownership across rebuilds. +# +# Deployed via apk8s HelmRelease at kubernetes/apps/agents/code-server/. + +# renovate: datasource=docker depName=codercom/code-server +ARG CODE_SERVER_VERSION=4.100.3 + +FROM codercom/code-server:${CODE_SERVER_VERSION} + +ARG NODE_VERSION=22 +# renovate: datasource=github-releases depName=cli/cli extractVersion=^v(?P.+)$ +ARG GH_VERSION=2.87.3 +# 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 via ARG. +ENV DISABLE_AUTOUPDATER=true + +USER root + +# System packages: tmux. +# curl and git are already present in the upstream image. +RUN set -eux; \ + apt-get update; \ + apt-get install -y --no-install-recommends tmux; \ + rm -rf /var/lib/apt/lists/* + +# GitHub CLI — pinned binary release (not the apt repo, to match the version +# pin pattern used in the rest of the codex-shell toolchain). +RUN set -eux; \ + arch="$(dpkg --print-architecture)"; \ + curl -fsSL \ + "https://github.com/cli/cli/releases/download/v${GH_VERSION}/gh_${GH_VERSION}_linux_${arch}.tar.gz" \ + | tar -xz -C /tmp; \ + mv "/tmp/gh_${GH_VERSION}_linux_${arch}/bin/gh" /usr/local/bin/gh; \ + rm -rf "/tmp/gh_${GH_VERSION}_linux_${arch}"; \ + gh --version | head -1 + +# Node.js — the upstream image ships node internally (/usr/lib/code-server/lib/node) +# but that binary is not on the system PATH for integrated terminal users. +# Install Node.js via NodeSource so `node`, `npm`, and agent CLIs are available. +RUN set -eux; \ + curl -fsSL "https://deb.nodesource.com/setup_${NODE_VERSION}.x" | bash -; \ + apt-get install -y --no-install-recommends nodejs; \ + rm -rf /var/lib/apt/lists/*; \ + node --version; npm --version + +# Agent CLIs: codex (OpenAI) and claude (Anthropic). +# Installed as root (writes to /usr/lib/node_modules); chown the scope +# directories so the coder user (uid/gid 1000) can run them without EACCES. +RUN set -eux; \ + npm install -g \ + "@openai/codex@${OPENAI_CODEX_VERSION}" \ + "@anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}"; \ + npm cache clean --force; \ + chown -R 1000:1000 /usr/lib/node_modules/@openai; \ + chown -h 1000:1000 /usr/bin/codex; \ + chown -R 1000:1000 /usr/lib/node_modules/@anthropic-ai; \ + chown -h 1000:1000 /usr/bin/claude + +USER coder