
The GitLab integration gives agents access to GitLab repositories and APIs. You can either provide a token directly (PAT mode) or let Daevix provision a dedicated identity per agent automatically (automated mode via a [credential provider](#credential-providers)).

## Choose Your Mode

| | Personal Access Token | Automated |
|---|---|---|
| **Setup effort** | Provide one token per agent | One-time credential provider setup, then per-agent linking is automatic |
| **Identity** | Shared - all agents use the operator's GitLab identity | Isolated - each agent gets its own GitLab user |
| **Scope** | Whatever the token has access to | Group-wide (service account) or project-specific (project access token) |
| **Deprovisioning** | Manual - revoke the token in GitLab yourself | Automatic - Daevix deletes the service account or revokes the token on unlink |
| **GitLab tier** | Any (Free, Premium, Ultimate) | On GitLab.com: service account mode works on Free; project access token mode requires Premium. Self-managed may vary. |

## Personal Access Token Mode

Use this when you want to link a single token directly to an agent.

### Step 1: Create a GitLab PAT

1. In GitLab, go to **User Settings > Access Tokens** (or **Profile > Access Tokens**)
2. Create a token with the required scopes:
   - `read_api` - **required** for Daevix to validate the token and identify the user
   - Plus whatever scopes the agent needs for its work (e.g., `write_repository` for pushing code)
3. Set an expiry date and click **Create personal access token**
4. Copy the token (`glpat-...`)

The `read_api` scope is required because Daevix calls GitLab's `/api/v4/user` endpoint during linking to validate the token and resolve the username. A token with only repository scopes will be rejected.

### Step 2: Link to the Agent

```bash
# With --pat flag (instance URL defaults to https://gitlab.com)
dvx agent integration gitlab link <agent> --pat glpat-...

# With a custom instance URL
dvx agent integration gitlab link <agent> --pat glpat-... --instance-url https://gitlab.example.com

# Interactive prompt (token hidden)
dvx agent integration gitlab link <agent>

# Piped from stdin (avoids token in shell history)
echo "glpat-..." | dvx agent integration gitlab link <agent>
```

Daevix validates the token by calling GitLab's `/api/v4/user` endpoint, then stores it encrypted as the `gitlab:token` agent secret.

## Automated Mode

Use this when you want Daevix to provision a dedicated GitLab identity per agent. Requires a [credential provider](#credential-providers) to be set up first.

### Step 1: Set Up a Credential Provider

If you haven't already, create a credential provider - see [Credential providers](#credential-providers) below. You'll need:

- A GitLab token with **Owner access** to the target group
- The **Group ID** of that group (found on the group's settings page)
- A **provisioning mode** - service account or project access token

### Step 2: Link to the Agent

Link the agent in automated mode by passing the credential provider's ID with `--credential-provider <id>` instead of `--pat`:

```bash
# Service-account provisioning mode
dvx agent integration gitlab link <agent> --credential-provider 1

# Project-access-token provisioning mode (requires --project-id)
dvx agent integration gitlab link <agent> --credential-provider 1 --project-id 54321
```

Daevix uses the credential provider's token to create a new identity in GitLab for this agent:

- **Service account mode**: creates a service account in the group, then mints a PAT for it
- **Project access token mode**: creates a project access token scoped to the specified project

The minted token is stored encrypted as the `gitlab:token` agent secret.

## How Agents Use GitLab Credentials

Once linked, agents access their GitLab token through the enclave's credentials API. The token is not directly accessible via `dvxir secrets list` - it is stored with `agent_accessible = false` and must be retrieved through the credentials endpoint.

```bash
# Using the dvxir CLI
dvxir credentials list
# Output: gitlab    pat    my-user

dvxir credentials get gitlab
# Output: glpat-... (raw token, no newline - suitable for piping)

# Or via the HTTP API
curl -H "Authorization: Bearer $(cat ~/.dvx/token)" \
  $DVX_BROKER_URL/v1/agent/credentials
# [{"provider": "gitlab", "display_name": "my-user", "auth_type": "pat"}]

curl -H "Authorization: Bearer $(cat ~/.dvx/token)" \
  $DVX_BROKER_URL/v1/agent/credentials/gitlab
# {"token": "glpat-...", "expires_at": null}
```

Agents typically use the token for Git operations (clone, push, pull) or GitLab API calls by setting:

```bash
git clone https://oauth2:$GITLAB_TOKEN@gitlab.com/group/project.git
# or
curl -H "PRIVATE-TOKEN: $GITLAB_TOKEN" https://gitlab.com/api/v4/projects
```

## Unlinking

Unlinking removes the integration, its encrypted secrets, and any associated configuration.

```bash
dvx agent integration gitlab unlink <agent>
```

For automated integrations, Daevix also attempts to deprovision the identity in GitLab:

- **Service account mode**: deletes the service account from the group
- **Project access token mode**: revokes the project access token

This deprovisioning is best-effort - if the GitLab API call fails (e.g., the credential provider's token has expired), the local integration is still removed and the failure is logged.

## Token Lifetime and Rotation

| Mode | Token lifetime | Rotation |
|------|---------------|----------|
| PAT | Set by the operator when creating the token in GitLab | Manual - unlink and re-link with a new token |
| Automated (service account) | 30 days from provisioning | Unlink and re-link to mint a new token |
| Automated (project access token) | 30 days from provisioning | Unlink and re-link to mint a new token |

Automated tokens are minted with the `self_rotate` scope, which allows the agent to rotate the token itself via the GitLab API if needed.

## Credential providers

A credential provider is an org-level resource that automates per-agent identity provisioning. Instead of manually creating and pasting a token for each agent, you register a credential provider once with a privileged identity in GitLab, and Daevix uses it to mint a dedicated, scoped identity per agent automatically. Credential providers currently support **GitLab only**.

### How it works

1. An org admin registers a credential provider with a GitLab token that has **Owner access** to a group
2. When linking an agent to GitLab in automated mode, Daevix uses the provider's token to create a dedicated identity for that agent
3. Each agent gets its own scoped credential - no shared tokens
4. When an agent is unlinked, Daevix revokes the provisioned identity in GitLab

### Prerequisites

- A GitLab group where agent identities will be provisioned
- A GitLab token with **Owner access** (access level 50) to that group - this can be a personal access token from a user with the Owner role (any tier), a group access token with Owner role (requires GitLab Premium on GitLab.com), or a group service account token with Owner role (works on the GitLab.com free tier)
- The token needs the `api` scope at minimum

### Provisioning modes

**Service account** - creates a **GitLab service account** per agent within the group, then mints a personal access token for that service account.

- Each agent gets a distinct GitLab user identity (e.g., `service_account_dvx-agent-1-my-bot`) with access to all projects in the group
- On unlink, the service account is deleted from the group
- Works on the GitLab.com **free tier** - no Premium required. Free-tier top-level groups are capped at 100 service accounts (Premium/Ultimate is unlimited), and creating service accounts requires the group Owner to have verified their identity. Self-managed instances may vary.

Use this when you want each agent to have a group-wide identity that can access multiple projects.

**Project access token** - creates a **project access token** per agent, scoped to a specific project.

- Each agent gets a token scoped to one project only, created with Developer access level (level 30)
- On unlink, the project access token is revoked
- Requires a **project ID** when linking the agent
- Requires **GitLab Premium** (or Ultimate) on GitLab.com - project access tokens are not available on the free tier there. The provider's token must have Owner access to the group that contains the target project. Self-managed instances may vary.

Use this when you want agents scoped to individual projects rather than the entire group.

Both modes mint tokens with the `api`, `write_repository`, and `self_rotate` scopes by default. Provisioned tokens expire after **30 days**; there is no automatic rotation - unlink and re-link the agent to mint a new token, or use the `self_rotate` scope to rotate from the agent side.

### Managing credential providers

```bash
# List credential providers
dvx credential-provider list

# Create a credential provider
dvx credential-provider create \
  --provider gitlab \
  --name production-gitlab \
  --instance-url https://gitlab.com \
  --token glpat-... \
  --group-id 12345 \
  --provisioning-mode service_account

# Rotate the provider's admin token
dvx credential-provider rotate <id> --token glpat-new-...

# Delete (must unlink all agents first)
dvx credential-provider delete <id>
```

Daevix validates the token and group access before saving on create and rotate. Rotating the provider token does **not** invalidate existing agent tokens - agents keep their current credentials until they expire or are unlinked. A credential provider can only be deleted if **no agents reference it**, so unlink all agents using the provider first.

### Linking an agent to a credential provider

Once a credential provider exists, link an agent to GitLab using `--credential-provider <id>` instead of `--pat`:

```bash
# Service-account provisioning mode
dvx agent integration gitlab link <agent> --credential-provider 1

# Project-access-token provisioning mode (requires --project-id)
dvx agent integration gitlab link <agent> --credential-provider 1 --project-id 4567
```

`--pat` and `--credential-provider` are mutually exclusive. Passing both returns an error before any request is sent.

## Troubleshooting

### "Invalid GitLab personal access token" on link

The token failed validation against GitLab's `/api/v4/user` endpoint. Verify:
- The token is correct (starts with `glpat-`)
- The instance URL is correct
- The token hasn't expired or been revoked

### "Token does not have Owner access to the specified group" on credential provider creation

The token's user must have Owner role (access level 50) on the specified group. Check:
- The user is a member of the group (not just a project within the group)
- The user's role is **Owner**, not Maintainer or Developer
- The Group ID is correct

### "Credential provider is not active" on automated link

The credential provider has been marked as inactive, likely due to a validation failure. Check the provider's status with `dvx credential-provider list` and try rotating its token.

### "gitlab client not configured" (500 error)

The control plane was not configured with a GitLab client. Ensure the control plane binary includes the GitLab client wiring - this was fixed by adding `WithGitLabClient(gitlab.NewClient())` to the operator service options.

### Agent can't access GitLab after linking

- Verify the integration was linked successfully (the `dvx agent integration gitlab link` command reports an error if linking fails)
- Check that the token hasn't expired (automated tokens last 30 days)
- For automated service account mode, verify the service account still exists in the GitLab group
- For automated project access token mode, verify the token still exists in the project's access tokens
