test/config-dotenv-inline-comment.test.js
Rama master · réplica de lectura del repositorio original.
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { mkdtempSync, writeFileSync, existsSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { spawnSync } from 'node:child_process';
// src/config.js resolves .env as `resolve(EXE_DIR, '.env')`, and when `process.pkg`
// is truthy EXE_DIR becomes `dirname(process.execPath)`. So a child that sets
// `process.pkg` and pins execPath at a temp dir reads OUR fixture and never touches
// the repo's own .env (which does not exist; .gitignore excludes it).
//
// SCOPE NOTE, because it changed the verdict here. The audit first filed this as
// "the parser truncates an API key". It does — but so does every standard dotenv
// parser: a whitespace-preceded `#` starts a comment. `API_KEY=sk-live # note` is
// ambiguous by construction and NO parser can tell a note from a value. So this is
// not a parsing bug and the value is not recoverable. The defect is that it happened
// SILENTLY: the dashboard password kept working, the chat API answered 401, and
// nothing named the file just edited. The fix is a loud warning + a documented
// quoting rule — asserted below.
const REPO = join(dirname(fileURLToPath(import.meta.url)), '..');
function parseWith(fixtureLines) {
const dir = mkdtempSync(join(tmpdir(), 'wa-dotenv-'));
const fakeExe = join(dir, process.platform === 'win32' ? 'windsurfapi.exe' : 'windsurfapi');
writeFileSync(fakeExe, '');
writeFileSync(join(dir, '.env'), fixtureLines.join('\n') + '\n', 'utf8');
const script = `
process.pkg = {};
Object.defineProperty(process, 'execPath', { value: ${JSON.stringify(fakeExe)}, configurable: true });
await import('file://${REPO.replace(/\\/g, '/')}/src/config.js');
process.stdout.write(JSON.stringify({
API_KEY: process.env.API_KEY ?? null,
PORT: process.env.PORT ?? null,
_env: ${JSON.stringify(join(dir, '.env'))},
}));
`;
const r = spawnSync(process.execPath, ['--input-type=module', '-e', script], {
cwd: REPO,
encoding: 'utf8',
env: { ...process.env, WINDSURFAPI_SKIP_DOTENV: '0' },
});
if (r.status !== 0) throw new Error(`child failed: ${r.stderr || r.stdout}`);
const parsed = JSON.parse(r.stdout);
if (!existsSync(parsed._env)) throw new Error('fixture .env vanished');
return { ...parsed, stderr: r.stderr || '' };
}
describe('.env parsing: the truncation is standard, the silence was the defect', () => {
it('strips a whitespace-preceded comment (standard dotenv) AND warns about it', () => {
const got = parseWith(['API_KEY=sk-live-abc123 # rotated 2026-09-01']);
assert.equal(got.API_KEY, 'sk-live-abc123', 'standard dotenv semantics — kept as-is');
assert.match(got.stderr, /inline comment stripped/, 'the operator must be told');
assert.match(got.stderr, /API_KEY/, 'and told which key');
assert.match(got.stderr, /quote it/, 'and told how to fix it');
});
it('quoted values keep the hash and produce no warning', () => {
const got = parseWith(['API_KEY="sk-live # kept"']);
assert.equal(got.API_KEY, 'sk-live # kept');
assert.doesNotMatch(got.stderr, /inline comment stripped/);
});
it('a hash with no leading space is not a comment', () => {
const got = parseWith(['API_KEY=sk-live-abc#def']);
assert.equal(got.API_KEY, 'sk-live-abc#def');
assert.doesNotMatch(got.stderr, /inline comment stripped/);
});
it('the documented plain case stays silent (PORT=3003 # port)', () => {
const got = parseWith(['PORT=3003 # port']);
assert.equal(got.PORT, '3003');
assert.doesNotMatch(got.stderr, /inline comment stripped/, 'a short numeric note is not worth a warning');
});
});