diff --git a/docs/superpowers/specs/2026-09-26-docker-deployment-design.md b/docs/superpowers/specs/2026-09-26-docker-deployment-design.md index f92b6c9..8d73fe6 100644 --- a/docs/superpowers/specs/2026-09-26-docker-deployment-design.md +++ b/docs/superpowers/specs/2026-09-26-docker-deployment-design.md @@ -1,6 +1,6 @@ # Docker deployment (Coolify) — design -Date: 2026-09-26. Status: draft. +Date: 2026-09-26. Status: implemented (plan: docs/superpowers/plans/2026-09-26-docker-deployment.md). Depends on: `2026-09-26-process-environment-hook-design.md` (the secrets below stay out of agent-spawned processes), `2026-09-26-scheduler-design.md` §7 (the default time zone). @@ -215,7 +215,12 @@ the `claude` volume also works but is not the documented path. ## Verification -No unit tests (nothing in C# changes). Manual checklist in the implementation plan: +One unit test (`PlaywrightPresetTests.Dockerfile_version_matches_DefaultPackage`); no C# behaviour changes. Checked +during implementation without a real bot: both image variants build; bridge guard, `claude --version`, the agent +tools, uid 1654, `/data` ownership; root-owned PID 1 whose `/proc/1/environ` and the bot's are unreadable to `app`; +no `dotnet-diagnostic-*` socket; `playwright-mcp --version` offline and a headless Chromium launch as `app`; +`docker compose config`; host startup log and the `401` → exit 1 path. The rest of this list needs a real bot and +stays a manual checklist: 1. `docker compose build` succeeds with `INSTALL_PLAYWRIGHT=false` and `true`; the bridge guard and `claude --version` pass. 2. `docker compose up` with a real bot: allowed user gets answers; `/claude-code-login` then `/claude-code-doctor` @@ -227,12 +232,35 @@ No unit tests (nothing in C# changes). Manual checklist in the implementation pl 4. `docker compose down && docker compose up -d --build`: previous chat resumes, no re-login needed, workspace files remain. 5. Setting `ANTHROPIC_API_KEY` in compose makes the provider refuse with its documented error (then remove it). +Verification record (2026-09-27, Docker Desktop 29 on Windows 11, Linux containers): + +- `dotnet build`: 0 warnings, 0 errors. `dotnet test`: all green except the three Windows-only baseline failures in + `Volcanic.AgenticCore.Tests`. Changing the Dockerfile's `PLAYWRIGHT_MCP_VERSION` to `0.0.81` makes + `Dockerfile_version_matches_DefaultPackage` fail (`Expected "0.0.82", Actual "0.0.81"`). +- `docker build --build-arg INSTALL_PLAYWRIGHT=false` and `=true` both succeed. `claude --version` → `2.1.283 (Claude + Code)`; bridge `runtimeconfig.json` present; `DOTNET_EnableDiagnostics=0`; `git`, `rg`, `python3`, `node` (v24.21.0), + `npx`, `jq`, `setpriv` on `PATH`; `/data/{workspaces,agent,claude}` owned by `app`. With Playwright, + `playwright-mcp --version` → `Version 0.0.82` with `--network none`, Chromium under `/opt/ms-playwright`, and a + headless Chromium launch as `app` renders a page. +- Running host, `--init --network none`: PID 1 `docker-init` as root, the bot's `dotnet` as uid/gid 1654 with no + effective capabilities; `/proc/1/environ` and the bot's `environ` are `Permission denied` for `app` (the bot's also + for a root `docker exec`, since the host is not dumpable); no `dotnet-diagnostic-*` socket. The log shows + `Host process hardened: not dumpable`, `Process environment: 15 deny rules, allow: none`, the MCP line + (`disabled` / `enabled (headless, chromium)`), `Speech to text`, `Using Claude Code at /usr/bin/claude, model + claude-code/claude-opus-5-5`, `Scheduler`, `Default time zone: UTC`, `Allowed users: 1. Workspaces under + /data/workspaces`, then `Telegram unreachable` backoff. +- `docker compose config`: with a minimal `.env` (`INSTALL_PLAYWRIGHT=false`), `PLAYWRIGHT_ENABLED` follows it to + `"false"`; with `.env.example`'s defaults it is `"true"`; `--no-sandbox`, `playwright-mcp`, `init: true`, + `shm_size`, three named volumes, no ports. +- `docker compose up -d --build` with `TELEGRAM_BOT_TOKEN=123:fake`: same startup lines, then `Telegram rejected the bot + token (401 Unauthorized)`, exit 1, and a visible `restart: unless-stopped` loop; no other warnings. + ## Open questions 1. Persist `HOME` too? `~/.gitconfig`, `~/.ssh`, `gh` auth and the npm/npx cache are lost on redeploy with this design. A fourth volume at `/home/app` would keep them; left out until there is a need. -2. Playwright default: compose builds it in (`true`) on the assumption that the MCP spec ships; flip the compose - default to `false` if that spec lands later. (Sandboxing and which binary is launched are settled above.) +2. ~~Playwright default~~: resolved. The MCP spec shipped first, so compose keeps building it in (`true`). + (Sandboxing and which binary is launched are settled above.) 3. `CLAUDE_CODE_VERSION=2.1` tracks the newest 2.1.x at build time. Pin an exact, doctor-verified version instead, at the cost of manual bumps? 4. Should the agent get a .NET SDK in the image (`INSTALL_DOTNET_SDK` build arg, +~700 MB) so it can build .NET