mirror of
https://github.com/affaan-m/ECC.git
synced 2026-08-17 21:15:40 +02:00
fix(security): verify legacy files after opening
This commit is contained in:
@@ -17,21 +17,22 @@ function getStatePath(codexHome) {
|
||||
function openRegularFileNoFollow(filePath, writable = false) {
|
||||
const noFollow = fs.constants.O_NOFOLLOW || 0;
|
||||
const flags = (writable ? fs.constants.O_RDWR : fs.constants.O_RDONLY) | noFollow;
|
||||
let pathStat;
|
||||
try {
|
||||
pathStat = fs.lstatSync(filePath, { bigint: true });
|
||||
} catch (error) {
|
||||
if (error.code === 'ENOENT') return null;
|
||||
throw error;
|
||||
}
|
||||
if (!pathStat.isFile() || pathStat.isSymbolicLink()) {
|
||||
throw new Error(`Refusing to manage non-regular legacy sync path: ${filePath}`);
|
||||
}
|
||||
let descriptor;
|
||||
try {
|
||||
descriptor = fs.openSync(filePath, flags);
|
||||
} catch (error) {
|
||||
if (error.code === 'ENOENT') return null;
|
||||
if (error.code === 'ENOENT') {
|
||||
try {
|
||||
const unresolved = fs.lstatSync(filePath);
|
||||
if (unresolved.isSymbolicLink() || !unresolved.isFile()) {
|
||||
throw new Error(`Refusing to manage non-regular legacy sync path: ${filePath}`);
|
||||
}
|
||||
} catch (lstatError) {
|
||||
if (lstatError.code === 'ENOENT') return null;
|
||||
throw lstatError;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
if (error.code === 'ELOOP') {
|
||||
throw new Error(`Refusing to manage non-regular legacy sync path: ${filePath}`);
|
||||
}
|
||||
@@ -52,10 +53,10 @@ function openRegularFileNoFollow(filePath, writable = false) {
|
||||
!descriptorStat.isFile()
|
||||
|| !finalPathStat.isFile()
|
||||
|| finalPathStat.isSymbolicLink()
|
||||
|| descriptorStat.dev !== pathStat.dev
|
||||
|| descriptorStat.ino !== pathStat.ino
|
||||
|| descriptorStat.dev !== finalPathStat.dev
|
||||
|| descriptorStat.ino !== finalPathStat.ino
|
||||
|| descriptorStat.nlink !== 1n
|
||||
|| finalPathStat.nlink !== 1n
|
||||
) {
|
||||
fs.closeSync(descriptor);
|
||||
throw new Error(`Refusing to manage non-regular legacy sync path: ${filePath}`);
|
||||
|
||||
@@ -194,7 +194,8 @@ function runTests() {
|
||||
const createdPath = path.join(codexHome, 'prompts', 'ecc-review.md');
|
||||
fs.mkdirSync(path.dirname(existingPath), { recursive: true });
|
||||
fs.writeFileSync(existingPath, '# User prompt\n', { mode: 0o640 });
|
||||
const originalMode = fs.statSync(existingPath).mode & 0o777;
|
||||
const existingDescriptor = fs.openSync(existingPath, 'r+');
|
||||
const originalMode = fs.fstatSync(existingDescriptor).mode & 0o777;
|
||||
|
||||
const statePath = beginLegacySyncState({
|
||||
codexHome,
|
||||
@@ -204,7 +205,9 @@ function runTests() {
|
||||
});
|
||||
recordLegacySyncPath({ statePath, filePath: existingPath });
|
||||
recordLegacySyncPath({ statePath, filePath: createdPath });
|
||||
fs.writeFileSync(existingPath, '# Partial ECC write\n');
|
||||
const partialContent = Buffer.from('# Partial ECC write\n');
|
||||
fs.ftruncateSync(existingDescriptor, 0);
|
||||
fs.writeSync(existingDescriptor, partialContent, 0, partialContent.length, 0);
|
||||
fs.writeFileSync(createdPath, '# Partial new file\n');
|
||||
|
||||
let hooksValue = path.join(codexHome, 'git-hooks');
|
||||
@@ -215,8 +218,11 @@ function runTests() {
|
||||
});
|
||||
|
||||
assert.strictEqual(result.status, 'rolled-back');
|
||||
assert.strictEqual(fs.readFileSync(existingPath, 'utf8'), '# User prompt\n');
|
||||
assert.strictEqual(fs.statSync(existingPath).mode & 0o777, originalMode);
|
||||
const restoredContent = Buffer.alloc(Buffer.byteLength('# User prompt\n'));
|
||||
fs.readSync(existingDescriptor, restoredContent, 0, restoredContent.length, 0);
|
||||
assert.strictEqual(restoredContent.toString('utf8'), '# User prompt\n');
|
||||
assert.strictEqual(fs.fstatSync(existingDescriptor).mode & 0o777, originalMode);
|
||||
fs.closeSync(existingDescriptor);
|
||||
assert.ok(!fs.existsSync(createdPath));
|
||||
assert.strictEqual(hooksValue, '/tmp/user-hooks');
|
||||
assert.ok(!fs.existsSync(statePath));
|
||||
|
||||
Reference in New Issue
Block a user