Skip to content

Commit 072c635

Browse files
test_regexp: New file for testing stderr matching
Add a new test file for testing a few "real world" ssh messages against our regexps for classifying stderr messages. This can be expanded on later.
1 parent 7d706d5 commit 072c635

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed

test/test_regexp.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# ferny - asyncio SSH client library, using ssh(1)
2+
#
3+
# Copyright (C) 2023 Allison Karlitskaya <[email protected]>
4+
#
5+
# This program is free software: you can redistribute it and/or modify
6+
# it under the terms of the GNU General Public License as published by
7+
# the Free Software Foundation, either version 3 of the License, or
8+
# (at your option) any later version.
9+
#
10+
# This program is distributed in the hope that it will be useful,
11+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
# GNU General Public License for more details.
14+
#
15+
# You should have received a copy of the GNU General Public License
16+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
18+
import os
19+
import textwrap
20+
from typing import Optional
21+
22+
import pytest
23+
24+
import ferny
25+
26+
# Actual messages seen in the wild, for documentation and testing
27+
STDERR_MESSAGES = {
28+
'ChangedHostKeyError': r"""
29+
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
30+
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
31+
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
32+
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
33+
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
34+
It is also possible that a host key has just been changed.
35+
The fingerprint for the ED25519 key sent by the remote host is
36+
SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU.
37+
Please contact your system administrator.
38+
Add correct host key in x to get rid of this message.
39+
Offending ED25519 key in x:1
40+
Host key for github.com has changed and you have requested strict checking.
41+
Host key verification failed.
42+
""",
43+
44+
'UnknownHostKeyError': r"""
45+
No ED25519 host key is known for srv and you have requested strict checking.
46+
Host key verification failed.
47+
""",
48+
49+
# 'StrictHostKeyChecking=no (unsupported)': r"""
50+
# Password authentication is disabled to avoid man-in-the-middle attacks.
51+
# Keyboard-interactive authentication is disabled to avoid man-in-the-middle attacks.
52+
# [email protected]: Permission denied (publickey).
53+
# """,
54+
55+
'AuthenticationError': r"""
56+
xyz@srv: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
57+
""",
58+
59+
'SshError': r"""Something bad happened.
60+
""",
61+
}
62+
63+
64+
@pytest.mark.parametrize('msg_id', STDERR_MESSAGES)
65+
def test_categorize_errors(msg_id: str) -> None:
66+
expected_type = msg_id.split()[0]
67+
message = textwrap.dedent(STDERR_MESSAGES[msg_id])
68+
exc = ferny.errors.get_exception_for_ssh_stderr(message)
69+
assert exc.__class__.__name__ == expected_type
70+
71+
72+
class MockResponder(ferny.SshAskpassResponder):
73+
async def do_prompt(self, prompt: ferny.AskpassPrompt) -> Optional[str]:
74+
# respond with the type of the prompt
75+
assert prompt.stderr == ''
76+
return prompt.__class__.__name__
77+
78+
79+
@pytest.mark.parametrize('msg_id', STDERR_MESSAGES)
80+
@pytest.mark.asyncio
81+
async def test_mock_stderr(msg_id: str) -> None:
82+
expected_type = msg_id.split()[0]
83+
message = textwrap.dedent(STDERR_MESSAGES[msg_id])
84+
85+
# Spawn ferny-askpass to talk to a running agent which simply replies with
86+
# the name of the type of prompt object that was created.
87+
agent = ferny.InteractionAgent(MockResponder())
88+
os.write(agent.fileno(), message.encode())
89+
90+
with pytest.raises(ferny.SshError) as ssh_exc:
91+
# Until we get a better API, you have to do this, unfortunately:
92+
try:
93+
await agent.communicate()
94+
except ferny.InteractionError as int_exc:
95+
raise ferny.errors.get_exception_for_ssh_stderr(str(int_exc)) from None
96+
97+
assert ssh_exc.value.__class__.__name__ == expected_type

0 commit comments

Comments
 (0)