Repository: freedomofpress/securedrop

Issue:
Make `gpg` calls use `--trust-model` instead of `--no-auto-check-trustdb`
## Description

In #6390 we introduced the use of the `--no-auto-check-trustdb` option for `gpg` to keep it from wasting CPU cycles on checking whether keys are trusted or not. While this does the job, a side effect of this is that calling `gpg` will still check whether the trustdb is stale and inform the user by writing to stderr.

The way SecureDrop utilises `gpg` on the server though means all keys are always trusted. `gpg` has native support for alternative trust models with its `--trust-model` option, which supports [`always`](https://www.gnupg.org/documentation/manuals/gnupg/GPG-Configuration-Options.html#index-trust_002dmodel_003aalways) and [`direct`](https://www.gnupg.org/documentation/manuals/gnupg/GPG-Configuration-Options.html#index-trust_002dmodel_003adirect). Using either of would skip all WoT associated checks. My reading is that both options would be interchangeable in our case since all keys except the journalist key are generated locally, and so will therefore have ultimate trust.

This would also allow us to remove the associated monkey patch, because pretty-bad-protocol / python-gnupg supports the `--trust-model` options natively.



Discussion:

Resolving patch:
diff --git a/securedrop/encryption.py b/securedrop/encryption.py
--- a/securedrop/encryption.py
+++ b/securedrop/encryption.py
@@ -2,7 +2,7 @@
 from distutils.version import StrictVersion
 from io import StringIO, BytesIO
 from pathlib import Path
-from typing import Optional, Dict, List, FrozenSet
+from typing import Optional, Dict, List
 
 import pretty_bad_protocol as gnupg
 import os
@@ -43,26 +43,10 @@ def _updated_handle_status(self: gnupg._parsers.DeleteResult, key: str, value: s
     gnupg._parsers.DeleteResult._handle_status = _updated_handle_status
 
 
-def _monkey_patch_options_allow_list() -> None:
-    # To fix: https://github.com/freedomofpress/securedrop/issues/6389
-    unpatched_get_options_group = gnupg._parsers._get_options_group
-
-    def _allow_no_auto_check_trustdb(group: Optional[str] = None) -> Optional[FrozenSet[str]]:
-        if group in ["none_options", "allowed"]:
-            options = list(unpatched_get_options_group(group))
-            options.append("--no-auto-check-trustdb")
-            return frozenset(options)
-        else:
-            return unpatched_get_options_group(group)
-
-    gnupg._parsers._get_options_group = _allow_no_auto_check_trustdb
-
-
 def _setup_monkey_patches_for_gnupg() -> None:
     _monkey_patch_username_in_env()
     _monkey_patch_unknown_status_message()
     _monkey_patch_delete_handle_status()
-    _monkey_patch_options_allow_list()
 
 
 _setup_monkey_patches_for_gnupg()
@@ -112,14 +96,14 @@ def __init__(self, gpg_key_dir: Path, journalist_key_fingerprint: str) -> None:
         gpg = gnupg.GPG(
             binary="gpg2",
             homedir=str(self._gpg_key_dir),
-            options=["--no-auto-check-trustdb"]
+            options=["--trust-model direct"]
         )
         if StrictVersion(gpg.binary_version) >= StrictVersion("2.1"):
             # --pinentry-mode, required for SecureDrop on GPG 2.1.x+, was added in GPG 2.1.
             self._gpg = gnupg.GPG(
                 binary="gpg2",
                 homedir=str(gpg_key_dir),
-                options=["--pinentry-mode loopback", "--no-auto-check-trustdb"]
+                options=["--pinentry-mode loopback", "--trust-model direct"]
             )
         else:
             self._gpg = gpg
@@ -130,7 +114,7 @@ def __init__(self, gpg_key_dir: Path, journalist_key_fingerprint: str) -> None:
         self._gpg_for_key_deletion = gnupg.GPG(
             binary="gpg2",
             homedir=str(self._gpg_key_dir),
-            options=["--yes", "--no-auto-check-trustdb"]
+            options=["--yes", "--trust-model direct"]
         )
 
         # Ensure that the journalist public key has been previously imported in GPG


Test patch: