train-juniper 0.6.2 → 0.7.1
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/CHANGELOG.md +69 -9
- data/README.md +30 -13
- data/Rakefile +23 -16
- data/lib/train-juniper/connection/bastion_proxy.rb +92 -0
- data/lib/train-juniper/connection/command_executor.rb +112 -0
- data/lib/train-juniper/connection/error_handling.rb +71 -0
- data/lib/train-juniper/connection/ssh_session.rb +106 -0
- data/lib/train-juniper/connection/validation.rb +63 -0
- data/lib/train-juniper/connection.rb +120 -331
- data/lib/train-juniper/constants.rb +40 -0
- data/lib/train-juniper/file_abstraction/juniper_file.rb +69 -0
- data/lib/train-juniper/helpers/environment.rb +30 -0
- data/lib/train-juniper/helpers/logging.rb +77 -0
- data/lib/train-juniper/helpers/mock_responses.rb +57 -0
- data/lib/train-juniper/platform.rb +53 -82
- data/lib/train-juniper/transport.rb +13 -1
- data/lib/train-juniper/version.rb +2 -1
- data/train-juniper.gemspec +16 -0
- metadata +152 -2
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TrainPlugins
|
4
|
+
module Juniper
|
5
|
+
# Helper methods for safely handling environment variables
|
6
|
+
module Environment
|
7
|
+
# Helper method to safely get environment variable value
|
8
|
+
# Returns nil if env var is not set or is empty string
|
9
|
+
# @param key [String] The environment variable name
|
10
|
+
# @return [String, nil] The value or nil if not set/empty
|
11
|
+
def env_value(key)
|
12
|
+
value = ENV.fetch(key, nil)
|
13
|
+
return nil if value.nil? || value.empty?
|
14
|
+
|
15
|
+
value
|
16
|
+
end
|
17
|
+
|
18
|
+
# Helper method to get environment variable as integer
|
19
|
+
# Returns nil if env var is not set, empty, or not a valid integer
|
20
|
+
# @param key [String] The environment variable name
|
21
|
+
# @return [Integer, nil] The integer value or nil if not valid
|
22
|
+
def env_int(key)
|
23
|
+
value = env_value(key)
|
24
|
+
return nil unless value
|
25
|
+
|
26
|
+
value.to_i
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TrainPlugins
|
4
|
+
module Juniper
|
5
|
+
# Provides consistent logging patterns across the plugin
|
6
|
+
module Logging
|
7
|
+
# Log a command execution attempt
|
8
|
+
# @param cmd [String] The command being executed
|
9
|
+
def log_command(cmd)
|
10
|
+
@logger.debug("Executing command: #{cmd}")
|
11
|
+
end
|
12
|
+
|
13
|
+
# Log a connection attempt
|
14
|
+
# @param target [String] The host/target being connected to
|
15
|
+
# @param port [Integer] The port number
|
16
|
+
def log_connection_attempt(target, port = nil)
|
17
|
+
if port
|
18
|
+
@logger.debug("Attempting connection to #{target}:#{port}")
|
19
|
+
else
|
20
|
+
@logger.debug("Attempting connection to #{target}")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Log an error with consistent formatting
|
25
|
+
# @param error [Exception, String] The error to log
|
26
|
+
# @param context [String] Additional context for the error
|
27
|
+
def log_error(error, context = nil)
|
28
|
+
message = if error.is_a?(Exception)
|
29
|
+
"#{error.class}: #{error.message}"
|
30
|
+
else
|
31
|
+
error.to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
if context
|
35
|
+
@logger.error("#{context}: #{message}")
|
36
|
+
else
|
37
|
+
@logger.error(message)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Log successful connection
|
42
|
+
# @param target [String] The host that was connected to
|
43
|
+
def log_connection_success(target)
|
44
|
+
@logger.info("Successfully connected to #{target}")
|
45
|
+
end
|
46
|
+
|
47
|
+
# Log SSH session details (redacting sensitive info)
|
48
|
+
# @param options [Hash] SSH options hash
|
49
|
+
def log_ssh_options(options)
|
50
|
+
safe_options = options.dup
|
51
|
+
safe_options[:password] = '[REDACTED]' if safe_options[:password]
|
52
|
+
safe_options[:passphrase] = '[REDACTED]' if safe_options[:passphrase]
|
53
|
+
safe_options[:keys] = safe_options[:keys]&.map { |k| File.basename(k) } if safe_options[:keys]
|
54
|
+
|
55
|
+
@logger.debug("SSH options: #{safe_options.inspect}")
|
56
|
+
end
|
57
|
+
|
58
|
+
# Log platform detection results
|
59
|
+
# @param platform_name [String] Detected platform name
|
60
|
+
# @param version [String] Detected version
|
61
|
+
def log_platform_detection(platform_name, version)
|
62
|
+
@logger.info("Platform detected: #{platform_name} #{version}")
|
63
|
+
end
|
64
|
+
|
65
|
+
# Log bastion connection attempt
|
66
|
+
# @param bastion_host [String] The bastion host
|
67
|
+
def log_bastion_connection(bastion_host)
|
68
|
+
@logger.debug("Connecting through bastion host: #{bastion_host}")
|
69
|
+
end
|
70
|
+
|
71
|
+
# Log mock mode activation
|
72
|
+
def log_mock_mode
|
73
|
+
@logger.info('Running in mock mode - no real device connection')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Mock responses for Juniper device commands
|
4
|
+
# This module contains all mock data used in testing and mock mode
|
5
|
+
module TrainPlugins
|
6
|
+
module Juniper
|
7
|
+
# Mock responses for common JunOS commands
|
8
|
+
# Used when running in mock mode for testing without real devices
|
9
|
+
module MockResponses
|
10
|
+
# Configuration of mock responses
|
11
|
+
# Maps command patterns to response methods or strings
|
12
|
+
RESPONSES = {
|
13
|
+
'show version' => :mock_show_version_output,
|
14
|
+
'show chassis hardware' => :mock_chassis_output,
|
15
|
+
'show configuration' => "interfaces {\n ge-0/0/0 {\n unit 0;\n }\n}",
|
16
|
+
'show route' => "inet.0: 5 destinations, 5 routes\n0.0.0.0/0 *[Static/5] 00:00:01\n",
|
17
|
+
'show system information' => "Hardware: SRX240H2\nOS: JUNOS 12.1X47-D15.4\n",
|
18
|
+
'show interfaces' => "Physical interface: ge-0/0/0, Enabled, Physical link is Up\n"
|
19
|
+
}.freeze
|
20
|
+
|
21
|
+
# Mock JunOS version output for testing
|
22
|
+
# @return [String] mock output for 'show version' command
|
23
|
+
def self.mock_show_version_output
|
24
|
+
<<~OUTPUT
|
25
|
+
Hostname: lab-srx
|
26
|
+
Model: SRX240H2
|
27
|
+
Junos: 12.1X47-D15.4
|
28
|
+
JUNOS Software Release [12.1X47-D15.4]
|
29
|
+
OUTPUT
|
30
|
+
end
|
31
|
+
|
32
|
+
# Mock chassis hardware output
|
33
|
+
# @return [String] mock output for 'show chassis hardware' command
|
34
|
+
def self.mock_chassis_output
|
35
|
+
<<~OUTPUT
|
36
|
+
Hardware inventory:
|
37
|
+
Item Version Part number Serial number Description
|
38
|
+
Chassis JN123456 SRX240H2
|
39
|
+
OUTPUT
|
40
|
+
end
|
41
|
+
|
42
|
+
# Get mock response for a command
|
43
|
+
# @param cmd [String] the command to get response for
|
44
|
+
# @return [Array<String, Integer>] tuple of [output, exit_status]
|
45
|
+
def self.response_for(cmd)
|
46
|
+
response = RESPONSES.find { |pattern, _| cmd.match?(/#{pattern}/) }
|
47
|
+
|
48
|
+
if response
|
49
|
+
output = response[1].is_a?(Symbol) ? send(response[1]) : response[1]
|
50
|
+
[output, 0]
|
51
|
+
else
|
52
|
+
["% Unknown command: #{cmd}", 1]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -5,16 +5,19 @@
|
|
5
5
|
|
6
6
|
module TrainPlugins::Juniper
|
7
7
|
# Platform detection mixin for Juniper network devices
|
8
|
+
# @note This module is mixed into the Connection class to provide platform detection
|
8
9
|
module Platform
|
9
10
|
# Platform name constant for consistency
|
10
11
|
PLATFORM_NAME = 'juniper'
|
11
12
|
|
12
13
|
# Platform detection for Juniper network devices
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
14
|
+
# @return [Train::Platform] Platform object with JunOS details
|
15
|
+
# @note Uses force_platform! to bypass Train's automatic detection
|
16
|
+
# @example
|
17
|
+
# platform = connection.platform
|
18
|
+
# platform.name #=> "juniper"
|
19
|
+
# platform.release #=> "12.1X47-D15.4"
|
20
|
+
# platform.arch #=> "x86_64"
|
18
21
|
def platform
|
19
22
|
# Return cached platform if already computed
|
20
23
|
return @platform if defined?(@platform)
|
@@ -39,73 +42,75 @@ module TrainPlugins::Juniper
|
|
39
42
|
platform_obj = force_platform!(PLATFORM_NAME, platform_details)
|
40
43
|
logger&.debug("Set platform data: #{platform_obj.platform}")
|
41
44
|
|
45
|
+
# Log platform detection results if logging helpers available
|
46
|
+
log_platform_detection(PLATFORM_NAME, device_version) if respond_to?(:log_platform_detection)
|
47
|
+
|
42
48
|
# Cache the platform object to prevent repeated calls
|
43
49
|
@platform = platform_obj
|
44
50
|
end
|
45
51
|
|
46
52
|
private
|
47
53
|
|
48
|
-
#
|
49
|
-
#
|
50
|
-
|
51
|
-
|
52
|
-
|
54
|
+
# Generic detection helper for version and architecture
|
55
|
+
# @param attribute_name [String] Name of the attribute to detect
|
56
|
+
# @param command [String] Command to run (default: 'show version')
|
57
|
+
# @yield [String] Block that extracts the attribute from command output
|
58
|
+
# @return [String, nil] Detected attribute value or nil
|
59
|
+
def detect_attribute(attribute_name, command = 'show version', &extraction_block)
|
60
|
+
cache_var = "@detected_#{attribute_name}"
|
61
|
+
return instance_variable_get(cache_var) if instance_variable_defined?(cache_var)
|
53
62
|
|
54
|
-
# Only try version detection if we have an active connection
|
55
63
|
unless respond_to?(:run_command_via_connection)
|
56
64
|
logger&.debug('run_command_via_connection not available yet')
|
57
|
-
return
|
65
|
+
return instance_variable_set(cache_var, nil)
|
58
66
|
end
|
59
67
|
|
60
68
|
logger&.debug("Mock mode: #{@options&.dig(:mock)}, Connected: #{connected?}")
|
61
69
|
|
62
70
|
begin
|
63
|
-
|
64
|
-
unless connected?
|
65
|
-
logger&.debug('Not connected, skipping version detection')
|
66
|
-
return @detected_junos_version = nil
|
67
|
-
end
|
68
|
-
|
69
|
-
# Execute 'show version' command to get JunOS information
|
70
|
-
logger&.debug("Running 'show version' command")
|
71
|
-
result = run_command_via_connection('show version')
|
71
|
+
return instance_variable_set(cache_var, nil) unless connected?
|
72
72
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
end
|
73
|
+
# Reuse cached command result if available
|
74
|
+
result = @cached_show_version_result || run_command_via_connection(command)
|
75
|
+
@cached_show_version_result ||= result if command == 'show version' && result&.exit_status&.zero?
|
77
76
|
|
78
|
-
|
79
|
-
@cached_show_version_result = result
|
77
|
+
return instance_variable_set(cache_var, nil) unless result&.exit_status&.zero?
|
80
78
|
|
81
|
-
|
82
|
-
version = extract_version_from_output(result.stdout)
|
79
|
+
value = extraction_block.call(result.stdout)
|
83
80
|
|
84
|
-
if
|
85
|
-
logger&.debug("Detected
|
86
|
-
|
81
|
+
if value
|
82
|
+
logger&.debug("Detected #{attribute_name}: #{value}")
|
83
|
+
instance_variable_set(cache_var, value)
|
87
84
|
else
|
88
|
-
logger&.debug("Could not parse
|
89
|
-
|
85
|
+
logger&.debug("Could not parse #{attribute_name} from: #{result.stdout[0..100]}")
|
86
|
+
instance_variable_set(cache_var, nil)
|
90
87
|
end
|
91
88
|
rescue StandardError => e
|
92
|
-
#
|
93
|
-
|
94
|
-
@detected_junos_version = nil
|
89
|
+
logger&.debug("#{attribute_name} detection failed: #{e.message}")
|
90
|
+
instance_variable_set(cache_var, nil)
|
95
91
|
end
|
96
92
|
end
|
97
93
|
|
94
|
+
# Detect JunOS version from device output
|
95
|
+
# @return [String, nil] JunOS version string or nil if not detected
|
96
|
+
# @note This runs safely after the connection is established
|
97
|
+
def detect_junos_version
|
98
|
+
detect_attribute('junos_version') { |output| extract_version_from_output(output) }
|
99
|
+
end
|
100
|
+
|
98
101
|
# Extract version string from JunOS show version output
|
102
|
+
# @param output [String] Raw output from 'show version' command
|
103
|
+
# @return [String, nil] Extracted version string or nil
|
99
104
|
def extract_version_from_output(output)
|
100
105
|
return nil if output.nil? || output.empty?
|
101
106
|
|
102
107
|
# Try multiple JunOS version patterns
|
103
108
|
patterns = [
|
104
|
-
/Junos:\s+([\d
|
105
|
-
/JUNOS Software Release \[([\d
|
106
|
-
/junos version ([\d
|
107
|
-
/Model: \S+, JUNOS Base OS boot \[([\d
|
108
|
-
/([\d]+\.[\d]+[\w
|
109
|
+
/Junos:\s+([\w\d.-]+)/, # "Junos: 12.1X47-D15.4"
|
110
|
+
/JUNOS Software Release \[([\w\d.-]+)\]/, # "JUNOS Software Release [12.1X47-D15.4]"
|
111
|
+
/junos version ([\w\d.-]+)/i, # "junos version 21.4R3"
|
112
|
+
/Model: \S+, JUNOS Base OS boot \[([\w\d.-]+)\]/, # Some hardware variants
|
113
|
+
/([\d]+\.[\d]+[\w.-]*)/ # Generic version pattern
|
109
114
|
]
|
110
115
|
|
111
116
|
patterns.each do |pattern|
|
@@ -117,56 +122,22 @@ module TrainPlugins::Juniper
|
|
117
122
|
end
|
118
123
|
|
119
124
|
# Detect JunOS architecture from device output
|
120
|
-
#
|
125
|
+
# @return [String, nil] Architecture string or nil if not detected
|
126
|
+
# @note This runs safely after the connection is established
|
121
127
|
def detect_junos_architecture
|
122
|
-
|
123
|
-
return @detected_junos_architecture if defined?(@detected_junos_architecture)
|
124
|
-
|
125
|
-
# Only try architecture detection if we have an active connection
|
126
|
-
return @detected_junos_architecture = nil unless respond_to?(:run_command_via_connection)
|
127
|
-
|
128
|
-
begin
|
129
|
-
# Check if connection is ready before running commands
|
130
|
-
return @detected_junos_architecture = nil unless connected?
|
131
|
-
|
132
|
-
# Reuse version detection result to avoid duplicate 'show version' calls
|
133
|
-
# Both version and architecture come from the same command output
|
134
|
-
if defined?(@detected_junos_version) && @detected_junos_version
|
135
|
-
# We already have the output from version detection, parse architecture from it
|
136
|
-
result = @cached_show_version_result
|
137
|
-
else
|
138
|
-
# Execute 'show version' command and cache the result
|
139
|
-
result = run_command_via_connection('show version')
|
140
|
-
@cached_show_version_result = result if result&.exit_status&.zero?
|
141
|
-
end
|
142
|
-
|
143
|
-
return @detected_junos_architecture = nil unless result&.exit_status&.zero?
|
144
|
-
|
145
|
-
# Parse architecture from output using multiple patterns
|
146
|
-
arch = extract_architecture_from_output(result.stdout)
|
147
|
-
|
148
|
-
if arch
|
149
|
-
logger&.debug("Detected JunOS architecture: #{arch}")
|
150
|
-
@detected_junos_architecture = arch
|
151
|
-
else
|
152
|
-
logger&.debug("Could not parse JunOS architecture from: #{result.stdout[0..100]}")
|
153
|
-
@detected_junos_architecture = nil
|
154
|
-
end
|
155
|
-
rescue StandardError => e
|
156
|
-
# If architecture detection fails, log and return nil
|
157
|
-
logger&.debug("JunOS architecture detection failed: #{e.message}")
|
158
|
-
@detected_junos_architecture = nil
|
159
|
-
end
|
128
|
+
detect_attribute('junos_architecture') { |output| extract_architecture_from_output(output) }
|
160
129
|
end
|
161
130
|
|
162
131
|
# Extract architecture string from JunOS show version output
|
132
|
+
# @param output [String] Raw output from 'show version' command
|
133
|
+
# @return [String, nil] Architecture string (x86_64, arm64, etc.) or nil
|
163
134
|
def extract_architecture_from_output(output)
|
164
135
|
return nil if output.nil? || output.empty?
|
165
136
|
|
166
137
|
# Try multiple JunOS architecture patterns
|
167
138
|
patterns = [
|
168
139
|
/Model:\s+(\S+)/, # "Model: SRX240H2" -> extract model as arch indicator
|
169
|
-
/Junos:\s+[\d
|
140
|
+
/Junos:\s+[\w\d.-]+\s+built\s+[\d-]+\s+[\d:]+\s+by\s+builder\s+on\s+(\S+)/, # Build architecture
|
170
141
|
/JUNOS.*\[([\w-]+)\]/, # JUNOS package architecture
|
171
142
|
/Architecture:\s+(\S+)/i, # Direct architecture line
|
172
143
|
/Platform:\s+(\S+)/i, # Platform designation
|
@@ -7,6 +7,13 @@ require 'train-juniper/connection'
|
|
7
7
|
|
8
8
|
module TrainPlugins
|
9
9
|
module Juniper
|
10
|
+
# Transport plugin for Juniper JunOS devices
|
11
|
+
# @example Create a connection
|
12
|
+
# conn = Train.create('juniper',
|
13
|
+
# host: '192.168.1.1',
|
14
|
+
# user: 'admin',
|
15
|
+
# password: 'secret'
|
16
|
+
# )
|
10
17
|
class Transport < Train.plugin(1)
|
11
18
|
name 'juniper'
|
12
19
|
|
@@ -20,7 +27,7 @@ module TrainPlugins
|
|
20
27
|
|
21
28
|
# Proxy/Bastion host support (Train standard options)
|
22
29
|
option :bastion_host, default: nil
|
23
|
-
option :bastion_user, default: nil #
|
30
|
+
option :bastion_user, default: nil # Falls back to main user if not specified
|
24
31
|
option :bastion_port, default: 22
|
25
32
|
option :bastion_password, default: nil # Separate password for bastion authentication
|
26
33
|
option :proxy_command, default: nil
|
@@ -45,6 +52,11 @@ module TrainPlugins
|
|
45
52
|
option :disable_complete_on_space, default: false
|
46
53
|
|
47
54
|
# Create and return a connection to a Juniper device
|
55
|
+
# @param _instance_opts [Hash] Instance options (unused, for compatibility)
|
56
|
+
# @return [TrainPlugins::Juniper::Connection] Cached connection instance
|
57
|
+
# @example
|
58
|
+
# transport = TrainPlugins::Juniper::Transport.new(options)
|
59
|
+
# conn = transport.connection
|
48
60
|
def connection(_instance_opts = nil)
|
49
61
|
# Cache the connection instance for reuse
|
50
62
|
# @options contains parsed connection details from train URI
|
data/train-juniper.gemspec
CHANGED
@@ -70,4 +70,20 @@ Gem::Specification.new do |spec|
|
|
70
70
|
# FFI dependency - required by train-core
|
71
71
|
# Match InSpec 7's FFI version range for compatibility
|
72
72
|
spec.add_dependency 'ffi', '>= 1.15.5', '< 1.17.0'
|
73
|
+
|
74
|
+
# Development dependencies
|
75
|
+
spec.add_development_dependency 'bundler', '~> 2.0'
|
76
|
+
spec.add_development_dependency 'byebug', '~> 11.1'
|
77
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
78
|
+
spec.add_development_dependency 'mocha', '~> 2.0'
|
79
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
80
|
+
spec.add_development_dependency 'rubocop', '~> 1.0'
|
81
|
+
spec.add_development_dependency 'simplecov', '~> 0.22'
|
82
|
+
spec.add_development_dependency 'yard', '~> 0.9'
|
83
|
+
|
84
|
+
# Security testing
|
85
|
+
spec.add_development_dependency 'bundler-audit', '~> 0.9'
|
86
|
+
|
87
|
+
# Documentation generation
|
88
|
+
spec.add_development_dependency 'redcarpet', '~> 3.5'
|
73
89
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: train-juniper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- MITRE Corporation
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-06-
|
11
|
+
date: 2025-06-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: train-core
|
@@ -64,6 +64,146 @@ dependencies:
|
|
64
64
|
- - "<"
|
65
65
|
- !ruby/object:Gem::Version
|
66
66
|
version: 1.17.0
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: bundler
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '2.0'
|
74
|
+
type: :development
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - "~>"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '2.0'
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: byebug
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - "~>"
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '11.1'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - "~>"
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '11.1'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: minitest
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - "~>"
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '5.0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - "~>"
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '5.0'
|
109
|
+
- !ruby/object:Gem::Dependency
|
110
|
+
name: mocha
|
111
|
+
requirement: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - "~>"
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '2.0'
|
116
|
+
type: :development
|
117
|
+
prerelease: false
|
118
|
+
version_requirements: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - "~>"
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '2.0'
|
123
|
+
- !ruby/object:Gem::Dependency
|
124
|
+
name: rake
|
125
|
+
requirement: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - "~>"
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '13.0'
|
130
|
+
type: :development
|
131
|
+
prerelease: false
|
132
|
+
version_requirements: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - "~>"
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '13.0'
|
137
|
+
- !ruby/object:Gem::Dependency
|
138
|
+
name: rubocop
|
139
|
+
requirement: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - "~>"
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '1.0'
|
144
|
+
type: :development
|
145
|
+
prerelease: false
|
146
|
+
version_requirements: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - "~>"
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '1.0'
|
151
|
+
- !ruby/object:Gem::Dependency
|
152
|
+
name: simplecov
|
153
|
+
requirement: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - "~>"
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0.22'
|
158
|
+
type: :development
|
159
|
+
prerelease: false
|
160
|
+
version_requirements: !ruby/object:Gem::Requirement
|
161
|
+
requirements:
|
162
|
+
- - "~>"
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: '0.22'
|
165
|
+
- !ruby/object:Gem::Dependency
|
166
|
+
name: yard
|
167
|
+
requirement: !ruby/object:Gem::Requirement
|
168
|
+
requirements:
|
169
|
+
- - "~>"
|
170
|
+
- !ruby/object:Gem::Version
|
171
|
+
version: '0.9'
|
172
|
+
type: :development
|
173
|
+
prerelease: false
|
174
|
+
version_requirements: !ruby/object:Gem::Requirement
|
175
|
+
requirements:
|
176
|
+
- - "~>"
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: '0.9'
|
179
|
+
- !ruby/object:Gem::Dependency
|
180
|
+
name: bundler-audit
|
181
|
+
requirement: !ruby/object:Gem::Requirement
|
182
|
+
requirements:
|
183
|
+
- - "~>"
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
version: '0.9'
|
186
|
+
type: :development
|
187
|
+
prerelease: false
|
188
|
+
version_requirements: !ruby/object:Gem::Requirement
|
189
|
+
requirements:
|
190
|
+
- - "~>"
|
191
|
+
- !ruby/object:Gem::Version
|
192
|
+
version: '0.9'
|
193
|
+
- !ruby/object:Gem::Dependency
|
194
|
+
name: redcarpet
|
195
|
+
requirement: !ruby/object:Gem::Requirement
|
196
|
+
requirements:
|
197
|
+
- - "~>"
|
198
|
+
- !ruby/object:Gem::Version
|
199
|
+
version: '3.5'
|
200
|
+
type: :development
|
201
|
+
prerelease: false
|
202
|
+
version_requirements: !ruby/object:Gem::Requirement
|
203
|
+
requirements:
|
204
|
+
- - "~>"
|
205
|
+
- !ruby/object:Gem::Version
|
206
|
+
version: '3.5'
|
67
207
|
description: Provides SSH connectivity to Juniper Networks devices running JunOS for
|
68
208
|
InSpec compliance testing and infrastructure inspection. Supports platform detection,
|
69
209
|
command execution, and configuration file access.
|
@@ -84,6 +224,16 @@ files:
|
|
84
224
|
- SECURITY.md
|
85
225
|
- lib/train-juniper.rb
|
86
226
|
- lib/train-juniper/connection.rb
|
227
|
+
- lib/train-juniper/connection/bastion_proxy.rb
|
228
|
+
- lib/train-juniper/connection/command_executor.rb
|
229
|
+
- lib/train-juniper/connection/error_handling.rb
|
230
|
+
- lib/train-juniper/connection/ssh_session.rb
|
231
|
+
- lib/train-juniper/connection/validation.rb
|
232
|
+
- lib/train-juniper/constants.rb
|
233
|
+
- lib/train-juniper/file_abstraction/juniper_file.rb
|
234
|
+
- lib/train-juniper/helpers/environment.rb
|
235
|
+
- lib/train-juniper/helpers/logging.rb
|
236
|
+
- lib/train-juniper/helpers/mock_responses.rb
|
87
237
|
- lib/train-juniper/platform.rb
|
88
238
|
- lib/train-juniper/transport.rb
|
89
239
|
- lib/train-juniper/version.rb
|