Skip to content

feat: add support for github webhook secret #173

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions examples/github-webhook-example/src/github-webhook-stack.ts
Original file line number Diff line number Diff line change
@@ -18,12 +18,16 @@ export class GithubWebhookStack extends Stack {
// @see https://developer.github.com/v3/activity/events/types/
const events = ['*'];

// @see https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks#validating-payloads-from-github
const webhookSecret = process.env.SECURE_WEBHOOK === 'true' ? (process.env.WEBHOOK_SECRET || githubApiToken.serialize()) : undefined

new GithubWebhook(this, 'GithubWebhook', {
githubApiToken,
githubRepoUrl,
payloadUrl: api.url,
events,
logLevel: 'debug',
webhookSecret
});
}
}
4 changes: 4 additions & 0 deletions packages/cdk-github-webhook/README.md
Original file line number Diff line number Diff line change
@@ -45,13 +45,17 @@ export class GithubWebhookStack extends Stack {

// @see https://developer.github.com/v3/activity/events/types/
const events = ['*'];

// @see https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks#validating-payloads-from-github
const webhookSecret = process.env.SECURE_WEBHOOK === 'true' ? (process.env.WEBHOOK_SECRET || githubApiToken.serialize()) : undefined

new GithubWebhook(this, 'GithubWebhook', {
githubApiToken,
githubRepoUrl,
payloadUrl: api.url,
events,
logLevel: 'debug',
webhookSecret
});
}
}
7 changes: 7 additions & 0 deletions packages/cdk-github-webhook/src/github-webhook.ts
Original file line number Diff line number Diff line change
@@ -24,6 +24,12 @@ export interface GithubWebhookProps {
* @see https://developer.github.com/v3/activity/events/types/
*/
readonly events: string[];
/**
* The webhook secret that GitHub uses to create a
* hash signature with each payload
* @see https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks#validating-payloads-from-github
*/
readonly webhookSecret?: string

readonly logLevel?: 'debug' | 'info' | 'warning' | 'error';
}
@@ -57,6 +63,7 @@ export class GithubWebhook extends Construct {
payloadUrl: props.payloadUrl,
events: props.events,
logLevel: props.logLevel,
webhookSecret: props.webhookSecret
},
});
}
Original file line number Diff line number Diff line change
@@ -17,18 +17,19 @@ export interface WebhookProps {
githubRepoUrl: string;
payloadUrl: string;
events: string[];
webhookSecret?: string;
}

const handleCreate: OnCreateHandler = async (event): Promise<ResourceHandlerReturn> => {
const { githubApiTokenString, githubRepoUrl, payloadUrl, events } = camelizeKeys<
const { githubApiTokenString, githubRepoUrl, payloadUrl, events, webhookSecret } = camelizeKeys<
WebhookProps,
CloudFormationCustomResourceEventCommon['ResourceProperties']
>(event.ResourceProperties);

const secretKey = new SecretKey(githubApiTokenString);
const githubApiToken = await secretKey.getValue();

const { data } = await createWebhook(githubApiToken, githubRepoUrl, payloadUrl, events);
const { data } = await createWebhook(githubApiToken, githubRepoUrl, payloadUrl, events, webhookSecret);

const physicalResourceId = data.id.toString();

@@ -41,7 +42,7 @@ const handleCreate: OnCreateHandler = async (event): Promise<ResourceHandlerRetu
};

const handleUpdate: OnUpdateHandler = async (event): Promise<ResourceHandlerReturn> => {
const { githubApiTokenString, githubRepoUrl, payloadUrl, events } = camelizeKeys<
const { githubApiTokenString, githubRepoUrl, payloadUrl, events, webhookSecret } = camelizeKeys<
WebhookProps,
CloudFormationCustomResourceEventCommon['ResourceProperties']
>(event.ResourceProperties);
@@ -51,7 +52,7 @@ const handleUpdate: OnUpdateHandler = async (event): Promise<ResourceHandlerRetu

const hookId = event.PhysicalResourceId;

const { data } = await updateWebhook(githubApiToken, githubRepoUrl, payloadUrl, events, parseInt(hookId, 10));
const { data } = await updateWebhook(githubApiToken, githubRepoUrl, payloadUrl, events, parseInt(hookId, 10), webhookSecret);

const physicalResourceId = data.id.toString();

Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ export const createWebhook = async (
githubRepoUrl: string,
payloadUrl: string,
events: string[],
webhookSecret?: string
): Promise<RestEndpointMethodTypes['repos']['createWebhook']['response']> => {
const octokit = new Octokit({
auth: githubApiToken,
@@ -17,11 +18,16 @@ export const createWebhook = async (
throw new Error('GithubRepoUrl is not correct');
}

const config = { url: payloadUrl, content_type: 'json' };
if (webhookSecret != null) {
Object.assign(config, { secret: webhookSecret});
}

const params = {
name: 'web',
owner: gh.owner,
repo: gh.name,
config: { url: payloadUrl, content_type: 'json' },
config,
events,
active: true,
};
@@ -35,6 +41,7 @@ export const updateWebhook = async (
payloadUrl: string,
events: string[],
hookId: number,
webhookSecret?: string
): Promise<RestEndpointMethodTypes['repos']['updateWebhook']['response']> => {
const octokit = new Octokit({
auth: githubApiToken,
@@ -46,10 +53,15 @@ export const updateWebhook = async (
throw new Error('GithubRepoUrl is not correct');
}

const config = { url: payloadUrl, content_type: 'json' };
if (webhookSecret != null) {
Object.assign(config, { secret: webhookSecret});
}

const params = {
owner: gh.owner,
repo: gh.name,
config: { url: payloadUrl, content_type: 'json' },
config,
events,
active: true,
hook_id: hookId,