6d224861 came from a --no-checkout worktree whose empty index made the
commit drop every file except two. This restores 05b50d2b's full tree and
correctly adds stacks/stem95su/gdrive-sync.tf + the service-catalog stem95su
entry. Forward-only (parent=6d224861, no force-push); [ci skip] since the
live infra was never applied from the broken commit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3.8 KiB
Runbook: Onboarding a new Forgejo repo to Woodpecker
Last updated: 2026-05-07
Programmatic (preferred)
infra/scripts/woodpecker-register-forgejo-repo.sh viktor/<repo-name>
The script:
- Pulls the
viktor(Forgejo-OAuth'd) user'shashfrom the Woodpecker PGuserstable. - Mints a session JWT (HS256, signed with that hash) — Woodpecker
per-user session JWTs have payload
{"type":"user","user-id":"<id>"}and the signing key is the user'shashcolumn. (Confirmed against a known-good admin token: same payload shape, signature reproducible from the user's stored hash viaopenssl dgst -sha256 -hmac "$HASH".) - Looks up the Forgejo repo id and POSTs to
https://ci.viktorbarzin.me/api/repos?forge_remote_id=<id>as that user. Woodpecker server creates the per-repo webhook + per-repo signing key on the Forgejo side automatically (uses the user's stored Forgejo OAuthaccess_tokento do so — that's why this only works with viktor's user, not the GitHub admin's).
Pre-requisites:
vault login -method=oidcwith read access todatabase/static-creds/pg-woodpecker.kubectlcluster access (the script spawns a 5-min psql pod in thewoodpeckernamespace to query the DB).- A Forgejo PAT in
secret/viktor/forgejo_admin_token(or passFORGEJO_TOKEN=…env), used to look up the repo's numeric ID. - The
viktorWoodpecker user must already exist (i.e., they've logged in via Forgejo OAuth at least once on the Web UI). If user_id=2 / forge_id=2 doesn't exist inusers, the OAuth bootstrap is unavoidable — but it only needs to happen once for the lifetime of the Woodpecker DB.
Why the GitHub admin token can't do this
The earlier 500 from POST /api/repos?forge_remote_id=N was
because my admin session token authenticates as ViktorBarzin
(GitHub user, forge_id=1). Woodpecker tries to call Forgejo as
that user (using their stored Forgejo OAuth token) — which doesn't
exist for the GitHub user, hence the lookup error. There's no way
around this without acting as the Forgejo user.
Why the previous "JWT for the webhook" approach didn't work
I tried generating a webhook JWT signed with WOODPECKER_AGENT_SECRET
(the global agent secret) and registering it directly on Forgejo.
That fails because the webhook JWT verification path runs through a
DB-backed keyfunc — Woodpecker stores a per-repo signing key when
the repo is activated, and rejects any JWT signed with a different
key. POST /api/repos is what creates that per-repo key.
After registration
Pipelines fire automatically on push. The WOODPECKER_FORGE_TIMEOUT
default of 3s was too tight for our cluster (Forgejo response time
spikes to 1-2s under load) — bumped to 30s in
infra/stacks/woodpecker/values.yaml 2026-05-07. Without that bump,
config-loader hits the deadline and every pipeline errors with
could not load config from forge: context deadline exceeded.
When the v3.13 → v3.14 server upgrade matters
v3.14.0 doesn't fix this on its own — the timeout default is the
same. Set WOODPECKER_FORGE_TIMEOUT regardless of version. The
v3.14 upgrade was useful for unrelated forge-API changes (smarter
config-loader, fewer redundant calls per trigger).
Troubleshooting
- Pipeline status
errorwithcould not load config from forge: bumpWOODPECKER_FORGE_TIMEOUT. 30s is plenty. - Pipeline status
errorwithsecret "registry-password" not found: the repo's.woodpecker.ymlstill references registry-private credentials. Drop theregistry.viktorbarzin.meblock — Forgejo is the only registry now. - Pipeline status
failurewith"/vault": not found(or any other COPY of a binary): the gitignored binary wasn't pushed to Forgejo. Switch the Dockerfile tocurl … && unzipfrom the HashiCorp/upstream release URL. Seeclaude-agent-service/Dockerfilecommit bab6dd2 for the pattern.