feat(plugin-scaffolder-backend): Validate webhook event names

Webhook event names are validated against Octokit Webhooks `emitterEventNames`. Note `emitterEventNames` contains event/action combinations as well that are comma delimited. Therefore, extracting strings without '.' provides list of all events.

"@octokit/webhooks" version 9.14.0 is the minimum requirement because this is a version where I introduced exported `emitterEventNames` to be used here.

Signed-off-by: @pawelmitka <pawel.mitka@brainly.com>
This commit is contained in:
@pawelmitka
2021-09-06 13:00:39 +02:00
parent 88f1597175
commit 21ccd49970
6 changed files with 102 additions and 5 deletions
+1 -1
View File
@@ -179,7 +179,7 @@ export function createRouter(options: RouterOptions): Promise<express.Router>;
// @public (undocumented)
export const createTemplateAction: <
Input extends Partial<{
[name: string]: JsonValue | Partial<JsonObject> | undefined;
[name: string]: Partial<JsonObject> | JsonValue | undefined;
}>,
>(
templateAction: TemplateAction<Input>,
+1
View File
@@ -39,6 +39,7 @@
"@gitbeaker/core": "^30.2.0",
"@gitbeaker/node": "^30.2.0",
"@octokit/rest": "^18.5.3",
"@octokit/webhooks": "^9.14.1",
"@types/express": "^4.17.6",
"azure-devops-node-api": "^11.0.1",
"command-exists": "^1.2.9",
@@ -205,4 +205,62 @@ describe('github:repository:webhook:create', () => {
},
});
});
it('should validate input', async () => {
const Validator = require('jsonschema').Validator;
const v = new Validator();
// validate default input without events specified
expect(v.validate(mockContext.input, action.schema?.input).valid).toBe(
true,
);
const inputWithValidEvent = {
...mockContext.input,
events: ['push'],
};
expect(v.validate(inputWithValidEvent, action.schema?.input).valid).toBe(
true,
);
const inputWithMultipleValidEvents = {
...mockContext.input,
events: ['push', 'pull_request'],
};
expect(
v.validate(inputWithMultipleValidEvents, action.schema?.input).valid,
).toBe(true);
const inputWithInvalidEvent = {
...mockContext.input,
events: ['unexpected_event'],
};
expect(v.validate(inputWithInvalidEvent, action.schema?.input).valid).toBe(
false,
);
const inputWithOneInvalidEvent = {
...mockContext.input,
events: ['push', 'unexpected_event'],
};
expect(
v.validate(inputWithOneInvalidEvent, action.schema?.input).valid,
).toBe(false);
const inputWithAllEvents = {
...mockContext.input,
events: ['*'],
};
expect(v.validate(inputWithAllEvents, action.schema?.input).valid).toBe(
true,
);
const inputWithAllEventsAndMore = {
...mockContext.input,
events: ['*', 'push'],
};
expect(
v.validate(inputWithAllEventsAndMore, action.schema?.input).valid,
).toBe(false);
});
});
@@ -16,6 +16,7 @@
import { ScmIntegrationRegistry } from '@backstage/integration';
import { createTemplateAction } from '../../createTemplateAction';
import { OctokitProvider } from './OctokitProvider';
import { emitterEventNames } from '@octokit/webhooks';
type ContentType = 'form' | 'json';
@@ -25,6 +26,7 @@ export function createGithubWebhookAction(options: {
}) {
const { integrations, defaultWebhookSecret } = options;
const octokitProvider = new OctokitProvider(integrations);
const eventNames = emitterEventNames.filter(event => !event.includes('.'));
return createTemplateAction<{
repoUrl: string;
@@ -63,9 +65,20 @@ export function createGithubWebhookAction(options: {
description:
'Determines what events the hook is triggered for. Default: push',
type: 'array',
items: {
type: 'string',
},
oneOf: [
{
items: {
type: 'string',
enum: eventNames,
},
},
{
items: {
type: 'string',
const: '*',
},
},
],
},
active: {
title: 'Active',