scrum4me-docker/Dockerfile
janpeter visser c090e6c349 feat(bootstrap): GH_TOKEN-based clone of Scrum4Me + scrum4me-mcp
Fixes the 'no GitHub credentials' deadlock observed in the first
NAS-Docker batch run (2 May 2026): scrum4me-mcp's `wait_for_job`
expects a local clone at `~/Projects/<repo-name>` (convention-fallback
in resolveRepoRoot) but the container had no credentials and no clone.
Agent asked the user how to proceed; turn closed without claim.

Changes:
- `.env.example`: GH_TOKEN (fine-grained PAT, repo+PR scope) and
  GH_PRECLONE_REPOS (comma-separated owner/name list, default covers
  Scrum4Me + scrum4me-mcp).
- `bin/repo-bootstrap.sh` (new): runs as agent-user; configures git
  credential-helper with HTTPS oauth2 token, then clones-or-fetches
  each entry in GH_PRECLONE_REPOS into ~/Projects/<name>. Idempotent.
- `bin/entrypoint.sh`: hooks repo-bootstrap before run-agent.sh.
- `Dockerfile`:
  - installs `gh` CLI (used for auto_pr `gh pr create`; reads GH_TOKEN
    from env directly).
  - pre-creates `~agent/Projects` and `~agent/.scrum4me-agent-worktrees`
    so directory-ownership is right from the first boot.
- `README.md`: 'Repo bootstrap (clone-on-start)' section + GH_TOKEN
  step in the deploy checklist; corrects the obsolete 'no push
  credentials' note (agent now pushes feature-branches, gh creates PRs).

Same token covers clone, push and PR-creation — one secret to rotate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 19:48:57 +02:00

100 lines
4.3 KiB
Docker

# syntax=docker/dockerfile:1.6
FROM ubuntu:22.04
# ----- system deps -------------------------------------------------------
ENV DEBIAN_FRONTEND=noninteractive \
TZ=Europe/Amsterdam \
LANG=C.UTF-8 \
LC_ALL=C.UTF-8
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates curl git tini gosu jq xz-utils \
build-essential python3 \
tzdata logrotate \
gnupg \
&& ln -fs /usr/share/zoneinfo/$TZ /etc/localtime \
&& dpkg-reconfigure --frontend=noninteractive tzdata \
&& rm -rf /var/lib/apt/lists/*
# ----- gh CLI ------------------------------------------------------------
# Required for auto_pr (`gh pr create`) and authenticates via the GH_TOKEN
# env-var that is also used by the git credential helper for HTTPS.
RUN install -m 0755 -d /etc/apt/keyrings \
&& curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
| gpg --dearmor -o /etc/apt/keyrings/githubcli-archive-keyring.gpg \
&& chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
> /etc/apt/sources.list.d/github-cli.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends gh \
&& rm -rf /var/lib/apt/lists/*
# ----- node 22 LTS -------------------------------------------------------
# Voor zowel Claude Code (de native installer heeft geen node nodig, maar
# scrum4me-mcp draait op tsx) als de health-server.
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/* \
&& npm install -g pnpm@9 tsx@4 \
&& npm cache clean --force
# ----- claude code via native installer ---------------------------------
# Zet PATH zodat het user-binary gevonden wordt; native installer plaatst
# in $HOME/.local/bin standaard. We installeren als root om in /usr/local
# te belanden, of fallback naar /opt.
ARG CLAUDE_CODE_VERSION=latest
RUN curl -fsSL https://claude.ai/install.sh | bash -s ${CLAUDE_CODE_VERSION} \
&& cp /root/.local/bin/claude /usr/local/bin/claude \
&& chmod +x /usr/local/bin/claude \
&& claude --version
# ----- scrum4me-mcp ------------------------------------------------------
# Clone zonder submodules — de Prisma-schema zit al gecommit in het repo.
# De vendor/scrum4me submodule is alleen nodig om het schema te updaten,
# niet om te builden. Pin via build-arg; default = main.
ARG MCP_GIT_REPO=https://github.com/madhura68/scrum4me-mcp.git
ARG MCP_GIT_REF=main
RUN git clone --branch ${MCP_GIT_REF} --depth 1 \
${MCP_GIT_REPO} /opt/scrum4me-mcp \
&& cd /opt/scrum4me-mcp \
&& npm ci --omit=dev --omit=optional || npm install --omit=dev \
&& npx prisma generate
# ----- non-root user -----------------------------------------------------
# UID 1000 zodat bind-mounted /share/Agent/* schrijfrechten matchen met de
# admin op QNAP. Pas aan via build-arg als je een andere UID gebruikt.
ARG AGENT_UID=1000
ARG AGENT_GID=1000
RUN groupadd -g ${AGENT_GID} agent \
&& useradd -u ${AGENT_UID} -g ${AGENT_GID} -m -s /bin/bash agent \
&& mkdir -p /var/cache/repos /var/cache/npm /var/log/agent /var/run/agent \
&& mkdir -p /home/agent/Projects /home/agent/.scrum4me-agent-worktrees \
&& chown -R agent:agent /var/cache /var/log/agent /var/run/agent /home/agent
# ----- runner files ------------------------------------------------------
WORKDIR /opt/agent
COPY --chown=agent:agent bin/ ./bin/
COPY --chown=agent:agent etc/ ./etc/
COPY --chown=agent:agent CLAUDE.md ./
COPY --chown=agent:agent mcp-config.json ./
RUN chmod +x ./bin/*.sh
# ----- runtime config ----------------------------------------------------
ENV PATH=/opt/agent/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
HOME=/home/agent \
NPM_CONFIG_CACHE=/var/cache/npm \
PNPM_HOME=/var/cache/pnpm \
AGENT_STATE_DIR=/var/run/agent \
AGENT_LOG_DIR=/var/log/agent \
AGENT_REPO_CACHE=/var/cache/repos \
AGENT_JOB_ROOT=/tmp \
AGENT_HEALTH_PORT=8080
EXPOSE 8080
# tini als PID 1 → correcte signal handling, geen zombies
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["/opt/agent/bin/entrypoint.sh"]