diff --git a/package.json b/package.json index c42352555..e6fc811c4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "coolify", "description": "An open-source & self-hostable Heroku / Netlify alternative.", - "version": "2.4.5", + "version": "2.4.6", "license": "AGPL-3.0", "scripts": { "dev": "docker-compose -f docker-compose-dev.yaml up -d && cross-env NODE_ENV=development & svelte-kit dev", diff --git a/src/lib/common.ts b/src/lib/common.ts index a9157d1dc..1b5754917 100644 --- a/src/lib/common.ts +++ b/src/lib/common.ts @@ -93,11 +93,16 @@ export const getUserDetails = async ( }> => { const teamId = getTeam(event); const userId = event?.locals?.session?.data?.userId || null; - const { permission = 'read' } = await db.prisma.permission.findFirst({ - where: { teamId, userId }, - select: { permission: true }, - rejectOnNotFound: true - }); + let permission = 'read'; + if (teamId && userId) { + const data = await db.prisma.permission.findFirst({ + where: { teamId, userId }, + select: { permission: true }, + rejectOnNotFound: true + }); + if (data.permission) permission = data.permission; + } + const payload = { teamId, userId, diff --git a/src/lib/database/common.ts b/src/lib/database/common.ts index cdc1d5b92..541fb8685 100644 --- a/src/lib/database/common.ts +++ b/src/lib/database/common.ts @@ -219,7 +219,6 @@ export function generateDatabaseConfiguration(database: Database & { settings: D return { privatePort: 5432, environmentVariables: { - POSTGRESQL_POSTGRES_PASSWORD: rootUserPassword, POSTGRESQL_PASSWORD: dbUserPassword, POSTGRESQL_USERNAME: dbUser, POSTGRESQL_DATABASE: defaultDatabase diff --git a/src/lib/haproxy/configuration.ts b/src/lib/haproxy/configuration.ts index f0bd2bb08..36dded536 100644 --- a/src/lib/haproxy/configuration.ts +++ b/src/lib/haproxy/configuration.ts @@ -215,7 +215,8 @@ export async function configureHAProxy(): Promise { plausibleAnalytics: true, vscodeserver: true, wordpress: true, - ghost: true + ghost: true, + meiliSearch: true } }); diff --git a/src/lib/letsencrypt/index.ts b/src/lib/letsencrypt/index.ts index b90cac5bd..a3a1522e1 100644 --- a/src/lib/letsencrypt/index.ts +++ b/src/lib/letsencrypt/index.ts @@ -6,6 +6,7 @@ import cuid from 'cuid'; import fs from 'fs/promises'; import getPort, { portNumbers } from 'get-port'; import { supportedServiceTypesAndVersions } from '$lib/components/common'; +import { promises as dns } from 'dns'; export async function letsEncrypt(domain: string, id?: string, isCoolify = false): Promise { try { @@ -148,7 +149,8 @@ export async function generateSSLCerts(): Promise { plausibleAnalytics: true, vscodeserver: true, wordpress: true, - ghost: true + ghost: true, + meiliSearch: true }, orderBy: { createdAt: 'desc' } }); @@ -198,6 +200,15 @@ export async function generateSSLCerts(): Promise { file.endsWith('.pem') && certificates.push(file.replace(/\.pem$/, '')); } } + const resolver = new dns.Resolver({ timeout: 2000 }); + resolver.setServers(['8.8.8.8', '1.1.1.1']); + let ipv4, ipv6; + try { + ipv4 = await (await asyncExecShell(`curl -4s https://ifconfig.io`)).stdout; + } catch (error) {} + try { + ipv6 = await (await asyncExecShell(`curl -6s https://ifconfig.io`)).stdout; + } catch (error) {} for (const ssl of ssls) { if (!dev) { if ( @@ -206,8 +217,27 @@ export async function generateSSLCerts(): Promise { ) { console.log(`Certificate for ${ssl.domain} already exists`); } else { - console.log('Generating SSL for', ssl.domain); - await letsEncrypt(ssl.domain, ssl.id, ssl.isCoolify); + // Checking DNS entry before generating certificate + if (ipv4 || ipv6) { + let domains4 = []; + let domains6 = []; + try { + domains4 = await resolver.resolve4(ssl.domain); + } catch (error) {} + try { + domains6 = await resolver.resolve6(ssl.domain); + } catch (error) {} + if (domains4.length > 0 || domains6.length > 0) { + if ( + (ipv4 && domains4.includes(ipv4.replace('\n', ''))) || + (ipv6 && domains6.includes(ipv6.replace('\n', ''))) + ) { + console.log('Generating SSL for', ssl.domain, '.'); + return await letsEncrypt(ssl.domain, ssl.id, ssl.isCoolify); + } + } + } + console.log('DNS settings is incorrect for', ssl.domain, 'skipping.'); } } else { if ( @@ -216,7 +246,27 @@ export async function generateSSLCerts(): Promise { ) { console.log(`Certificate for ${ssl.domain} already exists`); } else { - console.log('Generating SSL for', ssl.domain); + // Checking DNS entry before generating certificate + if (ipv4 || ipv6) { + let domains4 = []; + let domains6 = []; + try { + domains4 = await resolver.resolve4(ssl.domain); + } catch (error) {} + try { + domains6 = await resolver.resolve6(ssl.domain); + } catch (error) {} + if (domains4.length > 0 || domains6.length > 0) { + if ( + (ipv4 && domains4.includes(ipv4.replace('\n', ''))) || + (ipv6 && domains6.includes(ipv6.replace('\n', ''))) + ) { + console.log('Generating SSL for', ssl.domain, '.'); + return; + } + } + } + console.log('DNS settings is incorrect for', ssl.domain, 'skipping.'); } } } diff --git a/src/lib/queues/builder.ts b/src/lib/queues/builder.ts index 7419fa5dc..e76104376 100644 --- a/src/lib/queues/builder.ts +++ b/src/lib/queues/builder.ts @@ -285,7 +285,15 @@ export default async function (job: Job): Promise { await asyncExecShell(`DOCKER_HOST=${host} docker rmi -f ${images}`); } } catch (error) { - console.log(error); + //console.log(error); } try { await asyncExecShell(`DOCKER_HOST=${host} docker container prune -f`); } catch (error) { - console.log(error); + //console.log(error); } try { await asyncExecShell(`DOCKER_HOST=${host} docker image prune -f --filter "until=2h"`); } catch (error) { - console.log(error); + //console.log(error); + } + // Cleanup old images older than a day + try { + await asyncExecShell(`DOCKER_HOST=${host} docker image prune --filter "until=24h" -a -f`); + } catch (error) { + //console.log(error); } - // Tagging images with labels - // try { - // const images = [ - // `coollabsio/${defaultProxyImageTcp}`, - // `coollabsio/${defaultProxyImageHttp}`, - // 'certbot/certbot:latest', - // 'node:16.14.0-alpine', - // 'alpine:latest', - // 'nginx:stable-alpine', - // 'node:lts', - // 'php:apache', - // 'rust:latest' - // ]; - // for (const image of images) { - // try { - // await asyncExecShell(`DOCKER_HOST=${host} docker image inspect ${image}`); - // } catch (error) { - // await asyncExecShell( - // `DOCKER_HOST=${host} docker pull ${image} && echo "FROM ${image}" | docker build --label coolify.image="true" -t "${image}" -` - // ); - // } - // } - // } catch (error) {} - // if (!dev) { - // // Cleanup images that are not managed by coolify - // try { - // await asyncExecShell( - // `DOCKER_HOST=${host} docker image prune --filter 'label!=coolify.image=true' -a -f` - // ); - // } catch (error) { - // console.log(error); - // } - // // Cleanup old images >3 days - // try { - // await asyncExecShell(`DOCKER_HOST=${host} docker image prune --filter "until=72h" -a -f`); - // } catch (error) { - // console.log(error); - // } - // } } } diff --git a/src/lib/types/composeFile.ts b/src/lib/types/composeFile.ts index 1e2a0723c..33dfbdd43 100644 --- a/src/lib/types/composeFile.ts +++ b/src/lib/types/composeFile.ts @@ -23,6 +23,14 @@ export type ComposeFileService = { dockerfile: string; args?: Record; }; + deploy?: { + restart_policy?: { + condition?: string; + delay?: string; + max_attempts?: number; + window?: string; + }; + }; }; export type ComposerFileVersion = diff --git a/src/routes/applications/[id]/configuration/_GithubRepositories.svelte b/src/routes/applications/[id]/configuration/_GithubRepositories.svelte index 06e58be58..08ee1298f 100644 --- a/src/routes/applications/[id]/configuration/_GithubRepositories.svelte +++ b/src/routes/applications/[id]/configuration/_GithubRepositories.svelte @@ -36,8 +36,15 @@ }); } + async function loadBranchesByPage(page = 0) { + return await get(`${apiUrl}/repos/${selected.repository}/branches?per_page=100&page=${page}`, { + Authorization: `token ${$gitTokens.githubToken}` + }); + } + let reposSelectOptions; let branchSelectOptions; + async function loadRepositories() { let page = 1; let reposCount = 0; @@ -58,24 +65,28 @@ })); } async function loadBranches(event) { + branches = []; selected.repository = event.detail.value; - loading.branches = true; - selected.branch = undefined; selected.projectId = repositories.find((repo) => repo.full_name === selected.repository).id; - try { - branches = await get(`${apiUrl}/repos/${selected.repository}/branches`, { - Authorization: `token ${$gitTokens.githubToken}` - }); - branchSelectOptions = branches.map((branch) => ({ - value: branch.name, - label: branch.name - })); - return; - } catch ({ error }) { - return errorNotification(error); - } finally { - loading.branches = false; + let page = 1; + let branchCount = 0; + loading.branches = true; + const loadedBranches = await loadBranchesByPage(); + branches = branches.concat(loadedBranches); + branchCount = branches.length; + if (branchCount === 100) { + while (branchCount === 100) { + page = page + 1; + const nextBranches = await loadBranchesByPage(page); + branches = branches.concat(nextBranches); + branchCount = nextBranches.length; + } } + loading.branches = false; + branchSelectOptions = branches.map((branch) => ({ + value: branch.name, + label: branch.name + })); } async function isBranchAlreadyUsed(event) { selected.branch = event.detail.value; @@ -166,30 +177,36 @@ {:else}
-
+