diff --git a/src/lib/common.ts b/src/lib/common.ts index c36196113..db6e55e51 100644 --- a/src/lib/common.ts +++ b/src/lib/common.ts @@ -11,6 +11,7 @@ import { version as currentVersion } from '../../package.json'; import dayjs from 'dayjs'; import Cookie from 'cookie'; import os from 'os'; +import cuid from 'cuid'; try { if (!dev) { diff --git a/src/lib/database/applications.ts b/src/lib/database/applications.ts index 64cc1444e..43bacd46a 100644 --- a/src/lib/database/applications.ts +++ b/src/lib/database/applications.ts @@ -58,15 +58,6 @@ export async function removeApplication({ id, teamId }) { const id = containerObj.ID; const preview = containerObj.Image.split('-')[1]; await removeDestinationDocker({ id, engine: destinationDocker.engine }); - try { - if (preview) { - await removeProxyConfiguration({ domain: `${preview}.${domain}` }); - } else { - await removeProxyConfiguration({ domain }); - } - } catch (error) { - console.log(error); - } } } } @@ -79,7 +70,7 @@ export async function removeApplication({ id, teamId }) { export async function getApplicationWebhook({ projectId, branch }) { try { - let body = await prisma.application.findFirst({ + let applications = await prisma.application.findMany({ where: { projectId, branch }, include: { destinationDocker: true, @@ -88,30 +79,40 @@ export async function getApplicationWebhook({ projectId, branch }) { secrets: true } }); - - if (body.gitSource?.githubApp?.clientSecret) { - body.gitSource.githubApp.clientSecret = decrypt(body.gitSource.githubApp.clientSecret); + for (const application of applications) { + if (application.gitSource?.githubApp?.clientSecret) { + application.gitSource.githubApp.clientSecret = decrypt( + application.gitSource.githubApp.clientSecret + ); + } + if (application.gitSource?.githubApp?.webhookSecret) { + application.gitSource.githubApp.webhookSecret = decrypt( + application.gitSource.githubApp.webhookSecret + ); + } + if (application.gitSource?.githubApp?.privateKey) { + application.gitSource.githubApp.privateKey = decrypt( + application.gitSource.githubApp.privateKey + ); + } + if (application?.gitSource?.gitlabApp?.appSecret) { + application.gitSource.gitlabApp.appSecret = decrypt( + application.gitSource.gitlabApp.appSecret + ); + } + if (application?.gitSource?.gitlabApp?.webhookToken) { + application.gitSource.gitlabApp.webhookToken = decrypt( + application.gitSource.gitlabApp.webhookToken + ); + } + if (application?.secrets.length > 0) { + application.secrets = application.secrets.map((s) => { + s.value = decrypt(s.value); + return s; + }); + } } - if (body.gitSource?.githubApp?.webhookSecret) { - body.gitSource.githubApp.webhookSecret = decrypt(body.gitSource.githubApp.webhookSecret); - } - if (body.gitSource?.githubApp?.privateKey) { - body.gitSource.githubApp.privateKey = decrypt(body.gitSource.githubApp.privateKey); - } - if (body?.gitSource?.gitlabApp?.appSecret) { - body.gitSource.gitlabApp.appSecret = decrypt(body.gitSource.gitlabApp.appSecret); - } - if (body?.gitSource?.gitlabApp?.webhookToken) { - body.gitSource.gitlabApp.webhookToken = decrypt(body.gitSource.gitlabApp.webhookToken); - } - if (body?.secrets.length > 0) { - body.secrets = body.secrets.map((s) => { - s.value = decrypt(s.value); - return s; - }); - } - - return { ...body }; + return [...applications]; } catch (e) { throw { status: 404, body: { message: e.message } }; } diff --git a/src/lib/queues/index.ts b/src/lib/queues/index.ts index 9b93c6c0c..d26126d59 100644 --- a/src/lib/queues/index.ts +++ b/src/lib/queues/index.ts @@ -120,7 +120,7 @@ buildWorker.on('completed', async (job: Bullmq.Job) => { } catch (err) { console.log(err); } finally { - const workdir = `/tmp/build-sources/${job.data.repository}/`; + const workdir = `/tmp/build-sources/${job.data.repository}/${job.data.build_id}`; await asyncExecShell(`rm -fr ${workdir}`); } return; diff --git a/src/routes/applications/[id]/configuration/_GithubRepositories.svelte b/src/routes/applications/[id]/configuration/_GithubRepositories.svelte index 960d19d10..776f719a3 100644 --- a/src/routes/applications/[id]/configuration/_GithubRepositories.svelte +++ b/src/routes/applications/[id]/configuration/_GithubRepositories.svelte @@ -172,7 +172,7 @@ class="w-96" disabled={!selected.repository} bind:value={selected.branch} - on:change={isBranchAlreadyUsed} + on:change={() => (showSave = true)} > {#if !selected.repository} diff --git a/src/routes/applications/[id]/configuration/_GitlabRepositories.svelte b/src/routes/applications/[id]/configuration/_GitlabRepositories.svelte index 3319d2134..737d08c04 100644 --- a/src/routes/applications/[id]/configuration/_GitlabRepositories.svelte +++ b/src/routes/applications/[id]/configuration/_GitlabRepositories.svelte @@ -305,7 +305,7 @@ name="branch" class="w-96" bind:value={selected.branch} - on:change={isBranchAlreadyUsed} + on:change={() => (showSave = true)} disabled={!selected.project} > diff --git a/src/routes/webhooks/github/events.ts b/src/routes/webhooks/github/events.ts index b50c19929..1d2ad03b2 100644 --- a/src/routes/webhooks/github/events.ts +++ b/src/routes/webhooks/github/events.ts @@ -20,7 +20,6 @@ export const options: RequestHandler = async () => { 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(); @@ -45,137 +44,147 @@ export const post: RequestHandler = async (event) => { branch = body.pull_request.head.ref.split('/')[2]; } - const applicationFound = await db.getApplicationWebhook({ projectId, branch }); - if (applicationFound) { - const webhookSecret = applicationFound.gitSource.githubApp.webhookSecret; - const hmac = crypto.createHmac('sha256', webhookSecret); - const digest = Buffer.from( - 'sha256=' + hmac.update(JSON.stringify(body)).digest('hex'), - 'utf8' - ); - const checksum = Buffer.from(githubSignature, 'utf8'); - if (!dev) { - if (checksum.length !== digest.length || !crypto.timingSafeEqual(digest, checksum)) { - return { - status: 500, - body: { - message: 'SHA256 checksum failed. Are you doing something fishy?' - } - }; - } - } + const applications = await db.getApplicationWebhook({ projectId, branch }); + if (applications.length > 0) { + for (const application of applications) { + const buildId = cuid(); - if (githubEvent === 'push') { - if (!applicationFound.configHash) { - const configHash = crypto - .createHash('sha256') - .update( - JSON.stringify({ - buildPack: applicationFound.buildPack, - port: applicationFound.port, - 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 buildQueue.add(buildId, { - build_id: buildId, - type: 'webhook_commit', - ...applicationFound - }); - return { - status: 200, - body: { - message: 'Queued. Thank you!' + const webhookSecret = application.gitSource.githubApp.webhookSecret; + const hmac = crypto.createHmac('sha256', webhookSecret); + const digest = Buffer.from( + 'sha256=' + hmac.update(JSON.stringify(body)).digest('hex'), + 'utf8' + ); + const checksum = Buffer.from(githubSignature, 'utf8'); + if (!dev) { + if (checksum.length !== digest.length || !crypto.timingSafeEqual(digest, checksum)) { + return { + status: 500, + body: { + message: 'SHA256 checksum failed. Are you doing something fishy?' + } + }; } - }; - } 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) { + if (githubEvent === 'push') { + if (!application.configHash) { + const configHash = crypto + .createHash('sha256') + .update( + JSON.stringify({ + buildPack: application.buildPack, + port: application.port, + installCommand: application.installCommand, + buildCommand: application.buildCommand, + startCommand: application.startCommand + }) + ) + .digest('hex'); + await db.prisma.application.updateMany({ + where: { branch, projectId }, + data: { configHash } + }); + } + await db.prisma.application.update({ + where: { id: application.id }, + data: { updatedAt: new Date() } + }); + await buildQueue.add(buildId, { + build_id: buildId, + type: 'webhook_commit', + ...application + }); + 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 (application.settings.previews) { + if (application.destinationDockerId) { + const isRunning = await checkContainer( + application.destinationDocker.engine, + application.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: application.id }, + data: { updatedAt: new Date() } + }); + await buildQueue.add(buildId, { + build_id: buildId, + type: 'webhook_pr', + ...application, + sourceBranch, + pullmergeRequestId + }); return { - status: 500, + status: 200, body: { - message: 'Application not running.' + message: 'Queued. Thank you!' + } + }; + } else if (pullmergeRequestAction === 'closed') { + if (application.destinationDockerId) { + const id = `${application.id}-${pullmergeRequestId}`; + const engine = application.destinationDocker.engine; + await removeDestinationDocker({ id, engine }); + } + return { + status: 200, + body: { + message: 'Removed preview. Thank you!' } }; } - } - if ( - pullmergeRequestAction === 'opened' || - pullmergeRequestAction === 'reopened' || - pullmergeRequestAction === 'synchronize' - ) { - await db.prisma.application.update({ - where: { id: applicationFound.id }, - data: { updatedAt: new Date() } - }); - await buildQueue.add(buildId, { - build_id: buildId, - type: 'webhook_pr', - ...applicationFound, - sourceBranch, - pullmergeRequestId - }); + } else { return { - status: 200, + status: 500, 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!' + message: 'Pull request previews are not enabled.' } }; } - } else { - return { - status: 500, - body: { - message: 'Pull request previews are not enabled.' - } - }; } } + return { + status: 500, + body: { + message: 'Not handled event.' + } + }; } return { status: 500, body: { - message: 'Not handled event.' + message: 'No applications configured in Coolify.' } }; } catch (err) { diff --git a/src/routes/webhooks/gitlab/events.ts b/src/routes/webhooks/gitlab/events.ts index 1c125ec02..030815fdd 100644 --- a/src/routes/webhooks/gitlab/events.ts +++ b/src/routes/webhooks/gitlab/events.ts @@ -21,42 +21,46 @@ export const options: RequestHandler = async () => { export const post: RequestHandler = async (event) => { const allowedActions = ['opened', 'reopen', 'close', 'open', 'update']; const body = await event.request.json(); - const buildId = cuid(); + try { const { object_kind: objectKind } = body; if (objectKind === 'push') { const { ref } = body; const projectId = Number(body['project_id']); const branch = ref.split('/')[2]; - const applicationFound = await db.getApplicationWebhook({ projectId, branch }); - if (applicationFound) { - if (!applicationFound.configHash) { - const configHash = crypto - .createHash('sha256') - .update( - JSON.stringify({ - buildPack: applicationFound.buildPack, - port: applicationFound.port, - installCommand: applicationFound.installCommand, - buildCommand: applicationFound.buildCommand, - startCommand: applicationFound.startCommand - }) - ) - .digest('hex'); - await db.prisma.application.updateMany({ - where: { branch, projectId }, - data: { configHash } + const applications = await db.getApplicationWebhook({ projectId, branch }); + if (applications.length > 0) { + for (const application of applications) { + const buildId = cuid(); + if (!application.configHash) { + const configHash = crypto + .createHash('sha256') + .update( + JSON.stringify({ + buildPack: application.buildPack, + port: application.port, + installCommand: application.installCommand, + buildCommand: application.buildCommand, + startCommand: application.startCommand + }) + ) + .digest('hex'); + await db.prisma.application.updateMany({ + where: { branch, projectId }, + data: { configHash } + }); + } + await db.prisma.application.update({ + where: { id: application.id }, + data: { updatedAt: new Date() } + }); + await buildQueue.add(buildId, { + build_id: buildId, + type: 'webhook_commit', + ...application }); } - await db.prisma.application.update({ - where: { id: applicationFound.id }, - data: { updatedAt: new Date() } - }); - await buildQueue.add(buildId, { - build_id: buildId, - type: 'webhook_commit', - ...applicationFound - }); + return { status: 200, body: { @@ -64,6 +68,12 @@ export const post: RequestHandler = async (event) => { } }; } + return { + status: 500, + body: { + message: 'No applications configured in Coolify.' + } + }; } else if (objectKind === 'merge_request') { const webhookToken = event.request.headers.get('x-gitlab-token'); if (!webhookToken) { @@ -98,69 +108,73 @@ export const post: RequestHandler = async (event) => { }; } - const applicationFound = await db.getApplicationWebhook({ projectId, branch: targetBranch }); - if (applicationFound) { - if (applicationFound.settings.previews) { - if (applicationFound.destinationDockerId) { - const isRunning = await checkContainer( - applicationFound.destinationDocker.engine, - applicationFound.id - ); - if (!isRunning) { + const applications = await db.getApplicationWebhook({ projectId, branch: targetBranch }); + if (applications.length > 0) { + for (const application of applications) { + const buildId = cuid(); + if (application.settings.previews) { + if (application.destinationDockerId) { + const isRunning = await checkContainer( + application.destinationDocker.engine, + application.id + ); + if (!isRunning) { + return { + status: 500, + body: { + message: 'Application not running.' + } + }; + } + } + if (!dev && application.gitSource.gitlabApp.webhookToken !== webhookToken) { return { status: 500, body: { - message: 'Application not running.' + message: 'Ooops, something is not okay, are you okay?' + } + }; + } + if ( + action === 'opened' || + action === 'reopen' || + action === 'open' || + action === 'update' + ) { + await db.prisma.application.update({ + where: { id: application.id }, + data: { updatedAt: new Date() } + }); + await buildQueue.add(buildId, { + build_id: buildId, + type: 'webhook_mr', + ...application, + sourceBranch, + pullmergeRequestId + }); + return { + status: 200, + body: { + message: 'Queued. Thank you!' + } + }; + } else if (action === 'close') { + if (application.destinationDockerId) { + const id = `${application.id}-${pullmergeRequestId}`; + const engine = application.destinationDocker.engine; + await removeDestinationDocker({ id, engine }); + } + + return { + status: 200, + body: { + message: 'Removed preview. Thank you!' } }; } } - if (!dev && applicationFound.gitSource.gitlabApp.webhookToken !== webhookToken) { - return { - status: 500, - body: { - message: 'Ooops, something is not okay, are you okay?' - } - }; - } - if ( - action === 'opened' || - action === 'reopen' || - action === 'open' || - action === 'update' - ) { - await db.prisma.application.update({ - where: { id: applicationFound.id }, - data: { updatedAt: new Date() } - }); - await buildQueue.add(buildId, { - build_id: buildId, - type: 'webhook_mr', - ...applicationFound, - sourceBranch, - pullmergeRequestId - }); - return { - status: 200, - body: { - message: 'Queued. Thank you!' - } - }; - } else if (action === 'close') { - 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!' - } - }; - } } + return { status: 500, body: {