-
Notifications
You must be signed in to change notification settings - Fork 3.1k
fix(uninstall): do not fail cleanup on another user's gateway process #9005
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
a20e8d7
fix(uninstall): do not fail cleanup on another user's gateway process
laitingsheng b598d88
merge: resolve conflicts with main
github-actions[bot] b0e7be4
Merge branch 'main' into fix/cross-user-gateway-uninstall
prekshivyas eeac154
Merge branch 'main' into fix/cross-user-gateway-uninstall
prekshivyas aa6f71a
fix(ci): satisfy repository growth guardrails
prekshivyas 95caf5b
fix(test): keep the UID fixture tuple mutable
prekshivyas 2078f38
fix(test): preserve explicit WSL overrides
prekshivyas 06e49c3
merge: sync main for CI repair
prekshivyas 03e21f4
fix(hermes): admit the managed API port
prekshivyas 3fb2e26
test(onboard): use valid replacement identity
prekshivyas 1b7da08
merge: resolve conflicts with main
prekshivyas 1f575ba
test(uninstall): close foreign gateway review gaps
apurvvkumaria 1ac20a1
merge: resolve main conflicts for #9005
rsliter File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
99 changes: 99 additions & 0 deletions
99
src/lib/actions/uninstall/run-plan-foreign-user-gateway.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| import fs from "node:fs"; | ||
| import os from "node:os"; | ||
| import path from "node:path"; | ||
|
|
||
| import { describe, expect, it, vi } from "vitest"; | ||
|
|
||
| import { type RunResult, runUninstallPlan } from "./run-plan"; | ||
|
|
||
| const HOST_GATEWAY_PID = 9999043; | ||
|
|
||
| function ok(stdout = ""): RunResult { | ||
| return { status: 0, stdout, stderr: "" }; | ||
| } | ||
|
|
||
| function notFound(): RunResult { | ||
| return { status: 1, stdout: "", stderr: "" }; | ||
| } | ||
|
|
||
| function uninstallWithHostGatewayOwnedBy(uid: number): { | ||
| errors: string[]; | ||
| exitCode: number; | ||
| } { | ||
| const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-uninstall-foreign-")); | ||
| const errors: string[] = []; | ||
| const psResults = new Map<string, RunResult>([ | ||
| ["stat=", ok("S\n")], | ||
| ["args=", ok("/usr/local/bin/openshell-gateway\n")], | ||
| ["user=", ok("otheruser\n")], | ||
| ["uid=", ok(`${uid}\n`)], | ||
| ]); | ||
| const run = (command: string, args: string[]): RunResult => | ||
| command === "pgrep" | ||
| ? args.some((arg) => arg.includes("openshell-gateway")) | ||
| ? ok(`${HOST_GATEWAY_PID}\n`) | ||
| : notFound() | ||
| : command === "ps" | ||
| ? (psResults.get(args.at(-1) ?? "") ?? notFound()) | ||
| : command === "openshell" && args.join(" ") === "gateway list -o json" | ||
| ? ok("[]") | ||
| : ok(); | ||
| try { | ||
| const result = runUninstallPlan( | ||
| { assumeYes: true, deleteModels: false, keepOpenShell: false }, | ||
| { | ||
| commandExists: (command) => command === "pgrep" || command === "openshell", | ||
| env: { HOME: tmpHome, NO_COLOR: "1" }, | ||
| error: (message) => errors.push(message), | ||
| existsSync: () => false, | ||
| isTty: false, | ||
| kill: () => false, | ||
| log: vi.fn(), | ||
| requireCompleteGatewayProcessCleanup: true, | ||
| resolveGatewayTeardownAuthority: ({ gatewayName, gatewayPort }) => ({ | ||
| gatewayName, | ||
| gatewayPort, | ||
| mode: "nemoclaw-managed", | ||
| source: "standalone", | ||
| endpoint: null, | ||
| stateDir: null, | ||
| supervisor: null, | ||
| requiredCapabilities: [], | ||
| }), | ||
| rmSync: vi.fn(), | ||
| run, | ||
| runDocker: () => ok(), | ||
| }, | ||
| ); | ||
| return { errors, exitCode: result.exitCode }; | ||
| } finally { | ||
| fs.rmSync(tmpHome, { force: true, recursive: true }); | ||
| } | ||
| } | ||
|
|
||
| describe("uninstall with a host gateway owned by another user", () => { | ||
| it("completes when the only unstoppable gateway process belongs to another user", () => { | ||
| const { errors, exitCode } = uninstallWithHostGatewayOwnedBy((process.getuid?.() ?? 0) + 1); | ||
|
|
||
| expect(exitCode).toBe(0); | ||
| expect(errors).toContainEqual( | ||
| `Kept otheruser-owned host openshell-gateway process ${HOST_GATEWAY_PID} running. ` + | ||
| "Cleanup does not stop a gateway process that another user owns.", | ||
| ); | ||
| expect(errors).not.toContainEqual( | ||
| "Cannot continue uninstall because host gateway process cleanup did not complete.", | ||
| ); | ||
| }); | ||
|
|
||
| it("still fails when the current user's own gateway process cannot be stopped", () => { | ||
| const { errors, exitCode } = uninstallWithHostGatewayOwnedBy(process.getuid?.() ?? 0); | ||
|
|
||
| expect(exitCode).toBe(1); | ||
| expect(errors).toContainEqual( | ||
| "Cannot continue uninstall because host gateway process cleanup did not complete.", | ||
| ); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.