// Verify GitHub webhook signature
async function verifyGitHubSignature(
request: Request,
secret: string
): Promise<boolean> {
const signature = request.headers.get('X-Hub-Signature-256');
if (!signature) return false;
const body = await request.clone().text();
const encoder = new TextEncoder();
const key = await crypto.subtle.importKey(
'raw',
encoder.encode(secret),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign']
);
const signed = await crypto.subtle.sign(
'HMAC',
key,
encoder.encode(body)
);
const expectedSignature = 'sha256=' + Array.from(new Uint8Array(signed))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
return signature === expectedSignature;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const conductor = new Conductor({ env });
if (request.url.endsWith('/webhook/github')) {
// Verify signature
const isValid = await verifyGitHubSignature(request, env.GITHUB_WEBHOOK_SECRET);
if (!isValid) {
return new Response('Invalid signature', { status: 401 });
}
const payload = await request.json();
await conductor.executeEnsemble('handle-github-event', {
event: request.headers.get('X-GitHub-Event'),
payload
});
return Response.json({ success: true });
}
return new Response('Not Found', { status: 404 });
}
};