fix(migrate): validate live source state

This commit is contained in:
Mohamed Boudra
2026-07-19 02:12:29 +02:00
parent af244d0f02
commit 4ed944db2f
5 changed files with 70 additions and 4 deletions
+30 -3
View File
@@ -19,7 +19,10 @@ test("discovers the configured local socket before TCP fallback", () => {
const paseoHome = mkdtempSync(path.join(os.tmpdir(), "paseo-node-client-"));
cleanup.push(paseoHome);
mkdirSync(paseoHome, { recursive: true });
writeFileSync(path.join(paseoHome, "paseo.pid"), JSON.stringify({ listen: "/tmp/paseo.sock" }));
writeFileSync(
path.join(paseoHome, "paseo.pid"),
JSON.stringify({ pid: process.pid, listen: "/tmp/paseo.sock" }),
);
writeFileSync(
path.join(paseoHome, "config.json"),
JSON.stringify({ daemon: { listen: "127.0.0.1:7777" } }),
@@ -35,7 +38,10 @@ test("discovers the configured local socket before TCP fallback", () => {
test("discovers the running daemon TCP address from its PID record", () => {
const paseoHome = mkdtempSync(path.join(os.tmpdir(), "paseo-node-client-pid-tcp-"));
cleanup.push(paseoHome);
writeFileSync(path.join(paseoHome, "paseo.pid"), JSON.stringify({ listen: "127.0.0.1:7789" }));
writeFileSync(
path.join(paseoHome, "paseo.pid"),
JSON.stringify({ pid: process.pid, listen: "127.0.0.1:7789" }),
);
expect(resolveDefaultDaemonHosts({ PASEO_HOME: paseoHome })).toEqual([
"127.0.0.1:7789",
@@ -46,7 +52,10 @@ test("discovers the running daemon TCP address from its PID record", () => {
test("normalizes the daemon's bare IPv6 loopback PID address", () => {
const paseoHome = mkdtempSync(path.join(os.tmpdir(), "paseo-node-client-pid-ipv6-"));
cleanup.push(paseoHome);
writeFileSync(path.join(paseoHome, "paseo.pid"), JSON.stringify({ listen: "::1:7789" }));
writeFileSync(
path.join(paseoHome, "paseo.pid"),
JSON.stringify({ pid: process.pid, listen: "::1:7789" }),
);
expect(resolveDefaultDaemonHosts({ PASEO_HOME: paseoHome })).toEqual([
"[::1]:7789",
@@ -102,3 +111,21 @@ test("skips malformed discovered candidates and keeps the default fallback", ()
resolveDefaultDaemonHosts({ PASEO_HOME: paseoHome, PASEO_LISTEN: "tcp://missing-port" }),
).toEqual(["localhost:6767"]);
});
test("ignores a stale PID listener before the configured daemon", () => {
const paseoHome = mkdtempSync(path.join(os.tmpdir(), "paseo-node-client-stale-pid-"));
cleanup.push(paseoHome);
writeFileSync(
path.join(paseoHome, "paseo.pid"),
JSON.stringify({ pid: 2_147_483_647, listen: "127.0.0.1:7789" }),
);
writeFileSync(
path.join(paseoHome, "config.json"),
JSON.stringify({ daemon: { listen: "127.0.0.1:7777" } }),
);
expect(resolveDefaultDaemonHosts({ PASEO_HOME: paseoHome })).toEqual([
"127.0.0.1:7777",
"localhost:6767",
]);
});
+17
View File
@@ -111,9 +111,17 @@ function readPidListen(paseoHome: string): string | null {
if (!existsSync(pidPath)) return null;
try {
const parsed = JSON.parse(readFileSync(pidPath, "utf8")) as {
pid?: unknown;
listen?: unknown;
sockPath?: unknown;
};
if (
typeof parsed.pid !== "number" ||
!Number.isInteger(parsed.pid) ||
!isProcessRunning(parsed.pid)
) {
return null;
}
if (typeof parsed.listen === "string") return parsed.listen;
return typeof parsed.sockPath === "string" ? parsed.sockPath : null;
} catch {
@@ -121,6 +129,15 @@ function readPidListen(paseoHome: string): string | null {
}
}
function isProcessRunning(pid: number): boolean {
try {
process.kill(pid, 0);
return true;
} catch (error) {
return typeof error === "object" && error !== null && "code" in error && error.code === "EPERM";
}
}
export function resolveDefaultDaemonHosts(env: NodeJS.ProcessEnv = process.env): string[] {
const paseoHome = resolvePaseoHome(env);
const direct = normalizeDaemonHost(env.PASEO_LISTEN ?? "");