diff --git a/app/atomic_svc.py b/app/atomic_svc.py index 32d3804..17bfafd 100644 --- a/app/atomic_svc.py +++ b/app/atomic_svc.py @@ -189,10 +189,12 @@ def _handle_multiline_commands(cmd, executor): @staticmethod def _concatenate_shell_commands(command_lines): """Concatenate multiple shell command lines. The ; character won't be added at the end of each command if the - command line ends in "then" or "do" or already ends with a ; character.""" + command line ends in "then" or "do" or already ends with a ; character. + Whitespace-only lines are skipped to avoid producing stray ';' separators.""" to_concat = [] - num_lines = len(command_lines) - for index, cmd in enumerate(command_lines): + non_empty_lines = [cmd for cmd in command_lines if cmd.strip()] + num_lines = len(non_empty_lines) + for index, cmd in enumerate(non_empty_lines): to_concat.append(cmd) if re.search(r'do\s*$', cmd) or re.search(r'then\s*$', cmd) or re.search(r';\s*$', cmd): if not re.search(r'\s+$', cmd): diff --git a/tests/test_atomic_svc.py b/tests/test_atomic_svc.py index 1329d3d..b8d4a53 100644 --- a/tests/test_atomic_svc.py +++ b/tests/test_atomic_svc.py @@ -1,5 +1,6 @@ import hashlib import os +import re import pytest from plugins.atomic.app.atomic_svc import AtomicService @@ -178,6 +179,19 @@ def test_handle_multiline_command_shell_ifthen(self): want = 'if condition; then innercommand; innercommand2; fi' assert AtomicService._handle_multiline_commands(commands, 'sh') == want + def test_handle_multiline_command_no_extra_semicolon_after_fi(self): + """Regression test for issue #3097: whitespace-only lines between prereq block + (ending with 'fi;') and the ability command must not produce a stray '; ' separator, + which resulted in commands like 'fi; ; ip neighbour show'.""" + # Simulate the precmd built by _prepare_executor: + # dep_construct ends with 'fi;', then ' \n ' (two spaces) separates it from the + # ability command — matching the double-space pattern of the actual bug report. + commands = 'if [ -x "$(command -v ip)" ]; then : ; else apt-get install iproute2 -y; fi;\n \n ip neighbour show' + result = AtomicService._handle_multiline_commands(commands, 'sh') + assert not re.search(r';\s+;', result), \ + f"Unexpected consecutive semicolons with only whitespace between them in: {result!r}" + assert 'ip neighbour show' in result + def test_use_default_inputs(self, atomic_svc, atomic_test): platform = 'windows' string_to_analyze = '#{recon_commands} -a'