abide_dev_utils 0.9.5 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'abide_dev_utils/files'
4
+ require 'abide_dev_utils/xccdf/parser/objects'
5
+
6
+ module AbideDevUtils
7
+ module XCCDF
8
+ # Contains methods and classes for parsing XCCDF files,
9
+ module Parser
10
+ def self.parse(file_path)
11
+ doc = AbideDevUtils::Files::Reader.read(file_path)
12
+ benchmark = AbideDevUtils::XCCDF::Parser::Objects::Benchmark.new(doc)
13
+ Linker.resolve_links(benchmark)
14
+ benchmark
15
+ end
16
+
17
+ # Links XCCDF objects by reference.
18
+ # Each link is resolved and then a bidirectional link is established
19
+ # between the two objects.
20
+ module Linker
21
+ def self.resolve_links(benchmark)
22
+ link_profile_rules(benchmark)
23
+ link_rule_values(benchmark)
24
+ end
25
+
26
+ def self.link_profile_rules(benchmark)
27
+ rules = benchmark.find_children_by_class(AbideDevUtils::XCCDF::Parser::Objects::Rule, recurse: true)
28
+ benchmark.profile.each do |profile|
29
+ profile.xccdf_select.each do |sel|
30
+ rules.select { |rule| rule.id == sel.idref }.each do |rule|
31
+ rule.add_link(profile)
32
+ profile.add_link(rule)
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ def self.link_rule_values(benchmark)
39
+ rules = benchmark.find_children_by_class(AbideDevUtils::XCCDF::Parser::Objects::Rule, recurse: true)
40
+ benchmark.value.each do |value|
41
+ rules.each do |rule|
42
+ unless rule.find_children_by_attribute_value('value-id', value.id, recurse: true).empty?
43
+ rule.add_link(value)
44
+ value.add_link(rule)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -34,21 +34,17 @@ module AbideDevUtils
34
34
 
35
35
  # Diffs two xccdf files
36
36
  def self.diff(file1, file2, opts)
37
+ require 'abide_dev_utils/xccdf/diff'
37
38
  bm1 = Benchmark.new(file1)
38
39
  bm2 = Benchmark.new(file2)
39
- profile = opts.fetch(:profile, nil)
40
- profile_diff = if profile.nil?
41
- bm1.diff_profiles(bm2).each do |_, v|
42
- v.transform_values! { |x| x.map!(&:to_s) }
43
- end
44
- else
45
- bm1.diff_profiles(bm2)[profile].transform_values! { |x| x.map!(&:to_s) }
46
- end
47
- profile_key = profile.nil? ? 'all_profiles' : profile
48
- {
49
- 'benchmark' => bm1.diff_title_version(bm2),
50
- profile_key => profile_diff
51
- }
40
+ AbideDevUtils::XCCDF::Diff.diff_benchmarks(bm1, bm2, opts)
41
+ end
42
+
43
+ # Use new-style diff
44
+ def self.new_style_diff(file1, file2, opts)
45
+ require 'abide_dev_utils/xccdf/diff/benchmark'
46
+ bm_diff = AbideDevUtils::XCCDF::Diff::BenchmarkDiff.new(file1, file2, opts)
47
+ bm_diff.diff
52
48
  end
53
49
 
54
50
  # Common constants and methods included by nearly everything else
@@ -164,25 +160,6 @@ module AbideDevUtils
164
160
  diff_properties.map { |x| send(x) } == other.diff_properties.map { |x| other.send(x) }
165
161
  end
166
162
 
167
- def default_diff_opts
168
- {
169
- similarity: 1,
170
- strict: true,
171
- strip: true,
172
- array_path: true,
173
- delimiter: '//',
174
- use_lcs: false
175
- }
176
- end
177
-
178
- def diff(other, **opts)
179
- Hashdiff.diff(
180
- to_h,
181
- other.to_h,
182
- default_diff_opts.merge(opts)
183
- )
184
- end
185
-
186
163
  def abide_object?
187
164
  true
188
165
  end
@@ -231,9 +208,12 @@ module AbideDevUtils
231
208
  profiles.select { |x| x.title == profile_title }.controls
232
209
  end
233
210
 
234
- def gen_map(dir: nil, type: 'CIS', parent_key_prefix: '', **_)
211
+ def gen_map(dir: nil, type: 'cis', parent_key_prefix: '', version_output_dir: false, **_)
235
212
  os, ver = facter_platform
236
- mapping_dir = dir ? File.expand_path(File.join(dir, type, os, ver)) : ''
213
+ output_path = [type, os, ver]
214
+ output_path.unshift(File.expand_path(dir)) if dir
215
+ output_path << version if version_output_dir
216
+ mapping_dir = File.expand_path(File.join(output_path))
237
217
  parent_key_prefix = '' if parent_key_prefix.nil?
