Run vault CLI config management tests against the stub agent where possible
Marco Ricci

Marco Ricci commited on 2026-06-21 21:02:26
Zeige 1 geänderte Dateien mit 67 Einfügungen und 66 Löschungen.


Several tests for the `vault` CLI check for failures when storing or
retrieving a selected SSH key to/from the `vault` settings file.  These
tests used to run against every known SSH agent, separately, but not
truly interact with the agent at all, because all high-level interaction
was stubbed out to return error responses anyway.  For externally
spawned or interfaced SSH agents, this is wasteful.  So we now restrict
these tests to run against the stubbed agent, which is specifically
designed for these purposes.

Half of these tests previously falsely claimed that they don't actually
need an external agent; now, they no longer lie.  The other half never
made any claims; now, they do.

There may be other tests that request external SSH agents but don't
actually require them, but this is somewhat hard to discover
exhaustively.  These tests were an obvious first group of tests that
could be fixed in one go.  Other groups (if any) will be left to future
commits.
... ...
@@ -19,7 +19,6 @@ import copy
19 19
 import errno
20 20
 import json
21 21
 import os
22
-import pathlib
23 22
 import shutil
24 23
 import types
25 24
 from typing import TYPE_CHECKING
... ...
@@ -32,7 +31,6 @@ from derivepassphrase import _types, cli, ssh_agent
32 31
 from derivepassphrase._internals import (
33 32
     cli_helpers,
34 33
 )
35
-from derivepassphrase.ssh_agent import socketprovider
36 34
 from tests import data, machinery
37 35
 from tests.data import callables
38 36
 from tests.machinery import hypothesis as hypothesis_machinery
... ...
@@ -49,6 +47,34 @@ DUMMY_SERVICE = data.DUMMY_SERVICE
49 47
 DUMMY_KEY1_B64 = data.DUMMY_KEY1_B64
50 48
 
51 49
 
50
+@pytest.fixture
51
+def use_stub_agent() -> Generator[None, None, None]:
52
+    """Enforce use of the stubbed SSH agent."""
53
+    with pytest.MonkeyPatch.context() as monkeypatch:
54
+        monkeypatch.setattr(
55
+            ssh_agent.SSHAgentClient,
56
+            "SOCKET_PROVIDERS",
57
+            (_types.BuiltinSSHAgentSocketProvider.STUB_AGENT,),
58
+        )
59
+        monkeypatch.delenv("SSH_AUTH_SOCK", raising=False)
60
+        yield
61
+
62
+
63
+@pytest.fixture
64
+def use_stub_agent_with_address() -> Generator[None, None, None]:
65
+    """Enforce use of the stubbed SSH agent with socket address."""
66
+    with pytest.MonkeyPatch.context() as monkeypatch:
67
+        monkeypatch.setattr(
68
+            ssh_agent.SSHAgentClient,
69
+            "SOCKET_PROVIDERS",
70
+            (_types.BuiltinSSHAgentSocketProvider.STUB_AGENT_WITH_ADDRESS,),
71
+        )
72
+        monkeypatch.setenv(
73
+            "SSH_AUTH_SOCK", machinery.StubbedSSHAgentSocketWithAddress.ADDRESS
74
+        )
75
+        yield
76
+
77
+
52 78
 def is_harmless_config_import_warning(record: tuple[str, int, str]) -> bool:
53 79
     """Return true if the warning is harmless, during config import."""
54 80
     possible_warnings = [
... ...
@@ -786,65 +812,40 @@ class TestStoringConfigurationFailures:
786 812
             )
787 813
 
788 814
     def test_fail_because_no_ssh_agent(
789
-        self, spawn_ssh_agent: data.SpawnedSSHAgentInfo
815
+        self,
816
+        use_stub_agent_with_address: None,
790 817
     ) -> None:
791 818
         """Not running an SSH agent during `--config --key` fails.
792 819
 
793
-        (This test does not actually need a running agent; the agent's
794
-        response is mocked by the test harness.)
820
+        (This test runs against the stub agent; it does not actually
821
+        need an agent installed on the user's system.)
795 822
 
796 823
         """
797
-        del spawn_ssh_agent
824
+        del use_stub_agent_with_address
798 825
         with self._test(
799 826
             ["--key"],
800 827
             error_text="Cannot find any running SSH agent",
801 828
             patch_suitable_ssh_keys=False,
802 829
         ) as monkeypatch:
803
-
804
-            def no_agent(
805
-                *_args: Any, **_kwargs: Any
806
-            ) -> NoReturn:  # pragma: no cover [failsafe]
807
-                raise KeyError("SSH_AUTH_SOCK")  # noqa: EM101
808
-
809
-            monkeypatch.setattr(
810
-                socketprovider.WindowsNamedPipeHandle, "for_pageant", no_agent
811
-            )
812
-            monkeypatch.setattr(
813
-                socketprovider.WindowsNamedPipeHandle, "for_openssh", no_agent
814
-            )
815 830
             monkeypatch.delenv("SSH_AUTH_SOCK", raising=False)
816 831
 
817 832
     def test_fail_because_bad_ssh_agent_connection(
818
-        self, spawn_ssh_agent: data.SpawnedSSHAgentInfo
833
+        self,
834
+        use_stub_agent_with_address: None,
819 835
     ) -> None:
