Feature Request: GitLab Integration Support
Summary
Add GitLab as a supported git provider alongside GitHub, enabling users to connect GitLab repositories, clone private projects, push branches, and create merge requests from the agent workflow. GitLab access tokens (personal, group, and project) must be supported as a first-class authentication method alongside OAuth, allowing granular permission scoping that OAuth alone cannot provide.
Motivation
Open Agents currently only supports GitHub as a git provider. The entire repo access, auth, and PR/push flow is tightly coupled to GitHub App primitives (installation tokens, GitHub OAuth, GitHub webhooks). This excludes a significant portion of teams — particularly enterprises and self-hosted shops — that use GitLab as their primary SCM.
Since the project is explicitly designed to be “forked and adapted, not treated as a black box,” supporting GitLab would meaningfully expand the audience and reinforce that goal. Many organizations evaluating cloud coding agents run GitLab (self-managed or SaaS) and cannot adopt Open Agents without building their own integration from scratch.
Why Access Tokens Are Required, Not Optional
GitLab’s OAuth application model grants broad scopes (api, read_repository, write_repository) that apply uniformly across every project the authenticated user can access. There is no mechanism in GitLab OAuth to restrict a token’s reach to a single project or group the way a GitHub App installation scopes access to selected repositories.
GitLab access tokens solve this directly:
- Project Access Tokens are scoped to a single repository with an explicit role (Reporter, Developer, Maintainer) and fine-grained scopes (
read_repository,write_repository,api). The agent never touches anything outside the target project. - Group Access Tokens are scoped to a group and its subgroups/projects — appropriate for teams that want the agent to operate across related repositories without granting org-wide access.
- Personal Access Tokens (PATs) provide user-level access with selectable scopes. They are the most common auth method for CI/CD, automation, and self-managed GitLab instances where OAuth apps are not configured.
For security-conscious organizations, OAuth-only support would be a non-starter. The ability to hand the agent a project-scoped token with write_repository and nothing else is a hard requirement for adoption in regulated environments.
Current GitHub-Specific Surface Area
Based on the current codebase structure and README, the following are tightly coupled to GitHub:
Authentication & OAuth
- GitHub App user authorization flow (
NEXT_PUBLIC_GITHUB_CLIENT_ID,GITHUB_CLIENT_SECRET) - OAuth callback route at
/api/github/app/callback - No separation between “git provider auth” and “GitHub auth” — the two are fused
Repository Access
- GitHub App installation tokens for cloning private repos
- Installation-based repo/org access model (
GITHUB_APP_ID,GITHUB_APP_PRIVATE_KEY) NEXT_PUBLIC_GITHUB_APP_SLUGfor app installation flow
Code Operations
- Auto-commit, push, and branch creation assumes GitHub remote
- PR creation uses GitHub API (not generic git forge API)
GITHUB_WEBHOOK_SECRETfor inbound event handling
Environment Variables
Six required env vars are GitHub-specific:
NEXT_PUBLIC_GITHUB_CLIENT_ID
GITHUB_CLIENT_SECRET
GITHUB_APP_ID
GITHUB_APP_PRIVATE_KEY
NEXT_PUBLIC_GITHUB_APP_SLUG
GITHUB_WEBHOOK_SECRETProposed Approach
1. Dual Auth Model: OAuth + Access Tokens
GitLab integration should support two authentication paths as equal first-class options:
Path A — OAuth Application (interactive, user-scoped) Standard OAuth 2.0 with PKCE. The user authorizes via browser redirect, and Open Agents receives a token with the granted scopes. Best for individual developers connecting their own account.
Path B — Access Token (static, scope-controlled) The user provides a pre-created access token (personal, group, or project-level). No browser redirect required. The token is encrypted at rest and used directly for API calls and git operations. Best for teams, CI-like workflows, and environments where granular permission control is required.
The two paths converge on the same downstream interface — once authenticated, the provider abstraction doesn’t care whether the credential came from OAuth or a pasted token.
Access Token Hierarchy
| Token Type | Scope | Best For |
|---|---|---|
| Project Access Token | Single repository, explicit role + scopes | Agent restricted to one repo. Tightest blast radius. |
| Group Access Token | All projects within a group/subgroup, explicit role + scopes | Agent operating across related repos in a team. |
| Personal Access Token | All projects the user can access, selectable scopes | Individual developer use, self-managed instances without OAuth apps. |
All three types support the same scope flags (read_repository, write_repository, api, etc.) and are validated the same way via the GitLab API.
Token Validation
On token submission, Open Agents should call the GitLab API to validate the token and determine its type and scope:
GET /api/v4/personal_access_tokens/self— returns token metadata including scopes, expiry, and whether it’s active- If that returns 404/403, the token may be a project or group access token — validate by attempting
GET /api/v4/projectsorGET /api/v4/groupswith the token and inspecting accessible resources - Display the resolved token type, scopes, and accessible projects/groups to the user before saving
2. Git Provider Abstraction Layer
Create an interface that encapsulates the operations both GitHub and GitLab need to support. The credential type is abstracted behind a union so the provider implementation handles the OAuth-vs-token difference internally:
type GitCredential =
| { type: 'oauth'; accessToken: string; refreshToken?: string }
| { type: 'access_token'; token: string; tokenLevel: 'personal' | 'group' | 'project' };
interface GitProvider {
readonly name: 'github' | 'gitlab';
// Auth — OAuth flow (optional for token-based auth)
getAuthorizationUrl?(state: string): string;
handleOAuthCallback?(code: string): Promise<GitCredential>;
refreshToken?(refreshToken: string): Promise<GitCredential>;
// Auth — Token flow
validateToken?(token: string, baseUrl: string): Promise<TokenValidationResult>;
// Repository access
listRepositories(credential: GitCredential): Promise<Repository[]>;
cloneRepository(repo: Repository, credential: GitCredential, sandbox: Sandbox): Promise<void>;
// Code operations
createBranch(repo: Repository, branchName: string, credential: GitCredential): Promise<void>;
pushChanges(repo: Repository, branch: string, credential: GitCredential): Promise<void>;
createMergeRequest(repo: Repository, mr: MergeRequestInput, credential: GitCredential): Promise<MergeRequest>;
// Webhooks
verifyWebhook(payload: string, signature: string): boolean;
parseWebhookEvent(payload: unknown): WebhookEvent;
}
interface TokenValidationResult {
valid: boolean;
tokenLevel: 'personal' | 'group' | 'project';
scopes: string[];
expiresAt: string | null;
accessibleProjects?: { id: number; pathWithNamespace: string }[];
missingScopes?: string[]; // scopes required by Open Agents but not granted
}The GitHubProvider implementation would only implement the OAuth methods (since GitHub Apps don’t use static tokens in the same way). The GitLabProvider would implement both.
3. Environment Variables
GitLab configuration supports both auth paths:
# Required
GITLAB_BASE_URL # defaults to https://gitlab.com, overridable for self-managed
# OAuth path (optional — not needed if using token auth only)
GITLAB_CLIENT_ID
GITLAB_CLIENT_SECRET
# Token path (optional — not needed if using OAuth only)
# Tokens are stored per-user in the database, not as env vars.
# But for single-tenant / self-hosted deployments, a default token can be set:
GITLAB_DEFAULT_ACCESS_TOKEN
# Webhooks (optional)
GITLAB_WEBHOOK_SECRETGITLAB_BASE_URL is critical — unlike GitHub, GitLab is widely self-hosted, so the integration cannot assume gitlab.com. Every API call and git clone URL must be constructed relative to this base.
For multi-user deployments, individual access tokens are stored encrypted in the database per-user (not in env vars). GITLAB_DEFAULT_ACCESS_TOKEN is a convenience for single-tenant or self-hosted setups where one token serves the whole instance.
4. API Route Refactoring
Current routes under /api/github/ should be restructured:
/api/git/[provider]/callback → OAuth callback (github | gitlab)
/api/git/[provider]/webhook → Inbound webhooks
/api/git/[provider]/repos → Repository listing
/api/git/[provider]/token/validate → Token validation + scope check (gitlab only)
/api/git/[provider]/token/connect → Save encrypted token + link provider (gitlab only)Or, keep /api/github/ and add /api/gitlab/ in parallel — simpler to ship incrementally but creates more duplication.
5. GitLab-Specific Considerations
| Concern | GitHub | GitLab Equivalent |
|---|---|---|
| App model | GitHub App (installation tokens) | OAuth Application or Access Tokens (project/group/personal) |
| Permission scoping | App installed on selected repos | Project token = single repo, Group token = group, PAT = user-wide |
| PR creation | POST /repos/{owner}/{repo}/pulls | POST /projects/{id}/merge_requests |
| Repo cloning auth | Installation token as password | OAuth token or access token as password via https://oauth2:{token}@gitlab.example.com/... |
| Webhook verification | HMAC-SHA256 on X-Hub-Signature-256 | Secret token on X-Gitlab-Token header (simple string match) |
| Org/group access | App installed on org | Group access token or OAuth scope |
| Self-hosted | GitHub Enterprise Cloud is a separate product | GITLAB_BASE_URL overrides all API and git paths |
| Token expiry | Installation tokens auto-expire (1h) | Access tokens have configurable expiry; OAuth tokens use refresh flow |
6. Database Schema Changes
The sessions/users tables likely store GitHub-specific identifiers (GitHub user ID, installation ID, etc.). These should be generalized:
- Add a
git_providercolumn (enum:github,gitlab) - Add a
git_auth_methodcolumn (enum:oauth,access_token) - Store provider-specific IDs in a flexible structure (JSONB or separate provider tables)
- Ensure repo references include provider context (not just
owner/repo— GitLab uses numeric project IDs andnamespace/projectpaths) - Access tokens stored encrypted at rest, with metadata: token level, scopes, expiry, and the resolved list of accessible projects at time of connection
7. UI Changes
- Connect GitLab flow in settings, offering two clear paths:
- “Sign in with GitLab” → OAuth redirect (only available if OAuth app is configured)
- “Connect with Access Token” → paste token, validate, show resolved scope/projects, save
- Repository picker should indicate which provider a repo comes from and, for token auth, show which token grants access
- Token management UI: list connected tokens, show type/scopes/expiry, revoke/replace
- Session/chat UI referencing “PR” should adapt to “Merge Request” when the repo is GitLab-hosted
- Warning when a token is approaching expiry
Implementation Phases
Phase 1 — Abstraction (no new functionality)
Extract the GitHub-specific code behind the GitProvider interface. Introduce the GitCredential union type. All existing GitHub behavior stays identical, but the coupling is broken.
Phase 2 — GitLab Access Token Auth + Repo Access Implement token validation, encrypted storage, and the “Connect with Access Token” UI flow. Support cloning and reading repos via project/group/personal access tokens. This is the minimum viable GitLab integration and can ship without OAuth support.
Phase 3 — GitLab OAuth (optional path) Add the OAuth flow for users who prefer browser-based auth. This is additive — token auth from Phase 2 continues to work independently.
Phase 4 — Push + Merge Request Creation Implement branch push and MR creation via the GitLab API. Auto-commit and auto-MR work the same as the GitHub flow. Both OAuth and token credentials are supported.
Phase 5 — Webhooks + Self-Managed Hardening Handle inbound GitLab webhooks (push events, MR events). Ensure the full flow works against self-managed GitLab instances with custom base URLs, internal CAs, and network restrictions.
Open Questions
- Should provider selection be per-user or per-session? A user might have both GitHub and GitLab repos. Ideally they can connect both providers and select per-session.
- Self-managed GitLab TLS: Self-hosted instances may use internal CAs. Should the sandbox trust custom CA bundles?
- Token rotation: Project and group access tokens can be rotated via the GitLab API (
POST /personal_access_tokens/{id}/rotate). Should Open Agents handle automatic rotation before expiry? - Minimum required scopes: The integration should enforce a minimum scope set (likely
read_repository+write_repository+apifor full functionality) and degrade gracefully when only read scopes are present (disable push/MR creation, allow clone/read). - Scope: Should this also cover Bitbucket, or is GitLab sufficient for a first pass? A clean abstraction layer would make Bitbucket straightforward to add later.
References
Activity
0No activity yet.