GitLab App Setup¶
Bernstein can receive GitLab webhooks (gitlab.com and self-managed) and automatically create tasks from GitLab events (merge requests, notes, pipeline failures). This is the GitLab parity surface for the GitHub App integration.
Overview¶
The webhook handler lives at POST /webhooks/gitlab on the Bernstein task server. When GitLab sends a webhook, Bernstein:
- Constant-time verifies the
X-Gitlab-Tokenheader against the configured shared secret. - Parses the
X-Gitlab-Eventheader + JSON body. - Maps the event to one or more Bernstein tasks.
- Creates the tasks in the task store.
Event mapping¶
| GitLab event | Condition | Bernstein task |
|---|---|---|
Merge Request Hook (action: open/reopen) | New / re-opened MR | Standard task, priority/role inferred from MR labels |
Pipeline Hook (status: failed) | Failed pipeline | CI-fix task; retries escalate to opus after attempt 2 |
Note Hook (note on MR/issue) | Slash command or actionable review language | /bernstein <verb> task, or fix task |
Slash commands¶
/bernstein <verb> is supported on MR / issue notes:
| Verb | Resulting task |
|---|---|
fix [description] | Priority-1 fix task, backend role |
plan [description] | Planning task, manager role |
evolve [description] | Upgrade proposal, backend role |
qa [description] | QA verification task, qa role |
review [description] | QA review task |
Setup¶
1. Create the webhook secret¶
For posting back to GitLab (pipeline statuses and MR cost notes):
For self-managed installs override the base URL:
The default is https://gitlab.com.
2. Configure the webhook in GitLab¶
In your project: Settings > Webhooks > Add new webhook.
- URL:
https://<your-server>/webhooks/gitlab - Secret token: paste the same value as
GITLAB_WEBHOOK_TOKEN. - Trigger: enable Merge request events, Pipeline events, Comments (Notes).
- SSL verification: keep enabled in production.
3. Start the server¶
GitLab will deliver to /webhooks/gitlab; Bernstein verifies the token via hmac.compare_digest (constant time) and routes events.
Local development¶
Use a tunneling tool (e.g. ngrok, cloudflared) to expose your server. Set the public URL as the webhook target in GitLab's project settings.
Self-managed GitLab¶
For self-managed installs:
- Set
BERNSTEIN_GITLAB_URLto the on-prem instance base URL. - Use a project / group access token (with
apiscope) instead of a personal access token if you want least-privilege. - The same
/webhooks/gitlabendpoint andX-Gitlab-Tokenheader apply - GitLab's webhook surface is identical between gitlab.com and self-managed.
Secret rotation¶
The webhook token rotates the same way as any shared secret:
- Generate a new value:
openssl rand -hex 32. - In GitLab: update the project's webhook Secret token.
- On the server: set
GITLAB_WEBHOOK_TOKENand restart Bernstein. - Confirm with a test delivery from the GitLab webhook page.
Between steps 2 and 3 you'll get 401s; perform during a brief maintenance window.
Label conventions¶
Priority mapping (mirrors GitHub):
bug,critical,security-- priority 1 (highest)enhancement,feature-- priority 2docs,documentation,chore-- priority 3
Role mapping:
backend,frontend,qa,security,docs-- mapped directly to Bernstein roles.
Architecture¶
GitLab --> POST /webhooks/gitlab --> verify_token() (constant-time)
--> parse_webhook()
--> mapper (merge_request_to_tasks /
pipeline_to_tasks /
note_to_task)
--> store.create()
Source code: src/bernstein/gitlab_app/.
| Module | Purpose |
|---|---|
app.py | Token-based auth + base-URL config (BERNSTEIN_GITLAB_URL) |
webhooks.py | X-Gitlab-Token constant-time verify + event parsing |
mapper.py | GitLab event → TriggerEvent normalisation |
slash_commands.py | /bernstein <verb> parser for MR / issue notes |
pipelines.py | Commit-status API: MR pipeline status from agent runs |
ci_router.py | Trace fetch + parse + blame for failed pipelines |
cost_reporter.py | MR note: posts agent run cost summary |