train-core 3.10.8 → 3.11.0
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/lib/train/audit_log.rb +21 -0
- data/lib/train/logger_ext.rb +8 -0
- data/lib/train/options.rb +30 -1
- data/lib/train/plugins/base_connection.rb +25 -9
- data/lib/train/plugins/transport.rb +6 -0
- data/lib/train/version.rb +1 -1
- data/lib/train.rb +2 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0b10470a7175d568ce7d0df7a3497deb7709ad5ca210f542654f3c560585bacb
|
4
|
+
data.tar.gz: 6d91bd6042737e52411a58c30b1c9127bf6a402402e1800abe708ca02434e7ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ce7f3b1b9c3bd621adbdecbb2e11b3815621f97e50ad24567eb70eeaa8b8b5e239e1a6393efec0d732960f3ad9d46072fff176ea40cf6108f6a1f1102bc5685
|
7
|
+
data.tar.gz: ee8265ac08e6c4ed064229cef212471fa3cb52f4be75e478342993a5901b591d545f21ef46cce35c39e734d8e283fe6d26d4f76b6fa98b5c7428649fb83a2c32
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Train
|
2
|
+
class AuditLog
|
3
|
+
# Default values for audit log options are set in the options.rb
|
4
|
+
def self.create(options = {})
|
5
|
+
# Load monkey-patch to disable leading comment in logfiles
|
6
|
+
require_relative "logger_ext"
|
7
|
+
|
8
|
+
logger = Logger.new(options[:audit_log_location], options[:audit_log_frequency], options[:audit_log_size])
|
9
|
+
logger.level = options[:level] || Logger::INFO
|
10
|
+
logger.progname = options[:audit_log_app_name]
|
11
|
+
logger.datetime_format = "%Y-%m-%d %H:%M:%S"
|
12
|
+
logger.formatter = proc do |severity, datetime, progname, msg|
|
13
|
+
{
|
14
|
+
timestamp: datetime.to_s,
|
15
|
+
app: progname,
|
16
|
+
}.merge(msg).compact.to_json + $/
|
17
|
+
end
|
18
|
+
logger
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
|
2
|
+
# Part of Audit Log.
|
3
|
+
# The default logger implementation injects a comment as the first line of the
|
4
|
+
# log file, which makes it an invalid JSON file. No way to disable that other than monkey-patching.
|
5
|
+
|
6
|
+
class Logger::LogDevice
|
7
|
+
def add_log_header(file); end
|
8
|
+
end
|
data/lib/train/options.rb
CHANGED
@@ -34,6 +34,18 @@ module Train
|
|
34
34
|
@default_options
|
35
35
|
end
|
36
36
|
|
37
|
+
# Created separate method to set the default audit log options so that it will be handled separately
|
38
|
+
# and will not break any existing functionality
|
39
|
+
def default_audit_log_options
|
40
|
+
{
|
41
|
+
enable_audit_log: { default: false },
|
42
|
+
audit_log_location: { required: true, default: nil },
|
43
|
+
audit_log_app_name: { default: "train" },
|
44
|
+
audit_log_size: { default: nil },
|
45
|
+
audit_log_frequency: { default: 0 },
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
37
49
|
def include_options(other)
|
38
50
|
unless other.respond_to?(:default_options)
|
39
51
|
raise "Trying to include options from module #{other.inspect}, "\
|
@@ -47,13 +59,18 @@ module Train
|
|
47
59
|
# @return [Hash] options, which created this Transport
|
48
60
|
attr_reader :options
|
49
61
|
|
62
|
+
def default_audit_log_options
|
63
|
+
self.class.default_audit_log_options
|
64
|
+
end
|
65
|
+
|
50
66
|
def default_options
|
51
67
|
self.class.default_options
|
52
68
|
end
|
53
69
|
|
54
70
|
def merge_options(base, opts)
|
55
71
|
res = base.merge(opts || {})
|
56
|
-
|
72
|
+
# Also merge the default audit log options into the options so that those are available at the time of validation.
|
73
|
+
default_options.merge(default_audit_log_options).each do |field, hm|
|
57
74
|
next unless res[field].nil? && hm.key?(:default)
|
58
75
|
|
59
76
|
default = hm[:default]
|
@@ -78,6 +95,18 @@ module Train
|
|
78
95
|
end
|
79
96
|
opts
|
80
97
|
end
|
98
|
+
|
99
|
+
# Introduced this method to validate only audit log options and avoiding call to validate_options so
|
100
|
+
# that it will no break existing implementation.
|
101
|
+
def validate_audit_log_options(opts)
|
102
|
+
default_audit_log_options.each do |field, hm|
|
103
|
+
if opts[field].nil? && hm[:required]
|
104
|
+
raise Train::ClientError,
|
105
|
+
"You must provide a value for #{field.to_s.inspect}."
|
106
|
+
end
|
107
|
+
end
|
108
|
+
opts
|
109
|
+
end
|
81
110
|
end
|
82
111
|
end
|
83
112
|
end
|
@@ -3,6 +3,7 @@ require_relative "../extras"
|
|
3
3
|
require_relative "../file"
|
4
4
|
require "fileutils" unless defined?(FileUtils)
|
5
5
|
require "logger"
|
6
|
+
require_relative "../audit_log"
|
6
7
|
|
7
8
|
class Train::Plugins::Transport
|
8
9
|
# A Connection instance can be generated and re-generated, given new
|
@@ -20,10 +21,21 @@ class Train::Plugins::Transport
|
|
20
21
|
# @yield [self] yields itself for block-style invocation
|
21
22
|
def initialize(options = nil)
|
22
23
|
@options = options || {}
|
24
|
+
|
23
25
|
@logger = @options.delete(:logger) || Logger.new($stdout, level: :fatal)
|
24
26
|
Train::Platforms::Detect::Specifications::OS.load
|
25
27
|
Train::Platforms::Detect::Specifications::Api.load
|
26
28
|
|
29
|
+
# In run_command all options are not accessible as some of them gets deleted in transit.
|
30
|
+
# To make the data like hostname, username available to aduit logs dup the options
|
31
|
+
@audit_log_data = options.dup || {}
|
32
|
+
# For transport other than local all audit log options accessible inside transport_options key
|
33
|
+
if !@options.empty? && @options[:transport_options] && @options[:transport_options][:enable_audit_log]
|
34
|
+
@audit_log = Train::AuditLog.create(options[:transport_options])
|
35
|
+
elsif !@options.empty? && @options[:enable_audit_log]
|
36
|
+
@audit_log = Train::AuditLog.create(@options)
|
37
|
+
end
|
38
|
+
|
27
39
|
# default caching options
|
28
40
|
@cache_enabled = {
|
29
41
|
file: true,
|
@@ -140,11 +152,14 @@ class Train::Plugins::Transport
|
|
140
152
|
# Some implementations do not accept an opts argument.
|
141
153
|
# We cannot update all implementations to accept opts due to them being separate plugins.
|
142
154
|
# Therefore here we check the implementation's arity to maintain compatibility.
|
155
|
+
@audit_log.info({ type: "cmd", command: "#{cmd}", user: @audit_log_data[:username], hostname: @audit_log_data[:hostname] }) if @audit_log
|
156
|
+
|
143
157
|
case method(:run_command_via_connection).arity.abs
|
144
158
|
when 1
|
145
159
|
return run_command_via_connection(cmd, &data_handler) unless cache_enabled?(:command)
|
146
160
|
|
147
161
|
@cache[:command][cmd] ||= run_command_via_connection(cmd, &data_handler)
|
162
|
+
|
148
163
|
when 2
|
149
164
|
return run_command_via_connection(cmd, opts, &data_handler) unless cache_enabled?(:command)
|
150
165
|
|
@@ -157,29 +172,31 @@ class Train::Plugins::Transport
|
|
157
172
|
# This is the main file call for all connections. This will call the private
|
158
173
|
# file_via_connection on the connection with optional caching
|
159
174
|
def file(path, *args)
|
175
|
+
@audit_log.info({ type: "file", path: "#{path}", user: @audit_log_data[:username], hostname: @audit_log_data[:hostname] }) if @audit_log
|
160
176
|
return file_via_connection(path, *args) unless cache_enabled?(:file)
|
161
177
|
|
162
178
|
@cache[:file][path] ||= file_via_connection(path, *args)
|
163
179
|
end
|
164
180
|
|
165
|
-
# Uploads local files
|
181
|
+
# Uploads local files to remote host.
|
166
182
|
#
|
167
|
-
# @param locals [Array<String>]
|
183
|
+
# @param locals [String, Array<String>] path to local files
|
168
184
|
# @param remote [String] path to remote destination
|
169
185
|
# @raise [TransportFailed] if the files could not all be uploaded
|
170
186
|
# successfully, which may vary by implementation
|
171
187
|
def upload(locals, remote)
|
172
|
-
|
173
|
-
|
188
|
+
remote_directory = file(remote).directory?
|
189
|
+
|
190
|
+
if locals.is_a?(Array) && !remote_directory
|
191
|
+
raise Train::TransportError, "#{self.class} expects remote directory as second upload parameter for multi-file uploads"
|
174
192
|
end
|
175
193
|
|
176
194
|
Array(locals).each do |local|
|
177
|
-
|
178
|
-
remote_file
|
179
|
-
|
195
|
+
remote_file = remote_directory ? File.join(remote, File.basename(local)) : remote
|
196
|
+
@audit_log.info({ type: "file upload", source: local, destination: remote_file, user: @audit_log_data[:username], hostname: @audit_log_data[:hostname] }) if @audit_log
|
180
197
|
logger.debug("Attempting to upload '#{local}' as file #{remote_file}")
|
181
198
|
|
182
|
-
file(remote_file).content =
|
199
|
+
file(remote_file).content = File.read(local)
|
183
200
|
end
|
184
201
|
end
|
185
202
|
|
@@ -197,7 +214,6 @@ class Train::Plugins::Transport
|
|
197
214
|
Array(remotes).each do |remote|
|
198
215
|
new_content = file(remote).content
|
199
216
|
local_file = File.join(local, File.basename(remote))
|
200
|
-
|
201
217
|
logger.debug("Attempting to download '#{remote}' as file #{local_file}")
|
202
218
|
|
203
219
|
File.open(local_file, "w") { |fp| fp.write(new_content) }
|
@@ -21,6 +21,12 @@ class Train::Plugins
|
|
21
21
|
def initialize(options = {})
|
22
22
|
@options = merge_options({}, options || {})
|
23
23
|
@logger = @options[:logger] || Logger.new($stdout, level: :fatal)
|
24
|
+
# Validates audit log configuration options if audit log is enabled
|
25
|
+
# The reason to implement different validate method for audit log options is
|
26
|
+
# to validate only audit log options and not to break any existing validate_option implementation.
|
27
|
+
if !@options.empty? && @options[:enable_audit_log]
|
28
|
+
validate_audit_log_options(options)
|
29
|
+
end
|
24
30
|
end
|
25
31
|
|
26
32
|
# Create a connection to the target. Options may be provided
|
data/lib/train/version.rb
CHANGED
data/lib/train.rb
CHANGED
@@ -26,7 +26,8 @@ module Train
|
|
26
26
|
# @return [Hash] map of default options
|
27
27
|
def self.options(name)
|
28
28
|
cls = load_transport(name)
|
29
|
-
|
29
|
+
# Merging default_audit_log_options so that they will get listed in the options that are available.
|
30
|
+
cls.default_options.merge(cls.default_audit_log_options) unless cls.nil?
|
30
31
|
end
|
31
32
|
|
32
33
|
# Load the transport plugin indicated by name. If the plugin is not
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: train-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chef InSpec Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-11-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -127,6 +127,7 @@ extra_rdoc_files: []
|
|
127
127
|
files:
|
128
128
|
- LICENSE
|
129
129
|
- lib/train.rb
|
130
|
+
- lib/train/audit_log.rb
|
130
131
|
- lib/train/errors.rb
|
131
132
|
- lib/train/extras.rb
|
132
133
|
- lib/train/extras/command_wrapper.rb
|
@@ -142,6 +143,7 @@ files:
|
|
142
143
|
- lib/train/file/remote/unix.rb
|
143
144
|
- lib/train/file/remote/windows.rb
|
144
145
|
- lib/train/globals.rb
|
146
|
+
- lib/train/logger_ext.rb
|
145
147
|
- lib/train/options.rb
|
146
148
|
- lib/train/platforms.rb
|
147
149
|
- lib/train/platforms/common.rb
|