238
218
  MAP_INDICES.each_with_object({}) do |idx, h|
239
219
  map_file_path = "#{mapping_dir}/#{idx}.yaml"
@@ -257,33 +237,6 @@ module AbideDevUtils
257
237
  }
258
238
  end
259
239
 
260
- def diff_title_version(other)
261
- Hashdiff.diff(
262
- to_h.reject { |k, _| k.to_s == 'profiles' },
263
- other.to_h.reject { |k, _| k.to_s == 'profiles' },
264
- default_diff_opts
265
- )
266
- end
267
-
268
- def diff_profiles(other)
269
- this_diff = {}
270
- other_hash = other.to_h[:profiles]
271
- to_h[:profiles].each do |name, data|
272
- diff_h = Hashdiff.diff(data, other_hash[name], default_diff_opts).each_with_object({}) do |x, a|
273
- val_to = x.length == 4 ? x[3] : nil
274
- a_key = x[2].is_a?(Hash) ? x[2][:title] : x[2]
275
- a[a_key] = [] unless a.key?(a_key)
276
- a[a_key] << ChangeSet.new(change: x[0], key: x[1], value: x[2], value_to: val_to)
277
- end
278
- this_diff[name] = diff_h
279
- end
280
- this_diff
281
- end
282
-
283
- def diff_controls(other)
284
- controls.diff(other.controls)
285
- end
286
-
287
240
  def map_indexed(index: 'title', framework: 'cis', key_prefix: '')
288
241
  c_map = profiles.each_with_object({}) do |profile, obj|
289
242
  obj[profile.level.downcase] = {} unless obj[profile.level.downcase].is_a?(Hash)
@@ -298,7 +251,16 @@ module AbideDevUtils
298
251
 
299
252
  def facter_platform
300
253
  cpe = xpath('xccdf:Benchmark/xccdf:platform')[0]['idref'].split(':')
301
- [cpe[4].split('_')[0], cpe[5].split('.')[0]]
254
+ if cpe.length > 4
255
+ product_name = cpe[4].split('_')
256
+ product_version = cpe[5].split('.') unless cpe[5].nil?
257
+ return [product_name[0], product_version[0]] unless product_version[0] == '-'
258
+
259
+ return [product_name[0], product_name[-1]] if product_version[0] == '-'
260
+ end
261
+
262
+ product = cpe[3].split('_')
263
+ [product[0], product[-1]] # This should wrap the name i.e 'Windows' and the version '10'
302
264
  end
303
265
 
304
266
  # Converts object to Hiera-formatted YAML
@@ -387,69 +349,6 @@ module AbideDevUtils
387
349
  end
388
350
  end
389
351
 
390
- class ChangeSet
391
- attr_reader :change, :key, :value, :value_to
392
-
393
- def initialize(change:, key:, value:, value_to: nil)
394
- validate_change(change)
395
- @change = change
396
- @key = key
397
- @value = value
398
- @value_to = value_to
399
- end
400
-
401
- def to_s
402
- val_to_str = value_to.nil? ? ' ' : " to #{value_to} "
403
- "#{change_string} value #{value}#{val_to_str}at #{key}"
404
- end
405
-
406
- def can_merge?(other)
407
- return false unless (change == '-' && other.change == '+') || (change == '+' && other.change == '-')
408
- return false unless key == other.key || value_hash_equality(other)
409
-
410
- true
411
- end
412
-
413
- def merge(other)
414
- unless can_merge?(other)
415
- raise ArgumentError, 'Cannot merge. Possible causes: change is identical; key or value do not match'
416
- end
417
-
418
- new_to_value = value == other.value ? nil : other.value
419
- ChangeSet.new(
420
- change: '~',
421
- key: key,
422
- value: value,
423
- value_to: new_to_value
424
- )
425
- end
426
-
427
- private
428
-
429
- def value_hash_equality(other)
430
- equality = false
431
- value.each do |k, v|
432
- equality = true if v == other.value[k]
433
- end
434
- equality
435
- end
436
-
437
- def validate_change(change)
438
- raise ArgumentError, "Change type #{change} in invalid" unless ['+', '-', '~'].include?(change)
439
- end
440
-
441
- def change_string
442
- case change
443
- when '-'
444
- 'remove'
445
- when '+'
446
- 'add'
447
- else
448
- 'change'
449
- end
450
- end
451
- end
452
-
453
352
  class ObjectContainer
454
353
  include AbideDevUtils::XCCDF::Common
455
354
 
