GitLab webhooks
How CodeHerder registers a GitLab project webhook for a repo, how to set one up by hand, and how to rotate, remove and troubleshoot it.
A GitLab webhook makes GitLab push merge request, comment, pipeline, job, push, tag and release events to CodeHerder. CodeHerder then does not need to poll GitLab for them. Each repo has its own hook and its own secret.
What you need
CodeHerder registers a hook through the GitLab API. The GitLab connection token must be able to do that. It needs the api scope and the Maintainer role on the project. A group access token or a project access token works.
The same connection token lets the server mint project tokens for your agents. The device holds no GitLab mint token. For each sandbox, the server creates a short-lived project access token with this connection, and revokes it when the sandbox ends. A connection token without the api scope and the Maintainer role cannot create project tokens. The device then uses its own token pool for GitLab, as it did before. On GitLab.com, project access tokens need the Premium or Ultimate plan. On a Free namespace, GitLab refuses the create call with HTTP 400, whatever the token’s scope and role. The server counts that refusal as a failed mint, so the device serves no GitLab credential and does not use its pool. The server log names GitLab’s reason. See Git credentials on a device.
The connection’s Sandbox git tokens setting controls this. project_access_token is the default, and a connection without the setting uses it. An owner can set off. The server then mints no project token for that connection, and each device uses its own GitLab credential, such as its token pool. Any other value is a failed mint. To turn minting off, edit the GitLab connection in Integrations, set Sandbox git tokens to off, and save. The server still revokes the tokens it minted before.
A token with only the read_api scope can still read merge state. It cannot create a hook. In that case CodeHerder shows manual setup steps. See Set up a hook by hand.
The api scope is optional. It gives the token write access to GitLab. Use it only if you want one-step setup. See Integrations to connect GitLab.
Automatic setup
- Connect GitLab in Settings → Integrations. Use a token with the
apiscope. - Add a GitLab repo to your workspace. See Connecting repositories.
- CodeHerder creates the hook in the background. Adding the repo does not wait for it.
CodeHerder also creates the hook when you restore an archived repo. It moves the hook when you change the repo’s git URL.
Open the repo page to see the Webhook section. It shows the status and the last error. An admin can click Register, Rotate or Remove there. You can do the same from the CLI:
ch repo hook show <repo>
ch repo hook register <repo>
ch repo hook rotate <repo>
ch repo hook remove <repo>
Register is safe to repeat. CodeHerder deletes any hook that already points at its receive URL, so GitLab never holds two copies.
Set up a hook by hand
Click Register when the token cannot create hooks. CodeHerder then shows the receive URL, a secret and a list of steps. The secret appears once. Copy it now. CodeHerder cannot show it again. If you lose it, click Rotate for a new one. A later Try automatic setup keeps the current secret, so a hook you set up by hand keeps working. It shows the steps again, but not the secret.
- In GitLab, open the project. Go to Settings, then Webhooks.
- Choose Add new webhook. Paste the receive URL into the URL field.
- Paste the secret into the Secret token field.
- Turn on these triggers: Push events, Tag push events, Comments, Merge request events, Job events, Pipeline events, Releases events.
- Keep Enable SSL verification on. Save the webhook.
Rotate the secret
Click Rotate or run ch repo hook rotate. CodeHerder makes a new secret and replaces the old one on both sides. In manual mode, CodeHerder shows the new secret once. Paste it into the GitLab webhook.
A delivery that is in flight during the change can fail verification. GitLab sends later events with the new secret.
Remove the hook
Click Remove or run ch repo hook remove. CodeHerder deletes the GitLab hook, the stored secret and the hook state. Later deliveries to the receive URL get a 401 answer.
If GitLab refuses the delete, CodeHerder still removes its own side. The answer names the hook id. Delete that hook by hand in Settings → Webhooks.
Archiving a repo removes its hook. Deleting a workspace does not. The receive URL then answers 401, and GitLab disables the hook after repeated failures. Delete the hook by hand if you want it gone sooner.
Self-managed GitLab
Set the Host field of the GitLab connection to your GitLab hostname. Use the bare name, for example gitlab.example.com. The flow is the same as for gitlab.com.
Your GitLab instance must reach the server’s public base URL (CH_BASE_URL). If CodeHerder runs on a private network, an instance admin must turn on Allow requests to the local network from webhooks and integrations. The setting is under Admin → Settings → Network → Outbound requests.
CodeHerder also refuses to call a private GitLab host unless the server allows internal hosts. In that case it falls back to manual setup.
Request changes on a merge request
CodeHerder records a GitLab “request changes” review as repo.merge_request_changes_requested. GitLab 17 or later sends it in the merge request hook, as the reviewer’s state requested_changes.
- Open the merge request in GitLab as the reviewer.
- Select Your review, or Start review.
- Select Request changes.
- Select Submit review.
Use the web UI. A Developer-role token could not set this state through the REST or GraphQL API. A review summary note arrives as a separate comment event.
An approval adds the approver to the reviewer list. CodeHerder does not read that as a review request.
Troubleshooting
The Webhook section shows one of these last errors.
| Last error | What to do |
|---|---|
| no GitLab token that can create webhooks is connected for this host | Connect GitLab for this host. Use a token with the api scope. Or set up the hook by hand. |
| GitLab refused the webhook request; the token needs the api scope and the Maintainer role | Give the token the api scope and the Maintainer role. Then click Register. |
| CodeHerder may not call this GitLab host | The host is private or not allowed. Set up the hook by hand. |
| GitLab did not answer the webhook request | Check that GitLab is up. Then click Register again. |
| GitLab answered the webhook request with an error | Check the GitLab status. Then click Register again. |
| secret out of sync; rotate again | GitLab holds a new secret and CodeHerder holds the old one. Click Rotate. |
| the server has no public base URL (CH_BASE_URL), so GitLab has no address to post to | Ask the server operator to set CH_BASE_URL. |
If GitLab shows failed deliveries with a 401 status, the secrets do not match. Click Rotate.
Check the repo’s integration health
The repo page has an Integration health section. ch repo health <repo> shows the same data. It reads Healthy when deliveries arrive and nothing is missing. It reads Gap when GitLab shows merge request activity that no delivery announced. It reads Failing when deliveries arrive and fail. It reads Setup failed when the hook is not registered. For a gap, open Settings → Webhooks in GitLab, edit the CodeHerder webhook, open Recent events, and resend the missed delivery. The section links to the hook when CodeHerder knows its id. While the status is not healthy, CodeHerder reads the repo from GitLab every 30 seconds, so task state stays correct.
Last updated