Merge pull request 'fix: feat: add Woodpecker agent to docker-compose stack — enable CI pipeline execution (#670)' (#689) from fix/issue-670 into main

This commit is contained in:
johba 2026-03-25 15:14:03 +01:00
commit d3ce0a92d4
3 changed files with 40 additions and 0 deletions

View file

@ -29,6 +29,7 @@ FORGE_BOT_USERNAMES= # [CONFIG] comma-separated bot userna
# ── Woodpecker CI ─────────────────────────────────────────────────────────
WOODPECKER_TOKEN= # [SECRET] Woodpecker API token
WOODPECKER_SERVER=http://localhost:8000 # [CONFIG] Woodpecker server URL
WOODPECKER_AGENT_SECRET= # [SECRET] shared secret for server↔agent auth (auto-generated)
# WOODPECKER_REPO_ID — now per-project, set in projects/*.toml [ci] section
# Woodpecker Postgres (for direct DB queries)

View file

@ -468,6 +468,19 @@ Meanwhile:
| Dev-agent churns through issues without waiting for open PRs to land | No single-threaded enforcement | `WAITING_PRS` check in dev-poll holds new work — verify TOML `name` is consistent across invocations |
| Label ping-pong (issue reopened then immediately re-closed) | `already_done` handler doesn't close issue | Review dev-agent log; `already_done` status should auto-close the issue |
## Security: Docker Socket Sharing in CI
The `woodpecker-agent` service mounts `/var/run/docker.sock` to execute `type: docker` CI pipelines. This grants root-equivalent access to the Docker host — any CI pipeline step can run privileged containers, mount arbitrary host paths, or access other containers' data.
**Mitigations:**
- **Run disinto in an LXD/VM container, not on bare metal.** When the Docker daemon runs inside an LXD container, LXD's user namespace mapping and resource limits contain the blast radius. A compromised CI step cannot reach the real host.
- **`WOODPECKER_MAX_WORKFLOWS: 1`** limits concurrent CI resource usage, preventing a runaway pipeline from exhausting host resources.
- **`WOODPECKER_AGENT_SECRET`** authenticates the agent↔server gRPC connection. `disinto init` auto-generates this secret and stores it in `.env` (or `.env.enc` when SOPS is available).
- Consider setting `WOODPECKER_BACKEND_DOCKER_VOLUMES` on the agent to restrict which host volumes CI pipelines can mount.
**Threat model:** PRs are created by the dev-agent (Claude) and auto-reviewed by the review-bot. A crafted backlog issue could theoretically produce a PR whose CI step exploits the Docker socket. The LXD containment boundary is the primary defense — treat the LXD container as the trust boundary, not the Docker daemon inside it.
## Action Runner — disinto (harb-staging)
Added 2026-03-19. Polls disinto repo for `action`-labeled issues.

View file

@ -189,6 +189,7 @@ services:
WOODPECKER_FORGEJO_CLIENT: ${WP_FORGEJO_CLIENT:-}
WOODPECKER_FORGEJO_SECRET: ${WP_FORGEJO_SECRET:-}
WOODPECKER_HOST: http://woodpecker:8000
WOODPECKER_AGENT_SECRET: ${WOODPECKER_AGENT_SECRET:-}
WOODPECKER_DATABASE_DRIVER: sqlite3
WOODPECKER_DATABASE_DATASOURCE: /var/lib/woodpecker/woodpecker.sqlite
depends_on:
@ -196,6 +197,22 @@ services:
networks:
- disinto-net
woodpecker-agent:
image: woodpeckerci/woodpecker-agent:latest
restart: unless-stopped
security_opt:
- apparmor=unconfined
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
WOODPECKER_SERVER: woodpecker:9000
WOODPECKER_AGENT_SECRET: ${WOODPECKER_AGENT_SECRET:-}
WOODPECKER_MAX_WORKFLOWS: 1
depends_on:
- woodpecker
networks:
- disinto-net
dendrite:
image: matrixdotorg/dendrite-monolith:latest
restart: unless-stopped
@ -1283,6 +1300,15 @@ p.write_text(text)
_WP_REPO_ID=""
create_woodpecker_oauth "$forge_url" "$forge_repo"
# Generate WOODPECKER_AGENT_SECRET for server↔agent auth
local env_file="${FACTORY_ROOT}/.env"
if ! grep -q '^WOODPECKER_AGENT_SECRET=' "$env_file" 2>/dev/null; then
local agent_secret
agent_secret="$(head -c 32 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | head -c 40)"
printf 'WOODPECKER_AGENT_SECRET=%s\n' "$agent_secret" >> "$env_file"
echo "Config: WOODPECKER_AGENT_SECRET generated and saved to .env"
fi
# Create labels on remote
create_labels "$forge_repo" "$forge_url"