mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-17 16:46:31 +03:00
fix: harden live-server liveness against pid reuse
greptile-apps[bot] repro: a helper that died without removing server.json leaves a pid the OS can hand to an unrelated process, which kill(pid, 0) classifies as a running server and routes repo-root helpers onto the stale app. The liveness check now also requires the pid's command line to look like a node process (ps-based, platform-guarded), removing reuse by arbitrary processes; the residual node-reuse case is covered by the multi-app warning and the --target escape hatch. This work was produced with AI assistance (Claude Code). Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Code
parent
5a85050230
commit
031e170d3e
@@ -302,3 +302,32 @@ describe('review regressions: helper --target', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('review regressions: pid reuse', () => {
|
||||
it('does not classify a non-node process reusing the recorded pid as a live server', () => {
|
||||
const repo = realpathSync(mkdtempSync(join(tmpdir(), 'impeccable-roots-pidreuse-')));
|
||||
try {
|
||||
mkdirSync(join(repo, '.git'), { recursive: true });
|
||||
for (const name of ['appA', 'appB']) {
|
||||
write(repo, `${name}/vite.config.js`, 'export default {};');
|
||||
}
|
||||
const a = resolveRoots({ cwd: repo, targetPath: join(repo, 'appA/vite.config.js') }).manifest;
|
||||
const b = resolveRoots({ cwd: repo, targetPath: join(repo, 'appB/vite.config.js') }).manifest;
|
||||
writeRootsManifest(a);
|
||||
writeRootsManifest(b); // B booted last.
|
||||
|
||||
// B's helper died; its pid was reused by a non-node process (launchd /
|
||||
// init: pid 1 is alive on every unix and is never a node process).
|
||||
write(repo, 'siteB-unused.txt', '');
|
||||
write(repo, 'appB/.impeccable/live/server.json', JSON.stringify({ pid: 1, port: 2, token: 't' }));
|
||||
// A holds the interrupted session the user is recovering.
|
||||
write(repo, 'appA/.impeccable/live/sessions/aa11bb22.snapshot.json',
|
||||
JSON.stringify({ id: 'aa11bb22', phase: 'variants_ready' }));
|
||||
|
||||
const resolved = resolveLiveRoots(repo);
|
||||
assert.equal(resolved.manifest.appRoot, join(repo, 'appA'));
|
||||
} finally {
|
||||
rmSync(repo, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user