Marco Ricci commited on 2026-06-13 19:22:20
Zeige 3 geänderte Dateien mit 153 Einfügungen und 139 Löschungen.
Rename the `Request` and `Response` classes to `AgentProtocolRequest` and `AgentProtocolResponse`, respectively, and move them into the `tests.data` package. Rename the `_RequestResponseIOQueue` class to `AgentProtocolResponseQueue`, and move it into the `tests.machinery` package. Along the way, fix the self-reference of `tests.data` and `tests.machinery` contents within the `tests.machinery` package.
| ... | ... |
@@ -255,6 +255,40 @@ class RunningSSHAgentInfo(NamedTuple): |
| 255 | 255 |
return self.socket |
| 256 | 256 |
|
| 257 | 257 |
|
| 258 |
+class AgentProtocolRequest(NamedTuple): |
|
| 259 |
+ """A request for the SSH agent protocol. |
|
| 260 |
+ |
|
| 261 |
+ Attributes: |
|
| 262 |
+ code: |
|
| 263 |
+ The expected request code. |
|
| 264 |
+ payload: |
|
| 265 |
+ The expected payload. Optional. |
|
| 266 |
+ |
|
| 267 |
+ """ |
|
| 268 |
+ |
|
| 269 |
+ code: _types.SSH_AGENTC | int |
|
| 270 |
+ """""" |
|
| 271 |
+ payload: bytes |
|
| 272 |
+ """""" |
|
| 273 |
+ |
|
| 274 |
+ |
|
| 275 |
+class AgentProtocolResponse(NamedTuple): |
|
| 276 |
+ """A response for the SSH agent protocol. |
|
| 277 |
+ |
|
| 278 |
+ Attributes: |
|
| 279 |
+ code: |
|
| 280 |
+ The desired response code. |
|
| 281 |
+ payload: |
|
| 282 |
+ The desired response payload. |
|
| 283 |
+ |
|
| 284 |
+ """ |
|
| 285 |
+ |
|
| 286 |
+ code: _types.SSH_AGENT | int |
|
| 287 |
+ """""" |
|
| 288 |
+ payload: bytes |
|
| 289 |
+ """""" |
|
| 290 |
+ |
|
| 291 |
+ |
|
| 258 | 292 |
# Vault configurations |
| 259 | 293 |
# ==================== |
| 260 | 294 |
|
| ... | ... |
@@ -12,6 +12,7 @@ wrappers, stub systems, and the like. |
| 12 | 12 |
|
| 13 | 13 |
from __future__ import annotations |
| 14 | 14 |
|
| 15 |
+import collections |
|
| 15 | 16 |
import contextlib |
| 16 | 17 |
import errno |
| 17 | 18 |
import logging |
| ... | ... |
@@ -23,16 +24,17 @@ from typing import TYPE_CHECKING, TypedDict |
| 23 | 24 |
import click.testing |
| 24 | 25 |
from typing_extensions import NamedTuple |
| 25 | 26 |
|
| 26 |
-import tests.data |
|
| 27 | 27 |
from derivepassphrase import _types, cli, ssh_agent, vault |
| 28 | 28 |
from derivepassphrase.ssh_agent import socketprovider |
| 29 |
+from tests import data |
|
| 29 | 30 |
|
| 30 | 31 |
__all__ = () |
| 31 | 32 |
|
| 32 | 33 |
if TYPE_CHECKING: |
| 34 |
+ import types |
|
| 33 | 35 |
from collections.abc import Callable, Iterator, Mapping, Sequence |
| 34 | 36 |
from contextlib import AbstractContextManager |
| 35 |
- from typing import IO, NotRequired |
|
| 37 |
+ from typing import IO, Literal, NotRequired |
|
| 36 | 38 |
|
| 37 | 39 |
from typing_extensions import Any, Buffer, Self |
| 38 | 40 |
|
| ... | ... |
@@ -191,7 +193,7 @@ class ReadableResult(NamedTuple): |
| 191 | 193 |
error_match(error, line) |
| 192 | 194 |
for line in self.stderr.splitlines(True) |
| 193 | 195 |
) |
| 194 |
- or tests.machinery.error_emitted(error, record_tuples) |
|
| 196 |
+ or error_emitted(error, record_tuples) |
|
| 195 | 197 |
) |
| 196 | 198 |
) |
| 197 | 199 |
|
| ... | ... |
@@ -295,6 +297,84 @@ class CliRunner: |
| 295 | 297 |
) |
| 296 | 298 |
|
| 297 | 299 |
|
| 300 |
+# Stubbed SSH agent request/response queue |
|
| 301 |
+# ======================================== |
|
| 302 |
+ |
|
| 303 |
+ |
|
| 304 |
+class AgentProtocolResponseQueue: |
|
| 305 |
+ """A response queue for the SSH agent protocol. |
|
| 306 |
+ |
|
| 307 |
+ This queue wraps a map of request messages |
|
| 308 |
+ ([`AgentProtocolRequest`][data.AgentProtocolRequest]) to multiple |
|
| 309 |
+ response messages |
|
| 310 |
+ ([`AgentProtocolResponse`][data.AgentProtocolResponse]). Whenever |
|
| 311 |
+ [`_request_message`][] is called with a payload that matches |
|
| 312 |
+ a [`AgentProtocolRequest`][data.AgentProtocolRequest] from the map, |
|
| 313 |
+ the corresponding |
|
| 314 |
+ [`AgentProtocolResponse`][data.AgentProtocolResponse] objects are |
|
| 315 |
+ added to the queue, to be read by subsequent [`_response_pair`][] |
|
| 316 |
+ calls. |
|
| 317 |
+ |
|
| 318 |
+ The queue is a context manager. When entered or exited, it |
|
| 319 |
+ verifies that the queue is empty. |
|
| 320 |
+ |
|
| 321 |
+ Use this agent stub implementation if you are modelling well-formed |
|
| 322 |
+ requests and responses, without network errors or protocol framing |
|
| 323 |
+ errors. For modelling the latter, see [`StubbedSSHAgentSocket`][]. |
|
| 324 |
+ |
|
| 325 |
+ """ |
|
| 326 |
+ |
|
| 327 |
+ def __init__( |
|
| 328 |
+ self, |
|
| 329 |
+ request_responses_mapping: Mapping[ |
|
| 330 |
+ data.AgentProtocolRequest, |
|
| 331 |
+ Sequence[data.AgentProtocolResponse], |
|
| 332 |
+ ], |
|
| 333 |
+ ) -> None: |
|
| 334 |
+ self.responses_map = request_responses_mapping |
|
| 335 |
+ self.queue: collections.deque[data.AgentProtocolResponse] = ( |
|
| 336 |
+ collections.deque() |
|
| 337 |
+ ) |
|
| 338 |
+ |
|
| 339 |
+ def __bool__(self) -> bool: |
|
| 340 |
+ return bool(self.queue) |
|
| 341 |
+ |
|
| 342 |
+ def __enter__(self) -> Self: |
|
| 343 |
+ assert not self, ( |
|
| 344 |
+ f"Agent I/O queue already has contents: {self.queue!r}"
|
|
| 345 |
+ ) |
|
| 346 |
+ return self |
|
| 347 |
+ |
|
| 348 |
+ def __exit__( |
|
| 349 |
+ self, |
|
| 350 |
+ exc_type: type[BaseException] | None, |
|
| 351 |
+ exc_value: BaseException | None, |
|
| 352 |
+ exc_tb: types.TracebackType | None, |
|
| 353 |
+ ) -> Literal[False]: |
|
| 354 |
+ if (exc_type, exc_value, exc_tb) != (None, None, None): |
|
| 355 |
+ return False |
|
| 356 |
+ assert not self, f"Agent I/O queue still has contents: {self.queue!r}"
|
|
| 357 |
+ return False |
|
| 358 |
+ |
|
| 359 |
+ def _send_request_message( |
|
| 360 |
+ self, |
|
| 361 |
+ request_code: int | _types.SSH_AGENTC, |
|
| 362 |
+ payload: bytes | bytearray, |
|
| 363 |
+ ) -> None: |
|
| 364 |
+ req = data.AgentProtocolRequest(request_code, bytes(payload)) |
|
| 365 |
+ assert req in self.responses_map, ( |
|
| 366 |
+ f"No prepared response for the request {req!r}"
|
|
| 367 |
+ ) |
|
| 368 |
+ self.queue.extend(self.responses_map[req]) |
|
| 369 |
+ |
|
| 370 |
+ def _get_response_pair( |
|
| 371 |
+ self, |
|
| 372 |
+ ) -> tuple[int | _types.SSH_AGENT, bytes | bytearray]: |
|
| 373 |
+ assert self.queue, "No more responses left to replay" |
|
| 374 |
+ response = self.queue.popleft() |
|
| 375 |
+ return response.code, response.payload |
|
| 376 |
+ |
|
| 377 |
+ |
|
| 298 | 378 |
# Stubbed SSH agent socket |
| 299 | 379 |
# ======================== |
| 300 | 380 |
|
| ... | ... |
@@ -522,18 +602,18 @@ class StubbedSSHAgentSocket: |
| 522 | 602 |
else: |
| 523 | 603 |
yield _types.SSH_AGENT.IDENTITIES_ANSWER |
| 524 | 604 |
signature_classes = [ |
| 525 |
- tests.data.SSHTestKeyDeterministicSignatureClass.SPEC, |
|
| 605 |
+ data.SSHTestKeyDeterministicSignatureClass.SPEC, |
|
| 526 | 606 |
] |
| 527 | 607 |
if ( |
| 528 | 608 |
"list-extended@putty.projects.tartarus.org" |
| 529 | 609 |
in self.enabled_extensions |
| 530 | 610 |
): |
| 531 | 611 |
signature_classes.append( |
| 532 |
- tests.data.SSHTestKeyDeterministicSignatureClass.RFC_6979 |
|
| 612 |
+ data.SSHTestKeyDeterministicSignatureClass.RFC_6979 |
|
| 533 | 613 |
) |
| 534 | 614 |
keys = [ |
| 535 | 615 |
v |
| 536 |
- for v in tests.data.ALL_KEYS.values() |
|
| 616 |
+ for v in data.ALL_KEYS.values() |
|
| 537 | 617 |
if any(cls in v.expected_signatures for cls in signature_classes) |
| 538 | 618 |
] |
| 539 | 619 |
yield from ssh_agent.SSHAgentClient.uint32(len(keys)) |
| ... | ... |
@@ -559,8 +639,8 @@ class StubbedSSHAgentSocket: |
| 559 | 639 |
"list-extended@putty.projects.tartarus.org" |
| 560 | 640 |
in self.enabled_extensions |
| 561 | 641 |
) |
| 562 |
- spec = tests.data.SSHTestKeyDeterministicSignatureClass.SPEC |
|
| 563 |
- rfc6979 = tests.data.SSHTestKeyDeterministicSignatureClass.RFC_6979 |
|
| 642 |
+ spec = data.SSHTestKeyDeterministicSignatureClass.SPEC |
|
| 643 |
+ rfc6979 = data.SSHTestKeyDeterministicSignatureClass.RFC_6979 |
|
| 564 | 644 |
key_blob, rest = ssh_agent.SSHAgentClient.unstring_prefix( |
| 565 | 645 |
self.receive_from_client[self.HEADER_SIZE + self.CODE_SIZE :] |
| 566 | 646 |
) |
| ... | ... |
@@ -572,7 +652,7 @@ class StubbedSSHAgentSocket: |
| 572 | 652 |
raise ValueError(self._UNSUPPORTED_REQUEST) |
| 573 | 653 |
if sign_data != vault.Vault.UUID: |
| 574 | 654 |
raise ValueError(self._UNSUPPORTED_REQUEST) |
| 575 |
- for key in tests.data.ALL_KEYS.values(): |
|
| 655 |
+ for key in data.ALL_KEYS.values(): |
|
| 576 | 656 |
if key.public_key_data == key_blob: |
| 577 | 657 |
if spec in key.expected_signatures: |
| 578 | 658 |
return int.to_bytes( |
| ... | ... |
@@ -7,7 +7,6 @@ |
| 7 | 7 |
from __future__ import annotations |
| 8 | 8 |
|
| 9 | 9 |
import base64 |
| 10 |
-import collections |
|
| 11 | 10 |
import contextlib |
| 12 | 11 |
import ctypes |
| 13 | 12 |
import importlib.metadata |
| ... | ... |
@@ -16,7 +15,7 @@ import re |
| 16 | 15 |
import socket |
| 17 | 16 |
import sys |
| 18 | 17 |
import types |
| 19 |
-from typing import TYPE_CHECKING, Final, NamedTuple |
|
| 18 |
+from typing import TYPE_CHECKING, Final |
|
| 20 | 19 |
|
| 21 | 20 |
import click |
| 22 | 21 |
import hypothesis |
| ... | ... |
@@ -34,7 +33,7 @@ from tests.machinery import pytest as pytest_machinery |
| 34 | 33 |
if TYPE_CHECKING: |
| 35 | 34 |
from collections.abc import Callable, Iterator, Mapping, Sequence |
| 36 | 35 |
|
| 37 |
- from typing_extensions import Any, Literal, Self |
|
| 36 |
+ from typing_extensions import Any, Literal |
|
| 38 | 37 |
|
| 39 | 38 |
if sys.version_info < (3, 11): |
| 40 | 39 |
from exceptiongroup import ExceptionGroup |
| ... | ... |
@@ -1159,116 +1158,13 @@ class TestOtherConstructorFeatures: |
| 1159 | 1158 |
class TestAgentErrorResponses: |
| 1160 | 1159 |
"""Test actually talking to the SSH agent: errors from the SSH agent.""" |
| 1161 | 1160 |
|
| 1162 |
- class Request(NamedTuple): |
|
| 1163 |
- """A request for the SSH agent protocol. |
|
| 1164 |
- |
|
| 1165 |
- Attributes: |
|
| 1166 |
- code: |
|
| 1167 |
- The expected request code. |
|
| 1168 |
- payload: |
|
| 1169 |
- The expected payload. Optional. |
|
| 1170 |
- |
|
| 1171 |
- """ |
|
| 1172 |
- |
|
| 1173 |
- code: _types.SSH_AGENTC | int |
|
| 1174 |
- """""" |
|
| 1175 |
- payload: bytes |
|
| 1176 |
- """""" |
|
| 1177 |
- |
|
| 1178 |
- class Response(NamedTuple): |
|
| 1179 |
- """A response for the SSH agent protocol. |
|
| 1180 |
- |
|
| 1181 |
- Attributes: |
|
| 1182 |
- code: |
|
| 1183 |
- The desired response code. |
|
| 1184 |
- payload: |
|
| 1185 |
- The desired response payload. |
|
| 1186 |
- |
|
| 1187 |
- """ |
|
| 1188 |
- |
|
| 1189 |
- code: _types.SSH_AGENT | int |
|
| 1190 |
- """""" |
|
| 1191 |
- payload: bytes |
|
| 1192 |
- """""" |
|
| 1193 |
- |
|
| 1194 |
- class _RequestResponseIOQueue: |
|
| 1195 |
- """A response queue for the SSH agent protocol. |
|
| 1196 |
- |
|
| 1197 |
- This queue wraps a map of request messages |
|
| 1198 |
- ([`Request`][TestAgentErrorResponses.Request]) to multiple |
|
| 1199 |
- response messages |
|
| 1200 |
- ([`Response`][TestAgentErrorResponses.Response]). Whenever |
|
| 1201 |
- [`_request_message`][] is called with a payload that matches |
|
| 1202 |
- a [`Request`][TestAgentErrorResponses.Response] from the map, |
|
| 1203 |
- the corresponding [`Response`][TestAgentErrorResponses.Response] |
|
| 1204 |
- objects are added to the queue, to be read by subsequent |
|
| 1205 |
- [`_response_pair`][] calls. |
|
| 1206 |
- |
|
| 1207 |
- Use this agent stub implementation if you are modelling |
|
| 1208 |
- well-formed requests and responses, without network errors or |
|
| 1209 |
- protocol framing errors. If the latter are needed, a custom SSH |
|
| 1210 |
- agent implementation may be necessary. |
|
| 1211 |
- |
|
| 1212 |
- The queue is a context manager. When entered or exited, it |
|
| 1213 |
- verifies that the queue is empty. |
|
| 1214 |
- |
|
| 1215 |
- """ |
|
| 1216 |
- |
|
| 1217 |
- def __init__( |
|
| 1218 |
- self, |
|
| 1219 |
- request_responses_mapping: Mapping[ |
|
| 1220 |
- TestAgentErrorResponses.Request, |
|
| 1221 |
- Sequence[TestAgentErrorResponses.Response], |
|
| 1222 |
- ], |
|
| 1223 |
- ) -> None: |
|
| 1224 |
- self.responses_map = request_responses_mapping |
|
| 1225 |
- self.queue: collections.deque[TestAgentErrorResponses.Response] = ( |
|
| 1226 |
- collections.deque() |
|
| 1227 |
- ) |
|
| 1228 |
- |
|
| 1229 |
- def __bool__(self) -> bool: |
|
| 1230 |
- return bool(self.queue) |
|
| 1231 |
- |
|
| 1232 |
- def __enter__(self) -> Self: |
|
| 1233 |
- assert not self, ( |
|
| 1234 |
- f"Agent I/O queue already has contents: {self.queue!r}"
|
|
| 1235 |
- ) |
|
| 1236 |
- return self |
|
| 1237 |
- |
|
| 1238 |
- def __exit__( |
|
| 1239 |
- self, |
|
| 1240 |
- exc_type: type[BaseException] | None, |
|
| 1241 |
- exc_value: BaseException | None, |
|
| 1242 |
- exc_tb: types.TracebackType | None, |
|
| 1243 |
- ) -> Literal[False]: |
|
| 1244 |
- if (exc_type, exc_value, exc_tb) != (None, None, None): |
|
| 1245 |
- return False |
|
| 1246 |
- assert not self, ( |
|
| 1247 |
- f"Agent I/O queue still has contents: {self.queue!r}"
|
|
| 1248 |
- ) |
|
| 1249 |
- return False |
|
| 1250 |
- |
|
| 1251 |
- def _send_request_message( |
|
| 1252 |
- self, |
|
| 1253 |
- request_code: int | _types.SSH_AGENTC, |
|
| 1254 |
- payload: bytes | bytearray, |
|
| 1255 |
- ) -> None: |
|
| 1256 |
- req = TestAgentErrorResponses.Request(request_code, bytes(payload)) |
|
| 1257 |
- assert req in self.responses_map, ( |
|
| 1258 |
- f"No prepared response for the request {req!r}"
|
|
| 1259 |
- ) |
|
| 1260 |
- self.queue.extend(self.responses_map[req]) |
|
| 1261 |
- |
|
| 1262 |
- def _get_response_pair( |
|
| 1263 |
- self, |
|
| 1264 |
- ) -> tuple[int | _types.SSH_AGENT, bytes | bytearray]: |
|
| 1265 |
- assert self.queue, "No more responses left to replay" |
|
| 1266 |
- response = self.queue.popleft() |
|
| 1267 |
- return response.code, response.payload |
|
| 1268 |
- |
|
| 1269 | 1161 |
@contextlib.contextmanager |
| 1270 | 1162 |
def _setup_agent_and_request_handler( |
| 1271 |
- self, request_responses_map: Mapping[Request, Sequence[Response]], / |
|
| 1163 |
+ self, |
|
| 1164 |
+ request_responses_map: Mapping[ |
|
| 1165 |
+ data.AgentProtocolRequest, Sequence[data.AgentProtocolResponse] |
|
| 1166 |
+ ], |
|
| 1167 |
+ /, |
|
| 1272 | 1168 |
) -> Iterator[tuple[pytest.MonkeyPatch, ssh_agent.SSHAgentClient]]: |
| 1273 | 1169 |
# TODO(the-13th-letter): Rewrite using parenthesized |
| 1274 | 1170 |
# with-statements. |
| ... | ... |
@@ -1278,7 +1174,7 @@ class TestAgentErrorResponses: |
| 1278 | 1174 |
client = stack.enter_context( |
| 1279 | 1175 |
ssh_agent.SSHAgentClient.ensure_agent_subcontext() |
| 1280 | 1176 |
) |
| 1281 |
- agent_io_queue = self._RequestResponseIOQueue( |
|
| 1177 |
+ agent_io_queue = machinery.AgentProtocolResponseQueue( |
|
| 1282 | 1178 |
request_responses_map |
| 1283 | 1179 |
) |
| 1284 | 1180 |
stack.enter_context(agent_io_queue) |
| ... | ... |
@@ -1337,9 +1233,9 @@ class TestAgentErrorResponses: |
| 1337 | 1233 |
""" |
| 1338 | 1234 |
del running_ssh_agent |
| 1339 | 1235 |
with self._setup_agent_and_request_handler({
|
| 1340 |
- self.Request(_types.SSH_AGENTC.REQUEST_IDENTITIES, b""): [ |
|
| 1341 |
- self.Response(response_code, response) |
|
| 1342 |
- ], |
|
| 1236 |
+ data.AgentProtocolRequest( |
|
| 1237 |
+ _types.SSH_AGENTC.REQUEST_IDENTITIES, b"" |
|
| 1238 |
+ ): [data.AgentProtocolResponse(response_code, response)], |
|
| 1343 | 1239 |
}) as contexts: |
| 1344 | 1240 |
_, client = contexts |
| 1345 | 1241 |
with pytest.raises(exc_type, match=exc_pattern): |
| ... | ... |
@@ -1378,9 +1274,9 @@ class TestAgentErrorResponses: |
| 1378 | 1274 |
+ ssh_agent.SSHAgentClient.uint32(0) |
| 1379 | 1275 |
) |
| 1380 | 1276 |
with self._setup_agent_and_request_handler({
|
| 1381 |
- self.Request(_types.SSH_AGENTC.SIGN_REQUEST, sign_payload): [ |
|
| 1382 |
- self.Response(response_code, response) |
|
| 1383 |
- ], |
|
| 1277 |
+ data.AgentProtocolRequest( |
|
| 1278 |
+ _types.SSH_AGENTC.SIGN_REQUEST, sign_payload |
|
| 1279 |
+ ): [data.AgentProtocolResponse(response_code, response)], |
|
| 1384 | 1280 |
}) as contexts: |
| 1385 | 1281 |
monkeypatch, client = contexts |
| 1386 | 1282 |
monkeypatch.setattr(client, "list_keys", lambda: loaded_keys) |
| ... | ... |
@@ -1424,11 +1320,11 @@ class TestAgentErrorResponses: |
| 1424 | 1320 |
"""Fail on malformed responses while querying extensions.""" |
| 1425 | 1321 |
del running_ssh_agent |
| 1426 | 1322 |
with self._setup_agent_and_request_handler({
|
| 1427 |
- self.Request( |
|
| 1323 |
+ data.AgentProtocolRequest( |
|
| 1428 | 1324 |
_types.SSH_AGENTC.EXTENSION, |
| 1429 | 1325 |
ssh_agent.SSHAgentClient.string(b"query"), |
| 1430 | 1326 |
): [ |
| 1431 |
- self.Response( |
|
| 1327 |
+ data.AgentProtocolResponse( |
|
| 1432 | 1328 |
_types.SSH_AGENT.EXTENSION_RESPONSE, response_data |
| 1433 | 1329 |
) |
| 1434 | 1330 |
], |
| ... | ... |
@@ -1447,7 +1343,7 @@ class TestAgentErrorResponses: |
| 1447 | 1343 |
code: Literal[ |
| 1448 | 1344 |
_types.SSH_AGENT.EXTENSION_RESPONSE, _types.SSH_AGENT.SUCCESS |
| 1449 | 1345 |
] = _types.SSH_AGENT.EXTENSION_RESPONSE, |
| 1450 |
- ) -> Response: |
|
| 1346 |
+ ) -> data.AgentProtocolResponse: |
|
| 1451 | 1347 |
"""Construct a response object from the given extensions. |
| 1452 | 1348 |
|
| 1453 | 1349 |
Args: |
| ... | ... |
@@ -1463,30 +1359,32 @@ class TestAgentErrorResponses: |
| 1463 | 1359 |
payload = bytearray(b"\x00\x00\x00\x05query") |
| 1464 | 1360 |
for ext in extensions: |
| 1465 | 1361 |
payload.extend(TestStaticFunctionality.as_ssh_string(ext.encode())) |
| 1466 |
- return self.Response(code, bytes(payload)) |
|
| 1362 |
+ return data.AgentProtocolResponse(code, bytes(payload)) |
|
| 1467 | 1363 |
|
| 1468 |
- IDENTITIES_REQUEST: Final = Request( |
|
| 1364 |
+ IDENTITIES_REQUEST: Final = data.AgentProtocolRequest( |
|
| 1469 | 1365 |
_types.SSH_AGENTC.REQUEST_IDENTITIES, b"" |
| 1470 | 1366 |
) |
| 1471 |
- IDENTITIES_RESPONSE: Final = Response( |
|
| 1367 |
+ IDENTITIES_RESPONSE: Final = data.AgentProtocolResponse( |
|
| 1472 | 1368 |
_types.SSH_AGENT.IDENTITIES_ANSWER, b"\x00\x00\x00\x00" |
| 1473 | 1369 |
) |
| 1474 |
- QUERY_REQUEST: Final = Request( |
|
| 1370 |
+ QUERY_REQUEST: Final = data.AgentProtocolRequest( |
|
| 1475 | 1371 |
_types.SSH_AGENTC.EXTENSION, b"\x00\x00\x00\x05query" |
| 1476 | 1372 |
) |
| 1477 |
- EXTRA_RESPONSE: Final = Response(_types.SSH_AGENT.SUCCESS, b"") |
|
| 1373 |
+ EXTRA_RESPONSE: Final = data.AgentProtocolResponse( |
|
| 1374 |
+ _types.SSH_AGENT.SUCCESS, b"" |
|
| 1375 |
+ ) |
|
| 1478 | 1376 |
|
| 1479 | 1377 |
@pytest.mark.parametrize( |
| 1480 | 1378 |
["success_after_query", "extensions"], |
| 1481 | 1379 |
[ |
| 1482 | 1380 |
pytest.param( |
| 1483 | 1381 |
False, |
| 1484 |
- Response(_types.SSH_AGENT.FAILURE, b""), |
|
| 1382 |
+ data.AgentProtocolResponse(_types.SSH_AGENT.FAILURE, b""), |
|
| 1485 | 1383 |
id="openssh-10.2", |
| 1486 | 1384 |
), |
| 1487 | 1385 |
pytest.param( |
| 1488 | 1386 |
True, |
| 1489 |
- Response(_types.SSH_AGENT.FAILURE, b""), |
|
| 1387 |
+ data.AgentProtocolResponse(_types.SSH_AGENT.FAILURE, b""), |
|
| 1490 | 1388 |
id="openssh-10.2-mocked", |
| 1491 | 1389 |
marks=[ |
| 1492 | 1390 |
pytest.mark.xfail( |
| ... | ... |
@@ -1528,7 +1426,9 @@ class TestAgentErrorResponses: |
| 1528 | 1426 |
], |
| 1529 | 1427 |
) |
| 1530 | 1428 |
def test_tolerating_extra_success_after_extension_response( |
| 1531 |
- self, success_after_query: bool, extensions: list[str] | Response |
|
| 1429 |
+ self, |
|
| 1430 |
+ success_after_query: bool, |
|
| 1431 |
+ extensions: list[str] | data.AgentProtocolResponse, |
|
| 1532 | 1432 |
) -> None: |
| 1533 | 1433 |
"""Tolerate an extra empty SUCCESS message from a "query" EXTENSION. |
| 1534 | 1434 |
|
| ... | ... |
@@ -1548,7 +1448,7 @@ class TestAgentErrorResponses: |
| 1548 | 1448 |
""" |
| 1549 | 1449 |
query_response = ( |
| 1550 | 1450 |
extensions |
| 1551 |
- if isinstance(extensions, self.Response) |
|
| 1451 |
+ if isinstance(extensions, data.AgentProtocolResponse) |
|
| 1552 | 1452 |
else self._query_response(*extensions) |
| 1553 | 1453 |
) |
| 1554 | 1454 |
request_responses_map = {
|
| 1555 | 1455 |