Kind: Service
Source: atloria-monorepo/apps/api/src/webhooks/webhook.service.ts
WebhookService processes incoming repository webhooks from GitHub, GitLab, and Azure DevOps. It validates provider-specific authentication, resolves the affected project and trigger configuration, and dispatches tag, push, or release events into background jobs when configured.
Methods
| Method | Signature | Returns | Description |
|---|---|---|---|
verifyGitHubSignature | `verifyGitHubSignature(signature: string, body: string | Buffer, secret: string)` | void |
verifyGitLabToken | verifyGitLabToken(token: string, secret: string) | void | Verify GitLab webhook token. |
verifyAzureDevOpsAuth | verifyAzureDevOpsAuth(authHeader: string, secret: string) | void | Verify Azure DevOps Basic Auth header. |
findProjectByRepoUrl | `findProjectByRepoUrl(repoUrl: string, event: 'push' | 'tag_create' | 'release')` |
getTriggerConfig | getTriggerConfig(projectId: string) | unknown | Get trigger config for a project. |
handleTagCreate | handleTagCreate(repoUrl: string, tagName: string, commitHash: string, provider: string, rawPayload: any, verify: WebhookVerification) | Promise<{ status: string; jobId?: string }> | Handle tag creation event. |
handlePush | handlePush(repoUrl: string, branch: string, commitHash: string, provider: string, rawPayload: any, verify: WebhookVerification) | Promise<{ status: string; jobId?: string }> | Handle push event. |
handleRelease | handleRelease(repoUrl: string, tagName: string, releaseName: string, commitHash: string, provider: string, rawPayload: any, verify: WebhookVerification) | Promise<{ status: string; jobId?: string }> | Handle release event. |
generateWebhookSecret | generateWebhookSecret() | string | Generate a new webhook secret. |
Dependencies
PrismaServiceDocAutomationServiceTechnicalDocsServiceDocsPrTrigger(optional)GithubAppService(optional)
Where it refuses work
WebhookServicestops the work withForbiddenExceptionwhen!signature || !secret— “Missing webhook signature or secret”.WebhookServicestops the work withForbiddenExceptionwhensigBuf.length !== expBuf.length || !crypto.timingSafeEqual(sigBuf, expBuf)— “Invalid webhook signature”.WebhookServicestops the work withForbiddenExceptionwhen!token || !this.timingSafeStrEq(token, secret)— “Invalid GitLab webhook token”.WebhookServicestops the work withForbiddenExceptionwhen!authHeader || !secret— “Missing Azure DevOps auth or secret”.WebhookServicestops the work withForbiddenExceptionwhen!this.timingSafeStrEq(authHeader, expected)— “Invalid Azure DevOps credentials”.WebhookServicestops the work withForbiddenExceptionwhen!secret— “Webhook secret is not configured for this project.”.
When something fails
WebhookServicehandles failure in 3 places: it turns it into a return value in 2, and logs it and continues in 1.
Diagram
mermaidsequenceDiagram participant Provider as Git Provider participant Controller as Webhook Controller participant Service as WebhookService participant Projects as Project Store participant Jobs as Job Queue Provider->>Controller: POST webhook event Controller->>Service: Verify provider signature/token alt GitHub Service->>Service: verifyGitHubSignature() else GitLab Service->>Service: verifyGitLabToken() else Azure DevOps Service->>Service: verifyAzureDevOpsAuth() end Controller->>Service: Handle event payload Service->>Projects: findProjectByRepoUrl(repoUrl) Service->>Projects: getTriggerConfig(project, event) alt Tag creation Service->>Service: handleTagCreate() else Push event Service->>Service: handlePush() else Release event Service->>Service: handleRelease() end Service->>Jobs: Enqueue configured job Jobs-->>Service: jobId Service-->>Controller: { status, jobId? } Controller-->>Provider: Webhook response
Usage
tsimport { Injectable } from '@nestjs/common';
import { WebhookService } from './webhook.service';
@Injectable()
export class GitHubWebhookHandler {
constructor(private readonly webhookService: WebhookService) {}
async handlePushWebhook(
payload: Record<string, unknown>,
signature: string,
rawBody: Buffer,
) {
this.webhookService.verifyGitHubSignature(rawBody, signature);
return this.webhookService.handlePush(payload);
// Example result:
// { status: 'queued', jobId: 'job_123' }
}
}
// Generate and persist a provider webhook secret during project setup.
const secret = webhookService.generateWebhookSecret();
AI Coding Instructions
- Always validate the provider signature, token, or authorization header before reading event data or scheduling jobs.
- Resolve projects using the canonical repository URL; normalize provider-specific URL formats consistently before calling
findProjectByRepoUrl(). - Route webhook payloads to
handleTagCreate(),handlePush(), orhandleRelease()based on the provider event type rather than inferred payload fields alone. - Preserve the
{ status, jobId? }response contract so controllers can return predictable acknowledgements to webhook providers. - Use
generateWebhookSecret()for new integrations and store the result securely; never log webhook secrets, signatures, or authorization tokens.
Relationships
- DEPENDS_ON →
PrismaService - DEPENDS_ON →
DocAutomationService - DEPENDS_ON →
TechnicalDocsService - DEPENDS_ON →
DocsPrTrigger - DEPENDS_ON →
GithubAppService
Referenced By
GithubAppController(DEPENDS_ON)WebhookController(DEPENDS_ON)WebhookModule(MODULE_PROVIDES)WebhookModule(MODULE_EXPORTS)
Was this page helpful?