fix: escape secrets
This commit is contained in:
parent
a70adc5eb3
commit
4261147fe8
@ -39,6 +39,7 @@
|
|||||||
"dayjs": "1.11.6",
|
"dayjs": "1.11.6",
|
||||||
"dockerode": "3.3.4",
|
"dockerode": "3.3.4",
|
||||||
"dotenv-extended": "2.9.0",
|
"dotenv-extended": "2.9.0",
|
||||||
|
"escape-string-regexp": "5.0.0",
|
||||||
"execa": "6.1.0",
|
"execa": "6.1.0",
|
||||||
"fastify": "4.10.2",
|
"fastify": "4.10.2",
|
||||||
"fastify-plugin": "4.3.0",
|
"fastify-plugin": "4.3.0",
|
||||||
|
@ -1,6 +1,17 @@
|
|||||||
import { base64Encode, decrypt, encrypt, executeCommand, generateTimestamp, getDomain, isARM, isDev, prisma, version } from "../common";
|
import {
|
||||||
|
base64Encode,
|
||||||
|
decrypt,
|
||||||
|
encrypt,
|
||||||
|
executeCommand,
|
||||||
|
generateTimestamp,
|
||||||
|
getDomain,
|
||||||
|
isARM,
|
||||||
|
isDev,
|
||||||
|
prisma,
|
||||||
|
version
|
||||||
|
} from '../common';
|
||||||
import { promises as fs } from 'fs';
|
import { promises as fs } from 'fs';
|
||||||
import { day } from "../dayjs";
|
import { day } from '../dayjs';
|
||||||
|
|
||||||
const staticApps = ['static', 'react', 'vuejs', 'svelte', 'gatsby', 'astro', 'eleventy'];
|
const staticApps = ['static', 'react', 'vuejs', 'svelte', 'gatsby', 'astro', 'eleventy'];
|
||||||
const nodeBased = [
|
const nodeBased = [
|
||||||
@ -17,7 +28,10 @@ const nodeBased = [
|
|||||||
'nextjs'
|
'nextjs'
|
||||||
];
|
];
|
||||||
|
|
||||||
export function setDefaultBaseImage(buildPack: string | null, deploymentType: string | null = null) {
|
export function setDefaultBaseImage(
|
||||||
|
buildPack: string | null,
|
||||||
|
deploymentType: string | null = null
|
||||||
|
) {
|
||||||
const nodeVersions = [
|
const nodeVersions = [
|
||||||
{
|
{
|
||||||
value: 'node:lts',
|
value: 'node:lts',
|
||||||
@ -316,8 +330,8 @@ export function setDefaultBaseImage(buildPack: string | null, deploymentType: st
|
|||||||
{
|
{
|
||||||
value: 'heroku/builder-classic:22',
|
value: 'heroku/builder-classic:22',
|
||||||
label: 'heroku/builder-classic:22'
|
label: 'heroku/builder-classic:22'
|
||||||
},
|
}
|
||||||
]
|
];
|
||||||
let payload: any = {
|
let payload: any = {
|
||||||
baseImage: null,
|
baseImage: null,
|
||||||
baseBuildImage: null,
|
baseBuildImage: null,
|
||||||
@ -327,7 +341,9 @@ export function setDefaultBaseImage(buildPack: string | null, deploymentType: st
|
|||||||
if (nodeBased.includes(buildPack)) {
|
if (nodeBased.includes(buildPack)) {
|
||||||
if (deploymentType === 'static') {
|
if (deploymentType === 'static') {
|
||||||
payload.baseImage = isARM(process.arch) ? 'nginx:alpine' : 'webdevops/nginx:alpine';
|
payload.baseImage = isARM(process.arch) ? 'nginx:alpine' : 'webdevops/nginx:alpine';
|
||||||
payload.baseImages = isARM(process.arch) ? staticVersions.filter((version) => !version.value.includes('webdevops')) : staticVersions;
|
payload.baseImages = isARM(process.arch)
|
||||||
|
? staticVersions.filter((version) => !version.value.includes('webdevops'))
|
||||||
|
: staticVersions;
|
||||||
payload.baseBuildImage = 'node:lts';
|
payload.baseBuildImage = 'node:lts';
|
||||||
payload.baseBuildImages = nodeVersions;
|
payload.baseBuildImages = nodeVersions;
|
||||||
} else {
|
} else {
|
||||||
@ -339,7 +355,9 @@ export function setDefaultBaseImage(buildPack: string | null, deploymentType: st
|
|||||||
}
|
}
|
||||||
if (staticApps.includes(buildPack)) {
|
if (staticApps.includes(buildPack)) {
|
||||||
payload.baseImage = isARM(process.arch) ? 'nginx:alpine' : 'webdevops/nginx:alpine';
|
payload.baseImage = isARM(process.arch) ? 'nginx:alpine' : 'webdevops/nginx:alpine';
|
||||||
payload.baseImages = isARM(process.arch) ? staticVersions.filter((version) => !version.value.includes('webdevops')) : staticVersions;
|
payload.baseImages = isARM(process.arch)
|
||||||
|
? staticVersions.filter((version) => !version.value.includes('webdevops'))
|
||||||
|
: staticVersions;
|
||||||
payload.baseBuildImage = 'node:lts';
|
payload.baseBuildImage = 'node:lts';
|
||||||
payload.baseBuildImages = nodeVersions;
|
payload.baseBuildImages = nodeVersions;
|
||||||
}
|
}
|
||||||
@ -357,12 +375,20 @@ export function setDefaultBaseImage(buildPack: string | null, deploymentType: st
|
|||||||
payload.baseImage = 'denoland/deno:latest';
|
payload.baseImage = 'denoland/deno:latest';
|
||||||
}
|
}
|
||||||
if (buildPack === 'php') {
|
if (buildPack === 'php') {
|
||||||
payload.baseImage = isARM(process.arch) ? 'php:8.1-fpm-alpine' : 'webdevops/php-apache:8.2-alpine';
|
payload.baseImage = isARM(process.arch)
|
||||||
payload.baseImages = isARM(process.arch) ? phpVersions.filter((version) => !version.value.includes('webdevops')) : phpVersions
|
? 'php:8.1-fpm-alpine'
|
||||||
|
: 'webdevops/php-apache:8.2-alpine';
|
||||||
|
payload.baseImages = isARM(process.arch)
|
||||||
|
? phpVersions.filter((version) => !version.value.includes('webdevops'))
|
||||||
|
: phpVersions;
|
||||||
}
|
}
|
||||||
if (buildPack === 'laravel') {
|
if (buildPack === 'laravel') {
|
||||||
payload.baseImage = isARM(process.arch) ? 'php:8.1-fpm-alpine' : 'webdevops/php-apache:8.2-alpine';
|
payload.baseImage = isARM(process.arch)
|
||||||
payload.baseImages = isARM(process.arch) ? phpVersions.filter((version) => !version.value.includes('webdevops')) : phpVersions
|
? 'php:8.1-fpm-alpine'
|
||||||
|
: 'webdevops/php-apache:8.2-alpine';
|
||||||
|
payload.baseImages = isARM(process.arch)
|
||||||
|
? phpVersions.filter((version) => !version.value.includes('webdevops'))
|
||||||
|
: phpVersions;
|
||||||
payload.baseBuildImage = 'node:18';
|
payload.baseBuildImage = 'node:18';
|
||||||
payload.baseBuildImages = nodeVersions;
|
payload.baseBuildImages = nodeVersions;
|
||||||
}
|
}
|
||||||
@ -405,7 +431,8 @@ export const setDefaultConfiguration = async (data: any) => {
|
|||||||
if (!publishDirectory) publishDirectory = template?.publishDirectory || null;
|
if (!publishDirectory) publishDirectory = template?.publishDirectory || null;
|
||||||
if (baseDirectory) {
|
if (baseDirectory) {
|
||||||
if (!baseDirectory.startsWith('/')) baseDirectory = `/${baseDirectory}`;
|
if (!baseDirectory.startsWith('/')) baseDirectory = `/${baseDirectory}`;
|
||||||
if (baseDirectory.endsWith('/') && baseDirectory !== '/') baseDirectory = baseDirectory.slice(0, -1);
|
if (baseDirectory.endsWith('/') && baseDirectory !== '/')
|
||||||
|
baseDirectory = baseDirectory.slice(0, -1);
|
||||||
}
|
}
|
||||||
if (dockerFileLocation) {
|
if (dockerFileLocation) {
|
||||||
if (!dockerFileLocation.startsWith('/')) dockerFileLocation = `/${dockerFileLocation}`;
|
if (!dockerFileLocation.startsWith('/')) dockerFileLocation = `/${dockerFileLocation}`;
|
||||||
@ -414,8 +441,10 @@ export const setDefaultConfiguration = async (data: any) => {
|
|||||||
dockerFileLocation = '/Dockerfile';
|
dockerFileLocation = '/Dockerfile';
|
||||||
}
|
}
|
||||||
if (dockerComposeFileLocation) {
|
if (dockerComposeFileLocation) {
|
||||||
if (!dockerComposeFileLocation.startsWith('/')) dockerComposeFileLocation = `/${dockerComposeFileLocation}`;
|
if (!dockerComposeFileLocation.startsWith('/'))
|
||||||
if (dockerComposeFileLocation.endsWith('/')) dockerComposeFileLocation = dockerComposeFileLocation.slice(0, -1);
|
dockerComposeFileLocation = `/${dockerComposeFileLocation}`;
|
||||||
|
if (dockerComposeFileLocation.endsWith('/'))
|
||||||
|
dockerComposeFileLocation = dockerComposeFileLocation.slice(0, -1);
|
||||||
} else {
|
} else {
|
||||||
dockerComposeFileLocation = '/Dockerfile';
|
dockerComposeFileLocation = '/Dockerfile';
|
||||||
}
|
}
|
||||||
@ -479,7 +508,6 @@ export const scanningTemplates = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const saveBuildLog = async ({
|
export const saveBuildLog = async ({
|
||||||
line,
|
line,
|
||||||
buildId,
|
buildId,
|
||||||
@ -491,7 +519,7 @@ export const saveBuildLog = async ({
|
|||||||
}): Promise<any> => {
|
}): Promise<any> => {
|
||||||
if (buildId === 'undefined' || buildId === 'null' || !buildId) return;
|
if (buildId === 'undefined' || buildId === 'null' || !buildId) return;
|
||||||
if (applicationId === 'undefined' || applicationId === 'null' || !applicationId) return;
|
if (applicationId === 'undefined' || applicationId === 'null' || !applicationId) return;
|
||||||
const { default: got } = await import('got')
|
const { default: got } = await import('got');
|
||||||
if (typeof line === 'object' && line) {
|
if (typeof line === 'object' && line) {
|
||||||
if (line.shortMessage) {
|
if (line.shortMessage) {
|
||||||
line = line.shortMessage + '\n' + line.stderr;
|
line = line.shortMessage + '\n' + line.stderr;
|
||||||
@ -504,7 +532,11 @@ export const saveBuildLog = async ({
|
|||||||
line = line.replace(regex, '<SENSITIVE_DATA_DELETED>@');
|
line = line.replace(regex, '<SENSITIVE_DATA_DELETED>@');
|
||||||
}
|
}
|
||||||
const addTimestamp = `[${generateTimestamp()}] ${line}`;
|
const addTimestamp = `[${generateTimestamp()}] ${line}`;
|
||||||
const fluentBitUrl = isDev ? process.env.COOLIFY_CONTAINER_DEV === 'true' ? 'http://coolify-fluentbit:24224' : 'http://localhost:24224' : 'http://coolify-fluentbit:24224';
|
const fluentBitUrl = isDev
|
||||||
|
? process.env.COOLIFY_CONTAINER_DEV === 'true'
|
||||||
|
? 'http://coolify-fluentbit:24224'
|
||||||
|
: 'http://localhost:24224'
|
||||||
|
: 'http://coolify-fluentbit:24224';
|
||||||
|
|
||||||
if (isDev && !process.env.COOLIFY_CONTAINER_DEV) {
|
if (isDev && !process.env.COOLIFY_CONTAINER_DEV) {
|
||||||
console.debug(`[${applicationId}] ${addTimestamp}`);
|
console.debug(`[${applicationId}] ${addTimestamp}`);
|
||||||
@ -514,15 +546,17 @@ export const saveBuildLog = async ({
|
|||||||
json: {
|
json: {
|
||||||
line: encrypt(line)
|
line: encrypt(line)
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return await prisma.buildLog.create({
|
return await prisma.buildLog.create({
|
||||||
data: {
|
data: {
|
||||||
line: addTimestamp, buildId, time: Number(day().valueOf()), applicationId
|
line: addTimestamp,
|
||||||
|
buildId,
|
||||||
|
time: Number(day().valueOf()),
|
||||||
|
applicationId
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function copyBaseConfigurationFiles(
|
export async function copyBaseConfigurationFiles(
|
||||||
@ -610,7 +644,7 @@ export function checkPnpm(installCommand = null, buildCommand = null, startComma
|
|||||||
|
|
||||||
export async function saveDockerRegistryCredentials({ url, username, password, workdir }) {
|
export async function saveDockerRegistryCredentials({ url, username, password, workdir }) {
|
||||||
if (!username || !password) {
|
if (!username || !password) {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let decryptedPassword = decrypt(password);
|
let decryptedPassword = decrypt(password);
|
||||||
@ -622,14 +656,14 @@ export async function saveDockerRegistryCredentials({ url, username, password, w
|
|||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
const payload = JSON.stringify({
|
const payload = JSON.stringify({
|
||||||
"auths": {
|
auths: {
|
||||||
[url]: {
|
[url]: {
|
||||||
"auth": Buffer.from(`${username}:${decryptedPassword}`).toString('base64')
|
auth: Buffer.from(`${username}:${decryptedPassword}`).toString('base64')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
await fs.writeFile(`${location}/config.json`, payload)
|
await fs.writeFile(`${location}/config.json`, payload);
|
||||||
return location
|
return location;
|
||||||
}
|
}
|
||||||
export async function buildImage({
|
export async function buildImage({
|
||||||
applicationId,
|
applicationId,
|
||||||
@ -647,22 +681,34 @@ export async function buildImage({
|
|||||||
} else {
|
} else {
|
||||||
await saveBuildLog({ line: `Building production image...`, buildId, applicationId });
|
await saveBuildLog({ line: `Building production image...`, buildId, applicationId });
|
||||||
}
|
}
|
||||||
const dockerFile = isCache ? `${dockerFileLocation}-cache` : `${dockerFileLocation}`
|
const dockerFile = isCache ? `${dockerFileLocation}-cache` : `${dockerFileLocation}`;
|
||||||
const cache = `${applicationId}:${tag}${isCache ? '-cache' : ''}`
|
const cache = `${applicationId}:${tag}${isCache ? '-cache' : ''}`;
|
||||||
|
|
||||||
let location = null
|
let location = null;
|
||||||
|
|
||||||
const { dockerRegistry } = await prisma.application.findUnique({ where: { id: applicationId }, select: { dockerRegistry: true } })
|
const { dockerRegistry } = await prisma.application.findUnique({
|
||||||
|
where: { id: applicationId },
|
||||||
|
select: { dockerRegistry: true }
|
||||||
|
});
|
||||||
if (dockerRegistry) {
|
if (dockerRegistry) {
|
||||||
const { url, username, password } = dockerRegistry
|
const { url, username, password } = dockerRegistry;
|
||||||
location = await saveDockerRegistryCredentials({ url, username, password, workdir })
|
location = await saveDockerRegistryCredentials({ url, username, password, workdir });
|
||||||
}
|
}
|
||||||
|
|
||||||
await executeCommand({ stream: true, debug, buildId, applicationId, dockerId, command: `docker ${location ? `--config ${location}` : ''} build --progress plain -f ${workdir}/${dockerFile} -t ${cache} --build-arg SOURCE_COMMIT=${commit} ${workdir}` })
|
await executeCommand({
|
||||||
|
stream: true,
|
||||||
|
debug,
|
||||||
|
buildId,
|
||||||
|
applicationId,
|
||||||
|
dockerId,
|
||||||
|
command: `docker ${
|
||||||
|
location ? `--config ${location}` : ''
|
||||||
|
} build --progress plain -f ${workdir}/${dockerFile} -t ${cache} --build-arg SOURCE_COMMIT=${commit} ${workdir}`
|
||||||
|
});
|
||||||
|
|
||||||
const { status } = await prisma.build.findUnique({ where: { id: buildId } })
|
const { status } = await prisma.build.findUnique({ where: { id: buildId } });
|
||||||
if (status === 'canceled') {
|
if (status === 'canceled') {
|
||||||
throw new Error('Canceled.')
|
throw new Error('Canceled.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export function makeLabelForSimpleDockerfile({ applicationId, port, type }) {
|
export function makeLabelForSimpleDockerfile({ applicationId, port, type }) {
|
||||||
@ -726,6 +772,7 @@ export function makeLabelForStandaloneApplication({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function buildCacheImageWithNode(data, imageForBuild) {
|
export async function buildCacheImageWithNode(data, imageForBuild) {
|
||||||
|
const { default: escapeStringRegexp } = await import('escape-string-regexp');
|
||||||
const {
|
const {
|
||||||
workdir,
|
workdir,
|
||||||
buildId,
|
buildId,
|
||||||
@ -744,15 +791,15 @@ export async function buildCacheImageWithNode(data, imageForBuild) {
|
|||||||
secrets.forEach((secret) => {
|
secrets.forEach((secret) => {
|
||||||
if (secret.isBuildSecret) {
|
if (secret.isBuildSecret) {
|
||||||
if (pullmergeRequestId) {
|
if (pullmergeRequestId) {
|
||||||
const isSecretFound = secrets.filter(s => s.name === secret.name && s.isPRMRSecret)
|
const isSecretFound = secrets.filter((s) => s.name === secret.name && s.isPRMRSecret);
|
||||||
if (isSecretFound.length > 0) {
|
if (isSecretFound.length > 0) {
|
||||||
Dockerfile.push(`ARG ${secret.name}=${isSecretFound[0].value}`);
|
Dockerfile.push(`ARG ${secret.name}=${escapeStringRegexp(isSecretFound[0].value)}`);
|
||||||
} else {
|
} else {
|
||||||
Dockerfile.push(`ARG ${secret.name}=${secret.value}`);
|
Dockerfile.push(`ARG ${secret.name}=${escapeStringRegexp(secret.value)}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!secret.isPRMRSecret) {
|
if (!secret.isPRMRSecret) {
|
||||||
Dockerfile.push(`ARG ${secret.name}=${secret.value}`);
|
Dockerfile.push(`ARG ${secret.name}=${escapeStringRegexp(secret.value)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -772,6 +819,7 @@ export async function buildCacheImageWithNode(data, imageForBuild) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function buildCacheImageForLaravel(data, imageForBuild) {
|
export async function buildCacheImageForLaravel(data, imageForBuild) {
|
||||||
|
const { default: escapeStringRegexp } = await import('escape-string-regexp');
|
||||||
const { workdir, buildId, secrets, pullmergeRequestId } = data;
|
const { workdir, buildId, secrets, pullmergeRequestId } = data;
|
||||||
|
|
||||||
const Dockerfile: Array<string> = [];
|
const Dockerfile: Array<string> = [];
|
||||||
@ -782,15 +830,15 @@ export async function buildCacheImageForLaravel(data, imageForBuild) {
|
|||||||
secrets.forEach((secret) => {
|
secrets.forEach((secret) => {
|
||||||
if (secret.isBuildSecret) {
|
if (secret.isBuildSecret) {
|
||||||
if (pullmergeRequestId) {
|
if (pullmergeRequestId) {
|
||||||
const isSecretFound = secrets.filter(s => s.name === secret.name && s.isPRMRSecret)
|
const isSecretFound = secrets.filter((s) => s.name === secret.name && s.isPRMRSecret);
|
||||||
if (isSecretFound.length > 0) {
|
if (isSecretFound.length > 0) {
|
||||||
Dockerfile.push(`ARG ${secret.name}=${isSecretFound[0].value}`);
|
Dockerfile.push(`ARG ${secret.name}=${escapeStringRegexp(isSecretFound[0].value)}`);
|
||||||
} else {
|
} else {
|
||||||
Dockerfile.push(`ARG ${secret.name}=${secret.value}`);
|
Dockerfile.push(`ARG ${secret.name}=${escapeStringRegexp(secret.value)}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!secret.isPRMRSecret) {
|
if (!secret.isPRMRSecret) {
|
||||||
Dockerfile.push(`ARG ${secret.name}=${secret.value}`);
|
Dockerfile.push(`ARG ${secret.name}=${escapeStringRegexp(secret.value)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -804,11 +852,7 @@ export async function buildCacheImageForLaravel(data, imageForBuild) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function buildCacheImageWithCargo(data, imageForBuild) {
|
export async function buildCacheImageWithCargo(data, imageForBuild) {
|
||||||
const {
|
const { applicationId, workdir, buildId } = data;
|
||||||
applicationId,
|
|
||||||
workdir,
|
|
||||||
buildId,
|
|
||||||
} = data;
|
|
||||||
|
|
||||||
const Dockerfile: Array<string> = [];
|
const Dockerfile: Array<string> = [];
|
||||||
Dockerfile.push(`FROM ${imageForBuild} as planner-${applicationId}`);
|
Dockerfile.push(`FROM ${imageForBuild} as planner-${applicationId}`);
|
||||||
|
@ -2,6 +2,7 @@ import { promises as fs } from 'fs';
|
|||||||
import { buildImage, checkPnpm } from './common';
|
import { buildImage, checkPnpm } from './common';
|
||||||
|
|
||||||
const createDockerfile = async (data, image): Promise<void> => {
|
const createDockerfile = async (data, image): Promise<void> => {
|
||||||
|
const { default: escapeStringRegexp } = await import('escape-string-regexp');
|
||||||
const {
|
const {
|
||||||
workdir,
|
workdir,
|
||||||
port,
|
port,
|
||||||
@ -23,15 +24,15 @@ const createDockerfile = async (data, image): Promise<void> => {
|
|||||||
secrets.forEach((secret) => {
|
secrets.forEach((secret) => {
|
||||||
if (secret.isBuildSecret) {
|
if (secret.isBuildSecret) {
|
||||||
if (pullmergeRequestId) {
|
if (pullmergeRequestId) {
|
||||||
const isSecretFound = secrets.filter(s => s.name === secret.name && s.isPRMRSecret)
|
const isSecretFound = secrets.filter((s) => s.name === secret.name && s.isPRMRSecret);
|
||||||
if (isSecretFound.length > 0) {
|
if (isSecretFound.length > 0) {
|
||||||
Dockerfile.push(`ARG ${secret.name}=${isSecretFound[0].value}`);
|
Dockerfile.push(`ARG ${secret.name}=${escapeStringRegexp(isSecretFound[0].value)}`);
|
||||||
} else {
|
} else {
|
||||||
Dockerfile.push(`ARG ${secret.name}=${secret.value}`);
|
Dockerfile.push(`ARG ${secret.name}=${escapeStringRegexp(secret.value)}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!secret.isPRMRSecret) {
|
if (!secret.isPRMRSecret) {
|
||||||
Dockerfile.push(`ARG ${secret.name}=${secret.value}`);
|
Dockerfile.push(`ARG ${secret.name}=${escapeStringRegexp(secret.value)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,7 @@ importers:
|
|||||||
dockerode: 3.3.4
|
dockerode: 3.3.4
|
||||||
dotenv-extended: 2.9.0
|
dotenv-extended: 2.9.0
|
||||||
esbuild: 0.15.15
|
esbuild: 0.15.15
|
||||||
|
escape-string-regexp: 5.0.0
|
||||||
eslint: 8.28.0
|
eslint: 8.28.0
|
||||||
eslint-config-prettier: 8.5.0
|
eslint-config-prettier: 8.5.0
|
||||||
eslint-plugin-prettier: 4.2.1
|
eslint-plugin-prettier: 4.2.1
|
||||||
@ -100,6 +101,7 @@ importers:
|
|||||||
dayjs: 1.11.6
|
dayjs: 1.11.6
|
||||||
dockerode: 3.3.4
|
dockerode: 3.3.4
|
||||||
dotenv-extended: 2.9.0
|
dotenv-extended: 2.9.0
|
||||||
|
escape-string-regexp: 5.0.0
|
||||||
execa: 6.1.0
|
execa: 6.1.0
|
||||||
fastify: 4.10.2
|
fastify: 4.10.2
|
||||||
fastify-plugin: 4.3.0
|
fastify-plugin: 4.3.0
|
||||||
|
Loading…
Reference in New Issue
Block a user