← back to Tk 10965 Zero Price Analysis
test/deny-side-effects.cjs
50 lines
const fs = require('node:fs');
const { syncBuiltinESMExports } = require('node:module');
const originalWrite = fs.writeSync.bind(fs);
const allowed = new Set(JSON.parse(process.env.GUARD_ALLOWED_READS));
function denied(name) {
return function () {
originalWrite(2, 'GUARD_ATTEMPT:' + name + '\n');
throw new Error('GUARD_BLOCKED:' + name);
};
}
// Only the actual entry point and its pure parser may be read by the loader.
for (const name of ['readFileSync', 'readFile', 'createReadStream']) {
const original = fs[name].bind(fs);
fs[name] = function (file, ...rest) {
const path = file instanceof URL ? require('node:url').fileURLToPath(file) : String(file);
if (!allowed.has(path)) return denied('fs.' + name)();
return original(file, ...rest);
};
}
for (const name of ['readFile', 'open']) {
const original = fs.promises[name].bind(fs.promises);
fs.promises[name] = async function(file, ...rest) {
const path = file instanceof URL ? require('node:url').fileURLToPath(file) : String(file);
if (!allowed.has(path) || (name === 'open' && rest[0] !== 'r' && rest[0] !== 0)) return denied('fs.promises.' + name)();
return original(file, ...rest);
};
}
for (const name of ['mkdir', 'mkdtemp', 'writeFile', 'appendFile', 'rename', 'unlink', 'rm', 'rmdir', 'copyFile', 'cp', 'link', 'symlink', 'truncate', 'chmod', 'chown', 'utimes', 'write', 'writev', 'ftruncate']) {
for (const key of [name, name + 'Sync']) if (typeof fs[key] === 'function') fs[key] = denied('fs.' + key);
if (typeof fs.promises[name] === 'function') fs.promises[name] = denied('fs.promises.' + name);
}
for (const name of ['open', 'openSync']) {
const original = fs[name].bind(fs);
fs[name] = function(file, flags, ...rest) {
const path = file instanceof URL ? require('node:url').fileURLToPath(file) : String(file);
if (!allowed.has(path) || (flags !== 'r' && flags !== 0)) return denied('fs.' + name)();
return original(file, flags, ...rest);
};
}
fs.createWriteStream = denied('fs.createWriteStream');
for (const [module, names] of Object.entries({
'node:child_process': ['spawn', 'spawnSync', 'exec', 'execSync', 'execFile', 'execFileSync', 'fork'],
'node:http': ['request', 'get'], 'node:https': ['request', 'get'],
'node:net': ['connect', 'createConnection', 'createServer'], 'node:tls': ['connect', 'createServer'],
'node:dgram': ['createSocket'], 'node:dns': ['lookup', 'resolve']
})) { const api = require(module); for (const name of names) api[name] = denied(module + '.' + name); }
require('node:net').Socket.prototype.connect = denied('net.Socket.connect');
globalThis.fetch = denied('fetch');
syncBuiltinESMExports();