mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-07-21 22:05:23 +02:00
- dockerImage (buildRemoteDocker) -> docker pull / echo - dockerContextPath (docker-file builder) -> cd - publishDirectory (nixpacks builder) -> docker cp source/dest paths These fields were interpolated unescaped into shell commands run via execAsync / execAsyncRemote during deployment. All are now passed through shell-quote. Registry credentials already went through safeDockerLoginCommand (unchanged). Closes GHSA-g9cg-4mmj-mh7p, GHSA-jxxj-gmpx-h5rj, GHSA-qjrc-g63x-qhp9, GHSA-98j8-6vjr-c3xw
106 lines
2.6 KiB
TypeScript
106 lines
2.6 KiB
TypeScript
import {
|
|
getEnvironmentVariablesObject,
|
|
prepareEnvironmentVariablesForShell,
|
|
} from "@dokploy/server/utils/docker/utils";
|
|
import { quote } from "shell-quote";
|
|
import {
|
|
getBuildAppDirectory,
|
|
getDockerContextPath,
|
|
} from "../filesystem/directory";
|
|
import type { ApplicationNested } from ".";
|
|
import { createEnvFileCommand } from "./utils";
|
|
|
|
export const getDockerCommand = (application: ApplicationNested) => {
|
|
const {
|
|
appName,
|
|
env,
|
|
publishDirectory,
|
|
buildArgs,
|
|
buildSecrets,
|
|
dockerBuildStage,
|
|
cleanCache,
|
|
createEnvFile,
|
|
} = application;
|
|
const dockerFilePath = getBuildAppDirectory(application);
|
|
|
|
try {
|
|
const image = `${appName}`;
|
|
|
|
const defaultContextPath =
|
|
dockerFilePath.substring(0, dockerFilePath.lastIndexOf("/") + 1) || ".";
|
|
|
|
const dockerContextPath =
|
|
getDockerContextPath(application) || defaultContextPath;
|
|
|
|
const commandArgs = ["build", "-t", image, "-f", dockerFilePath, "."];
|
|
|
|
if (dockerBuildStage) {
|
|
commandArgs.push("--target", dockerBuildStage);
|
|
}
|
|
|
|
if (cleanCache) {
|
|
commandArgs.push("--no-cache");
|
|
}
|
|
|
|
const args = prepareEnvironmentVariablesForShell(
|
|
buildArgs,
|
|
application.environment.project.env,
|
|
application.environment.env,
|
|
);
|
|
|
|
for (const arg of args) {
|
|
commandArgs.push("--build-arg", arg);
|
|
}
|
|
|
|
const secrets = getEnvironmentVariablesObject(
|
|
buildSecrets,
|
|
application.environment.project.env,
|
|
application.environment.env,
|
|
);
|
|
|
|
const joinedSecrets = Object.entries(secrets)
|
|
.map(([key, value]) => `${key}=${quote([value])}`)
|
|
.join(" ");
|
|
|
|
/*
|
|
Do not generate an environment file when publishDirectory is specified,
|
|
as it could be publicly exposed.
|
|
Also respect the createEnvFile flag.
|
|
*/
|
|
let command = "";
|
|
if (!publishDirectory && createEnvFile) {
|
|
command += createEnvFileCommand(
|
|
dockerFilePath,
|
|
env,
|
|
application.environment.project.env,
|
|
application.environment.env,
|
|
);
|
|
}
|
|
|
|
for (const key in secrets) {
|
|
// Although buildx is smart enough to know we may be referring to an environment variable name,
|
|
// we still make sure it doesn't fall back to `type=file`.
|
|
// See: https://docs.docker.com/reference/cli/docker/buildx/build/#secret
|
|
commandArgs.push("--secret", `type=env,id=${key}`);
|
|
}
|
|
|
|
command += `
|
|
echo ${quote([`Building ${appName}`])} ;
|
|
cd ${quote([dockerContextPath])} || {
|
|
echo ${quote([`❌ The path ${dockerContextPath} does not exist`])} ;
|
|
exit 1;
|
|
}
|
|
|
|
${joinedSecrets} docker ${commandArgs.join(" ")} || {
|
|
echo "❌ Docker build failed" ;
|
|
exit 1;
|
|
}
|
|
echo "✅ Docker build completed." ;
|
|
`;
|
|
|
|
return command;
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
};
|