abide_dev_utils 0.9.4 → 0.10.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.
@@ -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
@@ -257,33 +234,6 @@ module AbideDevUtils
257
234
  }
258
235
  end
259
236
 
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
237
  def map_indexed(index: 'title', framework: 'cis', key_prefix: '')
288
238
  c_map = profiles.each_with_object({}) do |profile, obj|
289
239
  obj[profile.level.downcase] = {} unless obj[profile.level.downcase].is_a?(Hash)
@@ -298,7 +248,16 @@ module AbideDevUtils
298
248
 
299
249
  def facter_platform
300
250
  cpe = xpath('xccdf:Benchmark/xccdf:platform')[0]['idref'].split(':')
301
- [cpe[4].split('_')[0], cpe[5].split('.')[0]]
251
+ if cpe.length > 4
252
+ product_name = cpe[4].split('_')
253
+ product_version = cpe[5].split('.') unless cpe[5].nil?
254
+ return [product_name[0], product_version[0]] unless product_version[0] == '-'
255
+
256
+ return [product_name[0], product_name[-1]] if product_version[0] == '-'
257
+ end
258
+
259
+ product = cpe[3].split('_')
260
+ [product[0], product[-1]] # This should wrap the name i.e 'Windows' and the version '10'
302
261
  end
303
262
 
304
263
  # Converts object to Hiera-formatted YAML
@@ -387,69 +346,6 @@ module AbideDevUtils
387
346
  end
388
347
  end
389
348
 
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
349
  class ObjectContainer
454
350
  include AbideDevUtils::XCCDF::Common
455
351
 
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.4
4
+ version: 0.10.0
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-01-25 00:00:00.000000000 Z
11
+ date: 2022-05-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '2.1'
61
+ version: '2.2'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '2.1'
68
+ version: '2.2'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: ruby-progressbar
71
71
  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