GitLab Source
What it ingests
Project activity — merge requests, issues, commits, and the comments (notes/discussions) on merge requests and issues — across a single group (including its subgroups) or an explicit list of projects.
Works against GitLab.com by default and against a self-hosted instance when you set base_url.
Credential
The GitLab source references a gitlab_token credential by id. Any of GitLab's three access-token flavors works — they are identical on the wire:
| Token | Where to create it | Use it when |
|---|---|---|
| Personal access token | User → Preferences → Access tokens | You want one credential across several groups |
| Group access token | Group → Settings → Access tokens | You are ingesting one group (least privilege) |
| Project access token | Project → Settings → Access tokens | You are ingesting a fixed project list |
Required scope: read_api. (api also works but grants writes the source never makes.) For a group or project token, the Reporter role is enough.
curl -sS -X POST https://your-corveil-host/api/credentials \
-H "Authorization: Bearer <admin>" -H "Content-Type: application/json" \
-d '{"type":"gitlab_token","name":"acme-gitlab-ro","secret":"glpat-..."}'Copy the returned credential id.
One token, one instance
A token is scoped to the instance that issued it. A gitlab.com token will not authenticate against gitlab.acme.com, so a self-hosted source needs its own credential alongside its own base_url.
Config fields
| Key | Required | Notes |
|---|---|---|
group | one of group / projects | Full group path, including parents — acme or acme/platform. Subgroups are included. |
projects | one of group / projects | Comma-separated full project paths, e.g. acme/api, acme/platform/web. |
base_url | no | Self-hosted instance URL. Defaults to https://gitlab.com. |
Provide either a group or an explicit project list (or both — they are unioned, not one overriding the other).
Notes on the values:
- Paths are the full path as it appears in the URL. For
https://gitlab.com/acme/platform/web, the project isacme/platform/web, notweb. base_urlmust behttps(plainhttpis accepted only forlocalhost, for development). Include a subpath if your instance is mounted on one, e.g.https://example.com/gitlab.- An invalid path or a plaintext-
httpbase_urlis rejected when you save the source, not silently on every later poll.
Provider-side setup
- Create the access token above with the
read_apiscope. - Give it access to the group or projects you want to ingest — for a personal token that means the account is a member; for a group/project token the role is granted at creation.
- For a self-hosted instance, make sure the Corveil deployment can reach it over HTTPS.
Wire-up
POST /api/sensors
{
"sensor_type": "gitlab",
"name": "Acme GitLab",
"config": { "group": "acme" },
"credentials": { "token": "<gitlab_token credential id>" }
}Scoped to specific projects instead:
{
"sensor_type": "gitlab",
"name": "Acme API + Web",
"config": { "projects": "acme/api, acme/platform/web" },
"credentials": { "token": "<gitlab_token credential id>" }
}Self-hosted:
{
"sensor_type": "gitlab",
"name": "Acme Internal GitLab",
"config": { "group": "platform", "base_url": "https://gitlab.acme.com" },
"credentials": { "token": "<gitlab_token credential id>" }
}What lands in the ontology
The source stamps a signal on every event; the default bindings map each one to an entity type. You can preview and edit these on the Add sensor form and change them later in the source's bindings drawer.
| Signal | Entity | Notes |
|---|---|---|
push | Repository, Organization | The project, and the top-level group as the Organization |
merge_request | PullRequest | Named group/project!12 — the same type GitHub PRs use, so cross-provider queries work |
issue | Issue | Named group/project#7 |
commit | Commit | From the backfill |
note | Comment | Comments on merge requests and issues |
People are resolved from the actor on each event and deduplicated against identities from your other sources.
Merge requests and issues can share a number
GitLab numbers them in separate sequences, so !12 and #12 are different objects. The sigils are part of the entity name for exactly that reason.
Verify
Use Test connection on the source — it authenticates against GET /api/v4/user on the configured instance. Then watch the first poll: a healthy source reports events flowing.
Common failures and what they mean:
- 401 — the token is wrong, revoked, or belongs to a different instance.
- 403 — the token is valid but its scope is too narrow; it needs
read_api. - 404 on a group or project you know exists — GitLab answers 404 rather than 403 for something a token cannot see, so this is usually a membership or scope gap rather than a typo. The source's error message says so.