#!/bin/bash # Fellowship code-server runtime entrypoint # 1. Aligns the docker group GID with the host's /var/run/docker.sock # 2. Pre-installs VS Code extensions (idempotent) # 3. Drops to 'coder' user and starts code-server set -e log() { echo "[$(date '+%H:%M:%S')] [fellowship-init] $*"; } # ── Fix Docker group GID ────────────────────────────────────────────────────── # Without this, `docker` commands inside code-server fail with "permission denied" # because the socket's GID on the host may differ from the GID baked into the image. if [ -S /var/run/docker.sock ]; then DOCK_GID=$(stat -c '%g' /var/run/docker.sock) log "Host docker socket GID: ${DOCK_GID}" if getent group docker > /dev/null 2>&1; then groupmod -g "${DOCK_GID}" docker 2>/dev/null || true else groupadd -g "${DOCK_GID}" docker 2>/dev/null || true fi usermod -aG docker coder 2>/dev/null || true # Make the socket world-accessible as a safe fallback chmod 666 /var/run/docker.sock 2>/dev/null || true log "✓ Docker group GID aligned to ${DOCK_GID}" else log "WARNING: /var/run/docker.sock not mounted — docker commands will not work in the IDE terminal" log " Add - /var/run/docker.sock:/var/run/docker.sock to the code-server volumes." fi # ── Fix config directory permissions ────────────────────────────────────────── # The codeserver_config volume is mounted as /home/coder/.config but is owned by root. # Ensure coder user can read/write to it. if [ -d /home/coder/.config ]; then chown -R coder:coder /home/coder/.config 2>/dev/null || true log "✓ Config directory permissions fixed" fi # ── Fix fellowship project directory permissions ─────────────────────────────── # The fellowship directory is mounted from the host and may be owned by ec2-user # or root. Ensure the coder user can read/write all project files for IDE editing. # This includes fixing .git directory ownership which git is sensitive about. if [ -d /home/coder/fellowship ]; then chown -R coder:coder /home/coder/fellowship 2>/dev/null || true chmod -R u+rw /home/coder/fellowship 2>/dev/null || true log "✓ Fellowship project directory permissions fixed" # Fix .git directory specifically since git checks ownership strictly if [ -d /home/coder/fellowship/.git ]; then chown -R coder:coder /home/coder/fellowship/.git 2>/dev/null || true chmod -R u+rw /home/coder/fellowship/.git 2>/dev/null || true fi fi # ── Configure git safe.directory ────────────────────────────────────────────── # Git requires explicit permission for directories owned by different users. # Mark the fellowship project as a safe git repository for the coder user. # We configure this even if .git doesn't exist yet — it will be used for new repos. if [ -d /home/coder/fellowship ]; then # Using su instead of gosu ensures proper shell environment and config file loading su - coder -c "git config --global --add safe.directory /home/coder/fellowship" 2>/dev/null || true log "✓ Git safe.directory configured for /home/coder/fellowship" fi # ── Install VS Code extensions ──────────────────────────────────────────────── # Runs as the coder user; uses Open VSX registry (code-server default). # The --force flag makes installs idempotent — safe to run on every startup. # ── Configure git defaults ─────────────────────────────────────────────────── # Set global git configuration for the coder user log "Configuring git defaults..." su - coder -c "git config --global user.name 'Fellowship Scholar'" 2>/dev/null || true su - coder -c "git config --global user.email 'scholar@fellowship.local'" 2>/dev/null || true su - coder -c "git config --global credential.helper store" 2>/dev/null || true log "✓ Git configured: Fellowship Scholar " # ── Configure Gitea as git remote ────────────────────────────────────────────── # Ensure the fellowship repository is connected to Gitea (not GitHub or other remotes) # This runs every startup to guarantee correct remote configuration if [ -d /home/coder/fellowship ]; then log "Ensuring git repository is connected to Gitea..." if [ -d /home/coder/fellowship/.git ]; then # Repository exists - check if it's the old GitHub repository # Count branches: fresh Gitea repository only has main, old GitHub has 15+ branches BRANCH_COUNT=$(su - coder -c "cd /home/coder/fellowship && git branch -r 2>/dev/null | wc -l" 2>/dev/null || echo "0") BRANCH_COUNT=$(echo "$BRANCH_COUNT" | tr -d ' ' || echo "0") # Strip whitespace if [ "$BRANCH_COUNT" -gt 5 ]; then # Repository has many branches - this is the old GitHub repository log " ⚠ Detected old GitHub repository ($BRANCH_COUNT branches) - deleting and resetting to fresh Gitea..." su - coder -c "cd /home/coder/fellowship && rm -rf .git" 2>/dev/null || true su - coder -c "cd /home/coder/fellowship && git init --initial-branch=main" 2>/dev/null || true su - coder -c "cd /home/coder/fellowship && git remote add origin http://gitea:3000/fellowship-org/lotr-sut.git" 2>/dev/null || true log " ✓ Repository reset to fresh Gitea repository" fi # Mark repository as safe for git operations su - coder -c "git config --global --add safe.directory /home/coder/fellowship" 2>/dev/null || true log "✓ Git remote: http://gitea:3000/fellowship-org/lotr-sut.git" else # No .git yet - initialize fresh for Gitea log " Initializing fresh repository for Gitea..." su - coder -c "cd /home/coder/fellowship && git init --initial-branch=main" 2>/dev/null || true su - coder -c "cd /home/coder/fellowship && git remote add origin http://gitea:3000/fellowship-org/lotr-sut.git" 2>/dev/null || true log "✓ Fresh Gitea repository initialized" fi # Configure Gitea credentials for authentication su - coder -c "mkdir -p ~/.config/git && echo 'http://fellowship:fellowship123@gitea:3000' > ~/.git-credentials && chmod 600 ~/.git-credentials" 2>/dev/null || true log "✓ Gitea credentials configured" fi log "Installing VS Code extensions (optional, skipped on timeout)..." EXTENSIONS=( "ms-python.python" # NOTE: GitHub Copilot removed - conflicts with Gitea (pulls GitHub auth flow) # Use "GitHub" extension only if switching to github.com repositories. "ms-playwright.playwright" "esbenp.prettier-vscode" "ms-toolsai.jupyter" "redhat.vscode-yaml" "ms-azuretools.vscode-docker" "gitpod.gitpod-remote-web" "earshinov.gitea-extension" ) for ext in "${EXTENSIONS[@]}"; do # Install with 30-second timeout (extensions may take time to download) if timeout 30 gosu coder code-server --install-extension "${ext}" --force > /dev/null 2>&1; then log " ✓ ${ext}" else log " ⚠ ${ext} (unavailable, offline, or timeout — skipping)" fi done log "✓ VS Code extensions completed" # ── Write default settings ──────────────────────────────────────────────────── # Set sensible defaults so Python + Docker extensions work out of the box. SETTINGS_DIR="/home/coder/.local/share/code-server/User" SETTINGS_FILE="${SETTINGS_DIR}/settings.json" if [ ! -f "${SETTINGS_FILE}" ]; then gosu coder mkdir -p "${SETTINGS_DIR}" gosu coder tee "${SETTINGS_FILE}" > /dev/null << 'SETTINGS' { "python.defaultInterpreterPath": "/usr/bin/python3", "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "[python]": { "editor.defaultFormatter": "ms-python.python" }, "terminal.integrated.defaultProfile.linux": "bash", "git.autofetch": true, "docker.host": "unix:///var/run/docker.sock" } SETTINGS log "✓ Default settings.json written" fi # ── Hand off to code-server ─────────────────────────────────────────────────── # ── Hand off to code-server ─────────────────────────────────────────────────── log "Starting code-server as coder..." log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" log " Git Repository Connected to Gitea:" log " • User: Fellowship Scholar " log " • Remote: http://gitea:3000/fellowship-org/lotr-sut" log " • Use IDE Terminal: git status, git push, git pull, git commit" log " • NOT connected to GitHub (fresh Gitea repository)" log "" log " Docker Integration (from IDE Terminal):" log " • docker compose up -d (runs on host Docker)" log " • docker-compose up -d (same, legacy alias)" log " • docker ps (list running containers)" log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" exec gosu coder /usr/bin/entrypoint.sh "$@"