fix(docker): trust bind-mounted repos via git safe.directory

The container runs as root over uid-1000-owned host repos; git's dubious-
ownership guard made every project read as not-a-repo, hiding the git diff
panel's Git tab and nulling the branch indicator. Bakes safe.directory='*'
into the runtime image. Applied live to the running container too.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-03 08:29:33 +00:00
parent aeb2777ad4
commit d10d79399b
2 changed files with 7 additions and 0 deletions

View File

@@ -2,6 +2,10 @@
All notable changes per release tag. Most recent on top, ordered by tag creation date (which matches the git history). Tag names follow `vMAJOR.MINOR.PATCH-slug` — the slug describes what shipped, so the tag name alone is enough to recall the batch.
## v2.7.16-container-git-safedir — 2026-06-03
Hotfix that makes the `v2.7.15-git-diff-panel` work in production. The `boocode` container runs as root but bind-mounts host project repos owned by uid 1000, so git rejected them with "detected dubious ownership" and the diff route reported every project as not-a-repo — which hid the Git tab entirely (and had been silently nulling the existing branch indicator too). Adds `git config --system --add safe.directory '*'` to the Dockerfile runtime stage so the container's git trusts the mounted repos; applied live to the running container and baked into the image for future rebuilds. Surfaced by a live smoke immediately after the v2.7.14/v2.7.15 deploy.
## v2.7.15-git-diff-panel — 2026-06-03
A Files / Git tab in the right-side file panel (the file-browser sidebar) that shows the project repository's git diff and lets the user stage, unstage, commit, and discard whole files in-session — modeled on Paseo's diff view, scoped and planned through the `plan-a-feature``plan-implementation` skills, then built and audited via `paseo-epic` in an isolated worktree. Two comparison modes (Uncommitted vs HEAD, and the current branch vs its base — the upstream tracking branch else `origin/HEAD`), auto-selected by repo dirty-state on first open and pinned after an explicit choice; per-file expand/collapse with lazy Shiki `lang:'diff'` highlighting, +/- stats, and binary/too-large placeholders. All git read and write logic lives in `apps/server` (new `git_diff.ts` + routes on `projects.ts`) — the read-only-server posture governs the assistant's tools, not the user's own actions, and the container already mounts `/opt` read-write while `project_bootstrap` already commits via `execFile`. Every write uses the safe `execFile` argv pattern (never a shell string) with `--` operand separators, per-file `pathGuard` + realpath symlink-escape validation, server-derived `-c` commit identity (the request body is `.strict()` and carries no author fields), and the write endpoints are deliberately absent from the assistant tool registry. Reads are bounded (30s deadline, 10MB); an index lock or an in-progress merge/rebase/cherry-pick/bisect surfaces as "repository busy" and disables writes. The panel stays current via a client `git_diff_refresh` sessionEvent (no new wire contract) coalesced across tab-open, mutations, turn completion, and pending-change apply; discard is an irrecoverable hard-delete behind a plain confirm distinguishing a tracked revert from an untracked delete. New `git_diff` pure-helper + temp-repo integration tests (59 cases); server 630 tests green, web tsc clean. Pairs with `v2.7.14-backlog-hardening` (shipped together).

View File

@@ -24,6 +24,9 @@ RUN pnpm deploy --filter=@boocode/server --prod --legacy /out/server
FROM node:20-alpine AS runtime
RUN apk add --no-cache ripgrep git openssh-client
# The container runs as root but bind-mounts host project repos owned by uid 1000;
# trust them so git read/write tools (git_status, the git diff panel) work over the mount.
RUN git config --system --add safe.directory '*'
RUN mkdir -p /root/.ssh && ssh-keyscan -p 2222 -H 100.114.205.53 git.indifferentketchup.com >> /root/.ssh/known_hosts && chmod 700 /root/.ssh && chmod 600 /root/.ssh/known_hosts
WORKDIR /app