Files
Nexus/server/infrastructure/ssh/remote_shell.py
T

64 lines
2.1 KiB
Python
Raw Normal View History

"""Remote shell execution with optional passwordless sudo fallback."""
from __future__ import annotations
import shlex
from server.domain.models import Server
from server.infrastructure.ssh.asyncssh_pool import exec_ssh_command
from server.utils.files_elevation import FilesElevation, get_files_elevation
def shell_output(result: dict) -> str:
return f"{result.get('stderr') or ''}{result.get('stdout') or ''}"
def is_permission_denied_result(result: dict) -> bool:
if result.get("exit_code") == 0:
return False
text = shell_output(result).lower()
return "permission denied" in text or "operation not permitted" in text
async def exec_ssh_command_with_fallback(
server: Server,
command: str,
*,
timeout: int = 120,
) -> dict:
"""Run command; elevation follows server ``extra_attrs.files_elevation``."""
elevation = get_files_elevation(server)
ssh_user = (server.username or "root").strip() or "root"
is_root_ssh = ssh_user == "root"
if elevation == FilesElevation.ALWAYS and not is_root_ssh:
sudo_cmd = f"sudo -n bash -c {shlex.quote(command)}"
sudo_result = await exec_ssh_command(server, sudo_cmd, timeout=timeout)
sudo_result = dict(sudo_result)
sudo_result["elevated"] = True
return sudo_result
result = await exec_ssh_command(server, command, timeout=timeout)
result = dict(result)
if result.get("exit_code") == 0:
result["elevated"] = False
return result
if elevation == FilesElevation.OFF or is_root_ssh:
result["elevated"] = False
return result
if not is_permission_denied_result(result):
result["elevated"] = False
return result
sudo_cmd = f"sudo -n bash -c {shlex.quote(command)}"
sudo_result = await exec_ssh_command(server, sudo_cmd, timeout=timeout)
sudo_result = dict(sudo_result)
if sudo_result.get("exit_code") == 0:
sudo_result["elevated"] = True
return sudo_result
if is_permission_denied_result(sudo_result):
sudo_result["elevated"] = True
return sudo_result
sudo_result["elevated"] = False
return sudo_result