mirror of
https://github.com/affaan-m/ECC.git
synced 2026-09-11 04:07:54 +02:00
fix(nasiko): use descriptor lock identity
This commit is contained in:
@@ -40,13 +40,13 @@ Commit `5aa66021` moved ambient-override checks into isolated child processes an
|
||||
## GREEN
|
||||
|
||||
- Focused installer, lifecycle, packaging, release-workflow, manifest, OpenCode, Antigravity, and uninstall tests passed.
|
||||
- Full repository suite: 3,985 passed, 0 failed.
|
||||
- Full repository suite: 3,986 passed, 0 failed.
|
||||
- `npm audit --audit-level=low`: 0 vulnerabilities.
|
||||
- Supply-chain IOC scan: 207 files inspected, no findings.
|
||||
- Both release workflow YAML files parsed successfully.
|
||||
- Both release workflows derive reviewed notes from the validated tag and fail clearly when that version's notes are absent.
|
||||
- Release-note selection follows the lowercase filename convention shared by prior release directories.
|
||||
- Exact packed archive lifecycle passed on macOS with Node 24.9.0 using SHA-256 `de51641fee3fd7318937ec3bb45fe86f597b06b36501bf31960efe5ab7c8b42c`.
|
||||
- Exact packed archive lifecycle passed on macOS with Node 24.9.0 using SHA-256 `cf3a5ccefda2608389c7039b6c8b7f5707fd3fdd99579e843ed1aa593c7b1a15`.
|
||||
- The packed lifecycle covered npm installation, public CLI setup, cumulative Cursor install, drift detection, repair, uninstall, user-file preservation, Antigravity install/doctor/uninstall, and OpenCode install/doctor/uninstall.
|
||||
- Simulated hosted-runner `OPENCODE_CONFIG_DIR` and `XDG_CONFIG_HOME` overrides passed the adapter, MCP inventory, lifecycle, legacy migration, doctor, repair, list, and uninstall suites while explicit CLI environments continued to honor those overrides.
|
||||
|
||||
|
||||
@@ -273,11 +273,11 @@ function processIsAlive(pid) {
|
||||
function inspectLifecycleLock(lockPath, fileSystem) {
|
||||
const descriptor = fileSystem.openSync(lockPath, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW || 0));
|
||||
try {
|
||||
const descriptorStats = fileSystem.fstatSync(descriptor);
|
||||
if (!descriptorStats.isFile() || descriptorStats.size <= 0 || descriptorStats.size > 4096) return null;
|
||||
const descriptorStats = fileSystem.fstatSync(descriptor, { bigint: true });
|
||||
if (!descriptorStats.isFile() || descriptorStats.size <= 0n || descriptorStats.size > 4096n) return null;
|
||||
const bytes = fileSystem.readFileSync(descriptor);
|
||||
const pathStats = fileSystem.lstatSync(lockPath);
|
||||
if (pathStats.isSymbolicLink() || !pathStats.isFile() || !sameFileIdentity(descriptorStats, pathStats)) return null;
|
||||
if (pathStats.isSymbolicLink() || !pathStats.isFile()) return null;
|
||||
let metadata;
|
||||
try { metadata = JSON.parse(bytes.toString('utf8')); } catch (_error) { return null; }
|
||||
if (
|
||||
@@ -291,14 +291,21 @@ function inspectLifecycleLock(lockPath, fileSystem) {
|
||||
}
|
||||
|
||||
function removeLockIfOwned(lockPath, expectedStats, fileSystem) {
|
||||
let descriptor;
|
||||
try {
|
||||
const current = fileSystem.lstatSync(lockPath);
|
||||
if (!current.isSymbolicLink() && current.isFile() && sameFileIdentity(current, expectedStats)) {
|
||||
descriptor = fileSystem.openSync(lockPath, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW || 0));
|
||||
const current = fileSystem.fstatSync(descriptor, { bigint: true });
|
||||
const pathStats = fileSystem.lstatSync(lockPath);
|
||||
if (!pathStats.isSymbolicLink() && pathStats.isFile() && current.isFile() && sameFileIdentity(current, expectedStats)) {
|
||||
fileSystem.closeSync(descriptor);
|
||||
descriptor = undefined;
|
||||
fileSystem.rmSync(lockPath, { force: true });
|
||||
return true;
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.code !== 'ENOENT') throw error;
|
||||
if (error.code !== 'ENOENT' && error.code !== 'ELOOP') throw error;
|
||||
} finally {
|
||||
if (descriptor !== undefined) fileSystem.closeSync(descriptor);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -316,12 +323,12 @@ function createLifecycleLock(lockPath, fileSystem) {
|
||||
}
|
||||
catch (error) {
|
||||
if (descriptor !== undefined) {
|
||||
const ownedStats = fileSystem.fstatSync(descriptor);
|
||||
const ownedStats = fileSystem.fstatSync(descriptor, { bigint: true });
|
||||
try { fileSystem.closeSync(descriptor); } finally { removeLockIfOwned(lockPath, ownedStats, fileSystem); }
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
const ownedStats = fileSystem.fstatSync(descriptor);
|
||||
const ownedStats = fileSystem.fstatSync(descriptor, { bigint: true });
|
||||
let released = false;
|
||||
return () => {
|
||||
if (released) return;
|
||||
|
||||
@@ -180,6 +180,29 @@ async function main() {
|
||||
assert.strictEqual(fs.existsSync(lockPath), true);
|
||||
} finally { fs.rmSync(installRoot, { recursive: true, force: true }); }
|
||||
}],
|
||||
['uses descriptor identity when Windows path stats disagree', () => {
|
||||
const { acquireLifecycleLock } = require('../../scripts/lib/nasiko-release');
|
||||
const installRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-nasiko-windows-identity-'));
|
||||
const lockPath = path.join(installRoot, '.ecc-nasiko-lifecycle.lock');
|
||||
const windowsLikeFileSystem = {
|
||||
...fs,
|
||||
lstatSync: target => {
|
||||
const stats = fs.lstatSync(target);
|
||||
return {
|
||||
...stats,
|
||||
dev: Number(stats.dev) + 1,
|
||||
isDirectory: () => stats.isDirectory(),
|
||||
isFile: () => stats.isFile(),
|
||||
isSymbolicLink: () => stats.isSymbolicLink(),
|
||||
};
|
||||
},
|
||||
};
|
||||
try {
|
||||
const releaseLock = acquireLifecycleLock(installRoot, windowsLikeFileSystem);
|
||||
releaseLock();
|
||||
assert.strictEqual(fs.existsSync(lockPath), false);
|
||||
} finally { fs.rmSync(installRoot, { recursive: true, force: true }); }
|
||||
}],
|
||||
['verifies manifest and blob digests before an atomic install', async () => {
|
||||
const { installNasiko } = require('../../scripts/lib/nasiko-release');
|
||||
const installRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-nasiko-green-'));
|
||||
|
||||
Reference in New Issue
Block a user