This commit is contained in:
jarek committed 2026-01-18 09:56:38 +01:00
1 parent c185d00dc3
commit 6483cea6c6
5 files changed
+93 -61

No files matched your search

+6 -6
View File
@@ -124,14 +124,14 @@ export const POST: RequestHandler = async ({ request, url, cookies }) => {
return json({ success: true, started: false });
}
// ALWAYS save compose file first - deployStack expects it to exist
await saveStackComposeFile(name, compose, true, envIdNum, {
composePath: composePath || undefined,
envPath: envPath || undefined
});
// Save environment variables BEFORE deploying so they're available during start
if (rawEnvContent || (envVars && Array.isArray(envVars) && envVars.length > 0)) {
// First ensure the stack directory exists by saving compose file
await saveStackComposeFile(name, compose, true, envIdNum, {
composePath: composePath || undefined,
envPath: envPath || undefined
});
// - rawEnvContent: non-secret vars with comments → .env file
// - envVars: ALL vars → DB (secrets stored for shell injection, non-secrets for metadata)
if (rawEnvContent) {
+36 -25
View File
@@ -16,42 +16,53 @@ interface ValidationResult {
/**
* Extract environment variables from compose YAML content.
* Matches ${VAR_NAME} and ${VAR_NAME:-default} patterns.
* Ignores variables in commented lines (lines starting with #).
* Returns { required: [...], optional: [...] }
*/
function extractComposeVars(yaml: string): { required: string[]; optional: string[] } {
const required: string[] = [];
const optional: string[] = [];
// Match ${VAR_NAME} (required) and ${VAR_NAME:-default} or ${VAR_NAME-default} (optional)
const regex = /\$\{([A-Za-z_][A-Za-z0-9_]*)(?:(:-?)[^}]*)?\}/g;
let match;
// Process line by line to skip commented lines
const lines = yaml.split('\n');
for (const line of lines) {
// Skip lines that are comments (start with # after optional whitespace)
const trimmedLine = line.trim();
if (trimmedLine.startsWith('#')) {
continue;
}
while ((match = regex.exec(yaml)) !== null) {
const varName = match[1];
const hasDefault = match[2] !== undefined;
// Match ${VAR_NAME} (required) and ${VAR_NAME:-default} or ${VAR_NAME-default} (optional)
const regex = /\$\{([A-Za-z_][A-Za-z0-9_]*)(?:(:-?)[^}]*)?\}/g;
let match;
if (hasDefault) {
if (!optional.includes(varName) && !required.includes(varName)) {
optional.push(varName);
}
} else {
// Move from optional to required if we find a non-default usage
const optIdx = optional.indexOf(varName);
if (optIdx !== -1) {
optional.splice(optIdx, 1);
}
if (!required.includes(varName)) {
required.push(varName);
while ((match = regex.exec(line)) !== null) {
const varName = match[1];
const hasDefault = match[2] !== undefined;
if (hasDefault) {
if (!optional.includes(varName) && !required.includes(varName)) {
optional.push(varName);
}
} else {
// Move from optional to required if we find a non-default usage
const optIdx = optional.indexOf(varName);
if (optIdx !== -1) {
optional.splice(optIdx, 1);
}
if (!required.includes(varName)) {
required.push(varName);
}
}
}
}
// Also match $VAR_NAME (simple variable substitution)
const simpleRegex = /\$([A-Za-z_][A-Za-z0-9_]*)(?![{A-Za-z0-9_])/g;
while ((match = simpleRegex.exec(yaml)) !== null) {
const varName = match[1];
if (!required.includes(varName) && !optional.includes(varName)) {
required.push(varName);
// Also match $VAR_NAME (simple variable substitution)
const simpleRegex = /\$([A-Za-z_][A-Za-z0-9_]*)(?![{A-Za-z0-9_])/g;
while ((match = simpleRegex.exec(line)) !== null) {
const varName = match[1];
if (!required.includes(varName) && !optional.includes(varName)) {
required.push(varName);
}
}
}