fix(worker): chmod materialized env file to 0600 even when it pre-exists
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { mkdir, rm, writeFile } from 'node:fs/promises';
|
import { chmod, mkdir, rm, writeFile } from 'node:fs/promises';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
|
|
||||||
import { assertContainedRealPath } from './path-containment';
|
import { assertContainedRealPath } from './path-containment';
|
||||||
@@ -24,6 +24,9 @@ export const writeMaterializedEnv = async (
|
|||||||
});
|
});
|
||||||
await mkdir(path.dirname(envPath), { recursive: true });
|
await mkdir(path.dirname(envPath), { recursive: true });
|
||||||
await writeFile(envPath, formatMaterializedEnv(secrets), { mode: 0o600 });
|
await writeFile(envPath, formatMaterializedEnv(secrets), { mode: 0o600 });
|
||||||
|
// writeFile's mode only applies on create; chmod unconditionally tightens an
|
||||||
|
// already-existing (possibly 0644) file so plaintext secrets never leak.
|
||||||
|
await chmod(envPath, 0o600);
|
||||||
return envPath;
|
return envPath;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
import { access, mkdtemp, readFile, rm, stat } from 'node:fs/promises';
|
import {
|
||||||
|
access,
|
||||||
|
chmod,
|
||||||
|
mkdtemp,
|
||||||
|
readFile,
|
||||||
|
rm,
|
||||||
|
stat,
|
||||||
|
writeFile,
|
||||||
|
} from 'node:fs/promises';
|
||||||
import os from 'node:os';
|
import os from 'node:os';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { afterEach, describe, expect, test } from 'vitest';
|
import { afterEach, describe, expect, test } from 'vitest';
|
||||||
@@ -39,6 +47,26 @@ describe('materialize env', () => {
|
|||||||
await expect(readFile(envPath, 'utf8')).resolves.toBe('A="x"\n');
|
await expect(readFile(envPath, 'utf8')).resolves.toBe('A="x"\n');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('tightens perms to 0600 and overwrites content when the env file pre-exists 0644', async () => {
|
||||||
|
const repoDir = await mkdtemp(path.join(os.tmpdir(), 'spoon-env-'));
|
||||||
|
tempDirs.push(repoDir);
|
||||||
|
|
||||||
|
const preExisting = path.join(repoDir, '.env.local');
|
||||||
|
// Pre-create the target with loose perms. umask may mask the writeFile
|
||||||
|
// mode, so chmod explicitly and assert the precondition really is 0644.
|
||||||
|
await writeFile(preExisting, 'OLD', { mode: 0o644 });
|
||||||
|
await chmod(preExisting, 0o644);
|
||||||
|
await expect(mode(preExisting)).resolves.toBe(0o644);
|
||||||
|
|
||||||
|
const envPath = await writeMaterializedEnv(repoDir, '.env.local', [
|
||||||
|
{ name: 'A', value: 'x' },
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Overwrote the plaintext content AND tightened perms unconditionally.
|
||||||
|
await expect(mode(envPath)).resolves.toBe(0o600);
|
||||||
|
await expect(readFile(envPath, 'utf8')).resolves.toBe('A="x"\n');
|
||||||
|
});
|
||||||
|
|
||||||
test('removeMaterializedEnv deletes an existing file and no-ops when absent', async () => {
|
test('removeMaterializedEnv deletes an existing file and no-ops when absent', async () => {
|
||||||
const repoDir = await mkdtemp(path.join(os.tmpdir(), 'spoon-env-'));
|
const repoDir = await mkdtemp(path.join(os.tmpdir(), 'spoon-env-'));
|
||||||
tempDirs.push(repoDir);
|
tempDirs.push(repoDir);
|
||||||
|
|||||||
Reference in New Issue
Block a user