diff --git a/uninstall.sh b/uninstall.sh index 4b461362a18..1300f5d2967 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -243,6 +243,7 @@ remove_file_with_optional_sudo() { info "Removed $path" } +# Stop NemoClaw helper services (e.g. Telegram bridge, cloudflared). stop_helper_services() { if [ -x "$SCRIPT_DIR/scripts/start-services.sh" ]; then run_optional "Stopped NemoClaw helper services" "$SCRIPT_DIR/scripts/start-services.sh" --stop @@ -251,6 +252,7 @@ stop_helper_services() { remove_glob_paths "${TMP_ROOT}/nemoclaw-services-*" } +# Stop openshell port-forward processes on the dashboard port. stop_openshell_forward_processes() { if ! command -v pgrep >/dev/null 2>&1; then warn "pgrep not found; skipping local OpenShell forward process cleanup." @@ -281,6 +283,71 @@ stop_openshell_forward_processes() { done } +# Kill orphaned openshell processes left behind after uninstall — +# sandbox create, ssh-proxy, and related ssh sessions. (#1940) +stop_orphaned_openshell_processes() { + if ! command -v pgrep >/dev/null 2>&1; then + warn "pgrep not found; skipping orphaned openshell process cleanup." + return 0 + fi + + local -a pids=() + local pid + + # Scope to the original invoking user to avoid killing other users' processes + # on shared systems. Under sudo, SUDO_USER holds the real caller; fall back + # to LOGNAME, then id -un. (#1940) + local _user + _user="${SUDO_USER:-${LOGNAME:-$(id -un 2>/dev/null || echo "")}}" + local -a _pgrep_user=() + if [ -n "$_user" ]; then + _pgrep_user=(-u "$_user") + fi + + # Collect openshell sandbox create, ssh-proxy, and related ssh processes. + while IFS= read -r pid; do + [ -n "$pid" ] || continue + pids+=("$pid") + done < <(pgrep "${_pgrep_user[@]}" -f "openshell (sandbox create|ssh-proxy)" 2>/dev/null || true) + + # Also collect ssh processes whose command line references openshell. + # Match "openshell ssh-proxy" or "openshell-" (gateway name pattern) to + # avoid false positives on unrelated ssh sessions. User scoping via + # _pgrep_user provides an additional safety net. + local cmd + while IFS= read -r pid; do + [ -n "$pid" ] || continue + cmd="$(ps -p "$pid" -o args= 2>/dev/null)" || continue + if [[ "$cmd" == *"openshell ssh-proxy"* ]] || [[ "$cmd" == *"openshell-"* ]]; then + pids+=("$pid") + fi + done < <(pgrep "${_pgrep_user[@]}" -x ssh 2>/dev/null || true) + + # Deduplicate + local -A seen=() + local -a unique_pids=() + for pid in "${pids[@]}"; do + if [ -z "${seen[$pid]:-}" ]; then + seen[$pid]=1 + unique_pids+=("$pid") + fi + done + + if [ "${#unique_pids[@]}" -eq 0 ]; then + info "No orphaned openshell processes found" + return 0 + fi + + for pid in "${unique_pids[@]}"; do + if kill "$pid" >/dev/null 2>&1 || kill -9 "$pid" >/dev/null 2>&1; then + info "Stopped orphaned openshell process $pid" + else + warn "Failed to stop orphaned openshell process $pid" + fi + done +} + +# Remove OpenShell sandboxes, providers, and gateway. remove_openshell_resources() { if ! command -v openshell >/dev/null 2>&1; then warn "openshell not found; skipping gateway/provider/sandbox cleanup." @@ -629,6 +696,7 @@ main() { step 1 "Stopping services" stop_helper_services stop_openshell_forward_processes + stop_orphaned_openshell_processes step 2 "OpenShell resources" remove_openshell_resources