inspec-core 3.0.64 → 3.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 51b87fd12aaccae196f61c1fe4066fd1b207b9f68139f510a92bf4a5c8ae700b
4
- data.tar.gz: 6450a4e5b0e50e14988a6fccfa00fb220ebb179e7d532839d87fcf1e772cfcb3
3
+ metadata.gz: 25ed99e0e7240b826ba13f6d6b1a9a1fdfb41a587b8534f714712541172c1e91
4
+ data.tar.gz: d3664df03d103f551e706847a518bc3a38845312905f9b54dda42277669e88c6
5
5
  SHA512:
6
- metadata.gz: 0e00c26b123e61c4104f57ae4ef87c6909ea8070a325b9ebb5c29c9e2969d9ea46ebae07938f6004b1056e5582bcc985e9c8ce0caa0057721910155b01f48bac
7
- data.tar.gz: cd7ab8068c6f18ff97f0d3b798bee1da0bad4bc268fff6a994cb5a607ec73cbf0ee92c025ae12d92d24dbb47b452f24027a03f2c39ced82a427feb32b1fa1578
6
+ metadata.gz: f998135df5aaf1aafd2516d4baa1ce29b0f53e0625d296e5b05d3071a0cbeb12ee8d1b2adfa84e731a945c55afd3481291128628b30a6a380b8f39b094d7a54e
7
+ data.tar.gz: f7a5db33d49a097aa4834709d555b6e41fa4bcb02e489916c6b77769c488f8a8b389f6776259c4c9e8bce1e9ac29d85d8181b234b28c2a61bfa1830056e8f29e
@@ -89,7 +89,7 @@ module Fetchers
89
89
  def resolve_ref(ref_name)
90
90
  command_string = "git ls-remote \"#{@remote_url}\" \"#{ref_name}*\""
91
91
  cmd = shellout(command_string)
92
- raise "Error running '#{command_string}': #{cmd.stderr}" unless cmd.stderr == ''
92
+ raise "Error running '#{command_string}': #{cmd.stderr}" unless cmd.exitstatus == 0
93
93
  ref = parse_ls_remote(cmd.stdout, ref_name)
94
94
  if !ref
95
95
  raise "Unable to resolve #{ref_name} to a specific git commit for #{@remote_url}"
@@ -24,6 +24,8 @@ module Fetchers
24
24
  resolve_from_string(target[:url], opts, target[:username], target[:password])
25
25
  elsif target.is_a?(String)
26
26
  resolve_from_string(target, opts)
27
+ elsif target.is_a?(URI)
28
+ resolve_from_string(target.to_s, opts)
27
29
  end
28
30
  end
29
31
 
@@ -94,8 +96,8 @@ module Fetchers
94
96
  attr_reader :files, :archive_path
95
97
 
96
98
  def initialize(url, opts)
97
- @target = url
98
- @target_uri = parse_uri(@target)
99
+ @target = url.to_s
100
+ @target_uri = url.is_a?(URI) ? url : parse_uri(url)
99
101
  @insecure = opts['insecure']
100
102
  @token = opts['token']
101
103
  @config = opts
@@ -5,6 +5,7 @@
5
5
  require 'thor'
6
6
  require 'inspec/log'
7
7
  require 'inspec/profile_vendor'
8
+ require 'inspec/ui'
8
9
 
9
10
  # Allow end of options during array type parsing
10
11
  # https://github.com/erikhuda/thor/issues/631
@@ -99,8 +100,6 @@ module Inspec
99
100
  option :reporter, type: :array,
100
101
  banner: 'one two:/output/file/path',
101
102
  desc: 'Enable one or more output reporters: cli, documentation, html, progress, json, json-min, json-rspec, junit, yaml'
102
- option :color, type: :boolean,
103
- desc: 'Use colors in output.'
104
103
  option :attrs, type: :array,
105
104
  desc: 'Load attributes file (experimental)'
106
105
  option :create_lockfile, type: :boolean,
@@ -219,24 +218,51 @@ module Inspec
219
218
  # but Thor interprets all methods as subcommands. The no_commands block
220
219
  # treats them as regular methods.
221
220
  no_commands do
221
+ def ui
222
+ return @ui if defined?(@ui)
223
+
224
+ # Make a new UI object, respecting context
225
+ if options[:color].nil?
226
+ enable_color = true # If the command does not support the color option, default to on
227
+ else
228
+ enable_color = options[:color]
229
+ end
230
+
231
+ # UI will probe for TTY if nil - just send the raw option value
232
+ enable_interactivity = options[:interactive]
233
+
234
+ @ui = Inspec::UI.new(color: enable_color, interactive: enable_interactivity)
235
+ end
236
+
237
+ # Rationale: converting this to attr_writer breaks Thor
238
+ def ui=(new_ui) # rubocop: disable Style/TrivialAccessors
239
+ @ui = new_ui
240
+ end
241
+
222
242
  def mark_text(text)
223
- "\e[0;36m#{text}\e[0m"
243
+ # TODO: - deprecate, call cli.ui directly
244
+ # Note that this one doesn't automatically print
245
+ ui.emphasis(text, print: false)
224
246
  end
225
247
 
226
248
  def headline(title)
227
- puts "\n== #{title}\n\n"
249
+ # TODO: - deprecate, call cli.ui directly
250
+ ui.headline(title)
228
251
  end
229
252
 
230
253
  def li(entry)
231
- puts " #{mark_text('*')} #{entry}"
254
+ # TODO: - deprecate, call cli.ui directly
255
+ ui.list_item(entry)
232
256
  end
233
257
 
234
- def exit(code)
235
- Kernel.exit code
258
+ def plain_text(msg)
259
+ # TODO: - deprecate, call cli.ui directly
260
+ ui.plain(msg + "\n")
236
261
  end
237
262
 
238
- def plain_text(msg)
239
- puts msg
263
+ def exit(code)
264
+ # TODO: - deprecate, call cli.ui directly
265
+ ui.exit code
240
266
  end
241
267
  end
242
268
 
@@ -26,6 +26,12 @@ class Inspec::InspecCLI < Inspec::BaseCLI
26
26
  class_option :diagnose, type: :boolean,
27
27
  desc: 'Show diagnostics (versions, configurations)'
28
28
 
29
+ class_option :color, type: :boolean,
30
+ desc: 'Use colors in output.'
31
+
32
+ class_option :interactive, type: :boolean,
33
+ desc: 'Allow or disable user interaction'
34
+
29
35
  desc 'json PATH', 'read all tests in PATH and generate a JSON summary'
30
36
  option :output, aliases: :o, type: :string,
31
37
  desc: 'Save the created profile to a path'
@@ -38,4 +38,6 @@ module Inspec
38
38
  attr_accessor :attribute_name
39
39
  end
40
40
  end
41
+
42
+ class UserInteractionRequired < Error; end
41
43
  end
@@ -0,0 +1,216 @@
1
+ require 'tty-table'
2
+ require 'tty-prompt'
3
+
4
+ module Inspec
5
+ # Provides simple terminal UI interaction primitives for CLI commands and plugins.
6
+ class UI
7
+ ANSI_CODES = {
8
+ reset: "\e[0m",
9
+ bold: "\e[1m",
10
+ color: {
11
+ red: "\e[38;5;9m", # 256-color light red
12
+ green: "\e[38;5;41m", # 256-color light green
13
+ yellow: "\e[33m",
14
+ cyan: "\e[36m",
15
+ white: "\e[37m",
16
+ grey: "\e[38;5;247m", # 256-color medium grey
17
+ },
18
+ }.freeze
19
+
20
+ GLYPHS = {
21
+ bullet: '•', # BULLET, Unicode: U+2022, UTF-8: E2 80 A2
22
+ check: '✔', # HEAVY CHECK MARK, Unicode: U+2714, UTF-8: E2 9C 94
23
+ swirl: '↺', # ANTICLOCKWISE OPEN CIRCLE ARROW, Unicode U+21BA, UTF-8: E2 86 BA
24
+ script_x: '×', # MULTIPLICATION SIGN, Unicode: U+00D7, UTF-8: C3 97
25
+ question: '?', # normal ASCII question mark
26
+ em_dash: '─', # BOX DRAWINGS LIGHT HORIZONTAL Unicode: U+2500, UTF-8: E2 94 80
27
+ heavy_dash: '≖', # RING IN EQUAL TO, Unicode: U+2256, UTF-8: E2 89 96
28
+ vertical_dash: '│', # BOX DRAWINGS LIGHT VERTICAL, Unicode: U+2502, UTF-8: E2 94 82
29
+ table_corner: '⨀', # N-ARY CIRCLED DOT OPERATOR, Unicode: U+2A00, UTF-8: E2 A8 80
30
+ }.freeze
31
+
32
+ EXIT_NORMAL = 0
33
+ EXIT_USAGE_ERROR = 1
34
+ EXIT_PLUGIN_ERROR = 2
35
+ EXIT_FAILED_TESTS = 100
36
+ EXIT_SKIPPED_TESTS = 101
37
+
38
+ attr_reader :io
39
+
40
+ def initialize(opts = {})
41
+ @color = opts[:color].nil? ? true : opts[:color]
42
+ @interactive = opts[:interactive].nil? ? $stdout.isatty : opts[:interactive]
43
+ @io = opts[:io] || $stdout
44
+ end
45
+
46
+ def color?
47
+ @color
48
+ end
49
+
50
+ def print_or_return(str, print_flag)
51
+ io.print(str) if print_flag
52
+ str
53
+ end
54
+
55
+ #=========================================================================#
56
+ # Low-level formatting methods
57
+ #=========================================================================#
58
+
59
+ def plain(str, opts = { print: true })
60
+ print_or_return(str.to_s, opts[:print])
61
+ end
62
+
63
+ def plain_line(str, opts = { print: true })
64
+ print_or_return(str.to_s + "\n", opts[:print])
65
+ end
66
+
67
+ def bold(str, opts = { print: true })
68
+ result = color? ? io.print(ANSI_CODES[:bold] + str.to_s + ANSI_CODES[:reset]) : str.to_s
69
+ print_or_return(result, opts[:print])
70
+ end
71
+
72
+ ANSI_CODES[:color].keys.each do |color|
73
+ define_method(color) do |str, opts = { print: true }|
74
+ result = color? ? (ANSI_CODES[:color][color] + str.to_s + ANSI_CODES[:reset]) : str.to_s
75
+ print_or_return(result, opts[:print])
76
+ end
77
+ end
78
+
79
+ #=========================================================================#
80
+ # High-Level formatting methods
81
+ #=========================================================================#
82
+
83
+ def emphasis(str, opts = { print: true })
84
+ cyan(str, opts)
85
+ end
86
+
87
+ def headline(str, opts = { print: true })
88
+ str = str.dup.to_s
89
+ if str.length < 76
90
+ dash_length = 80 - str.length - 4 # 4 spaces
91
+ dash_length /= 2
92
+ else
93
+ dash_length = 0
94
+ end
95
+
96
+ result = "\n"
97
+ result += ' ' + (color? ? GLYPHS[:em_dash] : '-') * dash_length + ' '
98
+ result += color? ? ANSI_CODES[:bold] + ANSI_CODES[:color][:white] : ''
99
+ result += str
100
+ result += color? ? ANSI_CODES[:reset] : ''
101
+ result += ' ' + (color? ? GLYPHS[:em_dash] : '-') * dash_length + ' '
102
+ result += "\n\n"
103
+
104
+ print_or_return(result, opts[:print])
105
+ end
106
+
107
+ # Issues a one-line message, with 'ERROR: ' prepended in bold red.
108
+ def error(str, opts = { print: true })
109
+ str = str.dup.to_s
110
+ result = ''
111
+ result += color? ? ANSI_CODES[:bold] + ANSI_CODES[:color][:red] : ''
112
+ result += 'ERROR:'
113
+ result += color? ? ANSI_CODES[:reset] : ''
114
+ result += ' '
115
+ result += str
116
+ result += "\n"
117
+ print_or_return(result, opts[:print])
118
+ end
119
+
120
+ # Issues a one-line message, with 'WARNING: ' prepended in bold yellow.
121
+ def warning(str, opts = { print: true })
122
+ str = str.dup.to_s
123
+ result = ''
124
+ result += color? ? ANSI_CODES[:bold] + ANSI_CODES[:color][:yellow] : ''
125
+ result += 'WARNING:'
126
+ result += color? ? ANSI_CODES[:reset] : ''
127
+ result += ' '
128
+ result += str
129
+ result += "\n"
130
+ print_or_return(result, opts[:print])
131
+ end
132
+
133
+ # Draws a horizontal line.
134
+ def line(opts = { print: true })
135
+ if color?
136
+ result = ANSI_CODES[:bold] + GLYPHS[:heavy_dash] * 80 + ANSI_CODES[:reset] + "\n"
137
+ else
138
+ result = '-' * 80 + "\n"
139
+ end
140
+ print_or_return(result, opts[:print])
141
+ end
142
+
143
+ # Makes a bullet point.
144
+ def list_item(str, opts = { print: true })
145
+ bullet = color? ? ANSI_CODES[:bold] + ANSI_CODES[:color][:white] + GLYPHS[:bullet] + ANSI_CODES[:reset] : '*'
146
+ result = ' ' + bullet + ' ' + str.to_s + "\n"
147
+ print_or_return(result, opts[:print])
148
+ end
149
+
150
+ # Makes a table. Call with a block; block arg will be a TTY::Table object,
151
+ # with an extension for setting the header.
152
+ # Typical use:
153
+ # ui.table do |t|
154
+ # t.header = ['Name', 'Rank', 'Cereal Number']
155
+ # t << ['Crunch', 'Captain', 1]
156
+ # t << ['', '', 1]
157
+ # end
158
+ def table(opts = { print: true })
159
+ the_table = TableHelper.new
160
+ yield(the_table)
161
+
162
+ colorizer = proc do |data, row, _col|
163
+ if color? && row == 0
164
+ ANSI_CODES[:bold] + ANSI_CODES[:color][:white] + data.to_s + ANSI_CODES[:reset]
165
+ else
166
+ data
167
+ end
168
+ end
169
+ render_mode = color? ? :unicode : :ascii
170
+ padding = [0, 1, 0, 1] # T R B L
171
+ result = the_table.render(render_mode, filter: colorizer, padding: padding) + "\n"
172
+ print_or_return(result, opts[:print])
173
+ end
174
+
175
+ class TableHelper < TTY::Table
176
+ def header=(ary)
177
+ cells = ary.dup.map { |label| { value: label, alignment: :center } }
178
+ @header = TTY::Table::Header.new(cells)
179
+ end
180
+ end
181
+
182
+ #=========================================================================#
183
+ # Exit Codes
184
+ #=========================================================================#
185
+
186
+ def exit(code_sym = :normal)
187
+ # If it's a number, give them a pass for now.
188
+ if code_sym.is_a? Numeric
189
+ code_int = code_sym
190
+ else
191
+ code_const = ('EXIT_' + code_sym.to_s.upcase).to_sym
192
+ unless self.class.const_defined?(code_const)
193
+ warning("Unrecognized exit constant #{code_const} - exit with code 1")
194
+ exit(:usage_error)
195
+ end
196
+ code_int = self.class.const_get(code_const)
197
+ end
198
+ Kernel.exit(code_int)
199
+ end
200
+
201
+ #=========================================================================#
202
+ # Interactivity
203
+ #=========================================================================#
204
+ def interactive?
205
+ @interactive
206
+ end
207
+
208
+ # This simply returns a TTY::Prompt object, gated on interactivity being enabled.
209
+ def prompt
210
+ unless interactive?
211
+ raise Inspec::UserInteractionRequired, 'Somthing is trying to ask the user a question, but interactivity is disabled.'
212
+ end
213
+ @prompt ||= TTY::Prompt.new
214
+ end
215
+ end
216
+ end
@@ -4,5 +4,5 @@
4
4
  # author: Christoph Hartmann
