blob: 04281c6b65923c4691151bdd01e2c85cbce0539b [file]
#!/usr/bin/env node
/**
* Run the headless Node test suite without inheriting user config or credentials.
*
* Usage:
* node scripts/run-headless-tests.mjs
* node scripts/run-headless-tests.mjs --help
*/
import { spawnSync } from 'node:child_process';
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
const scriptPath = fileURLToPath(import.meta.url);
const repoRoot = resolve(dirname(scriptPath), '..');
const headlessDir = join(repoRoot, 'packages', 'headless');
const testPattern = 'dist/**/*.test.js';
const usage = `Usage: node scripts/run-headless-tests.mjs
Runs packages/headless tests with isolated user config, credentials, proxies, and Git config.
`;
const sensitiveEnvName =
/(?:^|_)(?:API_KEY|ACCESS_KEY|PRIVATE_KEY|TOKEN|SECRET|PASSWORD|CREDENTIALS?)(?:_|$)/i;
const proxyEnvName = /^(?:HTTP_PROXY|HTTPS_PROXY|ALL_PROXY|NO_PROXY)$/i;
export function runHeadlessTests(options = {}) {
const cwd = options.cwd ?? headlessDir;
const spawn = options.spawnSync ?? spawnSync;
const inheritedEnv = options.env ?? process.env;
const tempDir = mkdtempSync(join(tmpdir(), 'maka-headless-test-env-'));
const credentialsPath = join(tempDir, 'credentials.json');
const globalConfigPath = join(tempDir, 'gitconfig');
try {
writeFileSync(credentialsPath, '{"version":1,"values":{}}\n', {
encoding: 'utf8',
mode: 0o600,
});
writeFileSync(globalConfigPath, '', { encoding: 'utf8', mode: 0o600 });
const result = spawn(process.execPath, ['--test', testPattern], {
cwd,
env: {
...Object.fromEntries(
Object.entries(inheritedEnv).filter(
([name]) => !sensitiveEnvName.test(name) && !proxyEnvName.test(name),
),
),
HOME: tempDir,
USERPROFILE: tempDir,
XDG_CONFIG_HOME: join(tempDir, 'config'),
XDG_DATA_HOME: join(tempDir, 'data'),
XDG_STATE_HOME: join(tempDir, 'state'),
XDG_CACHE_HOME: join(tempDir, 'cache'),
APPDATA: join(tempDir, 'appdata'),
MAKA_CREDENTIALS_PATH: credentialsPath,
GIT_CONFIG_GLOBAL: globalConfigPath,
GIT_CONFIG_NOSYSTEM: '1',
},
stdio: 'inherit',
});
if (result.error) throw result.error;
return result.status ?? 1;
} finally {
rmSync(tempDir, { recursive: true, force: true });
}
}
function main(args) {
if (args.length === 1 && (args[0] === '-h' || args[0] === '--help')) {
process.stdout.write(usage);
return 0;
}
if (args.length > 0) {
process.stderr.write(`${usage}\nUnexpected argument: ${args[0]}\n`);
return 2;
}
return runHeadlessTests();
}
if (process.argv[1] && resolve(process.argv[1]) === scriptPath) {
process.exitCode = main(process.argv.slice(2));
}