From 890d777392725c8fb83fd82ee07ce3bb862e738d Mon Sep 17 00:00:00 2001 From: jeanluc Date: Mon, 5 Dec 2022 13:24:30 +0100 Subject: [PATCH] Add gnupghome/keyring params to trust_key --- salt/modules/gpg.py | 38 +++++++++++++---- salt/states/gpg.py | 6 ++- tests/pytests/functional/modules/test_gpg.py | 41 +++++++++++++++++++ tests/pytests/functional/states/test_gpg.py | 43 +++++++++++++++++++- 4 files changed, 118 insertions(+), 10 deletions(-) diff --git a/salt/modules/gpg.py b/salt/modules/gpg.py index c2a8d13c9a8..9df012496e4 100644 --- a/salt/modules/gpg.py +++ b/salt/modules/gpg.py @@ -1047,7 +1047,14 @@ def receive_keys(keyserver=None, keys=None, user=None, gnupghome=None, keyring=N return ret -def trust_key(keyid=None, fingerprint=None, trust_level=None, user=None): +def trust_key( + keyid=None, + fingerprint=None, + trust_level=None, + user=None, + gnupghome=None, + keyring=None, +): """ Set the trust level for a key in GPG keychain @@ -1067,6 +1074,17 @@ def trust_key(keyid=None, fingerprint=None, trust_level=None, user=None): Passing the user as ``salt`` will set the GnuPG home directory to the ``/etc/salt/gpgkeys``. + gnupghome + Specify the location where GPG keyring and related files are stored. + + .. versionadded:: 3006 + + keyring + Limit the operation to this specific keyring, specified as + a local filesystem path. + + .. versionadded:: 3006 + CLI Example: .. code-block:: bash @@ -1094,7 +1112,7 @@ def trust_key(keyid=None, fingerprint=None, trust_level=None, user=None): if not fingerprint: if keyid: - key = get_key(keyid, user=user) + key = get_key(keyid, user=user, gnupghome=gnupghome, keyring=keyring) if key: if "fingerprint" not in key: ret["res"] = False @@ -1114,13 +1132,17 @@ def trust_key(keyid=None, fingerprint=None, trust_level=None, user=None): return "ERROR: Valid trust levels - {}".format(",".join(_VALID_TRUST_LEVELS)) stdin = f"{fingerprint}:{NUM_TRUST_DICT[trust_level]}\n" - cmd = [_gpg(), "--import-ownertrust"] - _user = user + gnupghome = gnupghome or _get_user_gnupghome(user) + cmd = [_gpg(), "--homedir", gnupghome, "--import-ownertrust"] + _user = user if user != "salt" else None + + if keyring: + if not isinstance(keyring, str): + raise SaltInvocationError( + "Please pass keyring as a string. Multiple keyrings are not allowed" + ) + cmd.extend(["--no-default-keyring", "--keyring", keyring]) - if user == "salt": - homeDir = os.path.join(__salt__["config.get"]("config_dir"), "gpgkeys") - cmd.extend(["--homedir", homeDir]) - _user = "root" res = __salt__["cmd.run_all"](cmd, stdin=stdin, runas=_user, python_shell=False) if not res["retcode"] == 0: diff --git a/salt/states/gpg.py b/salt/states/gpg.py index 4178269b668..e6fe7a1a691 100644 --- a/salt/states/gpg.py +++ b/salt/states/gpg.py @@ -109,6 +109,8 @@ def present( keyid=key, trust_level=trust, user=user, + gnupghome=gnupghome, + keyring=keyring, ) if result["res"] is False: ret["result"] = result["res"] @@ -159,6 +161,8 @@ def present( keyid=key, trust_level=trust, user=user, + gnupghome=gnupghome, + keyring=keyring, ) if result["res"] is False: ret["result"] = result["res"] @@ -276,7 +280,7 @@ def absent( and __salt__["file.file_exists"](keyring) ): __salt__["file.remove"](keyring) - ret["comment"].append(f"Removed keyring file {keyring}") + ret["comment"].append(f"Removed empty keyring file {keyring}") ret["changes"]["removed"] = keyring ret["comment"] = "\n".join(ret["comment"]) diff --git a/tests/pytests/functional/modules/test_gpg.py b/tests/pytests/functional/modules/test_gpg.py index 4dd7cbd79d7..a6f88ed4c68 100644 --- a/tests/pytests/functional/modules/test_gpg.py +++ b/tests/pytests/functional/modules/test_gpg.py @@ -608,6 +608,47 @@ def test_export_key_from_keyring(gpghome, gnupg, gpg, key_a_fp, keyring, gnupg_k assert res["comment"].endswith("-----END PGP PUBLIC KEY BLOCK-----\n") +@pytest.mark.usefixtures("pubkeys_present") +@pytest.mark.parametrize("use_keyid", [True, False]) +def test_trust_key(gpghome, key_a_fp, gnupg, gpg, use_keyid): + keyid = key_a_fp[-16:] if use_keyid else None + fingerprint = None if keyid else key_a_fp + res = gpg.trust_key( + fingerprint=fingerprint, + keyid=keyid, + trust_level="ultimately", + gnupghome=str(gpghome), + ) + assert res["res"] + assert "fingerprint" in res + assert res["fingerprint"] == key_a_fp + key_info = gnupg.list_keys(keys=key_a_fp) + assert key_info + assert key_info[0]["trust"] == "u" + + +@pytest.mark.parametrize("use_keyid", [True, False]) +def test_trust_key_keyring( + gpghome, key_a_fp, keyring, gnupg, gnupg_keyring, gpg, use_keyid +): + assert not gnupg.list_keys(keys=key_a_fp) + keyid = key_a_fp[-16:] if use_keyid else None + fingerprint = None if keyid else key_a_fp + res = gpg.trust_key( + fingerprint=fingerprint, + keyid=keyid, + trust_level="ultimately", + gnupghome=str(gpghome), + keyring=keyring, + ) + assert res["res"] + assert "fingerprint" in res + assert res["fingerprint"] == key_a_fp + key_info = gnupg_keyring.list_keys(keys=key_a_fp) + assert key_info + assert key_info[0]["trust"] == "u" + + @pytest.mark.usefixtures("privkeys_present") @pytest.mark.skip_unless_on_linux(reason="Test setup with private keys fails") @pytest.mark.requires_random_entropy() diff --git a/tests/pytests/functional/states/test_gpg.py b/tests/pytests/functional/states/test_gpg.py index 299b91ffa14..486c6642cc7 100644 --- a/tests/pytests/functional/states/test_gpg.py +++ b/tests/pytests/functional/states/test_gpg.py @@ -134,12 +134,53 @@ def test_gpg_present_keyring_no_changes( assert not gnupg.list_keys(keys=key_a_fp) assert gnupg_keyring.list_keys(keys=key_a_fp) ret = gpg.present( - key_a_fp[-16:], gnupghome=str(gpghome), keyserver="nonexistent", keyring=keyring + key_a_fp[-16:], + trust="unknown", + gnupghome=str(gpghome), + keyserver="nonexistent", + keyring=keyring, ) assert ret.result assert not ret.changes +@pytest.mark.usefixtures("_pubkeys_present") +def test_gpg_present_trust_change(gpghome, gpg, gnupg, key_a_fp): + assert gnupg.list_keys(keys=key_a_fp) + ret = gpg.present( + key_a_fp[-16:], + gnupghome=str(gpghome), + trust="ultimately", + keyserver="nonexistent", + ) + assert ret.result + assert ret.changes + assert ret.changes == {key_a_fp[-16:]: {"trust": "ultimately"}} + key_info = gnupg.list_keys(keys=key_a_fp) + assert key_info + assert key_info[0]["trust"] == "u" + + +def test_gpg_present_keyring_trust_change( + gpghome, gpg, gnupg, gnupg_keyring, keyring, key_a_fp +): + assert not gnupg.list_keys(keys=key_a_fp) + assert gnupg_keyring.list_keys(keys=key_a_fp) + ret = gpg.present( + key_a_fp[-16:], + gnupghome=str(gpghome), + trust="ultimately", + keyserver="nonexistent", + keyring=keyring, + ) + assert ret.result + assert ret.changes + assert ret.changes == {key_a_fp[-16:]: {"trust": "ultimately"}} + key_info = gnupg_keyring.list_keys(keys=key_a_fp) + assert key_info + assert key_info[0]["trust"] == "u" + + @pytest.mark.usefixtures("_pubkeys_present") def test_gpg_absent(gpghome, gpg, gnupg, key_a_fp): assert gnupg.list_keys(keys=key_a_fp)