mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47db6831b4 | ||
|
|
56cbd1abb3 | ||
|
|
cb40ac5c6b | ||
|
|
7218b3f79b | ||
|
|
19ea4d3fcd | ||
|
|
6edfd1e547 | ||
|
|
666a8ede97 | ||
|
|
08e4b8fe33 | ||
|
|
5fc265d14f | ||
|
|
c3887af5d1 |
@@ -166,7 +166,38 @@ describe("processTemplate", () => {
|
|||||||
if (!baseUrl || !secretKey) return;
|
if (!baseUrl || !secretKey) return;
|
||||||
|
|
||||||
expect(baseUrl).toContain(mockSchema.projectName);
|
expect(baseUrl).toContain(mockSchema.projectName);
|
||||||
expect(secretKey.split("=")[1]).toHaveLength(64);
|
const base64Value = secretKey.split("=")[1];
|
||||||
|
expect(base64Value).toBeDefined();
|
||||||
|
if (!base64Value) return;
|
||||||
|
expect(base64Value).toMatch(/^[A-Za-z0-9+/]+={0,2}$/);
|
||||||
|
expect(base64Value.length).toBeGreaterThanOrEqual(86);
|
||||||
|
expect(base64Value.length).toBeLessThanOrEqual(88);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should process env vars when provided as an array", () => {
|
||||||
|
const template: CompleteTemplate = {
|
||||||
|
metadata: {} as any,
|
||||||
|
variables: {},
|
||||||
|
config: {
|
||||||
|
domains: [],
|
||||||
|
env: [
|
||||||
|
'CLOUDFLARE_TUNNEL_TOKEN="<INSERT TOKEN>"',
|
||||||
|
'ANOTHER_VAR="some value"',
|
||||||
|
"DOMAIN=${domain}",
|
||||||
|
],
|
||||||
|
mounts: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = processTemplate(template, mockSchema);
|
||||||
|
expect(result.envs).toHaveLength(3);
|
||||||
|
|
||||||
|
// Should preserve exact format for static values
|
||||||
|
expect(result.envs[0]).toBe('CLOUDFLARE_TUNNEL_TOKEN="<INSERT TOKEN>"');
|
||||||
|
expect(result.envs[1]).toBe('ANOTHER_VAR="some value"');
|
||||||
|
|
||||||
|
// Should process variables in array items
|
||||||
|
expect(result.envs[2]).toContain(mockSchema.projectName);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should allow using utility functions directly in env vars", () => {
|
it("should allow using utility functions directly in env vars", () => {
|
||||||
@@ -195,7 +226,12 @@ describe("processTemplate", () => {
|
|||||||
if (!randomDomainEnv || !secretKeyEnv) return;
|
if (!randomDomainEnv || !secretKeyEnv) return;
|
||||||
|
|
||||||
expect(randomDomainEnv).toContain(mockSchema.projectName);
|
expect(randomDomainEnv).toContain(mockSchema.projectName);
|
||||||
expect(secretKeyEnv.split("=")[1]).toHaveLength(32);
|
const base64Value = secretKeyEnv.split("=")[1];
|
||||||
|
expect(base64Value).toBeDefined();
|
||||||
|
if (!base64Value) return;
|
||||||
|
expect(base64Value).toMatch(/^[A-Za-z0-9+/]+={0,2}$/);
|
||||||
|
expect(base64Value.length).toBeGreaterThanOrEqual(42);
|
||||||
|
expect(base64Value.length).toBeLessThanOrEqual(44);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -325,8 +361,22 @@ describe("processTemplate", () => {
|
|||||||
if (!baseUrl || !secretKey || !totpKey) return;
|
if (!baseUrl || !secretKey || !totpKey) return;
|
||||||
|
|
||||||
expect(baseUrl).toContain(mockSchema.projectName);
|
expect(baseUrl).toContain(mockSchema.projectName);
|
||||||
expect(secretKey.split("=")[1]).toHaveLength(64);
|
|
||||||
expect(totpKey.split("=")[1]).toHaveLength(32);
|
// Check base64 lengths and format
|
||||||
|
const secretKeyValue = secretKey.split("=")[1];
|
||||||
|
const totpKeyValue = totpKey.split("=")[1];
|
||||||
|
|
||||||
|
expect(secretKeyValue).toBeDefined();
|
||||||
|
expect(totpKeyValue).toBeDefined();
|
||||||
|
if (!secretKeyValue || !totpKeyValue) return;
|
||||||
|
|
||||||
|
expect(secretKeyValue).toMatch(/^[A-Za-z0-9+/]+={0,2}$/);
|
||||||
|
expect(secretKeyValue.length).toBeGreaterThanOrEqual(86);
|
||||||
|
expect(secretKeyValue.length).toBeLessThanOrEqual(88);
|
||||||
|
|
||||||
|
expect(totpKeyValue).toMatch(/^[A-Za-z0-9+/]+={0,2}$/);
|
||||||
|
expect(totpKeyValue.length).toBeGreaterThanOrEqual(42);
|
||||||
|
expect(totpKeyValue.length).toBeLessThanOrEqual(44);
|
||||||
|
|
||||||
// Check mounts
|
// Check mounts
|
||||||
expect(result.mounts).toHaveLength(1);
|
expect(result.mounts).toHaveLength(1);
|
||||||
@@ -334,8 +384,8 @@ describe("processTemplate", () => {
|
|||||||
expect(mount).toBeDefined();
|
expect(mount).toBeDefined();
|
||||||
if (!mount) return;
|
if (!mount) return;
|
||||||
expect(mount.content).toContain(mockSchema.projectName);
|
expect(mount.content).toContain(mockSchema.projectName);
|
||||||
expect(mount.content).toMatch(/secret=[A-Za-z0-9+/]{64}/);
|
expect(mount.content).toMatch(/secret=[A-Za-z0-9+/]{86,88}/);
|
||||||
expect(mount.content).toMatch(/totp=[A-Za-z0-9+/]{32}/);
|
expect(mount.content).toMatch(/totp=[A-Za-z0-9+/]{42,44}/);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ export const ShowProjects = () => {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
href={`${domain.https ? "https" : "http"}://${domain.host}${domain.path}`}
|
href={`${domain.https ? "https" : "http"}://${domain.host}${domain.path}`}
|
||||||
>
|
>
|
||||||
<span>{domain.host}</span>
|
<span className="truncate">{domain.host}</span>
|
||||||
<ExternalLinkIcon className="size-4 shrink-0" />
|
<ExternalLinkIcon className="size-4 shrink-0" />
|
||||||
</Link>
|
</Link>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
@@ -222,7 +222,7 @@ export const ShowProjects = () => {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
href={`${domain.https ? "https" : "http"}://${domain.host}${domain.path}`}
|
href={`${domain.https ? "https" : "http"}://${domain.host}${domain.path}`}
|
||||||
>
|
>
|
||||||
<span>{domain.host}</span>
|
<span className="truncate">{domain.host}</span>
|
||||||
<ExternalLinkIcon className="size-4 shrink-0" />
|
<ExternalLinkIcon className="size-4 shrink-0" />
|
||||||
</Link>
|
</Link>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "dokploy",
|
"name": "dokploy",
|
||||||
"version": "v0.20.1",
|
"version": "v0.20.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -607,7 +607,7 @@ export const composeRouter = createTRPCRouter({
|
|||||||
|
|
||||||
const processedTemplate = processTemplate(config, {
|
const processedTemplate = processTemplate(config, {
|
||||||
serverIp: serverIp,
|
serverIp: serverIp,
|
||||||
projectName: compose.project.name,
|
projectName: compose.appName,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -676,7 +676,7 @@ export const composeRouter = createTRPCRouter({
|
|||||||
|
|
||||||
const processedTemplate = processTemplate(config, {
|
const processedTemplate = processTemplate(config, {
|
||||||
serverIp: serverIp,
|
serverIp: serverIp,
|
||||||
projectName: compose.project.name,
|
projectName: compose.appName,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update compose file
|
// Update compose file
|
||||||
|
|||||||
@@ -53,14 +53,12 @@ export const generatePassword = (quantity = 16): string => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a random base64 string of specified length
|
* Generate a random base64 string from N random bytes
|
||||||
|
* @param bytes Number of random bytes to generate before base64 encoding (default: 32)
|
||||||
|
* @returns base64 encoded string of the random bytes
|
||||||
*/
|
*/
|
||||||
export function generateBase64(length: number): string {
|
export function generateBase64(bytes = 32): string {
|
||||||
// To get N characters in base64, we need to generate N * 3/4 bytes
|
return randomBytes(bytes).toString("base64");
|
||||||
const bytesNeeded = Math.ceil((length * 3) / 4);
|
|
||||||
return Buffer.from(randomBytes(bytesNeeded))
|
|
||||||
.toString("base64")
|
|
||||||
.substring(0, length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateJwt(length = 256): string {
|
export function generateJwt(length = 256): string {
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export interface CompleteTemplate {
|
|||||||
variables: Record<string, string>;
|
variables: Record<string, string>;
|
||||||
config: {
|
config: {
|
||||||
domains: DomainConfig[];
|
domains: DomainConfig[];
|
||||||
env: Record<string, string>;
|
env: Record<string, string> | string[];
|
||||||
mounts?: MountConfig[];
|
mounts?: MountConfig[];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -176,7 +176,6 @@ export function processDomains(
|
|||||||
schema: Schema,
|
schema: Schema,
|
||||||
): Template["domains"] {
|
): Template["domains"] {
|
||||||
if (!template?.config?.domains) return [];
|
if (!template?.config?.domains) return [];
|
||||||
|
|
||||||
return template?.config?.domains?.map((domain: DomainConfig) => ({
|
return template?.config?.domains?.map((domain: DomainConfig) => ({
|
||||||
...domain,
|
...domain,
|
||||||
host: domain.host
|
host: domain.host
|
||||||
@@ -195,7 +194,18 @@ export function processEnvVars(
|
|||||||
): Template["envs"] {
|
): Template["envs"] {
|
||||||
if (!template?.config?.env) return [];
|
if (!template?.config?.env) return [];
|
||||||
|
|
||||||
return Object.entries(template?.config?.env).map(
|
// Handle array of env vars
|
||||||
|
if (Array.isArray(template.config.env)) {
|
||||||
|
return template.config.env.map((env) => {
|
||||||
|
if (typeof env === "string") {
|
||||||
|
return processValue(env, variables, schema);
|
||||||
|
}
|
||||||
|
return env;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle object of env vars
|
||||||
|
return Object.entries(template.config.env).map(
|
||||||
([key, value]: [string, string]) => {
|
([key, value]: [string, string]) => {
|
||||||
const processedValue = processValue(value, variables, schema);
|
const processedValue = processValue(value, variables, schema);
|
||||||
return `${key}=${processedValue}`;
|
return `${key}=${processedValue}`;
|
||||||
|
|||||||
Reference in New Issue
Block a user