diff --git a/changelog/61816.fixed b/changelog/61816.fixed new file mode 100644 index 00000000000..f45856f2b5e --- /dev/null +++ b/changelog/61816.fixed @@ -0,0 +1 @@ +Made cmdmod._run[_all]_quiet work during minion startup on MacOS with runas specified (which fixed mac_service) diff --git a/salt/modules/cmdmod.py b/salt/modules/cmdmod.py index a53b5ed174b..a55afc7d04a 100644 --- a/salt/modules/cmdmod.py +++ b/salt/modules/cmdmod.py @@ -443,12 +443,13 @@ def _run( # Ensure environment is correct for a newly logged-in user by running # the command under bash as a login shell try: - user_shell = __salt__["user.info"](runas)["shell"] + # Do not rely on populated __salt__ dict (ie avoid __salt__['user.info']) + user_shell = [x for x in pwd.getpwall() if x.pw_name == runas][0].pw_shell if re.search("bash$", user_shell): cmd = "{shell} -l -c {cmd}".format( shell=user_shell, cmd=_cmd_quote(cmd) ) - except KeyError: + except (AttributeError, IndexError): pass # Ensure the login is simulated correctly (note: su runs sh, not bash, diff --git a/tests/pytests/unit/modules/test_cmdmod.py b/tests/pytests/unit/modules/test_cmdmod.py index fa7e032bb23..8ba48803665 100644 --- a/tests/pytests/unit/modules/test_cmdmod.py +++ b/tests/pytests/unit/modules/test_cmdmod.py @@ -455,11 +455,12 @@ def test_shell_properly_handled_on_macOS(): # User default shell is '/usr/local/bin/bash' user_default_shell = "/usr/local/bin/bash" - with patch.dict( - cmdmod.__salt__, - {"user.info": MagicMock(return_value={"shell": user_default_shell})}, + with patch( + "pwd.getpwall", + Mock( + return_value=[Mock(pw_shell=user_default_shell, pw_name="foobar")] + ), ): - cmd_handler.clear() cmdmod._run( "ls", cwd=tempfile.gettempdir(), runas="foobar", use_vt=False @@ -471,9 +472,11 @@ def test_shell_properly_handled_on_macOS(): # User default shell is '/bin/zsh' user_default_shell = "/bin/zsh" - with patch.dict( - cmdmod.__salt__, - {"user.info": MagicMock(return_value={"shell": user_default_shell})}, + with patch( + "pwd.getpwall", + Mock( + return_value=[Mock(pw_shell=user_default_shell, pw_name="foobar")] + ), ): cmd_handler.clear() @@ -486,6 +489,28 @@ def test_shell_properly_handled_on_macOS(): ), "cmd does not invoke user shell on macOS" +def test_run_all_quiet_does_not_depend_on_salt_dunder(): + """ + cmdmod._run_all_quiet should not depend on availability + of __salt__ dictionary (issue #61816) + """ + + proc = MagicMock(return_value=MockTimedProc(stdout=b"success", stderr=None)) + with patch("salt.utils.timed_subprocess.TimedProc", proc): + salt_dunder_mock = MagicMock(spec_set=dict) + salt_dunder_mock.__getitem__.side_effect = NameError( + "__salt__ might not be defined" + ) + + with patch.object(cmdmod, "__salt__", salt_dunder_mock): + ret = cmdmod._run_all_quiet("foo") + assert ret["stdout"] == "success" + assert salt_dunder_mock.__getitem__.call_count == 0 + ret = cmdmod._run_all_quiet("foo", runas="bar") + assert ret["stdout"] == "success" + assert salt_dunder_mock.__getitem__.call_count == 0 + + def test_run_cwd_doesnt_exist_issue_7154(): """ cmd.run should fail and raise