Try to respect custom GNUPGHOME env var

This commit is contained in:
jeanluc 2024-04-04 11:50:55 +02:00 committed by Daniel Wozniak
parent 596924e510
commit 4294a82322
3 changed files with 81 additions and 7 deletions

View file

@ -0,0 +1 @@
Made gpg modules respect user's GNUPGHOME if set in shell environment

View file

@ -11,6 +11,13 @@ Sign, encrypt, sign plus encrypt and verify text and files.
Be aware that the alternate ``gnupg`` and ``pretty-bad-protocol`` Be aware that the alternate ``gnupg`` and ``pretty-bad-protocol``
libraries are not supported. libraries are not supported.
.. versionchanged:: 3008.0
When ``gnupghome`` is not set explicitly, this module now tries to
respect a custom ``GNUPGHOME`` environmental variable.
If a ``user`` is not passed, the current process' environment is queried,
otherwise the user's configured shell environment is taken as a reference
in the same way the ``cmd`` modules operate.
""" """
import functools import functools
@ -23,6 +30,7 @@ import salt.utils.data
import salt.utils.files import salt.utils.files
import salt.utils.immutabletypes as immutabletypes import salt.utils.immutabletypes as immutabletypes
import salt.utils.path import salt.utils.path
import salt.utils.platform
import salt.utils.stringutils import salt.utils.stringutils
import salt.utils.versions import salt.utils.versions
from salt.exceptions import SaltInvocationError from salt.exceptions import SaltInvocationError
@ -153,11 +161,25 @@ def _get_user_gnupghome(user):
Return default GnuPG home directory path for a user Return default GnuPG home directory path for a user
""" """
if user == "salt": if user == "salt":
gnupghome = os.path.join(__salt__["config.get"]("config_dir"), "gpgkeys") return os.path.join(__salt__["config.get"]("config_dir"), "gpgkeys")
else:
gnupghome = os.path.join(_get_user_info(user)["home"], ".gnupg")
return gnupghome # Try to respect GNUPGHOME environment variable.
if user is None:
gnupghome_env = __salt__["environ.get"]("GNUPGHOME")
else:
cmd = 'echo -n "$GNUPGHOME"'
if salt.utils.platform.is_windows():
cmd = "echo %GNUPGHOME%"
gnupghome_env = __salt__["cmd.run_stdout"](
cmd, python_shell=True, runas=user
).strip()
if gnupghome_env.startswith("~"):
# This does not resolve `~` since that potentially complicates things a lot.
# It should have been resolved by the shell anyways.
log.warning("Found GNUPGHOME beginning with tilde, ignoring")
gnupghome_env = ""
return gnupghome_env or os.path.join(_get_user_info(user)["home"], ".gnupg")
def _restore_ownership(func): def _restore_ownership(func):

View file

@ -10,6 +10,7 @@ import shutil
import subprocess import subprocess
import time import time
import types import types
from pathlib import Path
import psutil import psutil
import pytest import pytest
@ -204,7 +205,14 @@ def gpghome(tmp_path):
@pytest.fixture @pytest.fixture
def configure_loader_modules(gpghome): def configure_loader_modules(gpghome):
return {gpg: {}} return {
gpg: {
"__salt__": {
"environ.get": lambda *x: "",
"cmd.run_stdout": lambda *x, **y: "",
}
}
}
def test_list_keys(): def test_list_keys():
@ -1101,7 +1109,9 @@ def _import_result_mock(request):
indirect=True, indirect=True,
) )
def test_gpg_receive_keys_no_user_id(_import_result_mock): def test_gpg_receive_keys_no_user_id(_import_result_mock):
with patch("salt.modules.gpg._create_gpg") as create: with patch("salt.modules.gpg._create_gpg") as create, patch(
"salt.modules.gpg._create_gnupghome"
):
with patch.dict( with patch.dict(
gpg.__salt__, {"user.info": MagicMock(), "config.option": Mock()} gpg.__salt__, {"user.info": MagicMock(), "config.option": Mock()}
): ):
@ -1123,7 +1133,9 @@ def test_gpg_receive_keys_no_user_id(_import_result_mock):
indirect=True, indirect=True,
) )
def test_gpg_receive_keys_keyserver_unavailable(_import_result_mock): def test_gpg_receive_keys_keyserver_unavailable(_import_result_mock):
with patch("salt.modules.gpg._create_gpg") as create: with patch("salt.modules.gpg._create_gpg") as create, patch(
"salt.modules.gpg._create_gnupghome"
):
with patch.dict( with patch.dict(
gpg.__salt__, {"user.info": MagicMock(), "config.option": Mock()} gpg.__salt__, {"user.info": MagicMock(), "config.option": Mock()}
): ):
@ -1131,3 +1143,42 @@ def test_gpg_receive_keys_keyserver_unavailable(_import_result_mock):
res = gpg.receive_keys(keys="abc", user="abc") res = gpg.receive_keys(keys="abc", user="abc")
assert res["res"] is False assert res["res"] is False
assert any("No keyserver available" in x for x in res["message"]) assert any("No keyserver available" in x for x in res["message"])
@pytest.mark.parametrize(
"user,envvar",
(
("testuser", ""),
("testuser", "/home/testuser/local/share/gnupg"),
(None, ""),
(None, "/home/testuser/local/share/gnupg"),
("salt", ""),
("salt", "/this/should/not/matter"),
),
)
def test_get_user_gnupghome_respects_shell_env_setup(user, envvar):
config_dir = "/etc/salt" # minion_opts["config_dir"] is not set, only conf_dir (?)
user = user or "testuser"
if user == "salt":
homedir = "/opt/saltstack/salt"
expected = str(Path(config_dir) / "gpgkeys")
else:
homedir = f"/home/{user}"
expected = envvar or str(Path(homedir) / ".gnupg")
userinfo = {
"home": homedir,
"uid": 1000,
"gid": 1000,
"shell": "/bin/bash",
}
with patch.dict(
gpg.__salt__,
{
"user.info": lambda *x: userinfo,
"environ.get": lambda *x: envvar,
"cmd.run_stdout": lambda *x, **y: envvar,
"config.get": lambda *x: config_dir,
},
):
res = gpg._get_user_gnupghome(user)
assert res == expected