87 lines
2.7 KiB
TypeScript
87 lines
2.7 KiB
TypeScript
import {
|
|
access,
|
|
chmod,
|
|
mkdtemp,
|
|
readFile,
|
|
rm,
|
|
stat,
|
|
writeFile,
|
|
} from 'node:fs/promises';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import { afterEach, describe, expect, test } from 'vitest';
|
|
|
|
import {
|
|
removeMaterializedEnv,
|
|
writeMaterializedEnv,
|
|
} from '../../src/materialize-env';
|
|
|
|
const tempDirs: string[] = [];
|
|
|
|
const mode = async (filePath: string) => (await stat(filePath)).mode & 0o777;
|
|
|
|
const exists = async (filePath: string) =>
|
|
access(filePath).then(
|
|
() => true,
|
|
() => false,
|
|
);
|
|
|
|
describe('materialize env', () => {
|
|
afterEach(async () => {
|
|
await Promise.all(
|
|
tempDirs.map((dir) => rm(dir, { force: true, recursive: true })),
|
|
);
|
|
tempDirs.length = 0;
|
|
});
|
|
|
|
test('writes the env file 0600 at the returned path with quoted values', async () => {
|
|
const repoDir = await mkdtemp(path.join(os.tmpdir(), 'spoon-env-'));
|
|
tempDirs.push(repoDir);
|
|
|
|
const envPath = await writeMaterializedEnv(repoDir, '.env.local', [
|
|
{ name: 'A', value: 'x' },
|
|
]);
|
|
|
|
await expect(exists(envPath)).resolves.toBe(true);
|
|
await expect(mode(envPath)).resolves.toBe(0o600);
|
|
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 () => {
|
|
const repoDir = await mkdtemp(path.join(os.tmpdir(), 'spoon-env-'));
|
|
tempDirs.push(repoDir);
|
|
|
|
const envPath = await writeMaterializedEnv(repoDir, '.env.local', [
|
|
{ name: 'A', value: 'x' },
|
|
]);
|
|
await expect(exists(envPath)).resolves.toBe(true);
|
|
|
|
await removeMaterializedEnv(envPath);
|
|
await expect(exists(envPath)).resolves.toBe(false);
|
|
|
|
// No-ops when the file is already gone or the path is undefined.
|
|
await expect(removeMaterializedEnv(envPath)).resolves.toBeUndefined();
|
|
await expect(removeMaterializedEnv(undefined)).resolves.toBeUndefined();
|
|
});
|
|
});
|