vagrant-ssh-config-manager 0.8.3 → 1.0.0.alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.bundle/config +1 -1
- data/.gitignore +2 -1
- data/.rspec +2 -0
- data/.rubocop.yml +62 -0
- data/Gemfile +11 -9
- data/README.md +2 -2
- data/Rakefile +10 -8
- data/TESTING.md +82 -0
- data/lib/vagrant/ssh/config/manager.rb +5 -0
- data/lib/vagrant_ssh_config_manager/action/destroy.rb +82 -0
- data/lib/vagrant_ssh_config_manager/action/halt.rb +66 -0
- data/lib/vagrant_ssh_config_manager/action/provision.rb +81 -0
- data/lib/vagrant_ssh_config_manager/action/reload.rb +105 -0
- data/lib/vagrant_ssh_config_manager/action/up.rb +98 -0
- data/lib/{vagrant-ssh-config-manager → vagrant_ssh_config_manager}/config.rb +45 -49
- data/lib/{vagrant-ssh-config-manager → vagrant_ssh_config_manager}/file_locker.rb +35 -37
- data/lib/{vagrant-ssh-config-manager → vagrant_ssh_config_manager}/file_manager.rb +90 -80
- data/lib/{vagrant-ssh-config-manager → vagrant_ssh_config_manager}/include_manager.rb +54 -53
- data/lib/{vagrant-ssh-config-manager → vagrant_ssh_config_manager}/plugin.rb +15 -13
- data/lib/vagrant_ssh_config_manager/ssh_config_manager.rb +1152 -0
- data/lib/{vagrant-ssh-config-manager → vagrant_ssh_config_manager}/ssh_info_extractor.rb +129 -141
- data/lib/vagrant_ssh_config_manager/version.rb +7 -0
- data/lib/{vagrant-ssh-config-manager.rb → vagrant_ssh_config_manager.rb} +15 -12
- data/test-all.sh +11 -0
- data/test-integration.sh +4 -0
- data/test-unit.sh +4 -0
- data/vagrant-ssh-config-manager.gemspec +25 -21
- metadata +28 -18
- data/lib/vagrant-ssh-config-manager/action/destroy.rb +0 -84
- data/lib/vagrant-ssh-config-manager/action/halt.rb +0 -68
- data/lib/vagrant-ssh-config-manager/action/provision.rb +0 -82
- data/lib/vagrant-ssh-config-manager/action/reload.rb +0 -106
- data/lib/vagrant-ssh-config-manager/action/up.rb +0 -99
- data/lib/vagrant-ssh-config-manager/ssh_config_manager.rb +0 -2150
- data/lib/vagrant-ssh-config-manager/version.rb +0 -5
@@ -1,48 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module VagrantPlugins
|
2
4
|
module SshConfigManager
|
3
5
|
class SshInfoExtractor
|
4
6
|
def initialize(machine)
|
5
7
|
@machine = machine
|
6
|
-
@logger = Log4r::Logger.new(
|
8
|
+
@logger = Log4r::Logger.new('vagrant::plugins::ssh_config_manager::ssh_info_extractor')
|
7
9
|
end
|
8
10
|
|
9
11
|
# Extract SSH information from Vagrant's internal APIs
|
10
12
|
# This replicates what 'vagrant ssh-config' does but using internal methods
|
11
13
|
def extract_ssh_info
|
12
|
-
|
13
|
-
|
14
|
-
return nil if ssh_info.nil?
|
14
|
+
ssh_info = @machine.ssh_info
|
15
|
+
return nil if ssh_info.nil?
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
# Additional validation for SSH info completeness
|
18
|
+
return nil unless valid_ssh_info?(ssh_info)
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
20
|
+
# Get the SSH configuration similar to what vagrant ssh-config provides
|
21
|
+
config = build_ssh_config(ssh_info)
|
22
|
+
|
23
|
+
@logger&.info("Extracted SSH info for machine: #{@machine.name}")
|
24
|
+
config
|
25
|
+
rescue Vagrant::Errors::SSHNotReady => e
|
26
|
+
@logger&.debug("SSH not ready for machine #{@machine.name}: #{e.message}")
|
27
|
+
nil
|
28
|
+
rescue Vagrant::Errors::SSHUnavailable => e
|
29
|
+
@logger&.debug("SSH unavailable for machine #{@machine.name}: #{e.message}")
|
30
|
+
nil
|
31
|
+
rescue StandardError => e
|
32
|
+
@logger&.warn("Failed to extract SSH info for machine #{@machine.name}: #{e.message}")
|
33
|
+
nil
|
34
34
|
end
|
35
35
|
|
36
36
|
# Check if the machine supports SSH with comprehensive validation
|
37
37
|
def ssh_capable?
|
38
38
|
# Simplified check - if machine is running and has SSH info, assume SSH is available
|
39
|
-
@machine &&
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
@logger.debug("SSH capability check failed: #{e.message}") if @logger
|
39
|
+
@machine&.state &&
|
40
|
+
@machine.state.id == :running &&
|
41
|
+
@machine.ssh_info &&
|
42
|
+
ssh_communicator?
|
43
|
+
rescue StandardError => e
|
44
|
+
@logger&.debug("SSH capability check failed: #{e.message}")
|
46
45
|
false
|
47
46
|
end
|
48
47
|
|
@@ -51,18 +50,18 @@ module VagrantPlugins
|
|
51
50
|
# Basic checks
|
52
51
|
return false unless @machine
|
53
52
|
return false unless @machine.communicate_ready?
|
54
|
-
|
53
|
+
|
55
54
|
# Check if machine state supports SSH
|
56
55
|
return false unless machine_state_supports_ssh?
|
57
|
-
|
56
|
+
|
58
57
|
# Check if communicator is SSH-based
|
59
58
|
return false unless ssh_communicator?
|
60
|
-
|
59
|
+
|
61
60
|
# Check if provider supports SSH
|
62
61
|
return false unless provider_supports_ssh?
|
63
|
-
|
62
|
+
|
64
63
|
true
|
65
|
-
rescue => e
|
64
|
+
rescue StandardError => e
|
66
65
|
@logger.debug("Machine SSH support check failed: #{e.message}")
|
67
66
|
false
|
68
67
|
end
|
@@ -73,11 +72,11 @@ module VagrantPlugins
|
|
73
72
|
def machine_state_supports_ssh?
|
74
73
|
state = @machine.state
|
75
74
|
return false unless state
|
76
|
-
|
75
|
+
|
77
76
|
# Common states that support SSH
|
78
|
-
ssh_ready_states = [
|
77
|
+
ssh_ready_states = %i[running up active created]
|
79
78
|
ssh_ready_states.include?(state.id)
|
80
|
-
rescue
|
79
|
+
rescue StandardError
|
81
80
|
false
|
82
81
|
end
|
83
82
|
|
@@ -85,7 +84,7 @@ module VagrantPlugins
|
|
85
84
|
def ssh_communicator?
|
86
85
|
communicator = @machine.config.vm.communicator
|
87
86
|
communicator.nil? || communicator == :ssh
|
88
|
-
rescue
|
87
|
+
rescue StandardError
|
89
88
|
# Default to assuming SSH if we can't determine
|
90
89
|
true
|
91
90
|
end
|
@@ -94,22 +93,22 @@ module VagrantPlugins
|
|
94
93
|
def provider_supports_ssh?
|
95
94
|
provider_name = @machine.provider_name
|
96
95
|
return true unless provider_name
|
97
|
-
|
96
|
+
|
98
97
|
# List of providers known to support SSH
|
99
|
-
ssh_providers = [
|
100
|
-
|
101
|
-
|
102
|
-
|
98
|
+
ssh_providers = %i[
|
99
|
+
virtualbox vmware_desktop vmware_fusion vmware_workstation
|
100
|
+
libvirt kvm qemu parallels hyper_v lxc docker
|
101
|
+
aws azure google digitalocean linode vultr
|
103
102
|
]
|
104
|
-
|
103
|
+
|
105
104
|
# Providers known to NOT support SSH
|
106
105
|
non_ssh_providers = [:winrm]
|
107
|
-
|
106
|
+
|
108
107
|
return false if non_ssh_providers.include?(provider_name)
|
109
|
-
|
108
|
+
|
110
109
|
# If it's a known SSH provider or unknown (assume SSH), return true
|
111
110
|
ssh_providers.include?(provider_name) || !non_ssh_providers.include?(provider_name)
|
112
|
-
rescue
|
111
|
+
rescue StandardError
|
113
112
|
# Default to assuming SSH support if we can't determine
|
114
113
|
true
|
115
114
|
end
|
@@ -119,85 +118,58 @@ module VagrantPlugins
|
|
119
118
|
return false if ssh_info.nil?
|
120
119
|
return false if ssh_info[:host].nil? || ssh_info[:host].to_s.strip.empty?
|
121
120
|
return false if ssh_info[:port].nil? || ssh_info[:port].to_i <= 0
|
122
|
-
|
121
|
+
|
123
122
|
# Username is not strictly required (can default to 'vagrant')
|
124
123
|
# but if present, it shouldn't be empty
|
125
|
-
if ssh_info[:username]
|
126
|
-
|
127
|
-
end
|
128
|
-
|
124
|
+
return false if ssh_info[:username] && ssh_info[:username].to_s.strip.empty?
|
125
|
+
|
129
126
|
true
|
130
|
-
rescue
|
127
|
+
rescue StandardError
|
131
128
|
false
|
132
129
|
end
|
133
130
|
|
134
131
|
# Enhanced SSH info extraction with edge case handling
|
135
132
|
def extract_ssh_info_safe
|
136
133
|
return nil unless machine_supports_ssh?
|
137
|
-
|
134
|
+
|
138
135
|
retries = 0
|
139
136
|
max_retries = 3
|
140
137
|
retry_delay = 1
|
141
|
-
|
138
|
+
|
142
139
|
begin
|
143
140
|
ssh_info = @machine.ssh_info
|
144
141
|
return nil unless valid_ssh_info?(ssh_info)
|
145
|
-
|
142
|
+
|
146
143
|
build_ssh_config(ssh_info)
|
147
144
|
rescue Vagrant::Errors::SSHNotReady => e
|
148
145
|
retries += 1
|
149
146
|
if retries <= max_retries
|
150
147
|
@logger.debug("SSH not ready, retrying in #{retry_delay}s (attempt #{retries}/#{max_retries})")
|
151
148
|
sleep(retry_delay)
|
152
|
-
retry_delay *= 2
|
149
|
+
retry_delay *= 2 # Exponential backoff
|
153
150
|
retry
|
154
151
|
else
|
155
152
|
@logger.debug("SSH still not ready after #{max_retries} attempts")
|
156
153
|
nil
|
157
154
|
end
|
158
|
-
rescue => e
|
155
|
+
rescue StandardError => e
|
159
156
|
@logger.warn("SSH info extraction failed: #{e.message}")
|
160
157
|
nil
|
161
158
|
end
|
162
159
|
end
|
163
160
|
|
164
|
-
# Safe host name generation with fallbacks
|
165
|
-
def generate_host_name
|
166
|
-
begin
|
167
|
-
# Generate a unique host name based on project directory and machine name
|
168
|
-
project_name = File.basename(@machine.env.root_path)
|
169
|
-
machine_name = @machine.name.to_s
|
170
|
-
|
171
|
-
# Sanitize names for SSH config
|
172
|
-
project_name = sanitize_name(project_name)
|
173
|
-
machine_name = sanitize_name(machine_name)
|
174
|
-
|
175
|
-
host_name = "#{project_name}-#{machine_name}"
|
176
|
-
|
177
|
-
# Ensure the host name is not empty after sanitization
|
178
|
-
if host_name.strip.empty? || host_name == '-'
|
179
|
-
host_name = "vagrant-#{@machine.id || 'unknown'}"
|
180
|
-
end
|
181
|
-
|
182
|
-
host_name
|
183
|
-
rescue => e
|
184
|
-
@logger.debug("Host name generation failed: #{e.message}")
|
185
|
-
"vagrant-#{@machine.name || 'unknown'}"
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
161
|
# Normalize SSH config data to ensure consistency
|
190
162
|
def normalize_ssh_config(config)
|
191
163
|
normalized = {}
|
192
|
-
|
164
|
+
|
193
165
|
config.each do |key, value|
|
194
166
|
# Normalize key names to proper SSH config format
|
195
167
|
normalized_key = normalize_config_key(key)
|
196
168
|
normalized_value = normalize_config_value(key, value)
|
197
|
-
|
169
|
+
|
198
170
|
normalized[normalized_key] = normalized_value if normalized_value
|
199
171
|
end
|
200
|
-
|
172
|
+
|
201
173
|
normalized
|
202
174
|
end
|
203
175
|
|
@@ -205,11 +177,11 @@ module VagrantPlugins
|
|
205
177
|
def parse_ssh_config_entry(entry_text)
|
206
178
|
config = {}
|
207
179
|
current_host = nil
|
208
|
-
|
180
|
+
|
209
181
|
entry_text.split("\n").each do |line|
|
210
182
|
line = line.strip
|
211
183
|
next if line.empty? || line.start_with?('#')
|
212
|
-
|
184
|
+
|
213
185
|
if line.start_with?('Host ')
|
214
186
|
current_host = line.sub(/^Host\s+/, '').strip
|
215
187
|
config['Host'] = current_host
|
@@ -218,18 +190,18 @@ module VagrantPlugins
|
|
218
190
|
config[key.strip] = value.strip
|
219
191
|
end
|
220
192
|
end
|
221
|
-
|
193
|
+
|
222
194
|
config
|
223
195
|
end
|
224
196
|
|
225
197
|
# Convert normalized config back to SSH config file format
|
226
198
|
def to_ssh_config_format(config)
|
227
199
|
lines = []
|
228
|
-
|
200
|
+
|
229
201
|
# Host entry always comes first
|
230
202
|
if config['Host']
|
231
203
|
lines << "Host #{config['Host']}"
|
232
|
-
|
204
|
+
|
233
205
|
# Add other entries in a logical order
|
234
206
|
ssh_option_order = %w[
|
235
207
|
HostName User Port IdentityFile IdentitiesOnly
|
@@ -237,25 +209,22 @@ module VagrantPlugins
|
|
237
209
|
LogLevel ProxyCommand Compression CompressionLevel
|
238
210
|
ConnectTimeout ForwardAgent ForwardX11
|
239
211
|
]
|
240
|
-
|
212
|
+
|
241
213
|
ssh_option_order.each do |key|
|
242
|
-
if config[key]
|
243
|
-
lines << " #{key} #{config[key]}"
|
244
|
-
end
|
214
|
+
lines << " #{key} #{config[key]}" if config[key]
|
245
215
|
end
|
246
|
-
|
216
|
+
|
247
217
|
# Add any remaining options not in the predefined order
|
248
218
|
config.each do |key, value|
|
249
219
|
next if key == 'Host' || ssh_option_order.include?(key)
|
220
|
+
|
250
221
|
lines << " #{key} #{value}"
|
251
222
|
end
|
252
223
|
end
|
253
|
-
|
224
|
+
|
254
225
|
lines.join("\n")
|
255
226
|
end
|
256
227
|
|
257
|
-
private
|
258
|
-
|
259
228
|
def build_ssh_config(ssh_info)
|
260
229
|
config = {
|
261
230
|
'Host' => generate_host_name,
|
@@ -267,23 +236,23 @@ module VagrantPlugins
|
|
267
236
|
# Add SSH key information
|
268
237
|
if ssh_info[:private_key_path] && !ssh_info[:private_key_path].empty?
|
269
238
|
# Use the first private key if multiple are provided
|
270
|
-
key_path = ssh_info[:private_key_path].is_a?(Array)
|
271
|
-
|
272
|
-
|
239
|
+
key_path = if ssh_info[:private_key_path].is_a?(Array)
|
240
|
+
ssh_info[:private_key_path].first
|
241
|
+
else
|
242
|
+
ssh_info[:private_key_path]
|
243
|
+
end
|
273
244
|
config['IdentityFile'] = key_path
|
274
245
|
config['IdentitiesOnly'] = 'yes'
|
275
246
|
end
|
276
247
|
|
277
248
|
# Add common SSH options for Vagrant VMs
|
278
249
|
config['StrictHostKeyChecking'] = 'no'
|
279
|
-
config['UserKnownHostsFile'] =
|
250
|
+
config['UserKnownHostsFile'] = File::NULL
|
280
251
|
config['PasswordAuthentication'] = 'no'
|
281
252
|
config['LogLevel'] = 'FATAL'
|
282
253
|
|
283
254
|
# Add proxy command if using a proxy
|
284
|
-
if ssh_info[:proxy_command]
|
285
|
-
config['ProxyCommand'] = ssh_info[:proxy_command]
|
286
|
-
end
|
255
|
+
config['ProxyCommand'] = ssh_info[:proxy_command] if ssh_info[:proxy_command]
|
287
256
|
|
288
257
|
# Add comprehensive SSH options from the machine config
|
289
258
|
add_comprehensive_ssh_options(config, ssh_info)
|
@@ -294,69 +263,88 @@ module VagrantPlugins
|
|
294
263
|
|
295
264
|
# Add comprehensive SSH options support
|
296
265
|
def add_comprehensive_ssh_options(config, ssh_info)
|
297
|
-
return unless ssh_info[:config]
|
298
|
-
|
266
|
+
return unless ssh_info[:config]&.ssh
|
267
|
+
|
299
268
|
ssh_config = ssh_info[:config].ssh
|
300
|
-
|
269
|
+
|
301
270
|
# Connection options
|
302
|
-
config['Compression'] = ssh_config.compression ? 'yes' : 'no'
|
271
|
+
config['Compression'] = ssh_config.compression ? 'yes' : 'no' unless ssh_config.compression.nil?
|
303
272
|
config['CompressionLevel'] = ssh_config.compression_level.to_s if ssh_config.compression_level
|
304
273
|
config['ConnectTimeout'] = ssh_config.connect_timeout.to_s if ssh_config.connect_timeout
|
305
274
|
config['ConnectionAttempts'] = ssh_config.connection_attempts.to_s if ssh_config.connection_attempts
|
306
275
|
config['ServerAliveInterval'] = ssh_config.server_alive_interval.to_s if ssh_config.server_alive_interval
|
307
276
|
config['ServerAliveCountMax'] = ssh_config.server_alive_count_max.to_s if ssh_config.server_alive_count_max
|
308
|
-
|
277
|
+
|
309
278
|
# Authentication options
|
310
|
-
config['ForwardAgent'] = ssh_config.forward_agent ? 'yes' : 'no'
|
311
|
-
|
312
|
-
|
313
|
-
|
279
|
+
config['ForwardAgent'] = ssh_config.forward_agent ? 'yes' : 'no' unless ssh_config.forward_agent.nil?
|
280
|
+
unless ssh_config.pubkey_authentication.nil?
|
281
|
+
config['PubkeyAuthentication'] =
|
282
|
+
ssh_config.pubkey_authentication ? 'yes' : 'no'
|
283
|
+
end
|
284
|
+
if ssh_config.preferred_authentications
|
285
|
+
config['PreferredAuthentications'] =
|
286
|
+
ssh_config.preferred_authentications
|
287
|
+
end
|
288
|
+
|
314
289
|
# Forwarding options
|
315
|
-
config['ForwardX11'] = ssh_config.forward_x11 ? 'yes' : 'no'
|
316
|
-
|
317
|
-
|
290
|
+
config['ForwardX11'] = ssh_config.forward_x11 ? 'yes' : 'no' unless ssh_config.forward_x11.nil?
|
291
|
+
unless ssh_config.forward_x11_trusted.nil?
|
292
|
+
config['ForwardX11Trusted'] =
|
293
|
+
ssh_config.forward_x11_trusted ? 'yes' : 'no'
|
294
|
+
end
|
295
|
+
|
318
296
|
# Security options
|
319
|
-
|
320
|
-
|
321
|
-
|
297
|
+
unless ssh_config.verify_host_key.nil?
|
298
|
+
config['StrictHostKeyChecking'] =
|
299
|
+
ssh_config.verify_host_key ? 'yes' : 'no'
|
300
|
+
end
|
301
|
+
config['CheckHostIP'] = ssh_config.check_host_ip ? 'yes' : 'no' unless ssh_config.check_host_ip.nil?
|
302
|
+
|
322
303
|
# Protocol options
|
323
304
|
config['Protocol'] = ssh_config.protocol if ssh_config.protocol
|
324
305
|
config['Ciphers'] = ssh_config.ciphers.join(',') if ssh_config.ciphers && !ssh_config.ciphers.empty?
|
325
306
|
config['MACs'] = ssh_config.macs.join(',') if ssh_config.macs && !ssh_config.macs.empty?
|
326
|
-
|
327
|
-
|
307
|
+
if ssh_config.kex_algorithms && !ssh_config.kex_algorithms.empty?
|
308
|
+
config['KexAlgorithms'] =
|
309
|
+
ssh_config.kex_algorithms.join(',')
|
310
|
+
end
|
311
|
+
|
328
312
|
# Terminal options
|
329
|
-
config['RequestTTY'] = ssh_config.pty ? 'yes' : 'no'
|
313
|
+
config['RequestTTY'] = ssh_config.pty ? 'yes' : 'no' unless ssh_config.pty.nil?
|
330
314
|
config['RemoteCommand'] = ssh_config.remote_command if ssh_config.remote_command
|
331
|
-
|
315
|
+
|
332
316
|
# File and directory options
|
333
317
|
config['ControlMaster'] = ssh_config.control_master if ssh_config.control_master
|
334
318
|
config['ControlPath'] = ssh_config.control_path if ssh_config.control_path
|
335
319
|
config['ControlPersist'] = ssh_config.control_persist.to_s if ssh_config.control_persist
|
336
|
-
|
320
|
+
|
337
321
|
# Logging options
|
338
322
|
config['LogLevel'] = ssh_config.log_level.to_s.upcase if ssh_config.log_level
|
339
323
|
config['SyslogFacility'] = ssh_config.syslog_facility if ssh_config.syslog_facility
|
340
|
-
|
324
|
+
|
341
325
|
# Banner and environment
|
342
326
|
config['Banner'] = ssh_config.banner if ssh_config.banner
|
343
327
|
config['SendEnv'] = ssh_config.send_env.join(' ') if ssh_config.send_env && !ssh_config.send_env.empty?
|
344
|
-
|
345
|
-
|
328
|
+
if ssh_config.set_env && !ssh_config.set_env.empty?
|
329
|
+
config['SetEnv'] = ssh_config.set_env.map do |k, v|
|
330
|
+
"#{k}=#{v}"
|
331
|
+
end.join(' ')
|
332
|
+
end
|
333
|
+
|
346
334
|
# Keep alive options
|
347
|
-
config['TCPKeepAlive'] = ssh_config.tcp_keep_alive ? 'yes' : 'no'
|
348
|
-
|
335
|
+
config['TCPKeepAlive'] = ssh_config.tcp_keep_alive ? 'yes' : 'no' unless ssh_config.tcp_keep_alive.nil?
|
336
|
+
|
349
337
|
# Escape character
|
350
338
|
config['EscapeChar'] = ssh_config.escape_char if ssh_config.escape_char
|
351
|
-
|
339
|
+
|
352
340
|
# Gateway options
|
353
341
|
config['ProxyJump'] = ssh_config.proxy_jump if ssh_config.proxy_jump
|
354
|
-
|
342
|
+
|
355
343
|
# Add any custom options that might be defined
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
344
|
+
return unless ssh_config.respond_to?(:extra_options) && ssh_config.extra_options
|
345
|
+
|
346
|
+
ssh_config.extra_options.each do |key, value|
|
347
|
+
config[key.to_s] = value.to_s
|
360
348
|
end
|
361
349
|
end
|
362
350
|
|
@@ -364,11 +352,11 @@ module VagrantPlugins
|
|
364
352
|
# Generate a unique host name based on project directory and machine name
|
365
353
|
project_name = File.basename(@machine.env.root_path)
|
366
354
|
machine_name = @machine.name.to_s
|
367
|
-
|
355
|
+
|
368
356
|
# Sanitize names for SSH config
|
369
357
|
project_name = sanitize_name(project_name)
|
370
358
|
machine_name = sanitize_name(machine_name)
|
371
|
-
|
359
|
+
|
372
360
|
"#{project_name}-#{machine_name}"
|
373
361
|
end
|
374
362
|
|
@@ -409,18 +397,18 @@ module VagrantPlugins
|
|
409
397
|
'forward_x11' => 'ForwardX11',
|
410
398
|
'forwardx11' => 'ForwardX11'
|
411
399
|
}
|
412
|
-
|
400
|
+
|
413
401
|
key_str = key.to_s.downcase
|
414
402
|
key_mappings[key_str] || key.to_s
|
415
403
|
end
|
416
404
|
|
417
405
|
def normalize_config_value(key, value)
|
418
406
|
return nil if value.nil? || value.to_s.strip.empty?
|
419
|
-
|
407
|
+
|
420
408
|
case key.to_s.downcase
|
421
409
|
when 'port'
|
422
410
|
value.to_i.to_s
|
423
|
-
when 'compression', 'identitiesonly', 'stricthostkeychecking',
|
411
|
+
when 'compression', 'identitiesonly', 'stricthostkeychecking',
|
424
412
|
'passwordauthentication', 'forwardagent', 'forwardx11'
|
425
413
|
# Normalize boolean-like values
|
426
414
|
case value.to_s.downcase
|
@@ -1,30 +1,33 @@
|
|
1
|
-
|
2
|
-
require "vagrant-ssh-config-manager/plugin"
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
3
|
+
require 'vagrant_ssh_config_manager/version'
|
4
|
+
require 'vagrant_ssh_config_manager/plugin'
|
5
|
+
|
6
|
+
# Main entrypoint module for SSH Config Manager plugin
|
4
7
|
module VagrantPlugins
|
5
8
|
module SshConfigManager
|
6
9
|
# Main plugin entry point
|
7
10
|
# This file is loaded when the plugin is activated
|
8
|
-
|
11
|
+
|
9
12
|
# Lazy load other components only when needed
|
10
13
|
def self.require_file_manager
|
11
|
-
require
|
14
|
+
require 'vagrant_ssh_config_manager/file_manager' unless defined?(FileManager)
|
12
15
|
end
|
13
|
-
|
16
|
+
|
14
17
|
def self.require_include_manager
|
15
|
-
require
|
18
|
+
require 'vagrant_ssh_config_manager/include_manager' unless defined?(IncludeManager)
|
16
19
|
end
|
17
|
-
|
20
|
+
|
18
21
|
def self.require_ssh_info_extractor
|
19
|
-
require
|
22
|
+
require 'vagrant_ssh_config_manager/ssh_info_extractor' unless defined?(SshInfoExtractor)
|
20
23
|
end
|
21
|
-
|
24
|
+
|
22
25
|
def self.require_file_locker
|
23
|
-
require
|
26
|
+
require 'vagrant_ssh_config_manager/file_locker' unless defined?(FileLocker)
|
24
27
|
end
|
25
|
-
|
28
|
+
|
26
29
|
def self.require_config
|
27
|
-
require
|
30
|
+
require 'vagrant_ssh_config_manager/config' unless defined?(Config)
|
28
31
|
end
|
29
32
|
end
|
30
33
|
end
|
data/test-all.sh
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
# Run all tests
|
3
|
+
echo "🎯 Running Whole Test Suite..."
|
4
|
+
echo ""
|
5
|
+
echo "📦 Unit Tests (Fast, Mocked):"
|
6
|
+
bundle exec rspec spec/unit/ --format progress
|
7
|
+
echo ""
|
8
|
+
echo "🔗 Integration Tests (Real APIs):"
|
9
|
+
bundle exec rspec spec/integration/ --format progress
|
10
|
+
echo ""
|
11
|
+
echo "✅ Testing complete!"
|
data/test-integration.sh
ADDED
data/test-unit.sh
ADDED
@@ -1,39 +1,43 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
2
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
-
require
|
5
|
+
require 'vagrant_ssh_config_manager/version'
|
4
6
|
|
5
7
|
Gem::Specification.new do |spec|
|
6
|
-
spec.name =
|
8
|
+
spec.name = 'vagrant-ssh-config-manager'
|
7
9
|
spec.version = VagrantPlugins::SshConfigManager::VERSION
|
8
|
-
spec.authors = [
|
9
|
-
spec.email = [
|
10
|
+
spec.authors = ['Marek Ruzicka']
|
11
|
+
spec.email = ['marek.ruzicka@glide.sk']
|
10
12
|
|
11
|
-
spec.summary =
|
12
|
-
spec.description =
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
13
|
+
spec.summary = 'Vagrant plugin that automatically manages SSH configurations'
|
14
|
+
spec.description = 'A Vagrant plugin that automatically manages SSH configurations. Creates and maintains SSH config entries when VMs are started and cleans them up when VMs are destroyed, with environment isolation and file locking support.'
|
15
|
+
spec.homepage = 'https://github.com/marekruzicka/vagrant-ssh-config-manager'
|
16
|
+
spec.license = 'MIT'
|
15
17
|
|
16
|
-
spec.metadata[
|
17
|
-
spec.metadata[
|
18
|
-
spec.metadata[
|
18
|
+
spec.metadata['documentation_uri'] = 'https://rubydoc.info/github/marekruzicka/vagrant-ssh-config-manager/main'
|
19
|
+
spec.metadata['source_code_uri'] = 'https://github.com/marekruzicka/vagrant-ssh-config-manager'
|
20
|
+
spec.metadata['changelog_uri'] = 'https://github.com/marekruzicka/vagrant-ssh-config-manager/blob/main/CHANGELOG.md'
|
19
21
|
|
20
22
|
# Specify which files should be added to the gem when it is released.
|
21
23
|
# The `git ls-files -z` loads the files in the RubyGems gemspec, but not Git submodules.
|
22
|
-
spec.files
|
24
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
23
25
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|tasks|.github|.ai)/}) }
|
24
26
|
end
|
25
|
-
|
27
|
+
# Include the direct entrypoint under vagrant/ssh/config in case it's not tracked
|
28
|
+
spec.files << 'lib/vagrant/ssh/config/manager.rb'
|
29
|
+
spec.require_paths = ['lib']
|
26
30
|
|
27
31
|
# Development dependencies
|
28
|
-
spec.add_development_dependency
|
29
|
-
spec.add_development_dependency
|
30
|
-
spec.add_development_dependency
|
31
|
-
spec.add_development_dependency
|
32
|
-
spec.add_development_dependency
|
32
|
+
spec.add_development_dependency 'bundler', '~> 2.0'
|
33
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
34
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
35
|
+
spec.add_development_dependency 'rspec-mocks', '~> 3.0'
|
36
|
+
spec.add_development_dependency 'simplecov', '~> 0.21'
|
33
37
|
|
34
38
|
# Ensure compatibility with supported Ruby versions
|
35
|
-
spec.required_ruby_version =
|
39
|
+
spec.required_ruby_version = '>= 3.0.0'
|
36
40
|
|
37
41
|
# Plugin metadata for Vagrant
|
38
|
-
spec.metadata[
|
42
|
+
spec.metadata['vagrant_plugin'] = 'true'
|
39
43
|
end
|