"""systemd's shell context sequences stay out of every command's output (#41). systemd 258 (Ubuntu 26.04) ships ``/etc/profile.d/80-systemd-osc-context.sh``. An interactive bash then wraps every command in OSC 3008 sequences, from ``PS0`` before it runs and from ``PROMPT_COMMAND`` before the next prompt, each with a fresh UUID. netmiko's interactive shell is such a bash: the sequences ended up in every parsed value, and since the prompt never looked the same twice, netmiko left the prompt line in the output as well. ``os_version`` grew past 255 characters and netOrk could not store the poll. """ from unittest.mock import MagicMock, patch from napalm_linux._shell import HISTORY_OFF, PROMPT_HOOKS_OFF from napalm_linux.linux import LinuxDriver #: What ``cat /etc/os-release | grep PRETTY_NAME ...`` returned through netmiko on #: an Ubuntu 26.04.1 host (2026-10-23), the prompt line already gone. _UBUNTU_2604_OS_RELEASE = ( "\x1b]3008;end=87c2e1c5-f850-4429-9f06-749e9be783e6;exit=success\x1b\\" "\x1b]3008;start=bc3bc23b-2652-4826-8192-be447f97dd6f;type=command;" "machineid=35cf42f3beb446bbb9aa95b937a0cf48;user=netork;hostname=ubuntu;" "bootid=d32bd88c-dfce-40fe-9869-257bf50ef0e0;pid=20059;cwd=/home/netork\x1b\\" "Ubuntu 26.04.1 LTS\n" ) def _opened(device: MagicMock) -> LinuxDriver: driver = LinuxDriver("h", "admin", "p") with patch("napalm_linux.linux.ConnectHandler", return_value=device): driver.open() return driver class TestPromptHooksOff: def test_the_session_drops_the_hooks_right_after_the_history(self): device = MagicMock() device.send_command.return_value = "/usr/bin/apt" _opened(device) sent = [c.args[0] for c in device.send_command.call_args_list] assert sent[:2] == [HISTORY_OFF, PROMPT_HOOKS_OFF] def test_it_unsets_both_hooks_including_an_array_prompt_command(self): # The script appends to PROMPT_COMMAND as an array; assigning the empty # string would only clear element 0 and leave systemd's hook running. assert PROMPT_HOOKS_OFF.startswith(" ") assert "unset PS0 PROMPT_COMMAND" in PROMPT_HOOKS_OFF def test_the_prompt_is_read_again_once_the_hooks_are_gone(self): # netmiko learned the prompt with the sequences in front of it; a prompt # carrying a UUID never matches again, so strip_prompt would keep failing. device = MagicMock() device.send_command.return_value = "/usr/bin/apt" _opened(device) calls = [(c[0], c.args[0] if c.args else None) for c in device.mock_calls] hooks_off = calls.index(("send_command", PROMPT_HOOKS_OFF)) assert "set_base_prompt" in [name for name, _ in calls[hooks_off + 1 :]] def test_a_shell_that_refuses_it_does_not_stop_the_connection(self): device = MagicMock() device.send_command.side_effect = ["", Exception("no prompt"), "", "/usr/bin/apt"] driver = _opened(device) assert driver._device is device class TestSendStripsTerminalCodes: def test_os_version_comes_back_without_the_context_sequences(self): device = MagicMock() device.send_command.return_value = _UBUNTU_2604_OS_RELEASE driver = LinuxDriver("h", "admin", "p") driver._device = device assert driver._send("cat /etc/os-release") == "Ubuntu 26.04.1 LTS"