OSSA Agents + GitLab Integration
OSSA Agents + GitLab Integration
Overview
20 OSSA agents with GitLab service accounts operate as first-class GitLab citizens.
Each agent:
- Has a dedicated service account
- Authenticates with GitLab API token
- Can read/write repos, MRs, issues, pipelines
- Reports telemetry to GitLab Ultimate
- Integrates with GitLab Duo (AI platform)
Architecture
GitLab Event (Webhook)
↓
Agent Mesh (Router)
↓
OSSA Agent (Service Account)
↓ GitLab API
├─ Read: Issues, MRs, Code, Pipelines
├─ Write: Comments, Commits, MRs, Labels
├─ Execute: CI/CD, Deployments
└─ Report: Telemetry, Alerts, Metrics
Service Accounts (20 Total)
Location: service-account-mapping.json
By Role:
- ANALYZER (6): ossa-validator, drupal-standards-checker, vulnerability-scanner, cost-intelligence-monitor
- REVIEWER (2): mr-reviewer, code-quality-reviewer
- ORCHESTRATOR (3): task-dispatcher, release-coordinator, issue-lifecycle-manager
- EXECUTOR (9): pipeline-remediation, module-generator, recipe-publisher, cluster-operator, kagent-catalog-sync, mcp-server-builder, documentation-aggregator, k8s-ops-worker, kagent-worker
- WORKER (2): ci-fixer-worker, drupal-standards-worker
Each has:
{ "agent_id": "mr-reviewer", "service_account_id": 32706577, "service_account_username": "agent-mr-reviewer", "token_var": "SA_TOKEN_MR_REVIEWER", "role": "REVIEWER", "status": "mapped" }
Authentication Pattern
TypeScript SDK
import { Gitlab } from '@gitbeaker/rest'; class OSSAAgent { private gitlab: InstanceType<typeof Gitlab>; constructor(agentId: string) { const mapping = loadServiceAccountMapping(); const agent = mapping.agents.find(a => a.agent_id === agentId); if (!agent || agent.status !== 'mapped') { throw new Error(`Agent ${agentId} not mapped`); } const token = process.env[agent.token_var]; if (!token) { throw new Error(`Missing token: ${agent.token_var}`); } this.gitlab = new Gitlab({ host: 'https://gitlab.com', token: token, }); } async listMyProjects() { return await this.gitlab.Projects.all({ owned: true }); } }
Use Cases
1. MR Reviewer Agent
Trigger: MR opened/updated Actions:
- Fetches MR diff via GitLab API
- Analyzes code with Claude/GPT-4
- Posts review comments
- Approves or requests changes
// packages/@ossa/mr-reviewer/src/index.ts import { Gitlab } from '@gitbeaker/rest'; class MRReviewerAgent { private gitlab: InstanceType<typeof Gitlab>; constructor() { this.gitlab = new Gitlab({ token: process.env.SA_TOKEN_MR_REVIEWER, }); } async reviewMR(projectId: number, mrIid: number) { // 1. Fetch MR details const mr = await this.gitlab.MergeRequests.show(projectId, mrIid); // 2. Get changes const changes = await this.gitlab.MergeRequests.changes(projectId, mrIid); // 3. Analyze with LLM const review = await this.analyzeDiff(changes.changes); // 4. Post review await this.gitlab.MergeRequestNotes.create(projectId, mrIid, { body: this.formatReview(review), }); // 5. Update labels if (review.hasIssues) { await this.gitlab.MergeRequests.edit(projectId, mrIid, { add_labels: 'needs-changes', }); } else { await this.gitlab.MergeRequests.edit(projectId, mrIid, { add_labels: 'approved-by-agent', }); } } }
2. CI Fixer Worker
Trigger: Pipeline failed Actions:
- Analyzes pipeline failure logs
- Identifies root cause
- Creates fix commit
- Pushes to branch
// packages/@ossa/ci-fixer-worker/src/index.ts import { Gitlab } from '@gitbeaker/rest'; class CIFixerAgent { private gitlab: InstanceType<typeof Gitlab>; constructor() { this.gitlab = new Gitlab({ token: process.env.SA_TOKEN_CI_FIXER_WORKER, }); } async fixPipeline(projectId: number, pipelineId: number) { // 1. Get pipeline details const pipeline = await this.gitlab.Pipelines.show(projectId, pipelineId); // 2. Get failed jobs const jobs = await this.gitlab.Jobs.showPipelineJobs(projectId, pipelineId, { scope: ['failed'], }); // 3. Analyze failure logs for (const job of jobs) { const trace = await this.gitlab.Jobs.showLog(projectId, job.id); const fix = await this.analyzeLogs(trace); if (fix) { // 4. Create fix commit await this.gitlab.Commits.create(projectId, pipeline.ref, { commit_message: `fix(ci): ${fix.description}`, actions: [{ action: 'update', file_path: fix.filePath, content: fix.content, }], }); } } } }
3. Issue Lifecycle Manager
Trigger: Issue created/labeled Actions:
- Analyzes issue description
- Creates implementation plan
- Creates branch and MR
- Assigns to appropriate team
// packages/@ossa/issue-lifecycle-manager/src/index.ts import { Gitlab } from '@gitbeaker/rest'; class IssueLifecycleAgent { private gitlab: InstanceType<typeof Gitlab>; constructor() { this.gitlab = new Gitlab({ token: process.env.SA_TOKEN_ISSUE_LIFECYCLE_MANAGER, }); } async processIssue(projectId: number, issueIid: number) { // 1. Fetch issue const issue = await this.gitlab.Issues.show(projectId, issueIid); // 2. Analyze with LLM const analysis = await this.analyzeIssue(issue); // 3. Post analysis comment await this.gitlab.IssueNotes.create(projectId, issueIid, { body: this.formatAnalysis(analysis), }); // 4. Create branch const branchName = `${issueIid}-${issue.title.toLowerCase().replace(/\s+/g, '-')}`; await this.gitlab.Branches.create(projectId, branchName, 'main'); // 5. Create MR const mr = await this.gitlab.MergeRequests.create(projectId, branchName, 'main', issue.title, { description: `Closes #${issueIid}\n\n${analysis.implementationPlan}`, }); // 6. Link issue to MR await this.gitlab.Issues.edit(projectId, issueIid, { add_labels: 'in-progress', }); } }
4. Vulnerability Scanner
Trigger: Code pushed, scheduled Actions:
- Scans code for vulnerabilities
- Creates security issues
- Updates security dashboard
// packages/@ossa/vulnerability-scanner/src/index.ts import { Gitlab } from '@gitbeaker/rest'; class VulnerabilityScannerAgent { private gitlab: InstanceType<typeof Gitlab>; constructor() { this.gitlab = new Gitlab({ token: process.env.SA_TOKEN_VULNERABILITY_SCANNER, }); } async scanProject(projectId: number) { // 1. Get latest commit const commits = await this.gitlab.Commits.all(projectId, { per_page: 1 }); const latestCommit = commits[0]; // 2. Get file tree const tree = await this.gitlab.Repositories.tree(projectId, { ref: latestCommit.id, recursive: true, }); // 3. Scan each file const vulnerabilities = []; for (const file of tree) { if (file.type === 'blob') { const content = await this.gitlab.RepositoryFiles.show( projectId, file.path, latestCommit.id, ); const vulns = await this.scanFileContent( Buffer.from(content.content, 'base64').toString(), file.path, ); vulnerabilities.push(...vulns); } } // 4. Create issues for vulnerabilities for (const vuln of vulnerabilities) { await this.gitlab.Issues.create(projectId, { title: `Security: ${vuln.title}`, description: this.formatVulnerability(vuln), labels: ['security', `severity::${vuln.severity}`], confidential: true, }); } // 5. Report to GitLab Security Dashboard // (via GitLab Security Report format) } }
5. Release Coordinator
Trigger: Tag pushed, milestone complete Actions:
- Generates changelog
- Creates release notes
- Triggers deployments
- Updates docs
// packages/@ossa/release-coordinator/src/index.ts import { Gitlab } from '@gitbeaker/rest'; class ReleaseCoordinatorAgent { private gitlab: InstanceType<typeof Gitlab>; constructor() { this.gitlab = new Gitlab({ token: process.env.SA_TOKEN_RELEASE_COORDINATOR, }); } async createRelease(projectId: number, tagName: string) { // 1. Get commits since last release const tags = await this.gitlab.Tags.all(projectId); const previousTag = tags[1]; // Assuming sorted const commits = await this.gitlab.Commits.all(projectId, { ref_name: tagName, since: previousTag.commit.created_at, }); // 2. Generate changelog const changelog = await this.generateChangelog(commits); // 3. Create release await this.gitlab.Releases.create(projectId, { tag_name: tagName, name: `Release ${tagName}`, description: changelog, }); // 4. Close milestone const milestones = await this.gitlab.ProjectMilestones.all(projectId, { title: tagName, }); if (milestones.length > 0) { await this.gitlab.ProjectMilestones.edit(projectId, milestones[0].id, { state_event: 'close', }); } // 5. Trigger deployment pipeline await this.gitlab.Pipelines.create(projectId, tagName, { variables: [{ key: 'RELEASE', value: tagName }], }); } }
GitLab API Capabilities (Per Agent)
Read Operations (All Agents)
- Projects, Groups, Users
- Issues, MRs, Comments
- Commits, Branches, Tags
- Pipelines, Jobs, Artifacts
- Files, Repository tree
Write Operations (By Role)
ANALYZER (Read-only + Comments):
- Post comments on issues/MRs
- Create security issues
REVIEWER (Analysis + Approval):
- Post review comments
- Approve/unapprove MRs
- Add/remove labels
ORCHESTRATOR (Coordination):
- Create/update issues
- Create/update MRs
- Manage milestones
- Trigger pipelines
EXECUTOR (Full Write):
- Create commits
- Create branches
- Push code
- Merge MRs
- Create releases
WORKER (Background Tasks):
- Process CI/CD jobs
- Update statuses
- Sync external data
Webhook Integration
Webhook Receiver
// infrastructure/webhook-receiver/src/server.ts import express from 'express'; import { verifyGitLabWebhook } from './auth.js'; import { routeToAgent } from './router.js'; const app = express(); app.use(express.json()); app.post('/webhooks/gitlab', verifyGitLabWebhook, async (req, res) => { const eventType = req.headers['x-gitlab-event']; const payload = req.body; // Route to appropriate agent const agentId = determineAgent(eventType, payload); // Trigger agent via agent-mesh await routeToAgent(agentId, { event: eventType, payload: payload, }); res.json({ status: 'received' }); });
Event Routing
MR Events → mr-reviewer, code-quality-reviewer
Pipeline Events → ci-fixer-worker, pipeline-remediation
Issue Events → issue-lifecycle-manager
Tag Events → release-coordinator
Push Events → vulnerability-scanner, drupal-standards-checker
GitLab Ultimate Integration
1. Observability
Each agent reports:
- OpenTelemetry traces
- Alerts for failures
- Metrics for operations
import { GitLabObservability } from '@bluefly/agent-registry'; const obs = new GitLabObservability({ gitlabUrl: 'https://gitlab.com', projectId: process.env.GITLAB_PROJECT_ID, serviceAccountToken: process.env.SA_TOKEN_MR_REVIEWER, agentName: 'mr-reviewer', agentRole: 'REVIEWER', }); // Export trace await obs.exportTrace({ traceId: '...', spanId: '...', name: 'review_mr', // ... OTLP format }); // Create alert await obs.createAlert({ title: 'MR Review Failed', severity: 'high', service: 'mr-reviewer', });
2. Service Catalog
Register all agents:
npm run gitlab:register-services
3. Error Tracking
Agents report errors to Sentry (via GitLab):
await obs.reportError(error, { context: 'review_mr' });
GitLab Duo Integration
Code Suggestions
// Use Duo for code generation const suggestions = await this.gitlab.Duo.suggestCode({ context: fileContent, instruction: 'Add error handling', });
Chat API
// Ask Duo for analysis const response = await this.gitlab.Duo.chat({ message: 'Explain this vulnerability', context: vulnerabilityDetails, });
Best Practices
- Token Security: Store tokens in environment variables, never in code
- Rate Limiting: Respect GitLab API rate limits (2000 req/min)
- Error Handling: Retry transient failures, log permanent errors
- Idempotency: Design operations to be idempotent
- Permissions: Use least-privilege access for each agent role
- Audit Logs: All operations logged to GitLab Ultimate observability
- A2A Communication: Inter-agent coordination via A2A collector
Environment Variables
# Service Account Tokens (20 total) SA_TOKEN_MR_REVIEWER=glpat-xxx SA_TOKEN_CI_FIXER_WORKER=glpat-xxx SA_TOKEN_ISSUE_LIFECYCLE_MANAGER=glpat-xxx # ... (17 more) # GitLab Configuration GITLAB_URL=https://gitlab.com GITLAB_PROJECT_ID=your-project-id # A2A Collector (for inter-agent communication) GITLAB_COLLECTOR_TOKEN=glpat-xxx
Next Steps
- Deploy A2A Collector with GitLab integration
- Register agents in service catalog
- Configure webhooks to trigger agents
- Enable GitLab Duo for enhanced AI capabilities
- Set up dashboards in GitLab Ultimate observability
All agents = TypeScript, Zod, DRY, SOLID, API-First. Zero .sh files.