216 lines
6.0 KiB
TypeScript
216 lines
6.0 KiB
TypeScript
import { getDomain, getTeam, getUserDetails, removeDestinationDocker } from '$lib/common';
|
|
import * as db from '$lib/database';
|
|
import type { RequestHandler } from '@sveltejs/kit';
|
|
import cuid from 'cuid';
|
|
import crypto from 'crypto';
|
|
import { buildQueue } from '$lib/queues';
|
|
import { checkContainer } from '$lib/haproxy';
|
|
import { dev } from '$app/env';
|
|
|
|
export const options: RequestHandler = async () => {
|
|
return {
|
|
status: 204,
|
|
headers: {
|
|
'Access-Control-Allow-Origin': '*',
|
|
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
|
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS'
|
|
}
|
|
};
|
|
};
|
|
|
|
export const post: RequestHandler = async (event) => {
|
|
try {
|
|
const buildId = cuid();
|
|
const allowedGithubEvents = ['push', 'pull_request'];
|
|
const allowedActions = ['opened', 'reopened', 'synchronize', 'closed'];
|
|
const githubEvent = event.request.headers.get('x-github-event')?.toLowerCase();
|
|
const githubSignature = event.request.headers.get('x-hub-signature-256')?.toLowerCase();
|
|
if (!allowedGithubEvents.includes(githubEvent)) {
|
|
return {
|
|
status: 500,
|
|
body: {
|
|
message: 'Event not allowed.'
|
|
}
|
|
};
|
|
}
|
|
let repository, projectId, branch;
|
|
const body = await event.request.json();
|
|
if (githubEvent === 'push') {
|
|
repository = body.repository;
|
|
projectId = repository.id;
|
|
branch = body.ref.split('/')[2];
|
|
} else if (githubEvent === 'pull_request') {
|
|
repository = body.pull_request.head.repo;
|
|
projectId = repository.id;
|
|
branch = body.pull_request.head.ref.split('/')[2];
|
|
}
|
|
|
|
const applicationFound = await db.getApplicationWebhook({ projectId, branch });
|
|
if (applicationFound) {
|
|
const webhookSecret = applicationFound.gitSource.githubApp.webhookSecret || null;
|
|
const hmac = crypto.createHmac('sha256', webhookSecret);
|
|
const digest = Buffer.from(
|
|
'sha256=' + hmac.update(JSON.stringify(body)).digest('hex'),
|
|
'utf8'
|
|
);
|
|
if (!dev) {
|
|
const checksum = Buffer.from(githubSignature, 'utf8');
|
|
if (checksum.length !== digest.length || !crypto.timingSafeEqual(digest, checksum)) {
|
|
return {
|
|
status: 500,
|
|
body: {
|
|
message: 'SHA256 checksum failed. Are you doing something fishy?'
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
if (githubEvent === 'push') {
|
|
if (!applicationFound.configHash) {
|
|
const configHash = crypto
|
|
.createHash('sha256')
|
|
.update(
|
|
JSON.stringify({
|
|
buildPack: applicationFound.buildPack,
|
|
port: applicationFound.port,
|
|
exposePort: applicationFound.exposePort,
|
|
installCommand: applicationFound.installCommand,
|
|
buildCommand: applicationFound.buildCommand,
|
|
startCommand: applicationFound.startCommand
|
|
})
|
|
)
|
|
.digest('hex');
|
|
await db.prisma.application.updateMany({
|
|
where: { branch, projectId },
|
|
data: { configHash }
|
|
});
|
|
}
|
|
await db.prisma.application.update({
|
|
where: { id: applicationFound.id },
|
|
data: { updatedAt: new Date() }
|
|
});
|
|
await db.prisma.build.create({
|
|
data: {
|
|
id: buildId,
|
|
applicationId: applicationFound.id,
|
|
destinationDockerId: applicationFound.destinationDocker.id,
|
|
gitSourceId: applicationFound.gitSource.id,
|
|
githubAppId: applicationFound.gitSource.githubApp?.id,
|
|
gitlabAppId: applicationFound.gitSource.gitlabApp?.id,
|
|
status: 'queued',
|
|
type: 'webhook_commit'
|
|
}
|
|
});
|
|
await buildQueue.add(buildId, {
|
|
build_id: buildId,
|
|
type: 'webhook_commit',
|
|
...applicationFound
|
|
});
|
|
return {
|
|
status: 200,
|
|
body: {
|
|
message: 'Queued. Thank you!'
|
|
}
|
|
};
|
|
} else if (githubEvent === 'pull_request') {
|
|
const pullmergeRequestId = body.number;
|
|
const pullmergeRequestAction = body.action;
|
|
const sourceBranch = body.pull_request.head.ref;
|
|
if (!allowedActions.includes(pullmergeRequestAction)) {
|
|
return {
|
|
status: 500,
|
|
body: {
|
|
message: 'Action not allowed.'
|
|
}
|
|
};
|
|
}
|
|
|
|
if (applicationFound.settings.previews) {
|
|
if (applicationFound.destinationDockerId) {
|
|
const isRunning = await checkContainer(
|
|
applicationFound.destinationDocker.engine,
|
|
applicationFound.id
|
|
);
|
|
if (!isRunning) {
|
|
return {
|
|
status: 500,
|
|
body: {
|
|
message: 'Application not running.'
|
|
}
|
|
};
|
|
}
|
|
}
|
|
if (
|
|
pullmergeRequestAction === 'opened' ||
|
|
pullmergeRequestAction === 'reopened' ||
|
|
pullmergeRequestAction === 'synchronize'
|
|
) {
|
|
await db.prisma.application.update({
|
|
where: { id: applicationFound.id },
|
|
data: { updatedAt: new Date() }
|
|
});
|
|
await db.prisma.build.create({
|
|
data: {
|
|
id: buildId,
|
|
applicationId: applicationFound.id,
|
|
destinationDockerId: applicationFound.destinationDocker.id,
|
|
gitSourceId: applicationFound.gitSource.id,
|
|
githubAppId: applicationFound.gitSource.githubApp?.id,
|
|
gitlabAppId: applicationFound.gitSource.gitlabApp?.id,
|
|
status: 'queued',
|
|
type: 'webhook_pr'
|
|
}
|
|
});
|
|
await buildQueue.add(buildId, {
|
|
build_id: buildId,
|
|
type: 'webhook_pr',
|
|
...applicationFound,
|
|
sourceBranch,
|
|
pullmergeRequestId
|
|
});
|
|
return {
|
|
status: 200,
|
|
body: {
|
|
message: 'Queued. Thank you!'
|
|
}
|
|
};
|
|
} else if (pullmergeRequestAction === 'closed') {
|
|
if (applicationFound.destinationDockerId) {
|
|
const id = `${applicationFound.id}-${pullmergeRequestId}`;
|
|
const engine = applicationFound.destinationDocker.engine;
|
|
await removeDestinationDocker({ id, engine });
|
|
}
|
|
return {
|
|
status: 200,
|
|
body: {
|
|
message: 'Removed preview. Thank you!'
|
|
}
|
|
};
|
|
}
|
|
} else {
|
|
return {
|
|
status: 500,
|
|
body: {
|
|
message: 'Pull request previews are not enabled.'
|
|
}
|
|
};
|
|
}
|
|
}
|
|
}
|
|
return {
|
|
status: 500,
|
|
body: {
|
|
message: 'Not handled event.'
|
|
}
|
|
};
|
|
} catch (err) {
|
|
console.log(err);
|
|
return {
|
|
status: 500,
|
|
body: {
|
|
message: err.message
|
|
}
|
|
};
|
|
}
|
|
};
|