abide_dev_utils 0.14.2 → 0.15.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.
- checksums.yaml +4 -4
- data/Gemfile.lock +19 -33
- data/abide_dev_utils.gemspec +0 -1
- data/lib/abide_dev_utils/cli/cem.rb +9 -8
- data/lib/abide_dev_utils/cli/jira.rb +48 -4
- data/lib/abide_dev_utils/cli/xccdf.rb +7 -13
- data/lib/abide_dev_utils/config.rb +3 -6
- data/lib/abide_dev_utils/files.rb +16 -6
- data/lib/abide_dev_utils/jira.rb +69 -1
- data/lib/abide_dev_utils/prompt.rb +3 -1
- data/lib/abide_dev_utils/version.rb +1 -1
- data/lib/abide_dev_utils/xccdf/diff.rb +64 -200
- data/lib/abide_dev_utils/xccdf/parser/helpers.rb +0 -93
- data/lib/abide_dev_utils/xccdf/parser/objects/diffable_object.rb +347 -0
- data/lib/abide_dev_utils/xccdf/parser/objects.rb +413 -89
- data/lib/abide_dev_utils/xccdf/parser.rb +8 -9
- data/lib/abide_dev_utils/xccdf.rb +1 -10
- metadata +4 -24
- data/lib/abide_dev_utils/xccdf/diff/benchmark/number_title.rb +0 -270
- data/lib/abide_dev_utils/xccdf/diff/benchmark/profile.rb +0 -104
- data/lib/abide_dev_utils/xccdf/diff/benchmark/property.rb +0 -127
- data/lib/abide_dev_utils/xccdf/diff/benchmark/property_existence.rb +0 -47
- data/lib/abide_dev_utils/xccdf/diff/benchmark.rb +0 -267
- data/lib/abide_dev_utils/xccdf/diff/utils.rb +0 -30
- data/lib/abide_dev_utils/xccdf/parser/objects/digest_object.rb +0 -118
@@ -27,10 +27,10 @@ module AbideDevUtils
|
|
27
27
|
def self.link_profile_rules(benchmark)
|
28
28
|
return unless benchmark.respond_to?(:profile)
|
29
29
|
|
30
|
-
rules = benchmark.
|
30
|
+
rules = benchmark.descendants.select { |d| d.label == 'rule' }
|
31
31
|
benchmark.profile.each do |profile|
|
32
32
|
profile.xccdf_select.each do |sel|
|
33
|
-
rules.select { |rule| rule.id == sel.idref }.each do |rule|
|
33
|
+
rules.select { |rule| rule.id.value == sel.idref.value }.each do |rule|
|
34
34
|
rule.add_link(profile)
|
35
35
|
profile.add_link(rule)
|
36
36
|
end
|
@@ -41,14 +41,13 @@ module AbideDevUtils
|
|
41
41
|
def self.link_rule_values(benchmark)
|
42
42
|
return unless benchmark.respond_to?(:value)
|
43
43
|
|
44
|
-
rules = benchmark.
|
44
|
+
rules = benchmark.descendants.select { |d| d.label == 'rule' }
|
45
45
|
benchmark.value.each do |value|
|
46
|
-
rules.
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
end
|
46
|
+
rule = rules.find { |r| r.title.to_s == value.title.to_s }
|
47
|
+
next unless rule
|
48
|
+
|
49
|
+
rule.add_link(value)
|
50
|
+
value.add_link(rule)
|
52
51
|
end
|
53
52
|
end
|
54
53
|
end
|
@@ -37,16 +37,7 @@ module AbideDevUtils
|
|
37
37
|
# Diffs two xccdf files
|
38
38
|
def self.diff(file1, file2, opts)
|
39
39
|
require 'abide_dev_utils/xccdf/diff'
|
40
|
-
|
41
|
-
bm2 = Benchmark.new(file2)
|
42
|
-
AbideDevUtils::XCCDF::Diff.diff_benchmarks(bm1, bm2, opts)
|
43
|
-
end
|
44
|
-
|
45
|
-
# Use new-style diff
|
46
|
-
def self.new_style_diff(file1, file2, opts)
|
47
|
-
require 'abide_dev_utils/xccdf/diff/benchmark'
|
48
|
-
bm_diff = AbideDevUtils::XCCDF::Diff::BenchmarkDiff.new(file1, file2, opts)
|
49
|
-
bm_diff.diff
|
40
|
+
AbideDevUtils::XCCDF::Diff.benchmark_diff(file1, file2, opts)
|
50
41
|
end
|
51
42
|
|
52
43
|
# Common constants and methods included by nearly everything else
|
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.
|
4
|
+
version: 0.15.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: 2023-
|
11
|
+
date: 2023-06-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -136,20 +136,6 @@ dependencies:
|
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: '1.0'
|
139
|
-
- !ruby/object:Gem::Dependency
|
140
|
-
name: amatch
|
141
|
-
requirement: !ruby/object:Gem::Requirement
|
142
|
-
requirements:
|
143
|
-
- - "~>"
|
144
|
-
- !ruby/object:Gem::Version
|
145
|
-
version: '0.4'
|
146
|
-
type: :runtime
|
147
|
-
prerelease: false
|
148
|
-
version_requirements: !ruby/object:Gem::Requirement
|
149
|
-
requirements:
|
150
|
-
- - "~>"
|
151
|
-
- !ruby/object:Gem::Version
|
152
|
-
version: '0.4'
|
153
139
|
- !ruby/object:Gem::Dependency
|
154
140
|
name: facterdb
|
155
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -448,16 +434,10 @@ files:
|
|
448
434
|
- lib/abide_dev_utils/version.rb
|
449
435
|
- lib/abide_dev_utils/xccdf.rb
|
450
436
|
- lib/abide_dev_utils/xccdf/diff.rb
|
451
|
-
- lib/abide_dev_utils/xccdf/diff/benchmark.rb
|
452
|
-
- lib/abide_dev_utils/xccdf/diff/benchmark/number_title.rb
|
453
|
-
- lib/abide_dev_utils/xccdf/diff/benchmark/profile.rb
|
454
|
-
- lib/abide_dev_utils/xccdf/diff/benchmark/property.rb
|
455
|
-
- lib/abide_dev_utils/xccdf/diff/benchmark/property_existence.rb
|
456
|
-
- lib/abide_dev_utils/xccdf/diff/utils.rb
|
457
437
|
- lib/abide_dev_utils/xccdf/parser.rb
|
458
438
|
- lib/abide_dev_utils/xccdf/parser/helpers.rb
|
459
439
|
- lib/abide_dev_utils/xccdf/parser/objects.rb
|
460
|
-
- lib/abide_dev_utils/xccdf/parser/objects/
|
440
|
+
- lib/abide_dev_utils/xccdf/parser/objects/diffable_object.rb
|
461
441
|
- lib/abide_dev_utils/xccdf/parser/objects/numbered_object.rb
|
462
442
|
- lib/abide_dev_utils/xccdf/utils.rb
|
463
443
|
- new_diff.rb
|
@@ -483,7 +463,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
483
463
|
- !ruby/object:Gem::Version
|
484
464
|
version: '0'
|
485
465
|
requirements: []
|
486
|
-
rubygems_version: 3.
|
466
|
+
rubygems_version: 3.4.6
|
487
467
|
signing_key:
|
488
468
|
specification_version: 4
|
489
469
|
summary: Helper utilities for developing compliance Puppet code
|
@@ -1,270 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'abide_dev_utils/xccdf/diff/benchmark/property_existence'
|
4
|
-
|
5
|
-
module AbideDevUtils
|
6
|
-
module XCCDF
|
7
|
-
module Diff
|
8
|
-
# Diffs two XCCDF benchmarks using the title / number of the items as the primary
|
9
|
-
# diff properties.
|
10
|
-
class NumberTitleDiff
|
11
|
-
SKIP_DIFF_TYPES = %i[equal both].freeze
|
12
|
-
|
13
|
-
def initialize(numbered_children, other_numbered_children)
|
14
|
-
new_number_title_objs(numbered_children, other_numbered_children)
|
15
|
-
end
|
16
|
-
|
17
|
-
def diff
|
18
|
-
@diff ||= find_diffs(@number_title_objs, @other_number_title_objs)
|
19
|
-
end
|
20
|
-
|
21
|
-
def to_s
|
22
|
-
parts = []
|
23
|
-
@diff.each do |_, diffs|
|
24
|
-
diffs.each do |dh|
|
25
|
-
parts << dh[:diff_text]
|
26
|
-
end
|
27
|
-
end
|
28
|
-
parts.join("\n")
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
attr_writer :diff
|
34
|
-
|
35
|
-
def added_number_title_objs
|
36
|
-
added_titles = @self_prop_checker.added_titles
|
37
|
-
@other_number_title_objs.select do |nto|
|
38
|
-
added_titles.include?(nto.title)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def removed_number_title_objs
|
43
|
-
removed_titles = @self_prop_checker.removed_titles
|
44
|
-
@number_title_objs.select do |nto|
|
45
|
-
removed_titles.include?(nto.title)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def find_diffs(objs, other_objs)
|
50
|
-
diffs = []
|
51
|
-
added_number_title_objs.each do |nto|
|
52
|
-
change_type = %i[both added]
|
53
|
-
stand_in = NumberTitleContainerStandIn.new(change_type)
|
54
|
-
diffs << process_diffs([diff_hash(change_type, stand_in, nto)])
|
55
|
-
end
|
56
|
-
removed_number_title_objs.each do |nto|
|
57
|
-
change_type = %i[both removed]
|
58
|
-
stand_in = NumberTitleContainerStandIn.new(change_type)
|
59
|
-
diffs << process_diffs([diff_hash(change_type, nto, stand_in)])
|
60
|
-
end
|
61
|
-
objs.each do |obj|
|
62
|
-
obj_diffs = other_objs.each_with_object([]) do |other_obj, o_ary|
|
63
|
-
obj_diff = obj.diff(other_obj)
|
64
|
-
next if SKIP_DIFF_TYPES.include?(obj_diff[0])
|
65
|
-
|
66
|
-
o_ary << diff_hash(obj_diff, obj, other_obj)
|
67
|
-
end
|
68
|
-
|
69
|
-
processed_obj_diffs = process_diffs(obj_diffs)
|
70
|
-
diffs << processed_obj_diffs unless obj_diffs.empty?
|
71
|
-
end
|
72
|
-
diffs
|
73
|
-
end
|
74
|
-
|
75
|
-
def process_diffs(diffs)
|
76
|
-
return {} if diffs.empty?
|
77
|
-
|
78
|
-
raise "Unexpected diffs: #{diffs}" if diffs.length > 2
|
79
|
-
|
80
|
-
return diffs[0] if diffs.length == 1
|
81
|
-
|
82
|
-
if diffs[0][:type][0] == PropChecker.inverse_existence_state[diffs[1][:type][0]]
|
83
|
-
diffs[0]
|
84
|
-
else
|
85
|
-
diffs[1]
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def diff_hash(diff_type, obj, other_obj)
|
90
|
-
{
|
91
|
-
self: obj.child,
|
92
|
-
other: other_obj.child,
|
93
|
-
type: diff_type,
|
94
|
-
text: diff_type_text(diff_type, obj, other_obj),
|
95
|
-
number: obj.number,
|
96
|
-
other_number: other_obj.number,
|
97
|
-
title: obj.title,
|
98
|
-
other_title: other_obj.title,
|
99
|
-
}
|
100
|
-
end
|
101
|
-
|
102
|
-
def diff_type_text(diff_type, obj, other_obj)
|
103
|
-
DiffTypeText.text(diff_type, obj, other_obj)
|
104
|
-
end
|
105
|
-
|
106
|
-
def new_number_title_objs(children, other_children)
|
107
|
-
number_title_objs = children.map { |c| NumberTitleContainer.new(c) }.sort
|
108
|
-
other_number_title_objs = other_children.map { |c| NumberTitleContainer.new(c) }.sort
|
109
|
-
@self_prop_checker = PropChecker.new(number_title_objs, other_number_title_objs)
|
110
|
-
@other_prop_checker = PropChecker.new(other_number_title_objs, number_title_objs)
|
111
|
-
number_title_objs.map { |n| n.prop_checker = @self_prop_checker }
|
112
|
-
other_number_title_objs.map { |n| n.prop_checker = @other_prop_checker }
|
113
|
-
@number_title_objs = number_title_objs
|
114
|
-
@other_number_title_objs = other_number_title_objs
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
# Creates string representations of diff types
|
119
|
-
class DiffTypeText
|
120
|
-
def self.text(diff_type, obj, other_obj)
|
121
|
-
case diff_type[0]
|
122
|
-
when :equal
|
123
|
-
'The objects are equal'
|
124
|
-
when :title
|
125
|
-
"Title changed: Number \"#{obj.number}\": #{obj.title} -> #{other_obj.title}"
|
126
|
-
when :number
|
127
|
-
number_diff_type_text(diff_type, obj, other_obj)
|
128
|
-
when :both
|
129
|
-
both_diff_type_text(diff_type, obj, other_obj)
|
130
|
-
when :add
|
131
|
-
"Add object with number \"#{other_obj.number}\" and title \"#{other_obj.title}\""
|
132
|
-
when :remove
|
133
|
-
"Remove object with number \"#{obj.number}\" and title \"#{obj.title}\""
|
134
|
-
else
|
135
|
-
raise ArgumentError, "Unknown diff type: #{diff_type}"
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
def self.number_diff_type_text(diff_type, obj, other_obj)
|
140
|
-
case diff_type[1]
|
141
|
-
when :added
|
142
|
-
"Number changed (New Number): Title \"#{obj.title}\": #{obj.number} -> #{other_obj.number}"
|
143
|
-
when :exists
|
144
|
-
"Number changed (Existing Number): Title \"#{obj.title}\": #{obj.number} -> #{other_obj.number}"
|
145
|
-
else
|
146
|
-
raise ArgumentError, "Unknown diff type for number change: #{diff_type[1]}"
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
def self.both_diff_type_text(diff_type, obj, other_obj)
|
151
|
-
case diff_type[1]
|
152
|
-
when :added
|
153
|
-
"Added object: Title \"#{other_obj.title}\": Number \"#{other_obj.number}\""
|
154
|
-
when :removed
|
155
|
-
"Removed object: Title \"#{obj.title}\": Number \"#{obj.number}\""
|
156
|
-
else
|
157
|
-
raise ArgumentError, "Unknown diff type for both change: #{diff_type[1]}"
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
# Checks properties for existence in both benchmarks.
|
163
|
-
class PropChecker < AbideDevUtils::XCCDF::Diff::PropertyExistenceChecker
|
164
|
-
attr_reader :all_numbers, :all_titles, :other_all_numbers, :other_all_titles
|
165
|
-
|
166
|
-
def initialize(number_title_objs, other_number_title_objs)
|
167
|
-
super
|
168
|
-
@all_numbers = number_title_objs.map(&:number)
|
169
|
-
@all_titles = number_title_objs.map(&:title)
|
170
|
-
@other_all_numbers = other_number_title_objs.map(&:number)
|
171
|
-
@other_all_titles = other_number_title_objs.map(&:title)
|
172
|
-
end
|
173
|
-
|
174
|
-
def title(title)
|
175
|
-
property_existence(title, @all_titles, @other_all_titles)
|
176
|
-
end
|
177
|
-
|
178
|
-
def number(number)
|
179
|
-
property_existence(number, @all_numbers, @other_all_numbers)
|
180
|
-
end
|
181
|
-
|
182
|
-
def added_numbers
|
183
|
-
added(@all_numbers, @other_all_numbers)
|
184
|
-
end
|
185
|
-
|
186
|
-
def removed_numbers
|
187
|
-
removed(@all_numbers, @other_all_numbers)
|
188
|
-
end
|
189
|
-
|
190
|
-
def added_titles
|
191
|
-
added(@all_titles, @other_all_titles)
|
192
|
-
end
|
193
|
-
|
194
|
-
def removed_titles
|
195
|
-
removed(@all_titles, @other_all_titles)
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
class NumberTitleDiffError < StandardError; end
|
200
|
-
class InconsistentDiffTypeError < StandardError; end
|
201
|
-
|
202
|
-
# Holds a number and title for a child of a benchmark
|
203
|
-
# and provides methods to compare it to another child.
|
204
|
-
class NumberTitleContainer
|
205
|
-
include ::Comparable
|
206
|
-
attr_accessor :prop_checker
|
207
|
-
attr_reader :child, :number, :title
|
208
|
-
|
209
|
-
def initialize(child, prop_checker = nil)
|
210
|
-
@child = child
|
211
|
-
@number = child.number.to_s
|
212
|
-
@title = child.title.to_s
|
213
|
-
@prop_checker = prop_checker
|
214
|
-
end
|
215
|
-
|
216
|
-
def diff(other)
|
217
|
-
return %i[equal exist] if number == other.number && title == other.title
|
218
|
-
|
219
|
-
if number == other.number && title != other.title
|
220
|
-
c_diff = correlate_prop_diff_types(@prop_checker.title(other.title),
|
221
|
-
other.prop_checker.title(other.title))
|
222
|
-
[:title, c_diff]
|
223
|
-
elsif title == other.title && number != other.number
|
224
|
-
c_diff = correlate_prop_diff_types(@prop_checker.number(other.number),
|
225
|
-
other.prop_checker.number(other.number))
|
226
|
-
[:number, c_diff]
|
227
|
-
else
|
228
|
-
%i[both exist]
|
229
|
-
end
|
230
|
-
rescue StandardError => e
|
231
|
-
err_str = [
|
232
|
-
'Error diffing number and title',
|
233
|
-
"Number: #{number}",
|
234
|
-
"Title: #{title}",
|
235
|
-
"Other number: #{other.number}",
|
236
|
-
"Other title: #{other.title}",
|
237
|
-
e.message,
|
238
|
-
]
|
239
|
-
raise NumberTitleDiffError, err_str.join(', ')
|
240
|
-
end
|
241
|
-
|
242
|
-
def <=>(other)
|
243
|
-
child <=> other.child
|
244
|
-
end
|
245
|
-
|
246
|
-
private
|
247
|
-
|
248
|
-
def correlate_prop_diff_types(self_type, other_type)
|
249
|
-
inverse_diff_type = PropChecker.inverse_existence_state[self_type]
|
250
|
-
return other_type if inverse_diff_type.nil?
|
251
|
-
|
252
|
-
self_type
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
# Stand-in object for a NumberTitleContainer when the NumberTitleContainer
|
257
|
-
# would not exist. This is used when a change is an add or remove.
|
258
|
-
class NumberTitleContainerStandIn
|
259
|
-
attr_reader :child, :number, :title
|
260
|
-
|
261
|
-
def initialize(change_type)
|
262
|
-
@change_type = change_type
|
263
|
-
@child = nil
|
264
|
-
@number = ''
|
265
|
-
@title = ''
|
266
|
-
end
|
267
|
-
end
|
268
|
-
end
|
269
|
-
end
|
270
|
-
end
|
@@ -1,104 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'abide_dev_utils/xccdf/diff/benchmark/property_existence'
|
4
|
-
|
5
|
-
module AbideDevUtils
|
6
|
-
module XCCDF
|
7
|
-
module Diff
|
8
|
-
# Diffs two sets of XCCDF profiles.
|
9
|
-
class ProfileDiff
|
10
|
-
def initialize(profiles, other_profiles)
|
11
|
-
new_profile_rule_objs(profiles, other_profiles)
|
12
|
-
end
|
13
|
-
|
14
|
-
def diff_hash(diff_type, profile1, prof1_rules, profile2, prof2_rules)
|
15
|
-
{
|
16
|
-
|
17
|
-
}
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def new_profile_rule_objs(profiles, other_profiles)
|
23
|
-
profile_objs = containers_from_profile_list(profiles)
|
24
|
-
other_profile_objs = containers_from_profile_list(other_profiles)
|
25
|
-
@self_prop_checker = PropertyExistenceChecker.new(profile_objs, other_profile_objs)
|
26
|
-
@other_prop_checker = PropertyExistenceChecker.new(other_profile_objs, profile_objs)
|
27
|
-
profile_objs.map { |p| p.prop_checker = @self_prop_checker }
|
28
|
-
other_profile_objs.map { |p| p.prop_checker = @other_prop_checker }
|
29
|
-
@profile_rule_objs = profile_objs
|
30
|
-
@other_profile_rule_objs = other_profile_objs
|
31
|
-
end
|
32
|
-
|
33
|
-
def containers_from_profile_list(profile_list)
|
34
|
-
profile_list.each_with_object([]) do |profile, ary|
|
35
|
-
ary << ProfileRuleContainer.new(profile)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# Checks property existence in both profiles.
|
41
|
-
class PropChecker < AbideDevUtils::XCCDF::Diff::Benchmark::PropertyExistence
|
42
|
-
def initialize(profile_rule_objs, other_profile_rule_objs)
|
43
|
-
super
|
44
|
-
@profile_rule_objs = profile_rule_objs
|
45
|
-
@other_profile_rule_objs = other_profile_rule_objs
|
46
|
-
@profiles = profile_rule_objs.map(&:profile)
|
47
|
-
@other_profiles = other_profile_rule_objs.map(&:profile)
|
48
|
-
end
|
49
|
-
|
50
|
-
def profile(profile)
|
51
|
-
profile_key = profile.respond_to?(:id) ? profile.id : profile
|
52
|
-
property_existence(profile_key, @profiles, @other_profiles)
|
53
|
-
end
|
54
|
-
|
55
|
-
def rule_in_profile(rule, profile, rule_key: :title)
|
56
|
-
rk = rule.respond_to?(rule_key) ? rule.send(rule_key) : rule
|
57
|
-
rules = @profiles.find { |p| p.id == profile }.linked_rule.map(&rk)
|
58
|
-
other_rules = @other_profiles.find { |p| p.id == profile }.linked_rule.map(&rk)
|
59
|
-
property_existence(rk, rules, other_rules)
|
60
|
-
end
|
61
|
-
|
62
|
-
def added_profiles
|
63
|
-
added(@other_profiles.map(&:id), @profiles.map(&:id))
|
64
|
-
end
|
65
|
-
|
66
|
-
def removed_profiles
|
67
|
-
removed(@profiles.map(&:id), @other_profiles.map(&:id))
|
68
|
-
end
|
69
|
-
|
70
|
-
def added_rules_by_profile
|
71
|
-
@rules_by_profile.each_with_object({}) do |(profile, rules), hsh|
|
72
|
-
next unless @other_rules_by_profile.key?(profile)
|
73
|
-
|
74
|
-
hsh[profile] = added(rules, @other_rules_by_profile[profile])
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def removed_rules_by_profile
|
79
|
-
@rules_by_profile.each_with_object({}) do |(profile, rules), hsh|
|
80
|
-
next unless @other_rules_by_profile.key?(profile)
|
81
|
-
|
82
|
-
hsh[profile] = removed(rules, @other_rules_by_profile[profile])
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
class ProfileRuleContainer
|
88
|
-
include ::Comparable
|
89
|
-
attr_accessor :prop_checker
|
90
|
-
attr_reader :profile, :rules
|
91
|
-
|
92
|
-
def initialize(profile, prop_checker = nil)
|
93
|
-
@profile = profile
|
94
|
-
@rules = profile.linked_rule
|
95
|
-
@prop_checker = prop_checker
|
96
|
-
end
|
97
|
-
|
98
|
-
def <=>(other)
|
99
|
-
@profile.id <=> other.profile.id
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
@@ -1,127 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'amatch'
|
4
|
-
|
5
|
-
module AbideDevUtils
|
6
|
-
module XCCDF
|
7
|
-
module Diff
|
8
|
-
# Diffs benchmark properties.
|
9
|
-
module BenchmarkPropertyDiff
|
10
|
-
DEFAULT_PROPERTY_DIFF_OPTS = {
|
11
|
-
rule_properties_for_similarity: %i[title description rationale fixtext],
|
12
|
-
rule_properties_for_confidence: %i[description rationale fixtext],
|
13
|
-
rule_confidence_property_threshold: 0.7,
|
14
|
-
rule_confidence_total_threshold: 0.5,
|
15
|
-
digest_similarity_threshold: 0.75,
|
16
|
-
digest_similarity_label_weights: {
|
17
|
-
'title' => 4.0,
|
18
|
-
},
|
19
|
-
digest_similarity_only_labels: %w[title description fixtext rationale],
|
20
|
-
digest_top_x_similarities: 10,
|
21
|
-
}.freeze
|
22
|
-
|
23
|
-
def safe_rule_prop(rule, prop)
|
24
|
-
rule.respond_to?(prop) ? rule.send(prop).to_s : :none
|
25
|
-
end
|
26
|
-
|
27
|
-
def self_rule_vals
|
28
|
-
@self_rule_vals ||= {}
|
29
|
-
end
|
30
|
-
|
31
|
-
def other_rule_vals
|
32
|
-
@other_rule_vals ||= {}
|
33
|
-
end
|
34
|
-
|
35
|
-
def add_rule_val(rule, prop, val, container: nil)
|
36
|
-
raise ArgumentError, 'container must not be nil' if container.nil?
|
37
|
-
|
38
|
-
return unless container.dig(rule, prop).nil?
|
39
|
-
|
40
|
-
container[rule] ||= {}
|
41
|
-
container[rule][prop] = val
|
42
|
-
end
|
43
|
-
|
44
|
-
def add_self_rule_val(rule, prop, val)
|
45
|
-
add_rule_val(rule, prop, val, container: self_rule_vals)
|
46
|
-
end
|
47
|
-
|
48
|
-
def add_other_rule_val(rule, prop, val)
|
49
|
-
add_rule_val(rule, prop, val, container: other_rule_vals)
|
50
|
-
end
|
51
|
-
|
52
|
-
def same_rule?(prop_similarities)
|
53
|
-
confidence_indicator = 0.0
|
54
|
-
opts[:rule_properties_for_confidence].each do |prop|
|
55
|
-
confidence_indicator += 1.0 if prop_similarities[prop] >= opts[:rule_confidence_property_threshold]
|
56
|
-
end
|
57
|
-
(confidence_indicator / opts[:rule_properties_for_confidence].length) >= opts[:rule_confidence_total_threshold]
|
58
|
-
end
|
59
|
-
|
60
|
-
def maxed_digest_similarities(child, other_children)
|
61
|
-
similarities = other_children.each_with_object([]) do |other_child, ary|
|
62
|
-
if other_child.digest_equal? child
|
63
|
-
ary << [1.0, other_child]
|
64
|
-
next
|
65
|
-
end
|
66
|
-
|
67
|
-
d_sim = child.digest_similarity(other_child,
|
68
|
-
only_labels: opts[:digest_similarity_only_labels],
|
69
|
-
label_weights: opts[:digest_similarity_label_weights])
|
70
|
-
ary << [d_sim, other_child]
|
71
|
-
end
|
72
|
-
max_digest_similarities(similarities)
|
73
|
-
end
|
74
|
-
|
75
|
-
def max_digest_similarities(digest_similarities)
|
76
|
-
digest_similarities.reject! { |s| s[0] < opts[:digest_similarity_threshold] }
|
77
|
-
return digest_similarities if digest_similarities.empty?
|
78
|
-
|
79
|
-
digest_similarities.max_by(opts[:digest_top_x_similarities]) { |s| s[0] }
|
80
|
-
end
|
81
|
-
|
82
|
-
def rule_property_similarity(rule1, rule2)
|
83
|
-
prop_similarities = {}
|
84
|
-
prop_diff = {}
|
85
|
-
opts[:rule_properties_for_similarity].each do |prop|
|
86
|
-
add_self_rule_val(rule1, prop, safe_rule_prop(rule1, prop).to_s)
|
87
|
-
add_other_rule_val(rule2, prop, safe_rule_prop(rule2, prop).to_s)
|
88
|
-
prop_similarities[prop] = self_rule_vals[rule1][prop].levenshtein_similar(other_rule_vals[rule2][prop])
|
89
|
-
if prop_similarities[prop] < 1.0
|
90
|
-
prop_diff[prop] = { self: self_rule_vals[rule1][prop], other: other_rule_vals[rule2][prop] }
|
91
|
-
end
|
92
|
-
end
|
93
|
-
total = prop_similarities.values.sum / opts[:rule_properties_for_similarity].length
|
94
|
-
{
|
95
|
-
total: total,
|
96
|
-
prop_similarities: prop_similarities,
|
97
|
-
prop_diff: prop_diff,
|
98
|
-
confident_same: same_rule?(prop_similarities),
|
99
|
-
}
|
100
|
-
end
|
101
|
-
|
102
|
-
def most_similar(child, maxed_digest_similarities)
|
103
|
-
most_similar_map = maxed_digest_similarities.each_with_object({}) do |similarity, h|
|
104
|
-
prop_similarities = rule_property_similarity(child, similarity[1])
|
105
|
-
if child.title.to_s == similarity[1].title.to_s
|
106
|
-
prop_similarities[:total] = 99.0 # magic number denoting a title match
|
107
|
-
end
|
108
|
-
h[prop_similarities[:total]] = { self: child, other: similarity[1] }.merge(prop_similarities)
|
109
|
-
end
|
110
|
-
most_similar_map[most_similar_map.keys.max]
|
111
|
-
end
|
112
|
-
|
113
|
-
def find_most_similar(children, other_children)
|
114
|
-
children.each_with_object({}) do |benchmark_child, h|
|
115
|
-
maxed_similarities = maxed_digest_similarities(benchmark_child, other_children)
|
116
|
-
next if maxed_similarities.empty?
|
117
|
-
|
118
|
-
best = most_similar(benchmark_child, maxed_similarities)
|
119
|
-
next if best.nil? || best.empty?
|
120
|
-
|
121
|
-
h[benchmark_child] = best
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module AbideDevUtils
|
4
|
-
module XCCDF
|
5
|
-
module Diff
|
6
|
-
# PropertyExistenceChecker provides methods to check existence state of various properties
|
7
|
-
class PropertyExistenceChecker
|
8
|
-
def initialize(*_args); end
|
9
|
-
|
10
|
-
# Compares two arrays (or other iterables implementing `#to_a`)
|
11
|
-
# containing properies and returns an array of the properties
|
12
|
-
# that are added by other_props but not in self_props.
|
13
|
-
def added(self_props, other_props)
|
14
|
-
other_props.to_a - self_props.to_a
|
15
|
-
end
|
16
|
-
|
17
|
-
# Compares two arrays (or other iterables implementing `#to_a`)
|
18
|
-
# containing properies and returns an array of the properties
|
19
|
-
# that are removed by other_props but exist in self_props.
|
20
|
-
def removed(this, other)
|
21
|
-
this.to_a - other.to_a
|
22
|
-
end
|
23
|
-
|
24
|
-
# Returns a hash of existence states and their inverse.
|
25
|
-
def self.inverse_existence_state
|
26
|
-
{
|
27
|
-
removed: :added,
|
28
|
-
added: :removed,
|
29
|
-
exists: :exists,
|
30
|
-
}
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def property_existence(property, self_props, other_props)
|
36
|
-
if self_props.include?(property) && !other_props.include?(property)
|
37
|
-
:removed
|
38
|
-
elsif !self_props.include?(property) && other_props.include?(property)
|
39
|
-
:added
|
40
|
-
else
|
41
|
-
:exists
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|