
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@gitlab/opencode-gitlab-plugin
Advanced tools
GitLab tools plugin for OpenCode - provides GitLab API access for merge requests, issues, pipelines, and more
A comprehensive GitLab API plugin for OpenCode that provides AI-powered access to GitLab's REST and GraphQL APIs. This plugin enables seamless interaction with merge requests, issues, pipelines, repositories, epics, snippets, audit events, and more through natural language commands.
first/after and last/before cursors for efficient data fetchingThe following tools use GitLab's GraphQL API for enhanced functionality:
| Category | Tools | Benefits |
|---|---|---|
| TODOs | gitlab_list_todos, gitlab_get_todo_count | Cursor-based pagination, rich filtering |
| Notes | gitlab_list_notes, gitlab_get_note, gitlab_create_note | Unified interface for all resource types, efficient pagination |
| Discussions | gitlab_list_discussions, gitlab_get_discussion, gitlab_create_discussion, gitlab_resolve_discussion | Unified interface for all resource types, cursor-based pagination, code position support |
| Auto-merge | gitlab_set_mr_auto_merge | MWPS (Merge When Pipeline Succeeds), merge train support |
| Security | All vulnerability management tools | Type-safe GID validation, mutation support |
graph TB
subgraph "OpenCode Environment"
AI[AI Assistant]
Plugin[GitLab Plugin]
end
subgraph "Plugin Components"
Tools[Tool Definitions]
Client[GitLab API Client]
Auth[Authentication Manager]
Validator[Zod Schema Validator]
end
subgraph "GitLab API"
REST[REST API v4]
GraphQL[GraphQL API]
MR[Merge Requests]
Issues[Issues]
Pipelines[Pipelines]
Repos[Repositories]
Epics[Epics]
Security[Security]
end
AI -->|Natural Language| Plugin
Plugin --> Tools
Tools --> Validator
Validator --> Client
Client --> Auth
Auth --> REST
Auth --> GraphQL
REST --> MR
REST --> Issues
REST --> Pipelines
REST --> Repos
REST --> Epics
GraphQL --> Security
GraphQL --> MR
graph LR
subgraph "src/index.ts"
A[GitLabApiClient Class]
B[Authentication Functions]
C[Tool Definitions]
D[Plugin Export]
end
A --> A1[HTTP Methods]
A --> A2[Merge Request APIs]
A --> A3[Issue APIs]
A --> A4[Pipeline APIs]
A --> A5[Repository APIs]
A --> A6[Epic APIs]
A --> A7[Search APIs]
B --> B1[readTokenFromAuthStorage]
B --> B2[getGitLabClient]
C --> C1[69 Tool Definitions]
D --> A
D --> B
D --> C
sequenceDiagram
participant User
participant Plugin
participant AuthManager
participant Storage
participant GitLab
User->>Plugin: Initialize Plugin
Plugin->>AuthManager: getGitLabClient()
AuthManager->>AuthManager: Check GITLAB_TOKEN env
alt Token in Environment
AuthManager->>GitLab: Use env token
else No env token
AuthManager->>Storage: Read ~/.local/share/opencode/auth.json
Storage->>AuthManager: Return token
AuthManager->>GitLab: Use stored token
end
GitLab->>Plugin: API Response
Plugin->>User: Tool Result
# Install the package
npm install @gitlab/opencode-gitlab-plugin
# Or with Bun
bun add @gitlab/opencode-gitlab-plugin
# Or with yarn
yarn add @gitlab/opencode-gitlab-plugin
# Using npm
npm install git+https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin.git
# Using Bun
bun add git+https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin.git
# Install specific version from npm
npm install @gitlab/opencode-gitlab-plugin@1.0.0
# Install from specific git tag
npm install git+https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin.git#v1.0.0
# Install from specific branch
npm install git+https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin.git#main
Add to your package.json:
{
"dependencies": {
"@gitlab/opencode-gitlab-plugin": "^1.0.0"
}
}
Then run:
npm install
# Required: GitLab API Token
export GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx
# Optional: Custom GitLab Instance (defaults to https://gitlab.com)
export GITLAB_INSTANCE_URL=https://gitlab.example.com
Add the following plugin to your opencode configuration ~/.config/opencode/opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["@gitlab/opencode-gitlab-plugin"]
}
The plugin supports reading tokens from OpenCode's auth storage:
Location: ~/.local/share/opencode/auth.json
Format:
{
"gitlab": {
"type": "oauth",
"access": "your-oauth-token"
}
}
Or for API tokens:
{
"gitlab": {
"type": "api",
"key": "glpat-xxxxxxxxxxxxxxxxxxxx"
}
}
GITLAB_TOKEN environment variable (highest priority)~/.local/share/opencode/auth.json)The plugin provides 64 tools organized into the following categories:
| Tool | Description |
|---|---|
gitlab_get_merge_request | Get details of a specific merge request with title, description, state, author, assignees, reviewers, labels, and diff stats |
gitlab_list_merge_requests | List merge requests with filtering by state, scope, and labels |
gitlab_create_merge_request | Create a new merge request |
gitlab_update_merge_request | Update merge request title, description, state, assignees, reviewers, and labels |
gitlab_get_mr_changes | Get file changes/diffs for a merge request |
gitlab_get_mr_details | Get additional MR details (commits or pipelines) with detail_type parameter |
gitlab_list_merge_request_diffs | List file diffs with pagination support for large changesets |
gitlab_set_mr_auto_merge | Enable auto-merge (MWPS) using GraphQL API when pipeline succeeds |
| Tool | Description |
|---|---|
gitlab_create_issue | Create a new issue with title, description, labels, assignees, and milestone |
gitlab_get_issue | Get issue details including state, author, assignees, labels, and comments |
gitlab_list_issues | List issues with filtering by state, labels, assignee, and milestone |
| Tool | Description |
|---|---|
gitlab_get_epic | Get epic details with title, description, state, dates, and associated issues |
gitlab_list_epics | List epics with filtering by state, author, and labels |
gitlab_create_epic | Create a new epic in a group |
gitlab_update_epic | Update epic title, description, labels, dates, and state |
gitlab_manage_epic_issues | Manage issues linked to an epic (list, add, remove) with action parameter |
| Tool | Description |
|---|---|
gitlab_list_pipelines | List pipelines with filtering by status, ref, and username |
gitlab_get_pipeline | Get pipeline details with jobs and status |
gitlab_list_pipeline_jobs | List all jobs in a pipeline with optional scope filtering |
gitlab_get_job_log | Get the log output of a specific CI job |
gitlab_retry_job | Retry a failed or canceled job |
gitlab_get_pipeline_failing_jobs | Get only failed jobs for easier debugging |
gitlab_lint_ci_config | Validate CI/CD YAML config with mode parameter (content or existing repository) |
| Tool | Description |
|---|---|
gitlab_get_file | Get file contents from any branch, tag, or commit |
gitlab_get_commit | Get commit details with metadata, author, and stats |
gitlab_list_commits | List commits with filtering by branch, path, and dates |
gitlab_get_commit_diff | Get diff for a specific commit |
gitlab_list_repository_tree | List files and directories at a given path |
gitlab_list_branches | List all branches in a repository |
gitlab_get_commit_comments | Get all commit comments in flat structure |
| Tool | Description |
|---|---|
gitlab_search | Unified search across all GitLab resources with scope-specific options (projects, issues, merge_requests, milestones, users, blobs, commits, notes, wiki_blobs, group_projects) |
gitlab_documentation_search | Search GitLab official documentation at docs.gitlab.com |
| Tool | Description |
|---|---|
gitlab_get_work_item | Get a work item (unified model for issues, epics, tasks) |
gitlab_list_work_items | List work items in a project or group |
gitlab_get_work_item_notes | Get all comments for a work item |
gitlab_create_work_item | Create a new work item |
gitlab_update_work_item | Update work item title, description, state, and labels |
gitlab_create_work_item_note | Add a comment to a work item |
| Tool | Description |
|---|---|
gitlab_list_vulnerabilities | List security vulnerabilities with filtering by state, severity, and type |
gitlab_get_vulnerability_details | Get detailed vulnerability information with remediation |
gitlab_create_vulnerability_issue | Create an issue linked to vulnerabilities (GraphQL) |
gitlab_dismiss_vulnerability | Dismiss vulnerability with reason (GraphQL) |
gitlab_confirm_vulnerability | Confirm a vulnerability as valid (GraphQL) |
gitlab_revert_vulnerability_to_detected | Revert vulnerability state (GraphQL) |
gitlab_update_vulnerability_severity | Update vulnerability severity level (GraphQL) |
gitlab_link_vulnerability_to_issue | Link vulnerabilities to existing issue (GraphQL) |
Note: All GraphQL-based security tools include automatic GID (Global ID) format validation.
| Tool | Description |
|---|---|
gitlab_list_todos | List TODO items with cursor-based pagination (GraphQL) |
gitlab_mark_todo_done | Mark TODOs as done with action parameter (one or all) |
gitlab_get_todo_count | Get count of pending TODOs (GraphQL) |
| Tool | Description |
|---|---|
gitlab_get_project | Get project details and metadata |
gitlab_list_project_members | List all members of a project |
gitlab_get_current_user | Get authenticated user information |
| Tool | Description |
|---|---|
gitlab_list_discussions | List discussions (comment threads) on any GitLab resource (MRs, issues, epics, commits, snippets) with cursor pagination |
gitlab_get_discussion | Get a specific discussion thread with all replies from any resource type |
gitlab_create_discussion | Create a new discussion thread OR reply to an existing one (supports code-position comments for MRs and commits) |
gitlab_resolve_discussion | Mark a discussion thread as resolved or unresolve it (MRs and issues only) |
| Tool | Description |
|---|---|
gitlab_list_notes | List all notes/comments on any resource (MRs, issues, epics, snippets) with cursor-based pagination |
gitlab_get_note | Get a single note by ID (issues and epics only) |
gitlab_create_note | Add a simple comment to any resource (for thread replies, use gitlab_create_discussion) |
| Tool | Description |
|---|---|
gitlab_list_project_audit_events | List audit events for a project (requires owner role) |
gitlab_list_group_audit_events | List audit events for a group (requires owner role) |
gitlab_list_instance_audit_events | List instance-level audit events (requires admin access) |
| Tool | Description |
|---|---|
run_git_command | Execute safe, read-only git commands (status, log, show, diff, blame, etc.) with security restrictions |
| Tool | Description |
|---|---|
gitlab_get_wiki_page | Get wiki page content and metadata |
import gitlabPlugin from '@gitlab/opencode-gitlab-plugin';
const plugin = await gitlabPlugin({});
// Create a new issue
const issue = await plugin.tool.gitlab_create_issue.execute({
project_id: 'my-group/my-project',
title: 'Fix authentication bug',
description:
'## Problem\n\nUsers cannot login with OAuth.\n\n## Steps to Reproduce\n1. Go to login page\n2. Click OAuth button\n3. Error occurs',
labels: 'bug,authentication,priority::high',
assignee_ids: [42],
milestone_id: 10,
due_date: '2025-12-31',
});
console.log(`Issue created: ${issue.web_url}`);
// Add a comment to the issue (using unified notes tool)
await plugin.tool.gitlab_create_note.execute({
resource_type: 'issue',
project_id: 'my-group/my-project',
iid: issue.iid,
body: 'I will start working on this today.',
});
// List all issues with specific labels
const issues = await plugin.tool.gitlab_list_issues.execute({
project_id: 'my-group/my-project',
labels: 'bug',
state: 'opened',
});
// Get merge request details
const mr = await plugin.tool.gitlab_get_merge_request.execute({
project_id: 'gitlab-org/gitlab',
mr_iid: 12345,
include_changes: true,
});
// Get discussions (unified tool supports all resource types)
const discussions = await plugin.tool.gitlab_list_discussions.execute({
resource_type: 'merge_request',
project_id: 'gitlab-org/gitlab',
iid: 12345,
});
// Add a review comment (creates a new discussion)
await plugin.tool.gitlab_create_discussion.execute({
resource_type: 'merge_request',
project_id: 'gitlab-org/gitlab',
iid: 12345,
body: 'LGTM! Great work on this feature.',
});
// Reply to an existing discussion thread
await plugin.tool.gitlab_create_discussion.execute({
resource_type: 'merge_request',
project_id: 'gitlab-org/gitlab',
iid: 12345,
discussion_id: discussions.discussions.nodes[0].id,
body: 'Thanks for addressing the feedback!',
});
// List recent pipelines
const pipelines = await plugin.tool.gitlab_list_pipelines.execute({
project_id: 'my-group/my-project',
status: 'failed',
limit: 5,
});
// Get failed jobs
const failedJobs = await plugin.tool.gitlab_get_pipeline_failing_jobs.execute({
project_id: 'my-group/my-project',
pipeline_id: pipelines[0].id,
});
// Get job logs
for (const job of failedJobs) {
const log = await plugin.tool.gitlab_get_job_log.execute({
project_id: 'my-group/my-project',
job_id: job.id,
});
console.log(`Job ${job.name} failed with:\n${log}`);
}
// Retry failed jobs
await plugin.tool.gitlab_retry_job.execute({
project_id: 'my-group/my-project',
job_id: failedJobs[0].id,
});
// Create an epic
const epic = await plugin.tool.gitlab_create_epic.execute({
group_id: 'my-group',
title: 'Q1 2025 Features',
description: 'All features planned for Q1 2025',
start_date: '2025-01-01',
end_date: '2025-03-31',
labels: 'Q1,planning',
});
// Add issues to epic
await plugin.tool.gitlab_add_issue_to_epic.execute({
group_id: 'my-group',
epic_iid: epic.iid,
issue_id: 123,
});
// List all issues in epic
const epicIssues = await plugin.tool.gitlab_list_epic_issues.execute({
group_id: 'my-group',
epic_iid: epic.iid,
});
// Add a comment (creates a new discussion)
await plugin.tool.gitlab_create_discussion.execute({
resource_type: 'epic',
group_id: 'my-group',
iid: epic.iid,
body: 'Epic created and issues linked successfully!',
});
// Search for code containing specific patterns
const codeResults = await plugin.tool.gitlab_blob_search.execute({
search: 'async function processPayment',
project_id: 'my-group/my-project',
limit: 10,
});
// Search for related issues
const issues = await plugin.tool.gitlab_issue_search.execute({
search: 'payment processing bug',
project_id: 'my-group/my-project',
state: 'opened',
});
// Get file content
const fileContent = await plugin.tool.gitlab_get_file.execute({
project_id: 'my-group/my-project',
file_path: 'src/payment/processor.ts',
ref: 'main',
});
// Get TODO count (uses GraphQL)
const todoCount = await plugin.tool.gitlab_get_todo_count.execute({});
// List pending TODOs with cursor-based pagination
const firstPage = await plugin.tool.gitlab_list_todos.execute({
state: 'pending',
type: 'MergeRequest',
first: 20,
});
// Get next page using cursor
if (firstPage.todos.pageInfo.hasNextPage) {
const nextPage = await plugin.tool.gitlab_list_todos.execute({
state: 'pending',
type: 'MergeRequest',
first: 20,
after: firstPage.todos.pageInfo.endCursor,
});
}
// Mark specific TODO as done
await plugin.tool.gitlab_mark_todo_done.execute({
todo_id: firstPage.todos.nodes[0].id,
});
// Mark all TODOs as done
await plugin.tool.gitlab_mark_all_todos_done.execute({});
// Create a commit with multiple file operations
const commit = await plugin.tool.gitlab_create_commit.execute({
project_id: 'my-group/my-project',
branch: 'feature/new-api',
commit_message: 'feat: add new API endpoints',
actions: [
{
action: 'create',
file_path: 'src/api/v2/users.ts',
content: 'export const getUsers = async () => { ... }',
},
{
action: 'update',
file_path: 'src/api/index.ts',
content: 'export * from "./v2/users";',
},
{
action: 'delete',
file_path: 'src/api/deprecated.ts',
},
],
author_name: 'John Doe',
author_email: 'john@example.com',
});
// Get merge request to retrieve current HEAD SHA
const mr = await plugin.tool.gitlab_get_merge_request.execute({
project_id: 'my-group/my-project',
mr_iid: 123,
});
// Enable auto-merge when pipeline succeeds (GraphQL)
const result = await plugin.tool.gitlab_set_mr_auto_merge.execute({
project_id: 'my-group/my-project',
mr_iid: 123,
sha: mr.sha, // Required to prevent race conditions
strategy: 'MERGE_WHEN_CHECKS_PASS', // or 'ADD_TO_MERGE_TRAIN_WHEN_CHECKS_PASS'
});
console.log(`Auto-merge enabled: ${result.mergeRequest.autoMergeEnabled}`);
// List vulnerabilities in a project
const vulnerabilities = await plugin.tool.gitlab_list_vulnerabilities.execute({
project_id: 'my-group/my-project',
state: 'detected',
severity: 'high',
report_type: 'sast',
});
// Create an issue for critical vulnerabilities
const issue = await plugin.tool.gitlab_create_vulnerability_issue.execute({
project_path: 'my-group/my-project',
vulnerability_ids: ['gid://gitlab/Vulnerability/123', 'gid://gitlab/Vulnerability/124'],
});
// Dismiss a false positive
await plugin.tool.gitlab_dismiss_vulnerability.execute({
vulnerability_id: 'gid://gitlab/Vulnerability/125',
reason: 'FALSE_POSITIVE',
comment: 'This is a test file and not part of production code',
});
// Confirm a real vulnerability
await plugin.tool.gitlab_confirm_vulnerability.execute({
vulnerability_id: 'gid://gitlab/Vulnerability/126',
comment: 'Confirmed - needs immediate attention',
});
// Update severity based on assessment
await plugin.tool.gitlab_update_vulnerability_severity.execute({
vulnerability_ids: ['gid://gitlab/Vulnerability/127'],
severity: 'CRITICAL',
comment: 'Upgrading to critical - affects production authentication',
});
// Link vulnerabilities to existing issue
await plugin.tool.gitlab_link_vulnerability_to_issue.execute({
issue_id: 'gid://gitlab/Issue/42',
vulnerability_ids: ['gid://gitlab/Vulnerability/128', 'gid://gitlab/Vulnerability/129'],
});
opencode-gitlab-plugin/
āāā src/
ā āāā client/ # API client modules
ā ā āāā base.ts # Base client with HTTP & GraphQL methods
ā ā āāā security.ts # Security/vulnerability management
ā ā āāā issues.ts # Issue management
ā ā āāā merge-requests.ts # Merge request operations
ā ā āāā pipelines.ts # CI/CD pipeline operations
ā ā āāā repository.ts # Repository operations
ā ā āāā epics.ts # Epic management
ā ā āāā search.ts # Search operations
ā ā āāā todos.ts # TODO management
ā ā āāā wikis.ts # Wiki operations
ā ā āāā work-items.ts # Work item operations
ā ā āāā audit.ts # Audit events
ā ā āāā git.ts # Git operations
ā ā āāā index.ts # Client exports
ā āāā tools/ # Tool definitions
ā ā āāā security.ts # Security tool definitions
ā ā āāā issues.ts # Issue tool definitions
ā ā āāā merge-requests.ts # MR tool definitions
ā ā āāā pipelines.ts # Pipeline tool definitions
ā ā āāā repository.ts # Repository tool definitions
ā ā āāā discussions-unified.ts # Unified discussion tools (4 tools)
ā ā āāā notes-unified.ts # Unified notes tools (3 tools)
ā ā āāā ... # Other tool definitions
ā āāā index.ts # Main plugin entry point
ā āāā utils.ts # Utility functions
ā āāā validation.ts # GID validation utilities
āāā tests/ # Test suite (180 tests)
ā āāā client/ # Client tests
ā āāā tools/ # Tool tests
ā āāā validation.test.ts # Validation tests
ā āāā utils.test.ts # Utility tests
āāā dist/ # Compiled output (generated)
ā āāā index.js # ESM bundle
ā āāā index.d.ts # TypeScript definitions
āāā .husky/ # Git hooks
ā āāā commit-msg # Commitlint hook
ā āāā pre-commit # Lint-staged hook
āāā .gitlab-ci.yml # CI/CD pipeline configuration
āāā package.json # Package metadata
āāā tsconfig.json # TypeScript configuration
āāā vitest.config.ts # Vitest test configuration
āāā .eslintrc.json # ESLint configuration
āāā .prettierrc.json # Prettier configuration
āāā .commitlintrc.json # Commitlint configuration
āāā .releaserc.json # Semantic-release configuration
āāā CHANGELOG.md # Auto-generated changelog
āāā INSTALLATION.md # Installation guide
āāā README.md # This file
# Clone the repository
git clone https://gitlab.com/gitlab-org/editor-extensions/opencode-gitlab-plugin.git
cd opencode-gitlab-plugin
# Install dependencies
npm install
# Build the plugin
npm run build
# Watch mode for development
npm run dev
# Run linting
npm run lint
# Fix linting issues
npm run lint:fix
# Format code
npm run format
# Check formatting
npm run format:check
The project uses Husky for Git hooks:
This project follows Conventional Commits:
<type>(<scope>): <subject>
<body>
<footer>
Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting, etc.)refactor: Code refactoringperf: Performance improvementstest: Adding or updating testsbuild: Build system changesci: CI/CD changeschore: Other changes (dependencies, etc.)revert: Revert a previous commitExamples:
git commit -m "feat: add support for GitLab wiki pages"
git commit -m "fix: handle empty API responses correctly"
git commit -m "docs: update installation instructions"
git commit -m "ci: add automated release workflow"
# Build for production
npm run build
# The build process:
# 1. Compiles TypeScript to ESM
# 2. Generates type definitions
# 3. Outputs to dist/ directory
# Run tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with coverage
npm run test:coverage
Test Coverage:
graph LR
A[Test] --> B[Build]
B --> C[Release]
A --> A1[Lint]
A --> A2[Format Check]
A --> A3[Unit Tests]
B --> B1[TypeScript Build]
B --> B2[Generate Types]
C --> C1[Semantic Release]
C --> C2[Publish to Registry]
C --> C3[Create Git Tag]
C --> C4[Update Changelog]
The .gitlab-ci.yml defines the following stages:
sequenceDiagram
participant Dev as Developer
participant Git as Git Repository
participant CI as GitLab CI
participant SR as Semantic Release
participant Reg as Package Registry
Dev->>Git: Push to main branch
Git->>CI: Trigger pipeline
CI->>CI: Run tests
CI->>CI: Build package
CI->>SR: Run semantic-release
SR->>SR: Analyze commits
SR->>SR: Determine version
SR->>SR: Generate changelog
SR->>Git: Create tag & commit
SR->>Reg: Publish package
SR->>Git: Create GitLab release
The release process is fully automated using semantic-release:
fix: ā Patch version (1.0.x)feat: ā Minor version (1.x.0)BREAKING CHANGE: ā Major version (x.0.0)The CI/CD pipeline uses the following variables:
CI_JOB_TOKEN: GitLab CI token (automatic)CI_PROJECT_ID: Project ID (automatic)CI_API_V4_URL: GitLab API URL (automatic)HUSKY: Set to 0 to disable hooks in CIThe core API client that handles all GitLab REST API interactions.
constructor(instanceUrl: string, token: string)
async fetch<T>(method: string, path: string, body?: unknown): Promise<T>
async fetchText(method: string, path: string): Promise<string>
/**
* Execute a GraphQL query or mutation
* @template T - The expected type of the data field in the GraphQL response
* @param query - The GraphQL query or mutation string
* @param variables - Optional variables for the query
* @returns The data from the GraphQL response
*/
async fetchGraphQL<T>(query: string, variables?: Record<string, unknown>): Promise<T>
Features:
Example:
const result = await client.fetchGraphQL<{ vulnerability: { id: string } }>(
`mutation($id: VulnerabilityID!) {
vulnerabilityConfirm(input: { id: $id }) {
vulnerability { id state }
errors
}
}`,
{ id: 'gid://gitlab/Vulnerability/123' }
);
Pagination Example:
// First page
const page1 = await plugin.tool.gitlab_list_todos.execute({ first: 20 });
// Navigate with cursor
const page2 = await plugin.tool.gitlab_list_todos.execute({
first: 20,
after: page1.todos.pageInfo.endCursor,
});
private encodeProjectId(projectId: string): string
Handles URL encoding for project paths (e.g., gitlab-org/gitlab ā gitlab-org%2Fgitlab)
function readTokenFromAuthStorage(): string | undefined;
Reads GitLab token from OpenCode auth storage (~/.local/share/opencode/auth.json).
Supports:
{ type: "oauth", access: "token" }{ type: "api", key: "token" }function getGitLabClient(): GitLabApiClient;
Creates and returns a configured GitLab API client.
Priority:
GITLAB_TOKEN environment variablefunction isValidGid(gid: string, expectedType?: string): boolean;
Validates GitLab Global ID (GID) format.
Parameters:
gid - The GID to validate (e.g., gid://gitlab/Vulnerability/123)expectedType - Optional expected resource type (e.g., 'Vulnerability', 'Issue')Returns: true if valid, false otherwise
Example:
isValidGid('gid://gitlab/Vulnerability/123'); // true
isValidGid('gid://gitlab/Issue/456', 'Issue'); // true
isValidGid('gid://gitlab/Vulnerability/123', 'Issue'); // false (wrong type)
isValidGid('invalid-gid'); // false
function validateGid(gid: string, expectedType?: string): void;
Validates GID format and throws descriptive error if invalid.
Parameters:
gid - The GID to validateexpectedType - Optional expected resource typeThrows: Error with descriptive message if GID format is invalid
Example:
validateGid('gid://gitlab/Vulnerability/123'); // No error
validateGid('invalid-gid'); // Throws: "Invalid GitLab Global ID: 'invalid-gid'. Expected format: gid://gitlab/ResourceType/{id}"
validateGid('gid://gitlab/Issue/123', 'Vulnerability'); // Throws: "Invalid GitLab Global ID of type 'Vulnerability'..."
Usage in Security Tools:
All GraphQL-based security tools automatically validate GID parameters:
createVulnerabilityIssue() - validates vulnerability IDsdismissVulnerability() - validates vulnerability IDconfirmVulnerability() - validates vulnerability IDrevertVulnerability() - validates vulnerability IDupdateVulnerabilitySeverity() - validates vulnerability IDslinkVulnerabilityToIssue() - validates both issue ID and vulnerability IDsAll tools use Zod for runtime validation:
import { tool } from '@opencode-ai/plugin';
const z = tool.schema; // Zod v4 compatible
// Example tool definition
gitlab_get_merge_request: tool({
description: 'Get details of a specific merge request',
args: {
project_id: z.string().describe('The project ID or URL-encoded path'),
mr_iid: z.number().describe('The internal ID of the merge request'),
include_changes: z.boolean().optional().describe('Include file changes'),
},
execute: async (args, ctx) => {
// Implementation
},
});
All API calls include comprehensive error handling:
if (!response.ok) {
const errorText = await response.text();
throw new Error(`GitLab API error ${response.status}: ${errorText}`);
}
All tool responses are JSON-formatted:
return JSON.stringify(result, null, 2);
.gitignore for sensitive filesThe plugin requires a GitLab token with appropriate scopes:
api: Full API access (recommended)read_api: Read-only access (limited functionality)read_repository: Repository read accesswrite_repository: Repository write access (for commits)GitLab API has rate limits:
The plugin does not implement rate limiting logic. Consider implementing retry logic in your application.
The plugin enforces HTTPS for all API calls. HTTP URLs are not supported.
Contributions are welcome! Please see our Contributing Guide for detailed guidelines on:
Quick Start for Contributors:
Commit Messages: Use conventional commits format
feat(scope): add new feature
fix(scope): fix bug
docs(scope): update documentation
Code Quality: Ensure all checks pass
npm run lint
npm test
Testing: Add tests for new features
For questions, issues, or feature requests:
This project is licensed under the MIT License - see the LICENSE file for details.
Made with ā¤ļø for the OpenCode community
FAQs
GitLab tools plugin for OpenCode - provides GitLab API access for merge requests, issues, pipelines, and more
We found that @gitlab/opencode-gitlab-plugin demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.Ā It has 6 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.