Let the `running_ssh_agent` test fixture report the agent type
Marco Ricci

Marco Ricci commited on 2024-11-26 14:26:21
Zeige 4 geänderte Dateien mit 33 Einfügungen und 22 Löschungen.


In the current test scenario, where multiple SSH agents are spawned if
possible, it is highly unhelpful to know *that* a running SSH agent
failed, but not *which* agent did.  For debugging purposes, it is better
if the `running_ssh_agent` test fixture reports not only the agent's
socket, but also its type.

It is sufficient to have the type passed as a fixture output/test
function input, because `pytest` will then pretty-print it when a test
function fails.
... ...
@@ -462,6 +462,11 @@ class SpawnedSSHAgentInfo(NamedTuple):
462 462
     isolated: bool
463 463
 
464 464
 
465
+class RunningSSHAgentInfo(NamedTuple):
466
+    socket: str
467
+    agent_type: KnownSSHAgent
468
+
469
+
465 470
 SUPPORTED_KEYS: Mapping[str, SSHTestKey] = {
466 471
     'ed25519': {
467 472
         'private_key': rb"""-----BEGIN OPENSSH PRIVATE KEY-----
... ...
@@ -234,7 +234,7 @@ _spawn_handlers = [
234 234
 @pytest.fixture
235 235
 def running_ssh_agent(  # pragma: no cover
236 236
     skip_if_no_af_unix_support: None,
237
-) -> Iterator[str]:
237
+) -> Iterator[tests.RunningSSHAgentInfo]:
238 238
     """Ensure a running SSH agent, if possible, as a pytest fixture.
239 239
 
240 240
     Check for a running SSH agent, or spawn a new one if possible.  We
... ...
@@ -245,9 +245,11 @@ def running_ssh_agent(  # pragma: no cover
245 245
     can it guarantee a particular set of loaded keys.
246 246
 
247 247
     Yields:
248
-        str:
249
-            The value of the SSH_AUTH_SOCK environment variable, to be
250
-            used to connect to the running agent.
248
+        :
249
+            A 2-tuple `(ssh_auth_sock, agent_type)`, where
250
+            `ssh_auth_sock` is the value of the `SSH_AUTH_SOCK`
251
+            environment variable, to be used to connect to the running
252
+            agent, and `agent_type` is the agent type.
251 253
 
252 254
     Raises:
253 255
         pytest.skip.Exception:
... ...
@@ -279,7 +281,7 @@ def running_ssh_agent(  # pragma: no cover
279 281
             monkeypatch.setenv('SSH_AUTH_SOCK', startup_ssh_auth_sock)
280 282
         else:  # pragma: no cover
281 283
             monkeypatch.delenv('SSH_AUTH_SOCK', raising=False)
282
-        for exec_name, spawn_func, _ in _spawn_handlers:
284
+        for exec_name, spawn_func, agent_type in _spawn_handlers:
283 285
             # Use match/case here once Python 3.9 becomes unsupported.
284 286
             if exec_name == '(system)':
285 287
                 assert (
... ...
@@ -291,7 +293,9 @@ def running_ssh_agent(  # pragma: no cover
291 293
                         client.list_keys()
292 294
                 except (KeyError, OSError):
293 295
                     continue
294
-                yield os.environ['SSH_AUTH_SOCK']
296
+                yield tests.RunningSSHAgentInfo(
297
+                    os.environ['SSH_AUTH_SOCK'], agent_type
298
+                )
295 299
                 assert (
296 300
                     os.environ.get('SSH_AUTH_SOCK', None)
297 301
                     == startup_ssh_auth_sock
... ...
@@ -342,7 +346,7 @@ def running_ssh_agent(  # pragma: no cover
342 346
                         pytest.MonkeyPatch.context()
343 347
                     )
344 348
                     monkeypatch2.setenv('SSH_AUTH_SOCK', ssh_auth_sock)
345
-                    yield ssh_auth_sock
349
+                    yield tests.RunningSSHAgentInfo(ssh_auth_sock, agent_type)
346 350
                 assert (
347 351
                     os.environ.get('SSH_AUTH_SOCK', None)
348 352
                     == startup_ssh_auth_sock
... ...
@@ -403,12 +403,12 @@ class TestCLI:
403 403
     def test_204c_key_override_on_command_line(
404 404
         self,
405 405
         monkeypatch: pytest.MonkeyPatch,
406
-        running_ssh_agent: str,
406
+        running_ssh_agent: tests.RunningSSHAgentInfo,
407 407
         config: dict[str, Any],
408 408
         key_index: int,
409 409
     ) -> None:
410 410
         with monkeypatch.context():
411
-            monkeypatch.setenv('SSH_AUTH_SOCK', running_ssh_agent)
411
+            monkeypatch.setenv('SSH_AUTH_SOCK', running_ssh_agent.socket)
412 412
             monkeypatch.setattr(
413 413
                 ssh_agent.SSHAgentClient, 'list_keys', tests.list_keys
414 414
             )
... ...
@@ -433,10 +433,10 @@ class TestCLI:
433 433
     def test_205_service_phrase_if_key_in_global_config(
434 434
         self,
435 435
         monkeypatch: pytest.MonkeyPatch,
436
-        running_ssh_agent: str,
436
+        running_ssh_agent: tests.RunningSSHAgentInfo,
437 437
     ) -> None:
438 438
         with monkeypatch.context():
439
-            monkeypatch.setenv('SSH_AUTH_SOCK', running_ssh_agent)
439
+            monkeypatch.setenv('SSH_AUTH_SOCK', running_ssh_agent.socket)
440 440
             monkeypatch.setattr(
441 441
                 ssh_agent.SSHAgentClient, 'list_keys', tests.list_keys
442 442
             )
... ...
@@ -491,11 +491,11 @@ class TestCLI:
491 491
     def test_206_setting_service_phrase_thus_overriding_key_in_config(
492 492
         self,
493 493
         monkeypatch: pytest.MonkeyPatch,
494
-        running_ssh_agent: str,
494
+        running_ssh_agent: tests.RunningSSHAgentInfo,
495 495
         config: _types.VaultConfig,
496 496
     ) -> None:
497 497
         with monkeypatch.context():
498
-            monkeypatch.setenv('SSH_AUTH_SOCK', running_ssh_agent)
498
+            monkeypatch.setenv('SSH_AUTH_SOCK', running_ssh_agent.socket)
499 499
             monkeypatch.setattr(
500 500
                 ssh_agent.SSHAgentClient, 'list_keys', tests.list_keys
501 501
             )
... ...
@@ -1789,11 +1789,11 @@ Boo.
1789 1789
     def test_227_get_suitable_ssh_keys(
1790 1790
         self,
1791 1791
         monkeypatch: pytest.MonkeyPatch,
1792
-        running_ssh_agent: str,
1792
+        running_ssh_agent: tests.RunningSSHAgentInfo,
1793 1793
         conn_hint: str,
1794 1794
     ) -> None:
1795 1795
         with monkeypatch.context():
1796
-            monkeypatch.setenv('SSH_AUTH_SOCK', running_ssh_agent)
1796
+            monkeypatch.setenv('SSH_AUTH_SOCK', running_ssh_agent.socket)
1797 1797
             monkeypatch.setattr(
1798 1798
                 ssh_agent.SSHAgentClient, 'list_keys', tests.list_keys
1799 1799
             )
... ...
@@ -1803,7 +1803,7 @@ Boo.
1803 1803
                 hint = ssh_agent.SSHAgentClient()
1804 1804
             elif conn_hint == 'socket':
1805 1805
                 hint = socket.socket(family=socket.AF_UNIX)
1806
-                hint.connect(running_ssh_agent)
1806
+                hint.connect(running_ssh_agent.socket)
1807 1807
             else:
1808 1808
                 assert conn_hint == 'none'
1809 1809
                 hint = None
... ...
@@ -348,10 +348,12 @@ class TestAgentInteraction:
348 348
     def test_300_constructor_bad_running_agent(
349 349
         self,
350 350
         monkeypatch: pytest.MonkeyPatch,
351
-        running_ssh_agent: str,
351
+        running_ssh_agent: tests.RunningSSHAgentInfo,
352 352
     ) -> None:
353 353
         with monkeypatch.context() as monkeypatch2:
354
-            monkeypatch2.setenv('SSH_AUTH_SOCK', running_ssh_agent + '~')
354
+            monkeypatch2.setenv(
355
+                'SSH_AUTH_SOCK', running_ssh_agent.socket + '~'
356
+            )
355 357
             sock = socket.socket(family=socket.AF_UNIX)
356 358
             with pytest.raises(OSError):  # noqa: PT011
357 359
                 ssh_agent.SSHAgentClient(socket=sock)
... ...
@@ -379,7 +381,7 @@ class TestAgentInteraction:
379 381
     def test_310_truncated_server_response(
380 382
         self,
381 383
         monkeypatch: pytest.MonkeyPatch,
382
-        running_ssh_agent: str,
384
+        running_ssh_agent: tests.RunningSSHAgentInfo,
383 385
         response: bytes,
384 386
     ) -> None:
385 387
         del running_ssh_agent
... ...
@@ -424,7 +426,7 @@ class TestAgentInteraction:
424 426
     def test_320_list_keys_error_responses(
425 427
         self,
426 428
         monkeypatch: pytest.MonkeyPatch,
427
-        running_ssh_agent: str,
429
+        running_ssh_agent: tests.RunningSSHAgentInfo,
428 430
         response_code: _types.SSH_AGENT,
429 431
         response: bytes | bytearray,
430 432
         exc_type: type[Exception],
... ...
@@ -500,7 +502,7 @@ class TestAgentInteraction:
500 502
     def test_330_sign_error_responses(
501 503
         self,
502 504
         monkeypatch: pytest.MonkeyPatch,
503
-        running_ssh_agent: str,
505
+        running_ssh_agent: tests.RunningSSHAgentInfo,
504 506
         key: bytes | bytearray,
505 507
         check: bool,
506 508
         response_code: _types.SSH_AGENT,
... ...
@@ -567,7 +569,7 @@ class TestAgentInteraction:
567 569
     )
568 570
     def test_340_request_error_responses(
569 571
         self,
570
-        running_ssh_agent: str,
572
+        running_ssh_agent: tests.RunningSSHAgentInfo,
571 573
         request_code: _types.SSH_AGENTC,
572 574
         response_code: _types.SSH_AGENT,
573 575
         exc_type: type[Exception],
574 576