diff --git a/changelog/64659.fixed.md b/changelog/64659.fixed.md new file mode 100644 index 000000000000..f3577aeb6d9b --- /dev/null +++ b/changelog/64659.fixed.md @@ -0,0 +1 @@ +Fix ``certutil.add_store`` and ``certutil.del_store`` states ignoring ``saltenv`` when resolving the certificate serial, causing "Invalid certificate file" errors when the certificate lives in a non-``base`` saltenv. diff --git a/salt/states/win_certutil.py b/salt/states/win_certutil.py index fa3c78e4af31..5445ea57758e 100644 --- a/salt/states/win_certutil.py +++ b/salt/states/win_certutil.py @@ -65,7 +65,7 @@ def add_store(name, store, saltenv="base"): ret["result"] = False return ret - cert_serial = __salt__["certutil.get_cert_serial"](name) + cert_serial = __salt__["certutil.get_cert_serial"](name, saltenv=saltenv) if cert_serial is None: ret["comment"] = f"Invalid certificate file: {name}" ret["result"] = False @@ -81,7 +81,7 @@ def add_store(name, store, saltenv="base"): ret["result"] = None return ret - retcode = __salt__["certutil.add_store"](name, store, retcode=True) + retcode = __salt__["certutil.add_store"](name, store, saltenv=saltenv, retcode=True) if retcode != 0: ret["comment"] = f"Error adding certificate: {name}" ret["result"] = False @@ -135,7 +135,7 @@ def del_store(name, store, saltenv="base"): ret["result"] = False return ret - cert_serial = __salt__["certutil.get_cert_serial"](name) + cert_serial = __salt__["certutil.get_cert_serial"](name, saltenv=saltenv) if cert_serial is None: ret["comment"] = f"Invalid certificate file: {name}" ret["result"] = False @@ -151,7 +151,7 @@ def del_store(name, store, saltenv="base"): ret["result"] = None return ret - retcode = __salt__["certutil.del_store"](name, store, retcode=True) + retcode = __salt__["certutil.del_store"](name, store, saltenv=saltenv, retcode=True) if retcode != 0: ret["comment"] = f"Error removing certificate: {name}" ret["result"] = False diff --git a/tests/pytests/unit/states/test_win_certutil.py b/tests/pytests/unit/states/test_win_certutil.py index 5e8a0a987dff..953687e501a7 100644 --- a/tests/pytests/unit/states/test_win_certutil.py +++ b/tests/pytests/unit/states/test_win_certutil.py @@ -119,3 +119,57 @@ def test_del_store_fail_check(): ): out = certutil.del_store("/path/to/cert.cer", "TrustedPublisher") assert expected == out + + +def test_add_store_saltenv_passed_to_get_cert_serial(): + """ + Test that saltenv is forwarded to certutil.get_cert_serial in add_store + so that certificates in non-base saltenvs can be found. + """ + cache_mock = MagicMock(return_value="/tmp/cert.cer") + get_cert_serial_mock = MagicMock(return_value="ABCDEF") + get_store_serials_mock = MagicMock(return_value=["123456"]) + add_mock = MagicMock(return_value=0) + with patch.dict( + certutil.__salt__, + { + "cp.cache_file": cache_mock, + "certutil.get_cert_serial": get_cert_serial_mock, + "certutil.get_stored_cert_serials": get_store_serials_mock, + "certutil.add_store": add_mock, + }, + ): + certutil.add_store("/path/to/cert.cer", "TrustedPublisher", saltenv="test") + get_cert_serial_mock.assert_called_once_with( + "/path/to/cert.cer", saltenv="test" + ) + add_mock.assert_called_once_with( + "/path/to/cert.cer", "TrustedPublisher", saltenv="test", retcode=True + ) + + +def test_del_store_saltenv_passed_to_get_cert_serial(): + """ + Test that saltenv is forwarded to certutil.get_cert_serial in del_store + so that certificates in non-base saltenvs can be found. + """ + cache_mock = MagicMock(return_value="/tmp/cert.cer") + get_cert_serial_mock = MagicMock(return_value="ABCDEF") + get_store_serials_mock = MagicMock(return_value=["123456", "ABCDEF"]) + del_mock = MagicMock(return_value=0) + with patch.dict( + certutil.__salt__, + { + "cp.cache_file": cache_mock, + "certutil.get_cert_serial": get_cert_serial_mock, + "certutil.get_stored_cert_serials": get_store_serials_mock, + "certutil.del_store": del_mock, + }, + ): + certutil.del_store("/path/to/cert.cer", "TrustedPublisher", saltenv="test") + get_cert_serial_mock.assert_called_once_with( + "/path/to/cert.cer", saltenv="test" + ) + del_mock.assert_called_once_with( + "/path/to/cert.cer", "TrustedPublisher", saltenv="test", retcode=True + )