test(security): bind fixture reads and mutations to private descriptors

This commit is contained in:
haelyra
2026-10-10 19:11:12 -04:00
parent 9aa9003e1b
commit e76ea52ae3
4 changed files with 64 additions and 29 deletions
+5 -2
View File
@@ -4666,9 +4666,12 @@ function runTests() {
}
for (const [rel, parts] of byFile) {
const file = path.join(trivialRoot, rel);
if (fs.existsSync(file)) continue;
fs.mkdirSync(path.dirname(file), { recursive: true });
fs.writeFileSync(file, `${parts.join('\n')}\n`);
try {
fs.writeFileSync(file, `${parts.join('\n')}\n`, { flag: 'wx' });
} catch (error) {
if (error.code !== 'EEXIST') throw error;
}
}
};
const trivialRun = (toolName, tool_input, env = {}) => {
+30 -21
View File
@@ -648,29 +648,38 @@ test('dry-run snapshots local-scope inventory into isolated Claude and project r
'.claude',
'settings.local.json'
);
assert.strictEqual(fs.lstatSync(shadowSettingsPath).isFile(), true);
const shadowInstalled = JSON.parse(fs.readFileSync(
path.join(runOptions.env.CLAUDE_CONFIG_DIR, 'plugins', 'installed_plugins.json'),
'utf8'
));
assert.strictEqual(
shadowInstalled.plugins['ecc@ecc'][0].projectPath,
runOptions.cwd
const shadowSettingsFd = fs.openSync(
shadowSettingsPath,
fs.constants.O_RDWR | (fs.constants.O_NOFOLLOW || 0)
);
assert.ok(
shadowInstalled.plugins['ecc@ecc'][0].installPath
.startsWith(runOptions.env.CLAUDE_CONFIG_DIR)
);
fs.writeFileSync(shadowSettingsPath, '{"providerRead":true}\n');
fs.mkdirSync(runOptions.env.XDG_DATA_HOME, { recursive: true });
fs.writeFileSync(
path.join(runOptions.env.XDG_DATA_HOME, 'claude-provider-read.json'),
'{"providerRead":true}\n'
);
if (args.join(' ') === 'plugin list --json') {
return { stdout: JSON.stringify([installedPlugin('local')]) };
try {
assert.strictEqual(fs.fstatSync(shadowSettingsFd).isFile(), true);
const shadowInstalled = JSON.parse(fs.readFileSync(
path.join(runOptions.env.CLAUDE_CONFIG_DIR, 'plugins', 'installed_plugins.json'),
'utf8'
));
assert.strictEqual(
shadowInstalled.plugins['ecc@ecc'][0].projectPath,
runOptions.cwd
);
assert.ok(
shadowInstalled.plugins['ecc@ecc'][0].installPath
.startsWith(runOptions.env.CLAUDE_CONFIG_DIR)
);
fs.ftruncateSync(shadowSettingsFd, 0);
fs.writeFileSync(shadowSettingsFd, '{"providerRead":true}\n');
fs.mkdirSync(runOptions.env.XDG_DATA_HOME, { recursive: true });
fs.writeFileSync(
path.join(runOptions.env.XDG_DATA_HOME, 'claude-provider-read.json'),
'{"providerRead":true}\n'
);
if (args.join(' ') === 'plugin list --json') {
return { stdout: JSON.stringify([installedPlugin('local')]) };
}
return { stdout: JSON.stringify([officialMarketplace('local')]) };
} finally {
fs.closeSync(shadowSettingsFd);
}
return { stdout: JSON.stringify([officialMarketplace('local')]) };
};
const result = setupClaudePlugin(
+18 -3
View File
@@ -903,15 +903,30 @@ function runTests() {
assert.strictEqual(fs.readFileSync(userPath, 'utf8'), 'Keep my settings.\n');
}
const modifiedContent = `${fs.readFileSync(toolPath, 'utf8')}\n// User test customisation.\n`;
fs.writeFileSync(toolPath, modifiedContent, 'utf8');
const toolFd = fs.openSync(toolPath, fs.constants.O_RDWR | (fs.constants.O_NOFOLLOW || 0));
let modifiedContent;
try {
assert.ok(fs.fstatSync(toolFd).isFile());
modifiedContent = `${fs.readFileSync(toolFd, 'utf8')}\n// User test customisation.\n`;
const modifiedBytes = Buffer.from(modifiedContent);
assert.strictEqual(fs.writeSync(toolFd, modifiedBytes, 0, modifiedBytes.length, 0), modifiedBytes.length);
fs.ftruncateSync(toolFd, modifiedBytes.length);
} finally {
fs.closeSync(toolFd);
}
const uninstalled = uninstallInstalledStates(lifecycleOptions);
assert.strictEqual(uninstalled.results.length, 1);
assert.strictEqual(uninstalled.results[0].status, 'partial', JSON.stringify(uninstalled));
assert.ok(uninstalled.results[0].removedPaths.includes(barrelPath));
assert.ok(!fs.existsSync(barrelPath), 'both legacy and repaired managed barrels are recognised');
assert.deepStrictEqual(uninstalled.results[0].retainedPaths, [toolPath]);
assert.strictEqual(fs.readFileSync(toolPath, 'utf8'), modifiedContent);
const retainedFd = fs.openSync(toolPath, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW || 0));
try {
assert.ok(fs.fstatSync(retainedFd).isFile());
assert.strictEqual(fs.readFileSync(retainedFd, 'utf8'), modifiedContent);
} finally {
fs.closeSync(retainedFd);
}
assert.strictEqual(fs.readFileSync(userPath, 'utf8'), 'Keep my settings.\n');
assert.ok(fs.existsSync(plan.installStatePath), 'modified managed content retains its ownership record');
}
+11 -3
View File
@@ -185,8 +185,8 @@ for (const phase of ['during hashing', 'after hashing']) {
const edited = 'user edit bytes\n';
assert.strictEqual(original.length, edited.length);
writeFile(file, original);
// Bind the fixture identity to its opened private file, keeping the later
// pathname read an assertion rather than relying on a prior stat check.
// Bind the fixture identity to its opened private file. Validate the
// retained pathname through a fresh descriptor after the injected race.
const identityFd = fs.openSync(file, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW || 0));
let identity;
try { identity = fs.fstatSync(identityFd, { bigint: true }); }
@@ -224,7 +224,15 @@ for (const phase of ['during hashing', 'after hashing']) {
fs.fstatSync = originalFstat;
}
assert.ok(mutationApplied, 'The equal-length mutation must actually execute');
assert.strictEqual(fs.readFileSync(file, 'utf8'), edited);
const retainedFd = fs.openSync(file, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW || 0));
try {
const retainedIdentity = fs.fstatSync(retainedFd, { bigint: true });
assert.ok(retainedIdentity.isFile());
assert.ok(matches(retainedIdentity), 'The mutated fixture inode must remain at the retained path');
assert.strictEqual(fs.readFileSync(retainedFd, 'utf8'), edited);
} finally {
fs.closeSync(retainedFd);
}
assert.deepStrictEqual(result.removedPaths, []);
assert.strictEqual(result.warnings.length, 1);
assert.match(result.warnings[0], /changed while being verified/);