Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package ansible-runner for openSUSE:Factory checked in at 2026-03-22 14:12:30 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ansible-runner (Old) and /work/SRC/openSUSE:Factory/.ansible-runner.new.8177 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ansible-runner" Sun Mar 22 14:12:30 2026 rev:18 rq:1341647 version:2.4.3 Changes: -------- --- /work/SRC/openSUSE:Factory/ansible-runner/ansible-runner.changes 2025-10-17 17:29:30.523409623 +0200 +++ /work/SRC/openSUSE:Factory/.ansible-runner.new.8177/ansible-runner.changes 2026-03-22 14:13:40.108959866 +0100 @@ -1,0 +2,8 @@ +Tue Mar 17 06:11:18 UTC 2026 - Johannes Kastl <[email protected]> + +- update to 2.4.3: + * Use get_option api from callback plugins (#1488). This fixes some + problems around using custom callback plugins. + * Fix container --tty detection in subprocess mode (#1489) + +------------------------------------------------------------------- Old: ---- ansible_runner-2.4.2.tar.gz New: ---- ansible_runner-2.4.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ansible-runner.spec ++++++ --- /var/tmp/diff_new_pack.UJspcc/_old 2026-03-22 14:13:40.668982902 +0100 +++ /var/tmp/diff_new_pack.UJspcc/_new 2026-03-22 14:13:40.672983067 +0100 @@ -1,7 +1,7 @@ # # spec file for package ansible-runner # -# Copyright (c) 2023 SUSE LLC +# Copyright (c) 2026 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -30,7 +30,7 @@ %endif Name: ansible-runner -Version: 2.4.2 +Version: 2.4.3 Release: 0 Summary: Run ansible-playbook inside an execution environment License: Apache-2.0 ++++++ ansible_runner-2.4.2.tar.gz -> ansible_runner-2.4.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_runner-2.4.2/.git_archival.txt new/ansible_runner-2.4.3/.git_archival.txt --- old/ansible_runner-2.4.2/.git_archival.txt 2025-10-14 21:06:40.000000000 +0200 +++ new/ansible_runner-2.4.3/.git_archival.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1,5 +0,0 @@ -node: $Format:%H$ -node-date: $Format:%cI$ -describe-name: $Format:%(describe:tags=true,match=*[0-9]*)$ -ref-names: $Format:%D$ - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_runner-2.4.2/.github/ISSUE_TEMPLATE/bug_report.yml new/ansible_runner-2.4.3/.github/ISSUE_TEMPLATE/bug_report.yml --- old/ansible_runner-2.4.2/.github/ISSUE_TEMPLATE/bug_report.yml 2025-10-14 21:06:40.000000000 +0200 +++ new/ansible_runner-2.4.3/.github/ISSUE_TEMPLATE/bug_report.yml 2026-03-16 19:39:50.000000000 +0100 @@ -9,37 +9,38 @@ value: | **Thank you for reporting a bug in Ansible Runner.** - If you are looking for community support, please visit - the [Community guide](https://ansible.readthedocs.io/projects/runner/en/latest/community/) - for information on how to get in touch. + If this is a question about using `ansible-runner`, please do not use a new issue for your question. + New issues should be used only for submitting a new bug report. Please consult the [Community guide](https://ansible.readthedocs.io/projects/runner/en/latest/community/) + for information on how to submit your question to the [Ansible Forum](https://forum.ansible.com/). - type: input - label: Ansible Runner version - description: Output from `ansible-runner --version` - render: console + attributes: + label: Ansible Runner version + description: Output from `ansible-runner --version` validations: required: true - - type: textarea - label: Python version - description: Output from `python -VV` - render: console + - type: input + attributes: + label: Python version + description: Output from `python -VV` validations: required: true - type: textarea - label: Operating System and Environment - description: Provide relevant information about the operating system and environment - render: console - placeholder: RHEL 8, Debian 10, output from `/etc/os-release`, any other relevant information + attributes: + label: Operating System and Environment + description: Provide relevant information about the operating system and environment + render: console + placeholder: RHEL 8, Debian 10, output from `/etc/os-release`, any other relevant information validations: required: true - type: input - label: Container Runtime - description: Output from `podman|docker --version` - render: console - placeholder: podman --version + attributes: + label: Container Runtime + description: Output from `podman|docker --version` + placeholder: podman --version validations: required: true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_runner-2.4.2/.github/ISSUE_TEMPLATE/config.yml new/ansible_runner-2.4.3/.github/ISSUE_TEMPLATE/config.yml --- old/ansible_runner-2.4.2/.github/ISSUE_TEMPLATE/config.yml 2025-10-14 21:06:40.000000000 +0200 +++ new/ansible_runner-2.4.3/.github/ISSUE_TEMPLATE/config.yml 2026-03-16 19:39:50.000000000 +0100 @@ -1 +1 @@ -blank_issue_enabled: false +blank_issues_enabled: false diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_runner-2.4.2/.github/ISSUE_TEMPLATE/documentation_report.yml new/ansible_runner-2.4.3/.github/ISSUE_TEMPLATE/documentation_report.yml --- old/ansible_runner-2.4.2/.github/ISSUE_TEMPLATE/documentation_report.yml 2025-10-14 21:06:40.000000000 +0200 +++ new/ansible_runner-2.4.3/.github/ISSUE_TEMPLATE/documentation_report.yml 2026-03-16 19:39:50.000000000 +0100 @@ -10,13 +10,12 @@ value: | **Thank you reporting an issue with Ansible Runner documentation.** - If you are looking for community support, please visit - the [Community guide](https://ansible.readthedocs.io/projects/runner/en/latest/community/) + If you are looking for community support, please visit the [Community guide](https://ansible.readthedocs.io/projects/runner/en/latest/community/) for information on how to get in touch. - - type: + - type: textarea attributes: label: Summary description: Describe the problem or suggestion with the documentation - validations: - required: true + validations: + required: true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_runner-2.4.2/.github/ISSUE_TEMPLATE/feature_request.yml new/ansible_runner-2.4.3/.github/ISSUE_TEMPLATE/feature_request.yml --- old/ansible_runner-2.4.2/.github/ISSUE_TEMPLATE/feature_request.yml 2025-10-14 21:06:40.000000000 +0200 +++ new/ansible_runner-2.4.3/.github/ISSUE_TEMPLATE/feature_request.yml 2026-03-16 19:39:50.000000000 +0100 @@ -10,13 +10,12 @@ value: | **Thank you for suggesting a new feature for Ansible Runner.** - If you are looking for community support, please visit - the [Community guide](https://ansible.readthedocs.io/projects/runner/en/latest/community/) + If you are looking for community support, please visit the [Community guide](https://ansible.readthedocs.io/projects/runner/en/latest/community/) for information on how to get in touch. - - type: + - type: textarea attributes: label: Summary description: Describe the new feature and how it would be used. - validations: - required: true + validations: + required: true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_runner-2.4.2/MANIFEST.in new/ansible_runner-2.4.3/MANIFEST.in --- old/ansible_runner-2.4.2/MANIFEST.in 2025-10-14 21:06:40.000000000 +0200 +++ new/ansible_runner-2.4.3/MANIFEST.in 1970-01-01 01:00:00.000000000 +0100 @@ -1,3 +0,0 @@ - -include README.md -include LICENSE.md diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_runner-2.4.2/PKG-INFO new/ansible_runner-2.4.3/PKG-INFO --- old/ansible_runner-2.4.2/PKG-INFO 2025-10-14 21:07:18.170615400 +0200 +++ new/ansible_runner-2.4.3/PKG-INFO 2026-03-16 19:40:14.871721700 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: ansible-runner -Version: 2.4.2 +Version: 2.4.3 Summary: "Consistent Ansible Python API and CLI with container and process isolation runtime capabilities" Home-page: https://ansible-runner.readthedocs.io Author: Ansible, Inc. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_runner-2.4.2/docs/execution_environments.rst new/ansible_runner-2.4.3/docs/execution_environments.rst --- old/ansible_runner-2.4.2/docs/execution_environments.rst 2025-10-14 21:06:40.000000000 +0200 +++ new/ansible_runner-2.4.3/docs/execution_environments.rst 2026-03-16 19:39:50.000000000 +0100 @@ -82,13 +82,13 @@ ~/.ssh/ symlinks ^^^^^^^^^^^^^^^^ -In order to make the ``run`` container execution of Ansible -easier, Ansible Runner will automatically bind mount your local ssh agent -UNIX-domain socket (``SSH_AUTH_SOCK``) into the container runtime. However, this -does not work if files in your ``~/.ssh/`` directory happen to be symlinked to -another directory that is also not mounted into the container runtime. The Ansible -Runner ``run`` subcommand provides the ``--container-volume-mount`` -option to address this, among other things. +When using the ``run_command()`` Python API method, Ansible Runner will automatically +bind mount your local SSH agent UNIX-domain socket (``SSH_AUTH_SOCK``) into the container runtime. +However, this does not work if files in your ``~/.ssh/`` directory happen to be symlinked to +another directory that is also not mounted into the container runtime. +To address this, or to manually mount your SSH directory, you may utilize the ``--container-volume-mount`` +CLI option, or the ``container_volume_mounts`` API parameter for the ``run_command()``, ``run()``, or ``run_async()`` +API methods. Here is an example of an ssh config file that is a symlink: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_runner-2.4.2/src/ansible_runner/config/_base.py new/ansible_runner-2.4.3/src/ansible_runner/config/_base.py --- old/ansible_runner-2.4.2/src/ansible_runner/config/_base.py 2025-10-14 21:06:40.000000000 +0200 +++ new/ansible_runner-2.4.3/src/ansible_runner/config/_base.py 2026-03-16 19:39:50.000000000 +0100 @@ -487,6 +487,15 @@ self._update_volume_mount_paths(args_list, optional_arg_value) + def should_allocate_tty(self) -> bool: + """Whether the container should get a ``--tty`` flag. + + The base implementation returns ``False``. + Subclasses (e.g. :class:`~ansible_runner.config.command.CommandConfig`) + may override this to implement richer logic. + """ + return False + def wrap_args_for_containerization(self, args: list[str], execution_mode: BaseExecutionMode, @@ -495,7 +504,7 @@ new_args = [self.process_isolation_executable] new_args.extend(['run', '--rm']) - if self.runner_mode == 'pexpect' or getattr(self, 'input_fd', False): + if self.runner_mode == 'pexpect' or self.should_allocate_tty(): new_args.extend(['--tty']) new_args.append('--interactive') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_runner-2.4.2/src/ansible_runner/config/command.py new/ansible_runner-2.4.3/src/ansible_runner/config/command.py --- old/ansible_runner-2.4.2/src/ansible_runner/config/command.py 2025-10-14 21:06:40.000000000 +0200 +++ new/ansible_runner-2.4.3/src/ansible_runner/config/command.py 2026-03-16 19:39:50.000000000 +0100 @@ -69,6 +69,20 @@ 'ansible-galaxy', ) + def should_allocate_tty(self) -> bool: + """Allocate a TTY only when *both* input and output fds are real terminals. + + If either side is redirected (file, pipe, ``/dev/null``) the container + must not get ``--tty``, otherwise tools like ``less`` hang or ANSI + escapes pollute the redirected output. + + See: https://github.com/ansible/ansible-navigator/issues/1607 + """ + return ( + self.input_fd is not None and hasattr(self.input_fd, 'isatty') and self.input_fd.isatty() + and self.output_fd is not None and hasattr(self.output_fd, 'isatty') and self.output_fd.isatty() + ) + def _set_runner_mode(self): if self.input_fd is not None or self.executable_cmd.split(os.pathsep)[-1] in CommandConfig._ANSIBLE_NON_INERACTIVE_CMDS: self.runner_mode = 'subprocess' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_runner-2.4.2/src/ansible_runner/display_callback/callback/awx_display.py new/ansible_runner-2.4.3/src/ansible_runner/display_callback/callback/awx_display.py --- old/ansible_runner-2.4.2/src/ansible_runner/display_callback/callback/awx_display.py 2025-10-14 21:06:40.000000000 +0200 +++ new/ansible_runner-2.4.3/src/ansible_runner/display_callback/callback/awx_display.py 2026-03-16 19:39:50.000000000 +0100 @@ -72,7 +72,7 @@ else: default_stdout_callback = 'default' -DefaultCallbackModule: CallbackBase = callback_loader.get(default_stdout_callback).__class__ +DefaultCallbackModule: CallbackBase = callback_loader.get(default_stdout_callback, class_only=True) CENSORED = "the output has been hidden due to the fact that 'no_log: true' was specified for this result" @@ -387,6 +387,12 @@ # NOTE: Ansible doesn't generate a UUID for playbook_on_start so do it for them. self.playbook_uuid = str(uuid.uuid4()) + def set_options(self, *args, **kwargs): + base_config = C.config.get_configuration_definition(DefaultCallbackModule._load_name, plugin_type='callback') + my_config = C.config.get_configuration_definition(self._load_name, plugin_type='callback') + C.config.initialize_plugin_configuration_definitions('callback', self._load_name, base_config | my_config) + return super().set_options(*args, **kwargs) + @contextlib.contextmanager def capture_event_data(self, event, **event_data): event_data.setdefault('uuid', str(uuid.uuid4())) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_runner-2.4.2/src/ansible_runner.egg-info/PKG-INFO new/ansible_runner-2.4.3/src/ansible_runner.egg-info/PKG-INFO --- old/ansible_runner-2.4.2/src/ansible_runner.egg-info/PKG-INFO 2025-10-14 21:07:18.000000000 +0200 +++ new/ansible_runner-2.4.3/src/ansible_runner.egg-info/PKG-INFO 2026-03-16 19:40:14.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: ansible-runner -Version: 2.4.2 +Version: 2.4.3 Summary: "Consistent Ansible Python API and CLI with container and process isolation runtime capabilities" Home-page: https://ansible-runner.readthedocs.io Author: Ansible, Inc. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_runner-2.4.2/src/ansible_runner.egg-info/SOURCES.txt new/ansible_runner-2.4.3/src/ansible_runner.egg-info/SOURCES.txt --- old/ansible_runner-2.4.2/src/ansible_runner.egg-info/SOURCES.txt 2025-10-14 21:07:18.000000000 +0200 +++ new/ansible_runner-2.4.3/src/ansible_runner.egg-info/SOURCES.txt 2026-03-16 19:40:14.000000000 +0100 @@ -1,7 +1,6 @@ .cherry_picker.toml .coveragerc .dockerignore -.git_archival.txt .gitattributes .gitignore .pre-commit-config.yaml @@ -10,7 +9,6 @@ CODEOWNERS CONTRIBUTING.md LICENSE.md -MANIFEST.in README.md SECURITY.md pyproject.toml diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_runner-2.4.2/test/integration/containerized/test_container_management.py new/ansible_runner-2.4.3/test/integration/containerized/test_container_management.py --- old/ansible_runner-2.4.2/test/integration/containerized/test_container_management.py 2025-10-14 21:06:40.000000000 +0200 +++ new/ansible_runner-2.4.3/test/integration/containerized/test_container_management.py 2026-03-16 19:39:50.000000000 +0100 @@ -1,4 +1,5 @@ import os +import pty import time import json @@ -7,7 +8,7 @@ import pytest -from ansible_runner.interface import run +from ansible_runner.interface import run, run_command @pytest.mark.test_all_runtimes @@ -100,11 +101,17 @@ @pytest.mark.test_all_runtimes def test_invalid_registry_host(tmp_path, runtime): + """ + Test using registry authentication. + + We use an invalid registry, so we expect the run to fail. But we will verify that the authentication + data is written to the auth configuration file correctly. + """ pdd_path = tmp_path / 'private_data_dir' pdd_path.mkdir() private_data_dir = str(pdd_path) - image_name = 'quay.io/kdelee/does-not-exist' + image_name = 'quay.io/ansible-runner/does-not-exist' res = run( private_data_dir=private_data_dir, @@ -124,15 +131,14 @@ with res.stdout as f: result_stdout = f.read() + + assert 'unauthorized' in result_stdout.lower() + auth_file_path = os.path.join(res.config.registry_auth_path, 'config.json') registry_conf = os.path.join(res.config.registry_auth_path, 'registries.conf') - error_msg = 'access to the requested resource is not authorized' if runtime == 'podman': - assert image_name in result_stdout - error_msg = 'unauthorized' auth_file_path = res.config.registry_auth_path registry_conf = os.path.join(os.path.dirname(res.config.registry_auth_path), 'registries.conf') - assert error_msg in result_stdout with open(auth_file_path, 'r') as f: content = f.read() @@ -177,3 +183,72 @@ discovered_registry_files = set(glob(auth_registry_glob)) - registry_files_before for file_name in discovered_registry_files: assert this_ident not in file_name + + [email protected]_all_runtimes [email protected]( + ('stdin_is_tty', 'stdout_is_tty'), + ( + pytest.param(False, False, id='piped-stdin'), + pytest.param(True, False, id='stdout-redirected'), + pytest.param(None, None, id='no-fd-headless'), + ), +) +def test_containerized_tty_allocation( + tmp_path, runtime, container_image, stdin_is_tty, stdout_is_tty, +): + """Regression for ansible-navigator#1607: --tty must not appear when fds are not real TTYs. + + The positive case (both fds are TTYs -> --tty is added) is already + covered by the unit test + ``test_prepare_run_command_containerized_tty_allocation[interactive-tty-*]`` + which asserts ``'--tty' in rc.command``. Testing it at the integration + level would require a pager (``less``) inside the container image and + complex pty plumbing, so we only verify the "no --tty" cases here. + """ + fds_to_close = [] + kwargs = { + 'executable_cmd': 'ansible-config', + 'cmdline_args': ['init'], + 'private_data_dir': str(tmp_path), + 'process_isolation': True, + 'process_isolation_executable': runtime, + 'container_image': container_image, + } + + if stdin_is_tty is not None: + if stdin_is_tty: + master, slave = pty.openpty() + kwargs['input_fd'] = os.fdopen(slave, 'r') + fds_to_close.append(('fd', kwargs['input_fd'])) + fds_to_close.append(('raw', master)) + else: + input_path = tmp_path / 'stdin.txt' + input_path.write_text('') + kwargs['input_fd'] = input_path.open('r', encoding='utf-8') + fds_to_close.append(('fd', kwargs['input_fd'])) + + if stdout_is_tty is not None: + kwargs['output_fd'] = (tmp_path / 'stdout.txt').open('w', encoding='utf-8') + fds_to_close.append(('fd', kwargs['output_fd'])) + + if stdin_is_tty is not None or stdout_is_tty is not None: + kwargs['error_fd'] = (tmp_path / 'stderr.txt').open('w', encoding='utf-8') + fds_to_close.append(('fd', kwargs['error_fd'])) + + try: + response, _, rc = run_command(**kwargs) + finally: + for kind, fd in fds_to_close: + if kind == 'fd': + fd.close() + else: + os.close(fd) + + if stdin_is_tty is None: + content = response + else: + content = (tmp_path / 'stdout.txt').read_text(encoding='utf-8') + assert rc == 0 + assert '[defaults]' in content + assert '\x1b' not in content diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_runner-2.4.2/test/integration/test_display_callback.py new/ansible_runner-2.4.3/test/integration/test_display_callback.py --- old/ansible_runner-2.4.2/test/integration/test_display_callback.py 2025-10-14 21:06:40.000000000 +0200 +++ new/ansible_runner-2.4.3/test/integration/test_display_callback.py 2026-03-16 19:39:50.000000000 +0100 @@ -439,3 +439,79 @@ with executor.stdout as f: text = f.read() assert text.count('"F"') == 150 + + [email protected]('playbook', [ + {'test_callback_with_options.yml': ''' +- name: Test callback plugins that use get_option + connection: local + hosts: all + gather_facts: no + tasks: + - name: Simple debug task + debug: + msg: "Testing callback with options" +'''}, # noqa +]) [email protected]('callback_config', [ + { + 'callback_name': 'tree', + 'env_vars': { + 'ANSIBLE_CALLBACKS_ENABLED': 'tree', + 'ANSIBLE_STDOUT_CALLBACK': 'tree', + 'ANSIBLE_CALLBACK_TREE_DIR': None, # Will be set to tmp_path in test + }, + 'check_artifacts': True # Verify tree creates artifacts + }, +], ids=['tree-callback']) +def test_callback_plugins_with_get_option(tmp_path, playbook, callback_config): + """ + Test that callback plugins using get_option() work correctly with awx_display. + """ + private_data_dir = tmp_path / 'runner_test' + private_data_dir.mkdir() + + inventory = 'localhost ansible_connection=local ansible_python_interpreter="{{ ansible_playbook_python }}"' + + # Set up environment variables for the callback + envvars = { + "ANSIBLE_DEPRECATION_WARNINGS": "False", + "ANSIBLE_PYTHON_INTERPRETER": "auto_silent", + } + + # Add callback-specific environment variables + for key, value in callback_config['env_vars'].items(): + if value is None and key == 'ANSIBLE_CALLBACK_TREE_DIR': + # Set tree directory to a temp location + tree_dir = tmp_path / 'tree_output' + tree_dir.mkdir() + envvars[key] = str(tree_dir) + elif value is not None: + envvars[key] = value + + playbook = list(playbook.values())[0] + + r = init_runner( + private_data_dir=private_data_dir, + inventory=inventory, + envvars=envvars, + playbook=yaml.safe_load(playbook) + ) + + # Run the playbook + r.run() + + # Verify the run was successful + assert r.status == 'successful', f"Playbook run failed with status: {r.status}" + + # Verify events were captured (awx_display still works) + events = list(r.events) + assert len(events) > 0, "No events were captured" + assert 'playbook_on_start' in [e['event'] for e in events] + assert 'playbook_on_stats' in [e['event'] for e in events] + + if callback_config.get('check_artifacts'): + # For tree callback, verify it created output files + tree_dir = tmp_path / 'tree_output' + tree_files = list(tree_dir.glob('localhost')) + assert len(tree_files) > 0, "Tree callback did not create expected output files" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ansible_runner-2.4.2/test/unit/config/test_command.py new/ansible_runner-2.4.3/test/unit/config/test_command.py --- old/ansible_runner-2.4.2/test/unit/config/test_command.py 2025-10-14 21:06:40.000000000 +0200 +++ new/ansible_runner-2.4.3/test/unit/config/test_command.py 2026-03-16 19:39:50.000000000 +0100 @@ -124,3 +124,45 @@ expected_command_start.extend(cmdline_args) assert expected_command_start == rc.command + + [email protected]('runtime', ('docker', 'podman')) [email protected]( + ('stdin_is_tty', 'stdout_is_tty', 'expect_tty'), + ( + pytest.param(False, False, False, id='piped-stdin'), + pytest.param(True, True, True, id='interactive-tty'), + pytest.param(True, False, False, id='stdout-redirected'), + pytest.param(None, None, False, id='no-fd-headless'), + ), +) +def test_prepare_run_command_containerized_tty_allocation( + tmp_path, runtime, mocker, stdin_is_tty, stdout_is_tty, expect_tty, +): + """Regression for ansible-navigator#1607: --tty must only appear when both fds are real TTYs.""" + mocker.patch.dict('os.environ', {'HOME': str(tmp_path)}, clear=True) + tmp_path.joinpath('.ssh').mkdir() + + kwargs = { + 'private_data_dir': tmp_path, + 'process_isolation': True, + 'container_image': 'my_container', + 'process_isolation_executable': runtime, + } + + if stdin_is_tty is not None: + mock_stdin = mocker.Mock() + mock_stdin.isatty.return_value = stdin_is_tty + kwargs['input_fd'] = mock_stdin + if stdout_is_tty is not None: + mock_stdout = mocker.Mock() + mock_stdout.isatty.return_value = stdout_is_tty + kwargs['output_fd'] = mock_stdout + + rc = CommandConfig(**kwargs) + rc.ident = 'foo' + rc.prepare_run_command('ansible-config', cmdline_args=['init']) + + assert rc.runner_mode == 'subprocess' + assert ('--tty' in rc.command) == expect_tty + assert '--interactive' in rc.command
