diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9cc988e..fb31ee2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -64,3 +64,48 @@ jobs: labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha,scope=${{ matrix.agent }} cache-to: type=gha,mode=max,scope=${{ matrix.agent }} + + build-code-server: + 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: ./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/code-server/Dockerfile b/code-server/Dockerfile new file mode 100644 index 0000000..897ccfb --- /dev/null +++ b/code-server/Dockerfile @@ -0,0 +1,71 @@ +# code-server image — VS Code in the browser for apk8s. +# +# Extends the upstream codercom/code-server with: +# - gh CLI for GitHub operations from the integrated terminal +# - tmux for persistent terminal sessions +# - claude (Claude Code) and codex for integrated AI assistance +# - entrypoint that configures git identity + gh auth from env vars on boot +# +# Deployed at code-server.prodromou.com via WARP private routing +# (envoy-internal gateway, WOVED-35). +# +# Authentication is handled at the edge by WARP/Cloudflare Access; +# code-server itself runs with --auth none inside the cluster. +# +# Build (from repo root): +# docker build -t ghcr.io/nprodromou/codex-shell:code-server-dev \ +# -f code-server/Dockerfile code-server/ + +FROM codercom/code-server:latest + +USER root + +# tmux for persistent terminal sessions. +# git and curl are already present in the upstream image. +RUN apt-get update && apt-get install -y --no-install-recommends \ + tmux \ + && rm -rf /var/lib/apt/lists/* + +# gh CLI — pinned for reproducibility, bump in lockstep with codex-shell Dockerfile. +# renovate: datasource=github-releases depName=cli/cli extractVersion=^v(?.+)$ +ARG GH_VERSION=2.87.3 +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 — required for npm / claude-code. +# codercom/code-server bundles its own Node.js for the IDE but does not +# expose npm on PATH. Install a system-level LTS Node.js so the integrated +# terminal can use npm/npx like any dev machine. +# renovate: datasource=node-version depName=node versioning=node +ARG NODE_VERSION=22 +RUN 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/* + +# Claude Code + Codex CLI — AI coding assistants for the integrated terminal. +# Versions pinned in lockstep with the main codex-shell Dockerfile. +# DISABLE_AUTOUPDATER: pin is managed by Renovate, not at runtime. +# renovate: datasource=npm depName=@anthropic-ai/claude-code +ARG CLAUDE_CODE_VERSION=2.1.170 +# renovate: datasource=npm depName=@openai/codex +ARG OPENAI_CODEX_VERSION=0.130.0 +ENV DISABLE_AUTOUPDATER=true +RUN npm install -g \ + "@anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}" \ + "@openai/codex@${OPENAI_CODEX_VERSION}" \ + && npm cache clean --force + +# Startup script: configure git identity + gh auth from env vars, then start code-server. +COPY entrypoint.sh /usr/local/bin/code-server-entrypoint.sh +RUN chmod +x /usr/local/bin/code-server-entrypoint.sh + +USER coder + +EXPOSE 8080 + +ENTRYPOINT ["/usr/local/bin/code-server-entrypoint.sh"] diff --git a/code-server/entrypoint.sh b/code-server/entrypoint.sh new file mode 100644 index 0000000..bfe5d5c --- /dev/null +++ b/code-server/entrypoint.sh @@ -0,0 +1,30 @@ +#!/bin/sh +set -e + +# Configure git identity from env vars injected by the ExternalSecret. +# Without this, commits from the integrated terminal would land with no +# author identity and git would refuse to commit. +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 + +# Authenticate gh with the GitHub PAT. The token is provided via the +# GH_TOKEN env var from the ExternalSecret, which is the same mechanism +# used by the claude-cli and codex-cli pods. +if [ -n "$GH_TOKEN" ]; then + echo "$GH_TOKEN" | gh auth login --with-token 2>/dev/null || true +fi + +# Start code-server: +# --auth none WARP/CF Access handles auth at the edge +# --disable-telemetry no usage reporting +# /home/coder/workspace default folder to open (mounted from PVC) +exec /usr/bin/code-server \ + --bind-addr 0.0.0.0:8080 \ + --auth none \ + --disable-telemetry \ + /home/coder/workspace \ + "$@"