@@ -63,12 +63,16 @@ def generate_host_key(pkey: paramiko.PKey):
6363TEST_PRIVATE_KEY = generate_key_string (pkey = TEST_PKEY )
6464TEST_HOST_KEY = generate_host_key (pkey = TEST_PKEY )
6565
66+ TEST_PKEY_ECDSA = paramiko .ECDSAKey .generate ()
67+ TEST_PRIVATE_KEY_ECDSA = generate_key_string (pkey = TEST_PKEY_ECDSA )
68+
6669PASSPHRASE = '' .join (random .choice (string .ascii_letters ) for i in range (10 ))
6770TEST_ENCRYPTED_PRIVATE_KEY = generate_key_string (pkey = TEST_PKEY , passphrase = PASSPHRASE )
6871
6972
7073class TestSSHHook (unittest .TestCase ):
7174 CONN_SSH_WITH_PRIVATE_KEY_EXTRA = 'ssh_with_private_key_extra'
75+ CONN_SSH_WITH_PRIVATE_KEY_ECDSA_EXTRA = 'ssh_with_private_key_ecdsa_extra'
7276 CONN_SSH_WITH_PRIVATE_KEY_PASSPHRASE_EXTRA = 'ssh_with_private_key_passphrase_extra'
7377 CONN_SSH_WITH_EXTRA = 'ssh_with_extra'
7478 CONN_SSH_WITH_EXTRA_FALSE_LOOK_FOR_KEYS = 'ssh_with_extra_false_look_for_keys'
@@ -83,6 +87,7 @@ def tearDownClass(cls) -> None:
8387 conns_to_reset = [
8488 cls .CONN_SSH_WITH_PRIVATE_KEY_EXTRA ,
8589 cls .CONN_SSH_WITH_PRIVATE_KEY_PASSPHRASE_EXTRA ,
90+ cls .CONN_SSH_WITH_PRIVATE_KEY_ECDSA_EXTRA ,
8691 cls .CONN_SSH_WITH_EXTRA ,
8792 cls .CONN_SSH_WITH_HOST_KEY_EXTRA ,
8893 cls .CONN_SSH_WITH_HOST_KEY_AND_NO_HOST_KEY_CHECK_FALSE ,
@@ -134,6 +139,14 @@ def setUpClass(cls) -> None:
134139 ),
135140 )
136141 )
142+ db .merge_conn (
143+ Connection (
144+ conn_id = cls .CONN_SSH_WITH_PRIVATE_KEY_ECDSA_EXTRA ,
145+ host = 'localhost' ,
146+ conn_type = 'ssh' ,
147+ extra = json .dumps ({"private_key" : TEST_PRIVATE_KEY_ECDSA }),
148+ )
149+ )
137150 db .merge_conn (
138151 Connection (
139152 conn_id = cls .CONN_SSH_WITH_HOST_KEY_EXTRA ,
@@ -313,6 +326,29 @@ def test_tunnel_with_private_key_passphrase(self, ssh_mock):
313326 logger = hook .log ,
314327 )
315328
329+ @mock .patch ('airflow.providers.ssh.hooks.ssh.SSHTunnelForwarder' )
330+ def test_tunnel_with_private_key_ecdsa (self , ssh_mock ):
331+ hook = SSHHook (
332+ ssh_conn_id = self .CONN_SSH_WITH_PRIVATE_KEY_ECDSA_EXTRA ,
333+ remote_host = 'remote_host' ,
334+ port = 'port' ,
335+ username = 'username' ,
336+ timeout = 10 ,
337+ )
338+
339+ with hook .get_tunnel (1234 ):
340+ ssh_mock .assert_called_once_with (
341+ 'remote_host' ,
342+ ssh_port = 'port' ,
343+ ssh_username = 'username' ,
344+ ssh_pkey = TEST_PKEY_ECDSA ,
345+ ssh_proxy = None ,
346+ local_bind_address = ('localhost' ,),
347+ remote_bind_address = ('localhost' , 1234 ),
348+ host_pkey_directories = [],
349+ logger = hook .log ,
350+ )
351+
316352 def test_ssh_connection (self ):
317353 hook = SSHHook (ssh_conn_id = 'ssh_default' )
318354 with hook .get_conn () as client :
0 commit comments