fix(update): keep TUI gate user scoped

This commit is contained in:
Dallin Romney
2026-08-20 22:40:08 -07:00
parent dc2df01fe2
commit debad27b73
2 changed files with 47 additions and 6 deletions
+31 -3
View File
@@ -93,14 +93,28 @@ describe("local TUI processes", () => {
const spawnSync = vi.fn().mockReturnValue({
status: 0,
stdout: JSON.stringify([
{ ProcessId: 101, CommandLine: "C:\\openclaw.exe tui" },
{ ProcessId: 102, CommandLine: "C:\\openclaw.exe gateway" },
{ ProcessId: 103, CommandLine: '"C:\\Program Files\\OpenClaw\\openclaw.exe" chat' },
{ ProcessId: 101, CommandLine: "C:\\openclaw.exe tui", OwnerSid: "S-1", CurrentSid: "S-1" },
{
ProcessId: 102,
CommandLine: "C:\\openclaw.exe gateway",
OwnerSid: "S-1",
CurrentSid: "S-1",
},
{
ProcessId: 103,
CommandLine: '"C:\\Program Files\\OpenClaw\\openclaw.exe" chat',
OwnerSid: "S-1",
CurrentSid: "S-1",
},
{
ProcessId: 104,
CommandLine:
'"C:\\Program Files\\nodejs\\node.exe" "C:\\Program Files\\OpenClaw\\openclaw.mjs" terminal',
OwnerSid: "S-1",
CurrentSid: "S-1",
},
{ ProcessId: 105, CommandLine: "C:\\openclaw.exe tui", OwnerSid: "S-2", CurrentSid: "S-1" },
{ ProcessId: 106, CommandLine: "C:\\openclaw.exe tui", OwnerSid: null, CurrentSid: "S-1" },
]),
});
@@ -227,4 +241,18 @@ describe("local TUI processes", () => {
await waitForLocalTuiUpdate(vi.fn(async () => ({ lockPath: "test", release })));
expect(release).toHaveBeenCalledOnce();
});
it("keeps waiting after the bounded lock attempt while an update is still running", async () => {
const release = vi.fn(async () => {});
const timeout = Object.assign(new Error("busy"), { code: "file_lock_timeout" });
const acquireLock = vi
.fn()
.mockRejectedValueOnce(timeout)
.mockResolvedValueOnce({ lockPath: "test", release });
await waitForLocalTuiUpdate(acquireLock);
expect(acquireLock).toHaveBeenCalledTimes(2);
expect(release).toHaveBeenCalledOnce();
});
});
+16 -3
View File
@@ -119,7 +119,7 @@ export function listLocalTuiProcesses(
[
"-NoProfile",
"-Command",
"Get-CimInstance Win32_Process | Select-Object ProcessId,CreationDate,CommandLine | ConvertTo-Json -Compress",
"$currentSid=[Security.Principal.WindowsIdentity]::GetCurrent().User.Value; Get-CimInstance Win32_Process | ForEach-Object { $ownerSid=(Invoke-CimMethod -InputObject $_ -MethodName GetOwnerSid -ErrorAction SilentlyContinue).Sid; [pscustomobject]@{ProcessId=$_.ProcessId;CommandLine=$_.CommandLine;OwnerSid=$ownerSid;CurrentSid=$currentSid} } | ConvertTo-Json -Compress",
],
{ encoding: "utf8", killSignal: "SIGKILL", timeout: LOCAL_TUI_PROCESS_PROBE_TIMEOUT_MS },
);
@@ -134,6 +134,8 @@ export function listLocalTuiProcesses(
}
const pidValue = Reflect.get(entry, "ProcessId");
const commandValue = Reflect.get(entry, "CommandLine");
const ownerSidValue = Reflect.get(entry, "OwnerSid");
const currentSidValue = Reflect.get(entry, "CurrentSid");
const pid = typeof pidValue === "number" ? pidValue : undefined;
const command = typeof commandValue === "string" ? commandValue.trim() : undefined;
const startTime = pid
@@ -141,6 +143,8 @@ export function listLocalTuiProcesses(
: null;
return pid &&
pid !== (params.currentPid ?? process.pid) &&
typeof ownerSidValue === "string" &&
ownerSidValue === currentSidValue &&
command &&
isLocalTuiCommand(command, "win32")
? [{ pid, command, ...(startTime === null ? {} : { startTime: String(startTime) }) }]
@@ -309,6 +313,15 @@ export async function quiesceLocalTuiProcessesBeforeUpdate(
export async function waitForLocalTuiUpdate(
acquireLock: typeof acquireFileLock = acquireFileLock,
): Promise<void> {
const lock = await acquireLock(LOCAL_TUI_UPDATE_LOCK_PATH, LOCAL_TUI_UPDATE_LOCK_OPTIONS);
await lock.release();
for (;;) {
try {
const lock = await acquireLock(LOCAL_TUI_UPDATE_LOCK_PATH, LOCAL_TUI_UPDATE_LOCK_OPTIONS);
await lock.release();
return;
} catch (error) {
if (extractErrorCode(error) !== "file_lock_timeout") {
throw error;
}
}
}
}