data/new_diff.rb ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'yaml'
5
+ require 'pry'
6
+ require 'abide_dev_utils/xccdf/diff/benchmark'
7
+
8
+ xml_file1 = File.expand_path(ARGV[0])
9
+ xml_file2 = File.expand_path(ARGV[1])
10
+ legacy_config = ARGV.length > 2 ? YAML.load_file(File.expand_path(ARGV[2])) : nil
11
+
12
+ def convert_legacy_config(config, num_title_diff, key_format: :hiera_num)
13
+ nt_diff = num_title_diff.diff(key: :number)
14
+ updated_config = config['config']['control_configs'].each_with_object({}) do |(key, value), h|
15
+ next if value.nil?
16
+
17
+ diff_key = key.to_s.gsub(/^c/, '').tr('_', '.') if key_format == :hiera_num
18
+ if nt_diff.key?(diff_key)
19
+ if nt_diff[diff_key][0][:diff] == :number
20
+ new_key = "c#{nt_diff[diff_key][0][:other_number].to_s.tr('.', '_')}"
21
+ h[new_key] = value
22
+ puts "Converted #{key} to #{new_key}"
23
+ elsif nt_diff[diff_key][0][:diff] == :title
24
+
25
+ h[key] = value
26
+ end
27
+ else
28
+ h[key] = value
29
+ end
30
+ end
31
+ { 'config' => { 'control_configs' => updated_config } }.to_yaml
32
+ end
33
+
34
+ start_time = Time.now
35
+
36
+ bm_diff = AbideDevUtils::XCCDF::Diff::BenchmarkDiff.new(xml_file1, xml_file2)
37
+ self_nc_count, other_nc_count = bm_diff.numbered_children_counts
38
+ puts "Benchmark numbered children count: #{self_nc_count}"
39
+ puts "Other benchmark numbered children count: #{other_nc_count}"
40
+ puts "Rule count difference: #{bm_diff.numbered_children_count_diff}"
41
+ num_diff = bm_diff.number_title_diff
42
+ binding.pry if legacy_config.nil?
43
+ File.open('/tmp/legacy_converted.yaml', 'w') do |f|
44
+ converted = convert_legacy_config(legacy_config, num_diff)
45
+ f.write(converted)
46
+ end
47
+
48
+ puts "Computation time: #{Time.now - start_time}"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: abide_dev_utils
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.5
4
+ version: 0.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - abide-team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-02-10 00:00:00.000000000 Z
11
+ date: 2022-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.11'
19
+ version: '1.13'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.11'
26
+ version: '1.13'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: cmdparse
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
124
  version: '1.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: amatch
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.4'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.4'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: bundler
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -330,8 +344,10 @@ files:
330
344
  - bin/setup
331
345
  - exe/abide
332
346
  - lib/abide_dev_utils.rb
347
+ - lib/abide_dev_utils/cem.rb
333
348
  - lib/abide_dev_utils/cli.rb
334
349
  - lib/abide_dev_utils/cli/abstract.rb
350
+ - lib/abide_dev_utils/cli/cem.rb
335
351
  - lib/abide_dev_utils/cli/comply.rb
336
352
  - lib/abide_dev_utils/cli/jira.rb
337
353
  - lib/abide_dev_utils/cli/puppet.rb
@@ -364,6 +380,18 @@ files:
364
380
  - lib/abide_dev_utils/validate.rb
365
381
  - lib/abide_dev_utils/version.rb
366
382
  - lib/abide_dev_utils/xccdf.rb
383
+ - lib/abide_dev_utils/xccdf/diff.rb
384
+ - lib/abide_dev_utils/xccdf/diff/benchmark.rb
385
+ - lib/abide_dev_utils/xccdf/diff/benchmark/number_title.rb
386
+ - lib/abide_dev_utils/xccdf/diff/benchmark/profile.rb
387
+ - lib/abide_dev_utils/xccdf/diff/benchmark/property.rb
388
+ - lib/abide_dev_utils/xccdf/diff/benchmark/property_existence.rb
389
+ - lib/abide_dev_utils/xccdf/diff/utils.rb
390
+ - lib/abide_dev_utils/xccdf/parser.rb
391
+ - lib/abide_dev_utils/xccdf/parser/objects.rb
392
+ - lib/abide_dev_utils/xccdf/parser/objects/digest_object.rb
393
+ - lib/abide_dev_utils/xccdf/parser/objects/numbered_object.rb
394
+ - new_diff.rb
367
395
  homepage: https://github.com/puppetlabs/abide_dev_utils
368
396
  licenses:
369
397
  - MIT
@@ -386,7 +414,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
386
414
  - !ruby/object:Gem::Version
387
415
  version: '0'
388
416
  requirements: []
389
- rubygems_version: 3.1.6
417
+ rubygems_version: 3.1.4
390
418
  signing_key:
391
419
  specification_version: 4
392
420
  summary: Helper utilities for developing compliance Puppet code