1.0.5
This commit is contained in:
1 parent
b89470e965
commit
a1e07b1a10
11 files changed
+292
-72
No files matched your search
@@ -58,7 +58,14 @@ async function buildGitEnv(credential: GitCredential | null): Promise<GitEnv> {
|
||||
if (credential?.authType === 'ssh' && credential.sshPrivateKey) {
|
||||
// Create a temporary SSH key file (use absolute path so SSH can find it)
|
||||
const sshKeyPath = resolve(join(GIT_REPOS_DIR, `.ssh-key-${credential.id}`));
|
||||
await Bun.write(sshKeyPath, credential.sshPrivateKey);
|
||||
|
||||
// Ensure SSH key ends with a newline (newer SSH versions are strict about this)
|
||||
let keyContent = credential.sshPrivateKey;
|
||||
if (!keyContent.endsWith('\n')) {
|
||||
keyContent += '\n';
|
||||
}
|
||||
|
||||
await Bun.write(sshKeyPath, keyContent);
|
||||
// Ensure SSH key has correct permissions (0600 = owner read/write only)
|
||||
// Bun.write's mode option doesn't always work reliably, so use chmodSync
|
||||
chmodSync(sshKeyPath, 0o600);
|
||||
|
||||
+17
-22
@@ -263,24 +263,19 @@ export async function getStackComposeFile(
|
||||
): Promise<{ success: boolean; content?: string; stackDir?: string; error?: string }> {
|
||||
const stacksDir = getStacksDir();
|
||||
const stackDir = join(stacksDir, stackName);
|
||||
const composeFile = join(stackDir, 'docker-compose.yml');
|
||||
|
||||
const ymlFile = Bun.file(composeFile);
|
||||
if (await ymlFile.exists()) {
|
||||
return {
|
||||
success: true,
|
||||
content: await ymlFile.text(),
|
||||
stackDir
|
||||
};
|
||||
}
|
||||
// Check all common compose file names (Docker Compose v1 and v2 naming conventions)
|
||||
const composeFileNames = ['docker-compose.yml', 'docker-compose.yaml', 'compose.yml', 'compose.yaml'];
|
||||
|
||||
const yamlFile = Bun.file(join(stackDir, 'docker-compose.yaml'));
|
||||
if (await yamlFile.exists()) {
|
||||
return {
|
||||
success: true,
|
||||
content: await yamlFile.text(),
|
||||
stackDir
|
||||
};
|
||||
for (const fileName of composeFileNames) {
|
||||
const file = Bun.file(join(stackDir, fileName));
|
||||
if (await file.exists()) {
|
||||
return {
|
||||
success: true,
|
||||
content: await file.text(),
|
||||
stackDir
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -1289,8 +1284,10 @@ export async function writeStackEnvFile(
|
||||
const stacksDir = getStacksDir();
|
||||
const envFilePath = join(stacksDir, stackName, '.env');
|
||||
|
||||
// SECURITY: Only write non-secret variables to .env file
|
||||
// Secrets are stored in DB and injected via shell environment at runtime
|
||||
const rawContent = variables
|
||||
.filter(v => v.key?.trim())
|
||||
.filter(v => v.key?.trim() && !v.isSecret)
|
||||
.map(v => `${v.key.trim()}=${v.value}`)
|
||||
.join('\n') + '\n';
|
||||
|
||||
@@ -1299,16 +1296,14 @@ export async function writeStackEnvFile(
|
||||
|
||||
/**
|
||||
* Write raw environment content directly to the .env file (preserves comments/formatting)
|
||||
*
|
||||
* NOTE: Raw content should NOT contain secrets. Secrets are managed via the form view,
|
||||
* stored in DB, and injected via shell environment at runtime.
|
||||
*/
|
||||
export async function writeRawStackEnvFile(
|
||||
stackName: string,
|
||||
rawContent: string
|
||||
): Promise<void> {
|
||||
// Guard against writing masked secret placeholders (would corrupt the file)
|
||||
if (rawContent.match(/^[A-Za-z_][A-Za-z0-9_]*=\*\*\*$/m)) {
|
||||
throw new Error('Cannot write masked placeholder "***" to .env file - this would corrupt secret values');
|
||||
}
|
||||
|
||||
const stacksDir = getStacksDir();
|
||||
const stackDir = join(stacksDir, stackName);
|
||||
|
||||
|
||||
Reference in new issue
Block a user