fix: allow for webhookSecret to not be configured for GitHub and GitLab events backend

Signed-off-by: djamaile <rdjamaile@gmail.com>
This commit is contained in:
djamaile
2025-04-15 15:15:27 +02:00
parent 64e3225826
commit 735fe12b05
13 changed files with 99 additions and 28 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-events-backend-module-github': patch
'@backstage/plugin-events-backend-module-gitlab': patch
---
Don't hard fail for not configuring `webhookSecret` for the GitHub and GitLab events backend. Instead, we don't add the ingress.
+2
View File
@@ -27,6 +27,8 @@ export interface Config {
* See https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks
* for more details.
*
* Webhook listener will only be enabled if this is set.
*
* @visibility secret
*/
webhookSecret?: string;
@@ -13,7 +13,7 @@ import { SubTopicEventRouter } from '@backstage/plugin-events-node';
// @public
export function createGithubSignatureValidator(
config: Config,
): RequestValidator;
): RequestValidator | undefined;
// @public (undocumented)
const _default: BackendFeature;
@@ -65,9 +65,9 @@ describe('createGithubSignatureValidator', () => {
} as RequestDetails;
};
it('no secret configured, throw error', async () => {
expect(() => createGithubSignatureValidator(configWithoutSecret)).toThrow(
"Missing required config value at 'events.modules.github.webhookSecret'",
it('should return undefined if no secret is configured', async () => {
expect(createGithubSignatureValidator(configWithoutSecret)).toEqual(
undefined,
);
});
@@ -76,7 +76,7 @@ describe('createGithubSignatureValidator', () => {
const context = new TestContext();
const validator = createGithubSignatureValidator(configWithSecret);
await validator(request, context);
await validator!(request, context);
expect(context.details).not.toBeUndefined();
expect(context.details?.status).toBe(403);
@@ -88,7 +88,7 @@ describe('createGithubSignatureValidator', () => {
const context = new TestContext();
const validator = createGithubSignatureValidator(configWithSecret);
await validator(request, context);
await validator!(request, context);
expect(context.details).not.toBeUndefined();
expect(context.details?.status).toBe(403);
@@ -100,7 +100,7 @@ describe('createGithubSignatureValidator', () => {
const context = new TestContext();
const validator = createGithubSignatureValidator(configWithSecret);
await validator(request, context);
await validator!(request, context);
expect(context.details).toBeUndefined();
});
@@ -35,8 +35,13 @@ import { verify } from '@octokit/webhooks-methods';
*/
export function createGithubSignatureValidator(
config: Config,
): RequestValidator {
const secret = config.getString('events.modules.github.webhookSecret');
): RequestValidator | undefined {
const secret = config.getOptionalString(
'events.modules.github.webhookSecret',
);
if (!secret) {
return undefined;
}
return async (
request: RequestDetails,
@@ -42,6 +42,27 @@ describe('eventsModuleGithubWebhook', () => {
} as RequestDetails;
};
it('should not add ingress if validator is undefined', async () => {
let addedIngress: HttpPostIngressOptions | undefined;
const extensionPoint = {
addHttpPostIngress: (ingress: any) => {
addedIngress = ingress;
},
};
await startTestBackend({
extensionPoints: [[eventsExtensionPoint, extensionPoint]],
features: [
eventsModuleGithubWebhook,
mockServices.rootConfig.factory({
data: {},
}),
],
});
expect(addedIngress).toBeUndefined();
});
it('should be correctly wired and set up', async () => {
let addedIngress: HttpPostIngressOptions | undefined;
const extensionPoint = {
@@ -26,7 +26,7 @@ import { createGithubSignatureValidator } from '../http/createGithubSignatureVal
* registering an HTTP POST ingress with request validator
* which verifies the webhook signature based on a secret.
*
* @alpha
* @public
*/
export default createBackendModule({
pluginId: 'events',
@@ -38,10 +38,13 @@ export default createBackendModule({
events: eventsExtensionPoint,
},
async init({ config, events }) {
events.addHttpPostIngress({
topic: 'github',
validator: createGithubSignatureValidator(config),
});
const validator = createGithubSignatureValidator(config);
if (validator) {
events.addHttpPostIngress({
topic: 'github',
validator,
});
}
},
});
},
+2
View File
@@ -27,6 +27,8 @@ export interface Config {
* See https://docs.gitlab.com/ee/user/project/integrations/webhooks.html#validate-payloads-by-using-a-secret-token
* for more details.
*
* Webhook listener will only be enabled if this is set.
*
* @visibility secret
*/
webhookSecret?: string;
@@ -11,7 +11,9 @@ import { RequestValidator } from '@backstage/plugin-events-node';
import { SubTopicEventRouter } from '@backstage/plugin-events-node';
// @public
export function createGitlabTokenValidator(config: Config): RequestValidator;
export function createGitlabTokenValidator(
config: Config,
): RequestValidator | undefined;
// @public (undocumented)
const _default: BackendFeature;
@@ -55,10 +55,8 @@ describe('createGitlabTokenValidator', () => {
} as Partial<RequestDetails> as unknown as RequestDetails;
};
it('no secret configured, throw error', async () => {
expect(() => createGitlabTokenValidator(configWithoutSecret)).toThrow(
"Missing required config value at 'events.modules.gitlab.webhookSecret'",
);
it('should return undefined if no secret is configured', async () => {
expect(createGitlabTokenValidator(configWithoutSecret)).toEqual(undefined);
});
it('secret configured, reject request without token', async () => {
@@ -66,7 +64,7 @@ describe('createGitlabTokenValidator', () => {
const context = new TestContext();
const validator = createGitlabTokenValidator(configWithSecret);
await validator(request, context);
await validator!(request, context);
expect(context.details).not.toBeUndefined();
expect(context.details?.status).toBe(403);
@@ -78,7 +76,7 @@ describe('createGitlabTokenValidator', () => {
const context = new TestContext();
const validator = createGitlabTokenValidator(configWithSecret);
await validator(request, context);
await validator!(request, context);
expect(context.details).not.toBeUndefined();
expect(context.details?.status).toBe(403);
@@ -90,7 +88,7 @@ describe('createGitlabTokenValidator', () => {
const context = new TestContext();
const validator = createGitlabTokenValidator(configWithSecret);
await validator(request, context);
await validator!(request, context);
expect(context.details).toBeUndefined();
});
@@ -30,8 +30,16 @@ import {
* @param config - root config
* @public
*/
export function createGitlabTokenValidator(config: Config): RequestValidator {
const secret = config.getString('events.modules.gitlab.webhookSecret');
export function createGitlabTokenValidator(
config: Config,
): RequestValidator | undefined {
const secret = config.getOptionalString(
'events.modules.gitlab.webhookSecret',
);
if (!secret) {
return undefined;
}
return async (
request: RequestDetails,
@@ -31,6 +31,27 @@ describe('gitlabWebhookEventsModule', () => {
} as Partial<RequestDetails> as unknown as RequestDetails;
};
it('should not add ingress if validator is undefined', async () => {
let addedIngress: HttpPostIngressOptions | undefined;
const extensionPoint = {
addHttpPostIngress: (ingress: any) => {
addedIngress = ingress;
},
};
await startTestBackend({
extensionPoints: [[eventsExtensionPoint, extensionPoint]],
features: [
eventsModuleGitlabWebhook,
mockServices.rootConfig.factory({
data: {},
}),
],
});
expect(addedIngress).toBeUndefined();
});
it('should be correctly wired and set up', async () => {
let addedIngress: HttpPostIngressOptions | undefined;
const extensionPoint = {
@@ -40,10 +40,13 @@ export default createBackendModule({
events: eventsExtensionPoint,
},
async init({ config, events }) {
events.addHttpPostIngress({
topic: 'gitlab',
validator: createGitlabTokenValidator(config),
});
const validator = createGitlabTokenValidator(config);
if (validator) {
events.addHttpPostIngress({
topic: 'gitlab',
validator: createGitlabTokenValidator(config),
});
}
},
});
},