820
-        """Not running a reachable SSH agent during `--config --key` fails."""
821
-        del spawn_ssh_agent
836
+        """Not running a reachable SSH agent during `--config --key` fails.
837
+
838
+        (This test runs against the stub agent; it does not actually
839
+        need an agent installed on the user's system.)
840
+
841
+        """
842
+        del use_stub_agent_with_address
822 843
         with self._test(
823 844
             ["--key"],
824 845
             error_text="Cannot connect to the SSH agent",
825 846
             patch_suitable_ssh_keys=False,
826 847
         ) as monkeypatch:
827
-            cwd = pathlib.Path.cwd().resolve()
828
-            monkeypatch.setenv(
829
-                "SSH_AUTH_SOCK",
830
-                socketprovider.PIPE_PREFIX if os.name == "nt" else str(cwd),
831
-            )
832
-
833
-            def mangled_address(
834
-                *_args: Any, **_kwargs: Any
835
-            ) -> NoReturn:  # pragma: no cover [failsafe]
836
-                raise OSError(errno.ENOENT, os.strerror(errno.ENOENT))
837
-
838
-            monkeypatch.setattr(
839
-                socketprovider.WindowsNamedPipeHandle,
840
-                "for_pageant",
841
-                mangled_address,
842
-            )
843
-            monkeypatch.setattr(
844
-                socketprovider.WindowsNamedPipeHandle,
845
-                "for_openssh",
846
-                mangled_address,
847
-            )
848
+            monkeypatch.setenv("SSH_AUTH_SOCK", "invalid address format")
848 849
 
849 850
     @Parametrize.TRY_RACE_FREE_IMPLEMENTATION
850 851
     def test_fail_because_read_only_file(
... ...
@@ -883,20 +884,20 @@ class TestStoringConfigurationFailures:
883 884
 
884 885
     def test_fail_because_ssh_agent_has_no_keys_loaded(
885 886
         self,
886
-        request: pytest.FixtureRequest,
887
-        spawn_ssh_agent: data.SpawnedSSHAgentInfo,
887
+        use_stub_agent: None,
888 888
     ) -> None:
889
-        """Not holding any SSH keys during `--config --key` fails."""
889
+        """Not holding any SSH keys during `--config --key` fails.
890
+
891
+        (This test does not actually need a running agent; the agent's
892
+        response is mocked by the test harness.)
893
+
894
+        """
895
+        del use_stub_agent
890 896
         with self._test(
891 897
             ["--key"],
892 898
             error_text="no keys suitable",
893 899
             patch_suitable_ssh_keys=False,
894 900
         ) as monkeypatch:
895
-            pytest_machinery.ensure_singleton_client_if_non_reentrant_agent(
896
-                request=request,
897
-                monkeypatch=monkeypatch,
898
-                client=spawn_ssh_agent.client,
899
-            )
900 901
 
901 902
             def func(
902 903
                 *_args: Any,
... ...
@@ -908,20 +909,20 @@ class TestStoringConfigurationFailures:
908 909
 
909 910
     def test_store_config_fail_manual_ssh_agent_runtime_error(
910 911
         self,
911
-        request: pytest.FixtureRequest,
912
-        spawn_ssh_agent: data.SpawnedSSHAgentInfo,
912
+        use_stub_agent: None,
913 913
     ) -> None:
914
-        """Triggering an error in the SSH agent during `--config --key` leads to failure."""
914
+        """Triggering an error in the SSH agent during `--config --key` leads to failure.
915
+
916
+        (This test does not actually need a running agent; the agent's
917
+        response is mocked by the test harness.)
918
+
919
+        """
920
+        del use_stub_agent
915 921
         with self._test(
916 922
             ["--key"],
917 923
             error_text="violates the communication protocol",
918 924
             patch_suitable_ssh_keys=False,
919 925
         ) as monkeypatch:
920
-            pytest_machinery.ensure_singleton_client_if_non_reentrant_agent(
921
-                request=request,
922
-                monkeypatch=monkeypatch,
923
-                client=spawn_ssh_agent.client,
924
-            )
925 926
 
926 927
             def raiser(*_args: Any, **_kwargs: Any) -> None:
927 928
                 raise ssh_agent.TrailingDataError()
... ...
@@ -930,18 +931,18 @@ class TestStoringConfigurationFailures:
930 931
 
931 932
     def test_store_config_fail_manual_ssh_agent_refuses(
932 933
         self,
933
-        request: pytest.FixtureRequest,
934
-        spawn_ssh_agent: data.SpawnedSSHAgentInfo,
934
+        use_stub_agent: None,
935 935
     ) -> None:
936
-        """The SSH agent refusing during `--config --key` leads to failure."""
936
+        """The SSH agent refusing during `--config --key` leads to failure.
937
+
938
+        (This test does not actually need a running agent; the agent's
939
+        response is mocked by the test harness.)
940
+
941
+        """
942
+        del use_stub_agent
937 943
         with self._test(
938 944
             ["--key"], error_text="refused to", patch_suitable_ssh_keys=False
939 945
         ) as monkeypatch:
940
-            pytest_machinery.ensure_singleton_client_if_non_reentrant_agent(
941
-                request=request,
942
-                monkeypatch=monkeypatch,
943
-                client=spawn_ssh_agent.client,
944
-            )
945 946
 
946 947
             def func(*_args: Any, **_kwargs: Any) -> NoReturn:
947 948
                 raise ssh_agent.SSHAgentFailedError(
948 949