mirror of
https://github.com/0xWheatyz/handler.git
synced 2026-08-30 06:36:25 +00:00
fa2e97130d
Two changes so an operator can stand up and authenticate Handler entirely from the browser, with a self-contained control image. Bundle executables in the control image (Dockerfile.control) - Node.js (NodeSource) + the Claude Code CLI, mise (official apt repo), and forge (git-pkgs/forge, built in a Go stage) join the existing git/tmux/ssh. No more bring-your-own binaries: live agent spawning, the verification gate, CI resolution, and the login flow all work out of the box. Installed under /usr so the /var/lib/handler VOLUME never masks them; mise apt source pinned to $TARGETARCH for the multi-arch (amd64/arm64) build. Claude login from the web UI - New login_start / login_submit command types (migration 0005) drive the interactive `claude /login` through the same enqueue→worker handoff every other control action uses — the API container has no claude binary. - control/login.py opens `claude` in a dedicated tmux session, sends /login, selects the subscription account, and scrapes the claude.com authorization URL (tmux.capture_pane, -pJ so a wrapped URL rejoins); a second command feeds back the pasted code. Fully mockable via the tmux seam. - API: POST /login/start, POST /login/submit (admin-gated). - Dashboard: a "Claude Login" pane — a button that starts the flow, embeds the URL in an iframe (with a new-tab fallback, since claude.com may refuse framing), and takes the code to finish. Also un-ignores frontend/lib/ (a broad Python `lib/` rule was swallowing the UI's own api client + formatters, breaking rebuilds from a fresh clone) and reconstructs those two source files; rebuilt static export committed. Tests: control/login unit tests (tmux faked), worker dispatch, and API route tests. Full suite green (195 tests), ruff clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YKVyBmKvWDVgrFC9WER2f2
80 lines
3.1 KiB
YAML
80 lines
3.1 KiB
YAML
# Local/dev deployment: API + Postgres. For a single-node SQLite deploy, drop the
|
|
# `db` service and DATABASE_URL override — the image defaults to SQLite on the
|
|
# handler-data volume.
|
|
services:
|
|
api:
|
|
image: ghcr.io/0xwheatyz/handler:latest
|
|
build: .
|
|
ports:
|
|
- "8000:8000"
|
|
environment:
|
|
DATABASE_URL: postgresql+psycopg://handler:handler@db:5432/handler
|
|
# Required — the API refuses to start without it. Set in .env or the shell.
|
|
AUTH_TOKEN: ${AUTH_TOKEN:?set AUTH_TOKEN in .env or the environment}
|
|
SHARED_CONTEXT_WRITE_TOKEN: ${SHARED_CONTEXT_WRITE_TOKEN:-}
|
|
WEBHOOK_URL: ${WEBHOOK_URL:-}
|
|
UI_ENABLED: ${UI_ENABLED:-true}
|
|
CORS_ORIGINS: ${CORS_ORIGINS:-}
|
|
# The API computes new projects' root_dir under this path (shared volume with the
|
|
# control container, which does the actual cloning).
|
|
PROJECTS_ROOT: /var/lib/handler/projects
|
|
# Encrypts git-server tokens/SSH keys at rest; must match the control container.
|
|
HANDLER_SECRET_KEY: ${HANDLER_SECRET_KEY:-}
|
|
volumes:
|
|
- handler-data:/var/lib/handler
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
restart: unless-stopped
|
|
|
|
# Control layer: the `handler` worker. Drains the control-command queue the API enqueues
|
|
# (spawn/kill/resume/approve/reject/forge-init/poll-ci/sync), fires due schedules, and
|
|
# sweeps CI on an interval.
|
|
# Shares the database and the handler-data volume with the API. It waits for the API
|
|
# (which owns migrations), so RUN_MIGRATIONS is off here to avoid a startup race. Run
|
|
# one-shot control commands against the same image with, e.g.,
|
|
# `docker compose run --rm control handler list`. Every executable it shells out to —
|
|
# `git`, `tmux`, `node`+`claude`, `mise`, `forge` — is bundled in the image, so live
|
|
# agent spawning and the claude web-login flow work with no bring-your-own binaries.
|
|
control:
|
|
image: ghcr.io/0xwheatyz/handler/control:latest
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile.control
|
|
environment:
|
|
DATABASE_URL: postgresql+psycopg://handler:handler@db:5432/handler
|
|
RUN_MIGRATIONS: "false"
|
|
PROJECTS_ROOT: /var/lib/handler/projects
|
|
# Per-project forge credentials are resolved from credential_ref pointers at spawn;
|
|
# export the referenced vars here when spawning agents from this container.
|
|
FORGE_VERSION: ${FORGE_VERSION:-}
|
|
# Decrypts git-server tokens/SSH keys stored by the API; must match the API's key.
|
|
HANDLER_SECRET_KEY: ${HANDLER_SECRET_KEY:-}
|
|
volumes:
|
|
- handler-data:/var/lib/handler
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
api:
|
|
condition: service_healthy
|
|
restart: unless-stopped
|
|
|
|
db:
|
|
image: postgres:16-alpine
|
|
environment:
|
|
POSTGRES_USER: handler
|
|
POSTGRES_PASSWORD: handler
|
|
POSTGRES_DB: handler
|
|
volumes:
|
|
- postgres-data:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U handler -d handler"]
|
|
interval: 5s
|
|
timeout: 3s
|
|
retries: 10
|
|
restart: unless-stopped
|
|
|
|
volumes:
|
|
handler-data:
|
|
postgres-data:
|