train 1.4.25 → 1.4.29

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1e20385227ab1b9267ab2d34ca6880657f0d26682b66ca2a10f885ee5f349ce6
4
- data.tar.gz: f675b5c27b234f25ad7d3d73a5572422be938f1bb0b59f9e7ef970df665807c1
3
+ metadata.gz: 65be3294011740eca689d8b5de1273f14f37d5189eae2a29111a4d268701af3a
4
+ data.tar.gz: bceb7f68344642b8f010b3e1ed5882afa4f4587fd7ebd1459635c2ca8954c3c6
5
5
  SHA512:
6
- metadata.gz: 58c5b580ea0f04cbc602e52742bdc91bab4c98f41fab640bda1ea60b704cfc6b698022f44b18243ca9e8e317c88801816e302f894c30b1a453e4254f6730475a
7
- data.tar.gz: 1d1d9c27431bdbf2c6fbacbc444065c5ac7add670febfb52b8e7eb17ca7d941961effe6d49619204ba75943d8173fbe049fec5bc9560f9dabca3511afb70fefd
6
+ metadata.gz: 34e6e054bb02d891857461d62756f02f63b0f42491ed7768764c82a6f1b1c3ab9b8158878ac4a1ebf4d6482b4cec62be7de2168f2980c84f662725dca48d2490
7
+ data.tar.gz: 3104bcaf1ba5edf30ed53702248c0f52e02d50435812a5eb0b6158a7873f6e85f28109e680184f22c6f445fe319113a94ccb2e0ec362150cb8ac285d2805d3e9
@@ -1,24 +1,34 @@
1
- <!-- latest_release 1.4.25 -->
2
- ## [v1.4.25](https://github.com/inspec/train/tree/v1.4.25) (2018-08-01)
1
+ <!-- latest_release 1.4.29 -->
2
+ ## [v1.4.29](https://github.com/inspec/train/tree/v1.4.29) (2018-08-15)
3
3
 
4
4
  #### Merged Pull Requests
