fix: feat: add Woodpecker agent to docker-compose stack — enable CI pipeline execution (#670)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
842ab3e282
commit
8b8e29e071
3 changed files with 40 additions and 0 deletions
|
|
@ -29,6 +29,7 @@ FORGE_BOT_USERNAMES= # [CONFIG] comma-separated bot userna
|
||||||
# ── Woodpecker CI ─────────────────────────────────────────────────────────
|
# ── Woodpecker CI ─────────────────────────────────────────────────────────
|
||||||
WOODPECKER_TOKEN= # [SECRET] Woodpecker API token
|
WOODPECKER_TOKEN= # [SECRET] Woodpecker API token
|
||||||
WOODPECKER_SERVER=http://localhost:8000 # [CONFIG] Woodpecker server URL
|
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_REPO_ID — now per-project, set in projects/*.toml [ci] section
|
||||||
|
|
||||||
# Woodpecker Postgres (for direct DB queries)
|
# Woodpecker Postgres (for direct DB queries)
|
||||||
|
|
|
||||||
13
BOOTSTRAP.md
13
BOOTSTRAP.md
|
|
@ -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 |
|
| 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 |
|
| 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)
|
## Action Runner — disinto (harb-staging)
|
||||||
|
|
||||||
Added 2026-03-19. Polls disinto repo for `action`-labeled issues.
|
Added 2026-03-19. Polls disinto repo for `action`-labeled issues.
|
||||||
|
|
|
||||||
26
bin/disinto
26
bin/disinto
|
|
@ -189,6 +189,7 @@ services:
|
||||||
WOODPECKER_FORGEJO_CLIENT: ${WP_FORGEJO_CLIENT:-}
|
WOODPECKER_FORGEJO_CLIENT: ${WP_FORGEJO_CLIENT:-}
|
||||||
WOODPECKER_FORGEJO_SECRET: ${WP_FORGEJO_SECRET:-}
|
WOODPECKER_FORGEJO_SECRET: ${WP_FORGEJO_SECRET:-}
|
||||||
WOODPECKER_HOST: http://woodpecker:8000
|
WOODPECKER_HOST: http://woodpecker:8000
|
||||||
|
WOODPECKER_AGENT_SECRET: ${WOODPECKER_AGENT_SECRET:-}
|
||||||
WOODPECKER_DATABASE_DRIVER: sqlite3
|
WOODPECKER_DATABASE_DRIVER: sqlite3
|
||||||
WOODPECKER_DATABASE_DATASOURCE: /var/lib/woodpecker/woodpecker.sqlite
|
WOODPECKER_DATABASE_DATASOURCE: /var/lib/woodpecker/woodpecker.sqlite
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|
@ -196,6 +197,22 @@ services:
|
||||||
networks:
|
networks:
|
||||||
- disinto-net
|
- 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:
|
dendrite:
|
||||||
image: matrixdotorg/dendrite-monolith:latest
|
image: matrixdotorg/dendrite-monolith:latest
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
@ -1283,6 +1300,15 @@ p.write_text(text)
|
||||||
_WP_REPO_ID=""
|
_WP_REPO_ID=""
|
||||||
create_woodpecker_oauth "$forge_url" "$forge_repo"
|
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 on remote
|
||||||
create_labels "$forge_repo" "$forge_url"
|
create_labels "$forge_repo" "$forge_url"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue