Class: Inspec::Metadata

Inherits:
Object
  • Object
show all
Defined in:
lib/inspec/metadata.rb

Overview

Extract metadata.rb information

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(ref, logger = nil) ⇒ Metadata

Returns a new instance of Metadata.



16
17
18
19
20
21
22
# File 'lib/inspec/metadata.rb', line 16

def initialize(ref, logger = nil)
  @ref = ref
  @logger = logger || Logger.new(nil)
  @content = ''
  @params = {}
  @missing_methods = []
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(sth, *args) ⇒ Object



140
141
142
143
# File 'lib/inspec/metadata.rb', line 140

def method_missing(sth, *args)
  @logger.warn "#{ref} doesn't support: #{sth} #{args}"
  @missing_methods.push(sth)
end

Instance Attribute Details

#contentObject

Returns the value of attribute content.



15
16
17
# File 'lib/inspec/metadata.rb', line 15

def content
  @content
end

#paramsObject

Returns the value of attribute params.



15
16
17
# File 'lib/inspec/metadata.rb', line 15

def params
  @params
end

#refObject (readonly)

rubocop:disable Metrics/ClassLength



14
15
16
# File 'lib/inspec/metadata.rb', line 14

def ref
  @ref
end

Class Method Details

.finalize(metadata, profile_id, options, logger = nil) ⇒ Object



212
213
214
215
216
217
218
219
220
221
222
# File 'lib/inspec/metadata.rb', line 212

def self.finalize(, profile_id, options, logger = nil)
  return nil if .nil?
  param = .params || {}
  options ||= {}
  param['version'] = param['version'].to_s unless param['version'].nil?
  .params = symbolize_keys(param)
  .params[:supports] = finalize_supports(.params[:supports], logger)
  finalize_name(, profile_id, options[:target])

  
end

.finalize_name(metadata, profile_id, original_target) ⇒ Object



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/inspec/metadata.rb', line 195

def self.finalize_name(, profile_id, original_target)
  # profile_id always overwrites whatever already exists as the name
  unless profile_id.to_s.empty?
    .params[:name] = profile_id.to_s
    return
  end

  # don't overwrite an existing name
  return unless .params[:name].nil?

  # if there's a title, there is no need to set a name too
  return unless .params[:title].nil?

  # create a new name based on the original target if it exists
  .params[:name] = "tests from #{original_target}" unless original_target.to_s.empty?
end

.finalize_supports(supports, logger) ⇒ Object



181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/inspec/metadata.rb', line 181

def self.finalize_supports(supports, logger)
  case x = supports
  when Hash   then [finalize_supports_elem(x, logger)]
  when Array  then x.map { |e| finalize_supports_elem(e, logger) }.compact
  when nil    then []
  else
    logger ||= Logger.new(nil)
    logger.warn(
      "Do not use deprecated `supports: #{x}` syntax. Instead use:\n"\
      "supports:\n  - os-family: #{x}\n\n")
    [{ :'os-family' => x }]
  end
end

.finalize_supports_elem(elem, logger) ⇒ Object



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/inspec/metadata.rb', line 160

def self.finalize_supports_elem(elem, logger)
  case x = elem
  when Hash
    x[:release] = x[:release].to_s if x[:release]
    x
  when Array
    logger.warn(
      'Failed to read supports entry that is an array. Please use '\
      'the `supports: {os-family: xyz}` syntax.',
    )
    nil
  when nil then nil
  else
    logger ||= Logger.new(nil)
    logger.warn(
      "Do not use deprecated `supports: #{x}` syntax. Instead use:\n"\
      "supports:\n  - os-family: #{x}\n\n")
    { :'os-family' => x }
  end
end

.from_file(path, profile_id, logger = nil) ⇒ Object



253
254
255
256
257
258
259
260
261
# File 'lib/inspec/metadata.rb', line 253

def self.from_file(path, profile_id, logger = nil)
  unless File.file?(path)
    logger ||= Logger.new(nil)
    logger.error "Can't find metadata file #{path}"
    return nil
  end

  from_ref(File.basename(path), File.read(path), profile_id, logger)
end

.from_ref(ref, content, profile_id, logger = nil) ⇒ Object



238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/inspec/metadata.rb', line 238

def self.from_ref(ref, content, profile_id, logger = nil)
  # NOTE there doesn't have to exist an actual file, it may come from an
  # archive (i.e., content)
  case File.basename(ref)
  when 'inspec.yml'
    from_yaml(ref, content, profile_id, logger)
  when 'metadata.rb'
    from_ruby(ref, content, profile_id, logger)
  else
    logger ||= Logger.new(nil)
    logger.error "Don't know how to handle metadata in #{ref}"
    nil
  end
end

.from_ruby(ref, content, profile_id, logger = nil) ⇒ Object



231
232
233
234
235
236
# File 'lib/inspec/metadata.rb', line 231

def self.from_ruby(ref, content, profile_id, logger = nil)
  res = .new(ref, logger)
  res.instance_eval(content, ref, 1)
  res.content = content
  finalize(res, profile_id, {}, logger)
end

.from_yaml(ref, content, profile_id, logger = nil) ⇒ Object



224
225
226
227
228
229
# File 'lib/inspec/metadata.rb', line 224

def self.from_yaml(ref, content, profile_id, logger = nil)
  res = .new(ref, logger)
  res.params = YAML.load(content)
  res.content = content
  finalize(res, profile_id, {}, logger)
end

.symbolize_keys(obj) ⇒ Object



149
150
151
152
153
154
155
156
157
158
# File 'lib/inspec/metadata.rb', line 149

def self.symbolize_keys(obj)
  return obj.map { |i| symbolize_keys(i) } if obj.is_a?(Array)
  return obj unless obj.is_a?(Hash)

  obj.each_with_object({}) {|(k, v), h|
    v = symbolize_keys(v) if v.is_a?(Hash)
    v = symbolize_keys(v) if v.is_a?(Array)
    h[k.to_sym] = v
  }
end

Instance Method Details

#dependenciesObject



41
42
43
# File 'lib/inspec/metadata.rb', line 41

def dependencies
  params[:depends] || []
end

#inspec_requirementObject



80
81
82
83
# File 'lib/inspec/metadata.rb', line 80

def inspec_requirement
  inspec = params[:supports].find { |x| !x[:inspec].nil? } || {}
  Gem::Requirement.create(inspec[:inspec])
end

#is_supported?(os, entry) ⇒ Boolean

Returns:

  • (Boolean)


51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/inspec/metadata.rb', line 51

def is_supported?(os, entry)
  name = entry[:'os-name'] || entry[:os]
  family = entry[:'os-family']
  release = entry[:release]

  # return true if the backend matches the supported OS's
  # fields act as masks, i.e. any value configured for os-name, os-family,
  # or release must be met by the backend; any field that is nil acts as
  # a glob expression i.e. is true

  # os name is both saved in :family and :name, so check both
  name_ok = name.nil? ||
            os[:name] == name || os[:family] == name

  family_check = family.to_s + '?'
  family_ok = family.nil? || os[:family] == family ||
              (
                os.respond_to?(family_check) &&
                # this call will return true if the family matches
                os.method(family_check).call
              )

  # ensure we do have a string if we have a non-nil value eg. 16.06
  release_ok = release.nil? || os[:release] == release

  # we want to make sure that all matchers are true
  name_ok && family_ok && release_ok
end

#supports(sth, version = nil) ⇒ Object



45
46
47
48
49
# File 'lib/inspec/metadata.rb', line 45

def supports(sth, version = nil)
  # Ignore supports with metadata.rb. This file is legacy and the way it
  # it handles `supports` deprecated. A deprecation warning will be printed
  # already.
end

#supports_runtime?Boolean

Returns:

  • (Boolean)


85
86
87
88
# File 'lib/inspec/metadata.rb', line 85

def supports_runtime?
  running = Gem::Version.new(Inspec::VERSION)
  inspec_requirement.satisfied_by?(running)
end

#supports_transport?(backend) ⇒ Boolean

Returns:

  • (Boolean)


90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/inspec/metadata.rb', line 90

def supports_transport?(backend)
  # with no supports specified, always return true, as there are no
  # constraints on the supported backend; it is equivalent to putting
  # all fields into accept-all mode
  return true if params[:supports].empty?

  found = params[:supports].find do |entry|
    is_supported?(backend.os, entry)
  end

  # finally, if we found a supported entry, we are good to go
  !found.nil?
end

#unsupportedObject



145
146
147
# File 'lib/inspec/metadata.rb', line 145

def unsupported
  @missing_methods
end

#validObject

return all warn and errors



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/inspec/metadata.rb', line 105

def valid
  errors = []
  warnings = []

  %w{ name version }.each do |field|
    next unless params[field.to_sym].nil?
    errors.push("Missing profile #{field} in #{ref}")
  end

  # if version is set, ensure it is correct
  if !params[:version].nil? && !valid_version?(params[:version])
    errors.push('Version needs to be in SemVer format')
  end

  %w{ title summary maintainer copyright }.each do |field|
    next unless params[field.to_sym].nil?
    warnings.push("Missing profile #{field} in #{ref}")
  end

  [errors, warnings]
end

#valid?Boolean

returns true or false

Returns:

  • (Boolean)


128
129
130
131
# File 'lib/inspec/metadata.rb', line 128

def valid?
  errors, _warnings = valid
  errors.empty? && unsupported.empty?
end

#valid_version?(value) ⇒ Boolean

Returns:

  • (Boolean)


133
134
135
136
137
138
# File 'lib/inspec/metadata.rb', line 133

def valid_version?(value)
  Semverse::Version.new(value)
  true
rescue Semverse::InvalidVersionFormat
  false
end