5
- - Remove not needed google-cloud dependency (see #328) and correct GCP … [#329](https://github.com/inspec/train/pull/329) ([skpaterson](https://github.com/skpaterson))
5
+ - Add non_interactive support for SSH [#336](https://github.com/inspec/train/pull/336) ([marcparadise](https://github.com/marcparadise))
6
6
  <!-- latest_release -->
7
7
 
8
- <!-- release_rollup since=1.4.24 -->
9
- ### Changes since 1.4.24 release
8
+ <!-- release_rollup since=1.4.25 -->
9
+ ### Changes since 1.4.25 release
10
+
11
+ #### Features & Enhancements
12
+ - Pulls file credentials parsing out of Azure class [#324](https://github.com/inspec/train/pull/324) ([dmccown](https://github.com/dmccown)) <!-- 1.4.27 -->
10
13
 
11
14
  #### Merged Pull Requests
12
- - Remove not needed google-cloud dependency (see #328) and correct GCP … [#329](https://github.com/inspec/train/pull/329) ([skpaterson](https://github.com/skpaterson)) <!-- 1.4.25 -->
15
+ - Add non_interactive support for SSH [#336](https://github.com/inspec/train/pull/336) ([marcparadise](https://github.com/marcparadise)) <!-- 1.4.29 -->
16
+ - Require Ruby 2.0 and allow net-ssh 5.0 [#334](https://github.com/inspec/train/pull/334) ([tas50](https://github.com/tas50)) <!-- 1.4.28 -->
17
+ - Modify checksum logic to use system binaries [#251](https://github.com/inspec/train/pull/251) ([jerryaldrichiii](https://github.com/jerryaldrichiii)) <!-- 1.4.26 -->
13
18
  <!-- release_rollup -->
14
19
 
15
20
  <!-- latest_stable_release -->
21
+ ## [v1.4.25](https://github.com/inspec/train/tree/v1.4.25) (2018-08-01)
22
+
23
+ #### Merged Pull Requests
24
+ - Remove not needed google-cloud dependency (see #328) and correct GCP … [#329](https://github.com/inspec/train/pull/329) ([skpaterson](https://github.com/skpaterson))
25
+ <!-- latest_stable_release -->
26
+
16
27
  ## [v1.4.24](https://github.com/inspec/train/tree/v1.4.24) (2018-07-26)
17
28
 
18
29
  #### Merged Pull Requests
19
30
  - Add shallow_link_path to inspect symlink direct link [#309](https://github.com/inspec/train/pull/309) ([ColinHebert](https://github.com/ColinHebert))
20
31
  - Retry SSH command on IOError (Cisco IOS specific) [#326](https://github.com/inspec/train/pull/326) ([jerryaldrichiii](https://github.com/jerryaldrichiii))
21
- <!-- latest_stable_release -->
22
32
 
23
33
  ## [v1.4.22](https://github.com/inspec/train/tree/v1.4.22) (2018-07-16)
24
34
 
@@ -5,12 +5,10 @@
5
5
 
6
6
  require 'train/file/local'
7
7
  require 'train/file/remote'
8
- require 'digest/sha2'
9
- require 'digest/md5'
10
8
  require 'train/extras/stat'
11
9
 
12
10
  module Train
13
- class File
11
+ class File # rubocop:disable Metrics/ClassLength
14
12
  def initialize(backend, path, follow_symlink = true)
15
13
  @backend = backend
16
14
  @path = path || ''
@@ -48,22 +46,6 @@ module Train
48
46
  :unknown
49
47
  end
50
48
 
51
- def md5sum
52
- res = Digest::MD5.new
53
- res.update(content)
54
- res.hexdigest
55
- rescue TypeError => _
56
- nil
57
- end
58
-
59
- def sha256sum
60
- res = Digest::SHA256.new
61
- res.update(content)
62
- res.hexdigest
63
- rescue TypeError => _
64
- nil
65
- end
66
-
67
49
  def source
68
50
  if @follow_symlink
69
51
  self.class.new(@backend, @path, false)
@@ -147,5 +129,82 @@ module Train
147
129
 
148
130
  !mounted.nil? && !mounted.stdout.nil? && !mounted.stdout.empty?
149
131
  end
132
+
133
+ def md5sum
134
+ # Skip processing rest of method if fallback method is selected
135
+ return perform_checksum_ruby(:md5) if defined?(@ruby_checksum_fallback)
136
+
137
+ checksum = if @backend.os.family == 'windows'
138
+ perform_checksum_windows(:md5)
139
+ else
140
+ @md5_command ||= case @backend.os.family
141
+ when 'darwin'
142
+ 'md5 -r'
143
+ when 'solaris'
144
+ 'digest -a md5'
145
+ else
146
+ 'md5sum'
147
+ end
148
+
149
+ perform_checksum_unix(@md5_command)
150
+ end
151
+
152
+ checksum || perform_checksum_ruby(:md5)
153
+ end
154
+
155
+ def sha256sum
156
+ # Skip processing rest of method if fallback method is selected
157
+ return perform_checksum_ruby(:sha256) if defined?(@ruby_checksum_fallback)
158
+
159
+ checksum = if @backend.os.family == 'windows'
160
+ perform_checksum_windows(:sha256)
161
+ else
162
+ @sha256_command ||= case @backend.os.family
163
+ when 'darwin', 'hpux', 'qnx'
164
+ 'shasum -a 256'
165
+ when 'solaris'
166
+ 'digest -a sha256'
167
+ else
168
+ 'sha256sum'
169
+ end
170
+
171
+ perform_checksum_unix(@sha256_command)
172
+ end
173
+
174
+ checksum || perform_checksum_ruby(:sha256)
175
+ end
176
+
177
+ private
178
+
179
+ def perform_checksum_unix(cmd)
180
+ res = @backend.run_command("#{cmd} #{@path}")
181
+ res.stdout.split(' ').first if res.exit_status == 0
182
+ end
183
+
184
+ def perform_checksum_windows(method)
185
+ cmd = "CertUtil -hashfile #{@path} #{method.to_s.upcase}"
186
+ res = @backend.run_command(cmd)
187
+ res.stdout.split("\r\n")[1].tr(' ', '') if res.exit_status == 0
188
+ end
189
+
190
+ # This pulls the content of the file to the machine running Train and uses
191
+ # Digest to perform the checksum. This is less efficient than using remote
192
+ # system binaries and can lead to incorrect results due to encoding.
193
+ def perform_checksum_ruby(method)
194
+ # This is used to skip attempting other checksum methods. If this is set
195
+ # then we know all other methods have failed.
196
+ @ruby_checksum_fallback = true
197
+ case method
198
+ when :md5
199
+ res = Digest::MD5.new
200
+ when :sha256
201
+ res = Digest::SHA256.new
202
+ end
203
+
204
+ res.update(content)
205
+ res.hexdigest
206
+ rescue TypeError => _
207
+ nil
208
+ end
150
209
  end
151
210
  end
@@ -3,9 +3,9 @@
3
3
  require 'train/plugins'
4
4
  require 'ms_rest_azure'
5
5
  require 'azure_mgmt_resources'
6
- require 'inifile'
7
6
  require 'socket'
8
7
  require 'timeout'
8
+ require 'train/transports/helpers/azure/file_credentials'
9
9
 
10
10
  module Train::Transports
11
11
  class Azure < Train.plugin(1)
@@ -23,7 +23,7 @@ module Train::Transports
23
23
  @connection ||= Connection.new(@options)
24
24
  end
25
25
 
26
- class Connection < BaseConnection # rubocop:disable Metrics/ClassLength
26
+ class Connection < BaseConnection
27
27
  attr_reader :options
28
28
 
29
29
  def initialize(options)
@@ -38,7 +38,7 @@ module Train::Transports
38
38
  @cache[:api_call] = {}
39
39
 
40
40
  if @options[:client_secret].nil? && @options[:client_id].nil?
41
- parse_credentials_file
41
+ @options.merge!(Helpers::Azure::FileCredentials.parse(@options))
42
42
  end
43
43
 
44
44
  @options[:msi_port] = @options[:msi_port].to_i unless @options[:msi_port].nil?
@@ -149,40 +149,6 @@ module Train::Transports
149
149
  rescue Timeout::Error
150
150
  false
151
151
  end
152
-
153
- def parse_credentials_file # rubocop:disable Metrics/AbcSize
154
- # If an AZURE_CRED_FILE environment variable has been specified set the
155
- # the credentials file to that, otherwise set the one in home
156
- azure_creds_file = @options[:credentials_file]
157
- azure_creds_file = File.join(Dir.home, '.azure', 'credentials') if azure_creds_file.nil?
158
- return unless File.readable?(azure_creds_file)
159
-
160
- credentials = IniFile.load(File.expand_path(azure_creds_file))
161
- if @options[:subscription_id]
162
- id = @options[:subscription_id]
163
- elsif !ENV['AZURE_SUBSCRIPTION_NUMBER'].nil?
164
- subscription_number = ENV['AZURE_SUBSCRIPTION_NUMBER'].to_i
165
-
166
- # Check that the specified index is not greater than the number of subscriptions
167
- if subscription_number > credentials.sections.length
168
- raise format(
169
- 'Your credentials file only contains %s subscriptions. You specified number %s.',
170
- @credentials.sections.length,
171
- subscription_number,
172
- )
173
- end
174
- id = credentials.sections[subscription_number - 1]
175
- else
176
- raise 'Multiple credentials detected, please set the AZURE_SUBSCRIPTION_ID environment variable.' if credentials.sections.count > 1
177
- id = credentials.sections[0]
178
- end
179
-
180
- raise "No credentials found for subscription number #{id}" if credentials.sections.empty? || credentials[id].empty?
181
- @options[:subscription_id] = id
182
- @options[:tenant_id] = credentials[id]['tenant_id']
183
- @options[:client_id] = credentials[id]['client_id']
184
- @options[:client_secret] = credentials[id]['client_secret']
185
- end
186
152
  end
187
153
  end
188
154
  end
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+
3
+ require 'inifile'
4
+ require 'train/transports/helpers/azure/file_parser'
5
+ require 'train/transports/helpers/azure/subscription_number_file_parser'
6
+ require 'train/transports/helpers/azure/subscription_id_file_parser'
7
+
8
+ module Train::Transports
9
+ module Helpers
10
+ module Azure
11
+ class FileCredentials
12
+ DEFAULT_FILE = ::File.join(Dir.home, '.azure', 'credentials')
13
+
14
+ def self.parse(subscription_id: nil, credentials_file: DEFAULT_FILE, **_)
15
+ return {} unless ::File.readable?(credentials_file)
16
+ credentials = IniFile.load(::File.expand_path(credentials_file))
17
+ subscription_id = parser(subscription_id, ENV['AZURE_SUBSCRIPTION_NUMBER'], credentials).subscription_id
18
+ creds(subscription_id, credentials)
19
+ end
20
+
21
+ def self.parser(subscription_id, subscription_number, credentials)
22
+ if subscription_id
23
+ SubscriptionIdFileParser.new(subscription_id, credentials)
24
+ elsif !subscription_number.nil?
25
+ SubscriptionNumberFileParser.new(subscription_number.to_i, credentials)
26
+ else
27
+ FileParser.new(credentials)
28
+ end
29
+ end
30
+
31
+ def self.creds(subscription_id, credentials)
32
+ {
33
+ subscription_id: subscription_id,
34
+ tenant_id: credentials[subscription_id]['tenant_id'],
35
+ client_id: credentials[subscription_id]['client_id'],
36
+ client_secret: credentials[subscription_id]['client_secret'],
37
+ }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+
3
+ module Train::Transports
4
+ module Helpers
5
+ module Azure
6
+ class FileParser
7
+ def initialize(credentials)
8
+ @credentials = credentials
9
+
10
+ validate!
11
+ end
12
+
13
+ def validate!
14
+ return if @credentials.sections.count == 1
15
+
16
+ raise 'Credentials file must have one entry. Check your credentials file. If you have more than one entry set AZURE_SUBSCRIPTION_ID environment variable.'
17
+ end
18
+
19
+ def subscription_id
20
+ @subscription_id ||= @credentials.sections[0]
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ module Train::Transports
4
+ module Helpers
5
+ module Azure
6
+ class SubscriptionIdFileParser
7
+ attr_reader :subscription_id
8
+
9
+ def initialize(subscription_id, credentials)
10
+ @subscription_id = subscription_id
11
+ @credentials = credentials
12
+
13
+ validate!
14
+ end
15
+
16
+ def validate!
17
+ if @credentials.sections.empty? || @credentials[subscription_id].empty?
18
+ raise "No credentials found for subscription number #{subscription_id}"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ module Train::Transports
4
+ module Helpers
5
+ module Azure
6
+ class SubscriptionNumberFileParser
7
+ def initialize(index, credentials)
8
+ @index = index
9
+ @credentials = credentials
10
+
11
+ validate!
12
+ end
13
+
14
+ def validate!
15
+ if @index == 0
16
+ raise 'Index must be greater than 0.'
17
+ end
18
+
19
+ if @index > @credentials.sections.length
20
+ raise "Your credentials file only contains #{@credentials.sections.length} subscriptions. You specified number #{@index}."
21
+ end
22
+ end
23
+
24
+ def subscription_id
25
+ @subscription_id ||= @credentials.sections[@index - 1]
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -62,6 +62,7 @@ module Train::Transports
62
62
  option :bastion_host, default: nil
63
63
  option :bastion_user, default: 'root'
64
64
  option :bastion_port, default: 22
65
+ option :non_interactive, default: false
65
66
 
66
67
  option :compression_level do |opts|
67
68
  # on nil or false: set compression level to 0
@@ -162,9 +163,9 @@ module Train::Transports
162
163
  bastion_host: opts[:bastion_host],
163
164
  bastion_user: opts[:bastion_user],
164
165
  bastion_port: opts[:bastion_port],
166
+ non_interactive: opts[:non_interactive],
165
167
  transport_options: opts,
166
168
  }
167
-
168
169
  # disable host key verification. The hash key to use
169
170
  # depends on the version of net-ssh in use.
170
171
  connection_options[verify_host_key_option] = false
@@ -69,6 +69,7 @@ class Train::Transports::SSH
69
69
  args = %w{ -o UserKnownHostsFile=/dev/null }
70
70
  args += %w{ -o StrictHostKeyChecking=no }
71
71
  args += %w{ -o IdentitiesOnly=yes } if options[:keys]
72
+ args += %w{ -o BatchMode=yes } if options[:non_interactive]
72
73
  args += %W( -o LogLevel=#{level} )
73
74
  args += %W( -o ForwardAgent=#{fwd_agent} ) if options.key?(:forward_agent)
74
75
  Array(options[:keys]).each do |ssh_key|
@@ -3,5 +3,5 @@
3
3
  # Author:: Dominik Richter (<dominik.richter@gmail.com>)
4
4
 
5
5
  module Train
6
- VERSION = '1.4.25'.freeze
6
+ VERSION = '1.4.29'.freeze
7
7
  end
@@ -42,11 +42,11 @@ describe 'file interface' do
42
42
  file.link_path.must_be_nil
43
43
  end
44
44
 
45
- it 'has no md5sum' do
45
+ it 'has the correct md5sum' do
46
46
  file.md5sum.must_equal('d41d8cd98f00b204e9800998ecf8427e')
47
47
  end
48
48
 
49
- it 'has no sha256sum' do
49
+ it 'has the correct sha256sum' do
50
50
  file.sha256sum.must_equal('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
51
51
  end
52
52
 
@@ -37,12 +37,12 @@ describe 'file interface' do
37
37
  file.content.must_be_nil
38
38
  end
39
39
 
40
- it 'has an md5sum' do
41
- file.md5sum.must_be_nil
40
+ it 'raises an error if md5sum is attempted' do
41
+ proc { file.md5sum }.must_raise RuntimeError
42
42
  end
43
43
 
44
- it 'has an sha256sum' do
45
- file.sha256sum.must_be_nil
44
+ it 'raises an error if sha256sum is attempted' do
45
+ proc { file.sha256sum }.must_raise RuntimeError
46
46
  end
47
47
  end
48
48
 
@@ -44,12 +44,12 @@ describe 'file interface' do
44
44
  file.link_path.must_be_nil
45
45
  end
46
46
 
47
- it 'has an md5sum' do
48
- file.md5sum.must_be_nil
47
+ it 'raises an error if md5sum is attempted' do
48
+ proc { file.md5sum }.must_raise RuntimeError
49
49
  end
50
50
 
51
- it 'has an sha256sum' do
52
- file.sha256sum.must_be_nil
51
+ it 'raises an error if sha256sum is attempted' do
52
+ proc { file.sha256sum }.must_raise RuntimeError
53
53
  end
54
54
 
55
55
  it 'has a modified time' do