5
5
 
6
6
  module Inspec
7
- VERSION = '3.0.64'
7
+ VERSION = '3.1.3'
8
8
  end
@@ -30,7 +30,7 @@ module Inspec::Resources
30
30
  mysql_cmd = create_mysql_cmd(q, db)
31
31
  cmd = inspec.command(mysql_cmd)
32
32
  out = cmd.stdout + "\n" + cmd.stderr
33
- if out =~ /Can't connect to .* MySQL server/ || out.downcase =~ /^error/
33
+ if out =~ /Can't connect to .* MySQL server/ || out.downcase =~ /^error /
34
34
  # skip this test if the server can't run the query
35
35
  warn("Can't connect to MySQL instance for SQL checks.")
36
36
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inspec-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.64
4
+ version: 3.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dominik Richter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-06 00:00:00.000000000 Z
11
+ date: 2018-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: train-core
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: '1.5'
20
20
  - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: 1.5.6
22
+ version: 1.5.11
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: '1.5'
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: 1.5.6
32
+ version: 1.5.11
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: thor
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -288,6 +288,34 @@ dependencies:
288
288
  - - ">="
289
289
  - !ruby/object:Gem::Version
290
290
  version: '0'
291
+ - !ruby/object:Gem::Dependency
292
+ name: tty-table
293
+ requirement: !ruby/object:Gem::Requirement
294
+ requirements:
295
+ - - "~>"
296
+ - !ruby/object:Gem::Version
297
+ version: '0.10'
298
+ type: :runtime
299
+ prerelease: false
300
+ version_requirements: !ruby/object:Gem::Requirement
301
+ requirements:
302
+ - - "~>"
303
+ - !ruby/object:Gem::Version
304
+ version: '0.10'
305
+ - !ruby/object:Gem::Dependency
306
+ name: tty-prompt
307
+ requirement: !ruby/object:Gem::Requirement
308
+ requirements:
309
+ - - "~>"
310
+ - !ruby/object:Gem::Version
311
+ version: '0.17'
312
+ type: :runtime
313
+ prerelease: false
314
+ version_requirements: !ruby/object:Gem::Requirement
315
+ requirements:
316
+ - - "~>"
317
+ - !ruby/object:Gem::Version
318
+ version: '0.17'
291
319
  description: Core InSpec, local support only. See `inspec` for full support.
292
320
  email:
293
321
  - dominik.richter@gmail.com
@@ -296,15 +324,10 @@ executables:
296
324
  extensions: []
297
325
  extra_rdoc_files: []
298
326
  files:
299
- - CHANGELOG.md
300
- - Gemfile
301
327
  - LICENSE
302
- - MAINTAINERS.md
303
- - MAINTAINERS.toml
304
328
  - README.md
305
329
  - bin/inspec
306
330
  - etc/plugin_filters.json
307
- - inspec-core.gemspec
308
331
  - lib/bundles/README.md
309
332
  - lib/bundles/inspec-compliance/api.rb
310
333
  - lib/bundles/inspec-compliance/configuration.rb
@@ -414,6 +437,7 @@ files:
414
437
  - lib/inspec/shell.rb
415
438
  - lib/inspec/shell_detector.rb
416
439
  - lib/inspec/source_reader.rb
440
+ - lib/inspec/ui.rb
417
441
  - lib/inspec/version.rb
418
442
  - lib/matchers/matchers.rb
419
443
  - lib/plugins/README.md