Skip to content

Commit

Permalink
Merge pull request #68 from VladyslavLevinUA/add-default-webtrigger-e…
Browse files Browse the repository at this point in the history
…rror-response

Add default webtrigger error response
  • Loading branch information
VladyslavLevinUA authored Oct 20, 2023
2 parents 8a1dba3 + 1592860 commit 83ad962
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 29 deletions.
11 changes: 11 additions & 0 deletions src/entry/webtriggers/process-gitlab-event.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,17 @@ describe('processGitlabEvent', () => {
expect(serverResponse).toHaveBeenCalledWith('Invalid event format', 400);
});

it('returns server response error in case of unexpected error', async () => {
const webtriggerRequest = generateWebtriggerRequest('<p>Invalid body</p>');

storage.getSecret.mockRejectedValue(new Error());

await processGitlabEvent(webtriggerRequest, MOCK_CONTEXT);

expect(mockHandlePushEvent).not.toHaveBeenCalled();
expect(serverResponse).toHaveBeenCalledWith('The webhook could not be processed', 500);
});

it('handles pipeline event when FF is enabled', async () => {
const webtriggerRequest = generateWebtriggerRequest(JSON.stringify(MOCK_PIPELINE_EVENT));

Expand Down
70 changes: 41 additions & 29 deletions src/entry/webtriggers/process-gitlab-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,59 +19,71 @@ import {
handlePipelineEvent,
} from './gitlab-event-handlers';
import { listFeatures } from '../../services/feature-flags';
import { ParseWebhookEventPayloadError, ValidateWebhookSignatureError } from '../../models/errors';

type Context = {
principal: undefined;
installContext: string;
};

class ValidateWebhookSignatureError extends Error {}

const validateWebhookSignature = (eventSignature: string, controlSignature: string): void | never => {
if (eventSignature !== controlSignature) {
throw new ValidateWebhookSignatureError();
}
};

export const processGitlabEvent = async (event: WebtriggerRequest, context: Context): Promise<WebtriggerResponse> => {
const { installContext } = context;
const cloudId = parse(installContext).resourceId;
const groupId = event.queryParameters.groupId[0];
const groupToken = await storage.getSecret(`${STORAGE_SECRETS.GROUP_TOKEN_KEY_PREFIX}${groupId}`);
const eventPayload = event.body;
let parsedEvent: GitlabEvent;
const parseEventPayload = (eventPayload: string): GitlabEvent | never => {
try {
return JSON.parse(eventPayload);
} catch {
throw new ParseWebhookEventPayloadError();
}
};

export const processGitlabEvent = async (event: WebtriggerRequest, context: Context): Promise<WebtriggerResponse> => {
try {
const { installContext } = context;
const cloudId = parse(installContext).resourceId;
const groupId = event.queryParameters.groupId[0];
const groupToken = await storage.getSecret(`${STORAGE_SECRETS.GROUP_TOKEN_KEY_PREFIX}${groupId}`);
const eventPayload = event.body;

validateWebhookSignature(
event.headers['x-gitlab-token'][0],
await storage.get(`${STORAGE_KEYS.WEBHOOK_SIGNATURE_PREFIX}${groupId}`),
);
parsedEvent = JSON.parse(eventPayload);

const parsedEvent = parseEventPayload(eventPayload);

if (parsedEvent.object_kind === 'push') {
await handlePushEvent(parsedEvent as PushEvent, groupToken, cloudId);
}

if (parsedEvent.object_kind === 'merge_request') {
await handleMergeRequestEvent(parsedEvent as MergeRequestEvent, groupToken, cloudId);
}

if (parsedEvent.object_kind === 'pipeline') {
await handlePipelineEvent(parsedEvent as PipelineEvent, groupToken, cloudId);
}

if (parsedEvent.object_kind === 'deployment') {
await handleDeploymentEvent(parsedEvent as DeploymentEvent, groupToken, cloudId);
}

return serverResponse('Processed webhook event');
} catch (error) {
if (error instanceof ValidateWebhookSignatureError) {
console.error({ message: 'Webhook event secret is invalid', error });
return serverResponse('Invalid webhook secret', 403);
}

console.error({ message: 'Failed parsing webhook event', error });
return serverResponse('Invalid event format', 400);
}

if (parsedEvent.object_kind === 'push') {
await handlePushEvent(parsedEvent as PushEvent, groupToken, cloudId);
}

if (parsedEvent.object_kind === 'merge_request') {
await handleMergeRequestEvent(parsedEvent as MergeRequestEvent, groupToken, cloudId);
}

if (parsedEvent.object_kind === 'pipeline') {
await handlePipelineEvent(parsedEvent as PipelineEvent, groupToken, cloudId);
}
if (error instanceof ParseWebhookEventPayloadError) {
console.error({ message: 'Failed parsing webhook event', error });
return serverResponse('Invalid event format', 400);
}

if (parsedEvent.object_kind === 'deployment') {
await handleDeploymentEvent(parsedEvent as DeploymentEvent, groupToken, cloudId);
console.error({ message: 'Unexpected error while processing webhook', error });
return serverResponse('The webhook could not be processed', 500);
}

return serverResponse('Processed webhook event');
};
4 changes: 4 additions & 0 deletions src/models/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,7 @@ export class GitlabHttpMethodError extends Error {
this.statusText = statusText;
}
}

export class ValidateWebhookSignatureError extends Error {}

export class ParseWebhookEventPayloadError extends Error {}

0 comments on commit 83ad962

Please sign in to comment.