4646 UserKnownHostsFile ~/.ssh/known_hosts ~/.ssh/known_hosts.infra ~/.ssh/known_hosts.webservers
4747"""
4848
49+ SSH_CONFIG_IDENTITY_AGENT = """
50+ Host 10.0.0.1
51+ User agentuser
52+ IdentityAgent ~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock
53+ """
54+
55+ SSH_CONFIG_IDENTITY_AGENT_NONE = """
56+ Host 10.0.0.2
57+ User agentuser
58+ IdentityAgent none
59+ """
60+
4961BAD_SSH_CONFIG_DATA = """
5062&
5163"""
@@ -90,13 +102,20 @@ def setUp(self):
90102 def test_load_ssh_config_no_exist (self ):
91103 client = SSHClient ()
92104
93- _ , config , forward_agent , missing_host_key_policy , host_keys_file , keep_alive = (
94- client .parse_config (
95- "127.0.0.1" ,
96- )
105+ (
106+ _ ,
107+ config ,
108+ forward_agent ,
109+ missing_host_key_policy ,
110+ host_keys_file ,
111+ keep_alive ,
112+ identity_agent ,
113+ ) = client .parse_config (
114+ "127.0.0.1" ,
97115 )
98116
99117 assert config .get ("port" ) == 22
118+ assert identity_agent is None
100119
101120
102121@patch (
@@ -140,10 +159,16 @@ def setUp(self):
140159 def test_load_ssh_config (self ):
141160 client = SSHClient ()
142161
143- _ , config , forward_agent , missing_host_key_policy , host_keys_file , keep_alive = (
144- client .parse_config (
145- "127.0.0.1" ,
146- )
162+ (
163+ _ ,
164+ config ,
165+ forward_agent ,
166+ missing_host_key_policy ,
167+ host_keys_file ,
168+ keep_alive ,
169+ identity_agent ,
170+ ) = client .parse_config (
171+ "127.0.0.1" ,
147172 )
148173
149174 assert config .get ("key_filename" ) == ["/id_rsa" , "/id_rsa2" ]
@@ -153,6 +178,7 @@ def test_load_ssh_config(self):
153178 assert forward_agent is False
154179 assert isinstance (missing_host_key_policy , AskPolicy )
155180 assert host_keys_file == ("~/.ssh/known_hosts" ,) # OpenSSH default
181+ assert identity_agent is None
156182
157183 (
158184 _ ,
@@ -161,6 +187,7 @@ def test_load_ssh_config(self):
161187 missing_host_key_policy ,
162188 host_keys_file ,
163189 keep_alive ,
190+ identity_agent ,
164191 ) = client .parse_config ("192.168.1.1" )
165192
166193 assert other_config .get ("username" ) == "otheruser"
@@ -177,9 +204,15 @@ def test_load_ssh_config_inline_comments(self):
177204 """Test that inline comments are stripped from SSH config values (issue #1568)."""
178205 client = SSHClient ()
179206
180- _ , config , forward_agent , missing_host_key_policy , host_keys_file , keep_alive = (
181- client .parse_config ("127.0.0.1" )
182- )
207+ (
208+ _ ,
209+ config ,
210+ forward_agent ,
211+ missing_host_key_policy ,
212+ host_keys_file ,
213+ keep_alive ,
214+ identity_agent ,
215+ ) = client .parse_config ("127.0.0.1" )
183216
184217 assert config .get ("key_filename" ) == ["/id_rsa" ]
185218 assert config .get ("username" ) == "testuser"
@@ -206,6 +239,7 @@ def test_load_ssh_config_multiple_known_hosts(self):
206239 missing_host_key_policy ,
207240 host_keys_files ,
208241 keep_alive ,
242+ identity_agent ,
209243 ) = client .parse_config ("192.168.1.3" )
210244
211245 # Verify multiple known hosts files are parsed as a tuple
@@ -215,6 +249,34 @@ def test_load_ssh_config_multiple_known_hosts(self):
215249 "~/.ssh/known_hosts.webservers" ,
216250 )
217251
252+ @patch (
253+ "pyinfra.connectors.sshuserclient.client.open" ,
254+ mock_open (read_data = SSH_CONFIG_IDENTITY_AGENT ),
255+ create = True ,
256+ )
257+ def test_load_ssh_config_identity_agent (self ):
258+ """Test that IdentityAgent is parsed from SSH config."""
259+ client = SSHClient ()
260+
261+ _ , config , _ , _ , _ , _ , identity_agent = client .parse_config ("10.0.0.1" )
262+
263+ assert config .get ("username" ) == "agentuser"
264+ assert identity_agent == "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"
265+
266+ @patch (
267+ "pyinfra.connectors.sshuserclient.client.open" ,
268+ mock_open (read_data = SSH_CONFIG_IDENTITY_AGENT_NONE ),
269+ create = True ,
270+ )
271+ def test_load_ssh_config_identity_agent_none (self ):
272+ """Test that IdentityAgent set to 'none' is ignored."""
273+ client = SSHClient ()
274+
275+ _ , config , _ , _ , _ , _ , identity_agent = client .parse_config ("10.0.0.2" )
276+
277+ assert config .get ("username" ) == "agentuser"
278+ assert identity_agent is None
279+
218280 @patch (
219281 "pyinfra.connectors.sshuserclient.client.open" ,
220282 mock_open (read_data = BAD_SSH_CONFIG_DATA ),
@@ -262,7 +324,7 @@ def test_load_ssh_config_proxyjump(self, fake_gateway, fake_ssh_connect):
262324 client = SSHClient ()
263325
264326 # Load the SSH config with ProxyJump configured
265- _ , config , forward_agent , _ , _ , _ = client .parse_config (
327+ _ , config , forward_agent , _ , _ , _ , _ = client .parse_config (
266328 "192.168.1.2" ,
267329 {"port" : 1022 },
268330 ssh_config_file = "other_file" ,
0 commit comments