abide_dev_utils 0.14.2 → 0.16.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/cem/generate/reference.rb +74 -5
- data/lib/abide_dev_utils/cli/cem.rb +15 -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 +7 -27
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 220a0a755c0e337d22a853e106935f4355564e51a759eb93967e3aeba5a9f020
|
4
|
+
data.tar.gz: e0272122e07a4e53d3efa71486de5dc7a0229ca0d22214b3311c94df0c90100b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c7710f102655653f4181694c8dd076acff1dfd8040120c54157bc77a89f3db4a892854d2110ac4a47974ead2fdc23c3b3028c4459aa9e7bf75145e71fcebad0b
|
7
|
+
data.tar.gz: a5d0d101010f6ba4129346c4c4447f433b5a61e36e9000c3dab653a1709b78ff08203ec2dd014e61489d09eb2a78badfb51e233d8cbe33d85c903c3654cae90f
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
abide_dev_utils (0.
|
5
|
-
amatch (~> 0.4)
|
4
|
+
abide_dev_utils (0.16.0)
|
6
5
|
cmdparse (~> 3.0)
|
7
6
|
facterdb (>= 1.21)
|
8
7
|
google-cloud-storage (~> 1.34)
|
@@ -18,16 +17,13 @@ GEM
|
|
18
17
|
remote: https://rubygems.org/
|
19
18
|
specs:
|
20
19
|
CFPropertyList (2.3.6)
|
21
|
-
activesupport (7.0.4.
|
20
|
+
activesupport (7.0.4.3)
|
22
21
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
23
22
|
i18n (>= 1.6, < 2)
|
24
23
|
minitest (>= 5.1)
|
25
24
|
tzinfo (~> 2.0)
|
26
25
|
addressable (2.8.0)
|
27
26
|
public_suffix (>= 2.0.2, < 5.0)
|
28
|
-
amatch (0.4.1)
|
29
|
-
mize
|
30
|
-
tins (~> 1.0)
|
31
27
|
ast (2.4.2)
|
32
28
|
async (1.30.2)
|
33
29
|
console (~> 1.10)
|
@@ -61,7 +57,7 @@ GEM
|
|
61
57
|
diff-lcs (1.5.0)
|
62
58
|
digest-crc (0.6.4)
|
63
59
|
rake (>= 12.0.0, < 14.0.0)
|
64
|
-
facter (4.
|
60
|
+
facter (4.4.1)
|
65
61
|
hocon (~> 1.3)
|
66
62
|
thor (>= 1.0.1, < 2.0)
|
67
63
|
facterdb (1.21.0)
|
@@ -112,7 +108,7 @@ GEM
|
|
112
108
|
google-cloud-core (~> 1.6)
|
113
109
|
googleauth (>= 0.16.2, < 2.a)
|
114
110
|
mini_mime (~> 1.0)
|
115
|
-
googleauth (1.
|
111
|
+
googleauth (1.5.2)
|
116
112
|
faraday (>= 0.17.3, < 3.a)
|
117
113
|
jwt (>= 1.4, < 3.0)
|
118
114
|
memoist (~> 0.16)
|
@@ -122,7 +118,7 @@ GEM
|
|
122
118
|
hashdiff (1.0.1)
|
123
119
|
hashie (5.0.0)
|
124
120
|
hiera (3.12.0)
|
125
|
-
hocon (1.
|
121
|
+
hocon (1.4.0)
|
126
122
|
httpclient (2.8.3)
|
127
123
|
i18n (1.12.0)
|
128
124
|
concurrent-ruby (~> 1.0)
|
@@ -132,18 +128,16 @@ GEM
|
|
132
128
|
atlassian-jwt
|
133
129
|
multipart-post
|
134
130
|
oauth (~> 0.5, >= 0.5.0)
|
135
|
-
jwt (2.7.
|
131
|
+
jwt (2.7.1)
|
136
132
|
locale (2.1.3)
|
137
133
|
memoist (0.16.2)
|
138
134
|
method_source (1.0.0)
|
139
135
|
mini_mime (1.1.2)
|
140
|
-
minitest (5.
|
141
|
-
mize (0.4.1)
|
142
|
-
protocol (~> 2.0)
|
136
|
+
minitest (5.18.0)
|
143
137
|
multi_json (1.15.0)
|
144
138
|
multipart-post (2.3.0)
|
145
139
|
nio4r (2.5.8)
|
146
|
-
nokogiri (1.
|
140
|
+
nokogiri (1.15.2-x86_64-darwin)
|
147
141
|
racc (~> 1.4)
|
148
142
|
oauth (0.6.2)
|
149
143
|
snaky_hash (~> 2.0)
|
@@ -155,8 +149,6 @@ GEM
|
|
155
149
|
parallel (1.22.1)
|
156
150
|
parser (3.1.2.0)
|
157
151
|
ast (~> 2.4.1)
|
158
|
-
protocol (2.0.0)
|
159
|
-
ruby_parser (~> 3.0)
|
160
152
|
protocol-hpack (1.4.2)
|
161
153
|
protocol-http (0.22.6)
|
162
154
|
protocol-http1 (0.14.4)
|
@@ -168,7 +160,7 @@ GEM
|
|
168
160
|
coderay (~> 1.1)
|
169
161
|
method_source (~> 1.0)
|
170
162
|
public_suffix (4.0.7)
|
171
|
-
puppet (7.
|
163
|
+
puppet (7.24.0-universal-darwin)
|
172
164
|
CFPropertyList (~> 2.2)
|
173
165
|
concurrent-ruby (~> 1.0, < 1.2.0)
|
174
166
|
deep_merge (~> 1.0)
|
@@ -182,9 +174,9 @@ GEM
|
|
182
174
|
semantic_puppet (~> 1.0)
|
183
175
|
puppet-resource_api (1.8.14)
|
184
176
|
hocon (>= 1.0)
|
185
|
-
puppet-strings (
|
186
|
-
rgen (~> 0.9
|
187
|
-
yard (~> 0.9
|
177
|
+
puppet-strings (4.0.0)
|
178
|
+
rgen (~> 0.9)
|
179
|
+
yard (~> 0.9)
|
188
180
|
racc (1.6.2)
|
189
181
|
rainbow (3.1.1)
|
190
182
|
rake (13.0.6)
|
@@ -229,8 +221,6 @@ GEM
|
|
229
221
|
rubocop (~> 1.19)
|
230
222
|
ruby-progressbar (1.11.0)
|
231
223
|
ruby2_keywords (0.0.5)
|
232
|
-
ruby_parser (3.20.0)
|
233
|
-
sexp_processor (~> 4.16)
|
234
224
|
rubyzip (2.3.2)
|
235
225
|
sawyer (0.9.2)
|
236
226
|
addressable (>= 2.3.5)
|
@@ -240,8 +230,7 @@ GEM
|
|
240
230
|
childprocess (>= 0.5, < 5.0)
|
241
231
|
rexml (~> 3.2, >= 3.2.5)
|
242
232
|
rubyzip (>= 1.2.2)
|
243
|
-
semantic_puppet (1.0
|
244
|
-
sexp_processor (4.16.1)
|
233
|
+
semantic_puppet (1.1.0)
|
245
234
|
signet (0.17.0)
|
246
235
|
addressable (~> 2.8)
|
247
236
|
faraday (>= 0.17.5, < 3.a)
|
@@ -250,24 +239,21 @@ GEM
|
|
250
239
|
snaky_hash (2.0.1)
|
251
240
|
hashie
|
252
241
|
version_gem (~> 1.1, >= 1.1.1)
|
253
|
-
|
254
|
-
thor (1.2.1)
|
242
|
+
thor (1.2.2)
|
255
243
|
timers (4.3.3)
|
256
|
-
tins (1.32.1)
|
257
|
-
sync
|
258
244
|
traces (0.4.1)
|
259
245
|
trailblazer-option (0.1.2)
|
260
|
-
tzinfo (2.0.
|
246
|
+
tzinfo (2.0.6)
|
261
247
|
concurrent-ruby (~> 1.0)
|
262
248
|
uber (0.1.0)
|
263
249
|
unicode-display_width (2.1.0)
|
264
|
-
version_gem (1.1.
|
265
|
-
webrick (1.
|
266
|
-
yard (0.9.
|
267
|
-
webrick (~> 1.7.0)
|
250
|
+
version_gem (1.1.2)
|
251
|
+
webrick (1.8.1)
|
252
|
+
yard (0.9.34)
|
268
253
|
|
269
254
|
PLATFORMS
|
270
255
|
x86_64-darwin-19
|
256
|
+
x86_64-darwin-20
|
271
257
|
x86_64-linux
|
272
258
|
|
273
259
|
DEPENDENCIES
|
data/abide_dev_utils.gemspec
CHANGED
@@ -41,7 +41,6 @@ Gem::Specification.new do |spec|
|
|
41
41
|
spec.add_dependency 'selenium-webdriver', '~> 4.0.0.beta4'
|
42
42
|
spec.add_dependency 'google-cloud-storage', '~> 1.34'
|
43
43
|
spec.add_dependency 'hashdiff', '~> 1.0'
|
44
|
-
spec.add_dependency 'amatch', '~> 0.4'
|
45
44
|
spec.add_dependency 'facterdb', '>= 1.21'
|
46
45
|
|
47
46
|
# Dev dependencies
|
@@ -85,7 +85,7 @@ module AbideDevUtils
|
|
85
85
|
next if benchmark.framework == 'stig' && control.id_map_type != 'vulnid'
|
86
86
|
|
87
87
|
control_md = ControlMarkdown.new(control, @md, @strings, @module_name, benchmark.framework, opts: @opts)
|
88
|
-
control_md.generate!
|
88
|
+
control_md.generate! if control_md.verify_profile_and_level_selections
|
89
89
|
progress_bar.increment unless @opts[:quiet]
|
90
90
|
rescue StandardError => e
|
91
91
|
raise "Failed to generate markdown for control #{control.id}. Original message: #{e.message}"
|
@@ -248,6 +248,8 @@ module AbideDevUtils
|
|
248
248
|
@framework = framework
|
249
249
|
@formatter = formatter.nil? ? TypeExprValueFormatter : formatter
|
250
250
|
@opts = opts
|
251
|
+
@valid_level = []
|
252
|
+
@valid_profile = []
|
251
253
|
@control_data = {}
|
252
254
|
end
|
253
255
|
|
@@ -262,6 +264,43 @@ module AbideDevUtils
|
|
262
264
|
resource_reference_builder
|
263
265
|
end
|
264
266
|
|
267
|
+
# This function act as a filter for controls based on the profile and level selections.
|
268
|
+
# There are few scanarios that can happen:
|
269
|
+
# 1. If no selections are made for profile or level, then all profiles and levels of control will be selected.
|
270
|
+
# 2. If selections are made for profile, then only the selected profile and all levels of control will be selected.
|
271
|
+
# 3. If selections are made for level, then only the selected level and all profiles of control will be selected.
|
272
|
+
# This function adds in some runtime overhead because we're checking each control's level and profile which is
|
273
|
+
# what we're going to be doing later when building the level and profile markdown, but this is
|
274
|
+
# necessary to ensure that the reference.md is generated the way we want it to be.
|
275
|
+
def verify_profile_and_level_selections
|
276
|
+
return true if @opts[:select_profile].nil? && @opts[:select_level].nil?
|
277
|
+
|
278
|
+
if @opts[:select_profile].nil? && !@opts[:select_level].nil?
|
279
|
+
@control.levels.each do |level|
|
280
|
+
@valid_level << level if select_control_level(level)
|
281
|
+
end
|
282
|
+
|
283
|
+
return true unless @valid_level.empty?
|
284
|
+
elsif !@opts[:select_profile].nil? && @opts[:select_level].nil?
|
285
|
+
@control.profiles.each do |profile|
|
286
|
+
@valid_profile << profile if select_control_profile(profile)
|
287
|
+
end
|
288
|
+
|
289
|
+
return true unless @valid_profile.empty?
|
290
|
+
elsif !@opts[:select_profile].nil? && !@opts[:select_level].nil?
|
291
|
+
@control.levels.each do |level|
|
292
|
+
@valid_level << level if select_control_level(level)
|
293
|
+
end
|
294
|
+
|
295
|
+
@control.profiles.each do |profile|
|
296
|
+
@valid_profile << profile if select_control_profile(profile)
|
297
|
+
end
|
298
|
+
|
299
|
+
# As long as there are valid profiles and levels for the control at this stage, all is good
|
300
|
+
!@valid_level.empty? && !@valid_profile.empty?
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
265
304
|
private
|
266
305
|
|
267
306
|
def heading_builder
|
@@ -340,18 +379,36 @@ module AbideDevUtils
|
|
340
379
|
def control_levels_builder
|
341
380
|
return unless @control.levels
|
342
381
|
|
382
|
+
# @valid_level is populated in verify_profile_and_level_selections from the fact that we've given
|
383
|
+
# the generator a list of levels we want to use. If we didn't give it a list of levels, then we
|
384
|
+
# want to use all of the levels that the control supports from @control.
|
343
385
|
@md.add_ul('Supported Levels:')
|
344
|
-
@
|
345
|
-
@
|
386
|
+
if @valid_level.empty?
|
387
|
+
@control.levels.each do |l|
|
388
|
+
@md.add_ul(@md.code(l), indent: 1)
|
389
|
+
end
|
390
|
+
else
|
391
|
+
@valid_level.each do |l|
|
392
|
+
@md.add_ul(@md.code(l), indent: 1)
|
393
|
+
end
|
346
394
|
end
|
347
395
|
end
|
348
396
|
|
349
397
|
def control_profiles_builder
|
350
398
|
return unless @control.profiles
|
351
399
|
|
400
|
+
# @valid_profile is populated in verify_profile_and_level_selections from the fact that we've given
|
401
|
+
# the generator a list of profiles we want to use. If we didn't give it a list of profiles, then we
|
402
|
+
# want to use all of the profiles that the control supports from @control.
|
352
403
|
@md.add_ul('Supported Profiles:')
|
353
|
-
@
|
354
|
-
@
|
404
|
+
if @valid_profile.empty?
|
405
|
+
@control.profiles.each do |l|
|
406
|
+
@md.add_ul(@md.code(l), indent: 1)
|
407
|
+
end
|
408
|
+
else
|
409
|
+
@valid_profile.each do |l|
|
410
|
+
@md.add_ul(@md.code(l), indent: 1)
|
411
|
+
end
|
355
412
|
end
|
356
413
|
end
|
357
414
|
|
@@ -364,6 +421,18 @@ module AbideDevUtils
|
|
364
421
|
end
|
365
422
|
end
|
366
423
|
|
424
|
+
# Function that returns true if the profile is in the list of profiles that we want to use.
|
425
|
+
# @param profile [String] the profile to filter
|
426
|
+
def select_control_profile(profile)
|
427
|
+
@opts[:select_profile].include? profile
|
428
|
+
end
|
429
|
+
|
430
|
+
# Function that returns true if the level is in the list of levels that we want to use.
|
431
|
+
# @param level [String] the level to filter
|
432
|
+
def select_control_level(level)
|
433
|
+
@opts[:select_level].include? level
|
434
|
+
end
|
435
|
+
|
367
436
|
def dependent_controls_builder
|
368
437
|
dep_ctrls = @control.resource.dependent_controls
|
369
438
|
return if dep_ctrls.nil? || dep_ctrls.empty?
|
@@ -4,7 +4,7 @@ require 'abide_dev_utils/cem'
|
|
4
4
|
require 'abide_dev_utils/files'
|
5
5
|
require 'abide_dev_utils/output'
|
6
6
|
require 'abide_dev_utils/validate'
|
7
|
-
require 'abide_dev_utils/xccdf/diff
|
7
|
+
require 'abide_dev_utils/xccdf/diff'
|
8
8
|
require 'abide_dev_utils/cli/abstract'
|
9
9
|
|
10
10
|
module Abide
|
@@ -113,6 +113,12 @@ module Abide
|
|
113
113
|
options.on('-s', '--strict', 'Fails if there are any errors') do
|
114
114
|
@data[:strict] = true
|
115
115
|
end
|
116
|
+
options.on('-p [PROFILE]', '--select-profile [PROFILE]', 'The list of profiles that the reference.md will use separated by commas') do |pr|
|
117
|
+
@data[:select_profile] = pr.split(',')
|
118
|
+
end
|
119
|
+
options.on('-l [LEVEL]', '--select-level [LEVEL]', 'The list of level that the reference.md will use separated by commas') do |l|
|
120
|
+
@data[:select_level] = l.split(',')
|
121
|
+
end
|
116
122
|
end
|
117
123
|
|
118
124
|
def execute
|
@@ -162,13 +168,14 @@ module Abide
|
|
162
168
|
end
|
163
169
|
|
164
170
|
def execute(config_file, cur_xccdf, new_xccdf)
|
165
|
-
|
166
|
-
AbideDevUtils::Validate.file(
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
AbideDevUtils::
|
171
|
-
AbideDevUtils::Output.
|
171
|
+
warn 'This command is currently non-functional'
|
172
|
+
# AbideDevUtils::Validate.file(config_file, extension: 'yaml')
|
173
|
+
# AbideDevUtils::Validate.file(cur_xccdf, extension: 'xml')
|
174
|
+
# config_hiera = AbideDevUtils::Files::Reader.read(config_file, safe: true)
|
175
|
+
# diff = AbideDevUtils::XCCDF::Diff::BenchmarkDiff.new(cur_xccdf, new_xccdf).diff[:diff][:number_title]
|
176
|
+
# new_config_hiera, change_report = AbideDevUtils::CEM.update_legacy_config_from_diff(config_hiera, diff)
|
177
|
+
# AbideDevUtils::Output.yaml(new_config_hiera, console: @data[:verbose], file: @data[:out_file])
|
178
|
+
# AbideDevUtils::Output.simple(change_report) unless @data[:quiet]
|
172
179
|
end
|
173
180
|
end
|
174
181
|
|
@@ -23,6 +23,7 @@ module Abide
|
|
23
23
|
add_command(JiraNewIssueCommand.new)
|
24
24
|
add_command(JiraFromCoverageCommand.new)
|
25
25
|
add_command(JiraFromXccdfCommand.new)
|
26
|
+
add_command(JiraFromXccdfDiffCommand.new)
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
@@ -46,7 +47,7 @@ module Abide
|
|
46
47
|
end
|
47
48
|
|
48
49
|
class JiraGetIssueCommand < CmdParse::Command
|
49
|
-
CMD_NAME = '
|
50
|
+
CMD_NAME = 'get-issue'
|
50
51
|
CMD_SHORT = 'Gets a specific issue'
|
51
52
|
CMD_LONG = 'Returns JSON of a specific issue from key (<project>-<num>)'
|
52
53
|
def initialize
|
@@ -67,7 +68,7 @@ module Abide
|
|
67
68
|
end
|
68
69
|
|
69
70
|
class JiraNewIssueCommand < CmdParse::Command
|
70
|
-
CMD_NAME = '
|
71
|
+
CMD_NAME = 'new-issue'
|
71
72
|
CMD_SHORT = 'Creates a new issue in a project'
|
72
73
|
CMD_LONG = 'Allows you to create a new issue in a project'
|
73
74
|
def initialize
|
@@ -93,7 +94,7 @@ module Abide
|
|
93
94
|
end
|
94
95
|
|
95
96
|
class JiraFromCoverageCommand < CmdParse::Command
|
96
|
-
CMD_NAME = '
|
97
|
+
CMD_NAME = 'from-coverage'
|
97
98
|
CMD_SHORT = 'Creates a parent issue with subtasks from a coverage report'
|
98
99
|
CMD_LONG = 'Creates a parent issue with subtasks for a benchmark and any uncovered controls'
|
99
100
|
def initialize
|
@@ -116,7 +117,7 @@ module Abide
|
|
116
117
|
end
|
117
118
|
|
118
119
|
class JiraFromXccdfCommand < CmdParse::Command
|
119
|
-
CMD_NAME = '
|
120
|
+
CMD_NAME = 'from-xccdf'
|
120
121
|
CMD_SHORT = 'Creates a parent issue with subtasks from a xccdf file'
|
121
122
|
CMD_LONG = 'Creates a parent issue with subtasks for a benchmark and any uncovered controls'
|
122
123
|
def initialize
|
@@ -136,5 +137,48 @@ module Abide
|
|
136
137
|
JIRA.new_issues_from_xccdf(client, proj, path, epic: @data[:epic], dry_run: @data[:dry_run])
|
137
138
|
end
|
138
139
|
end
|
140
|
+
|
141
|
+
class JiraFromXccdfDiffCommand < CmdParse::Command
|
142
|
+
CMD_NAME = 'from-xccdf-diff'
|
143
|
+
CMD_SHORT = 'Creates an Epic with tasks from a xccdf diff'
|
144
|
+
CMD_LONG = 'Creates an Epic with tasks for changes in a diff of two XCCDF files'
|
145
|
+
def initialize
|
146
|
+
super(CMD_NAME, takes_commands: false)
|
147
|
+
short_desc(CMD_SHORT)
|
148
|
+
long_desc(CMD_LONG)
|
149
|
+
argument_desc(PATH1: 'An XCCDF file', PATH2: 'An XCCDF file', PROJECT: 'A Jira project')
|
150
|
+
options.on('-d', '--dry-run', 'Print to console instead of saving objects') { |_| @data[:dry_run] = true }
|
151
|
+
options.on('-y', '--yes', 'Automatically approve all yes / no prompts') { |_| @data[:auto_approve] = true }
|
152
|
+
options.on('-e [EPIC]', '--epic [EPIC]', 'If given, tasks will be created and assigned to this epic. Takes form <PROJECT>-<NUM>') { |e| @data[:epic] = e }
|
153
|
+
options.on('-p [PROFILE]', '--profile', 'Only diff rules belonging to the matching profile. Takes a string that is treated as RegExp') do |x|
|
154
|
+
@data[:diff_opts] ||= {}
|
155
|
+
@data[:diff_opts][:profile] = x
|
156
|
+
end
|
157
|
+
options.on('-l [LEVEL]', '--level', 'Only diff rules belonging to the matching level. Takes a string that is treated as RegExp') do |x|
|
158
|
+
@data[:diff_opts] ||= {}
|
159
|
+
@data[:diff_opts][:level] = x
|
160
|
+
end
|
161
|
+
options.on('-i [PROPS]', '--ignore-changed-properties', 'Ignore changes to specified properties. Takes a comma-separated list.') do |x|
|
162
|
+
@data[:diff_opts] ||= {}
|
163
|
+
@data[:diff_opts][:ignore_changed_properties] = x.split(',')
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def execute(path1, path2, project)
|
168
|
+
Abide::CLI::VALIDATE.file(path1)
|
169
|
+
Abide::CLI::VALIDATE.file(path2)
|
170
|
+
@data[:dry_run] = false if @data[:dry_run].nil?
|
171
|
+
client = JIRA.client(options: {})
|
172
|
+
proj = JIRA.project(client, project)
|
173
|
+
JIRA.new_issues_from_xccdf_diff(client,
|
174
|
+
proj,
|
175
|
+
path1,
|
176
|
+
path2,
|
177
|
+
epic: @data[:epic],
|
178
|
+
dry_run: @data[:dry_run],
|
179
|
+
auto_approve: @data[:auto_approve],
|
180
|
+
diff_opts: @data[:diff_opts])
|
181
|
+
end
|
182
|
+
end
|
139
183
|
end
|
140
184
|
end
|
@@ -104,27 +104,21 @@ module Abide
|
|
104
104
|
super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: false)
|
105
105
|
argument_desc(FILE1: CMD_FILE1_ARG, FILE2: CMD_FILE2_ARG)
|
106
106
|
options.on('-o [PATH]', '--out-file', 'Save the report as a yaml file') { |x| @data[:outfile] = x }
|
107
|
-
options.on('-p [PROFILE]', '--profile', 'Only diff
|
107
|
+
options.on('-p [PROFILE]', '--profile', 'Only diff rules belonging to the matching profile. Takes a string that is treated as RegExp') do |x|
|
108
108
|
@data[:profile] = x
|
109
109
|
end
|
110
|
-
options.on('-l [LEVEL]', '--level', 'Only diff the
|
110
|
+
options.on('-l [LEVEL]', '--level', 'Only diff rules belonging to the matching level. Takes a string that is treated as RegExp') do |x|
|
111
111
|
@data[:level] = x
|
112
112
|
end
|
113
|
-
options.on('-
|
113
|
+
options.on('-i [PROPS]', '--ignore-changed-properties', 'Ignore changes to specified properties. Takes a comma-separated list.') do |x|
|
114
|
+
@data[:ignore_changed_properties] = x.split(',')
|
115
|
+
end
|
116
|
+
options.on('-r', '--raw', 'Output the diff in raw format') { @data[:raw] = true }
|
114
117
|
options.on('-q', '--quiet', 'Show no output in the terminal') { @data[:quiet] = false }
|
115
|
-
options.on('--no-diff-profiles', 'Do not diff the profiles in the XCCDF files') { @data[:diff_profiles] = false }
|
116
|
-
options.on('--no-diff-controls', 'Do not diff the controls in the XCCDF files') { @data[:diff_controls] = false }
|
117
|
-
options.on('--old-style', 'Use old-style diffs') { @data[:old_style] = true }
|
118
118
|
end
|
119
119
|
|
120
120
|
def execute(file1, file2)
|
121
|
-
diffreport =
|
122
|
-
AbideDevUtils::XCCDF.diff(file1, file2, @data)
|
123
|
-
else
|
124
|
-
dr = AbideDevUtils::XCCDF.new_style_diff(file1, file2, @data)
|
125
|
-
dr[:diff][:number_title].map! { |d| d[:text] }
|
126
|
-
dr
|
127
|
-
end
|
121
|
+
diffreport = AbideDevUtils::XCCDF.diff(file1, file2, @data)
|
128
122
|
AbideDevUtils::Output.yaml(diffreport, console: @data.fetch(:quiet, true), file: @data.fetch(:outfile, nil))
|
129
123
|
end
|
130
124
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require_relative 'files'
|
4
4
|
|
5
5
|
module AbideDevUtils
|
6
6
|
module Config
|
@@ -9,15 +9,12 @@ module AbideDevUtils
|
|
9
9
|
def self.to_h(path = DEFAULT_PATH)
|
10
10
|
return {} unless File.file?(path)
|
11
11
|
|
12
|
-
h =
|
12
|
+
h = AbideDevUtils::Files::Reader.read(path)
|
13
13
|
h.transform_keys(&:to_sym)
|
14
14
|
end
|
15
15
|
|
16
16
|
def to_h(path = DEFAULT_PATH)
|
17
|
-
|
18
|
-
|
19
|
-
h = YAML.safe_load(File.open(path), [Symbol])
|
20
|
-
h.transform_keys(&:to_sym)
|
17
|
+
self.class.to_h(path)
|
21
18
|
end
|
22
19
|
|
23
20
|
def self.config_section(section, path = DEFAULT_PATH)
|
@@ -12,12 +12,7 @@ module AbideDevUtils
|
|
12
12
|
extension = File.extname(path)
|
13
13
|
case extension
|
14
14
|
when /\.yaml|\.yml/
|
15
|
-
|
16
|
-
if safe
|
17
|
-
YAML.safe_load(File.read(path))
|
18
|
-
else
|
19
|
-
YAML.load_file(path)
|
20
|
-
end
|
15
|
+
read_yaml(path, safe: safe, opts: opts)
|
21
16
|
when '.json'
|
22
17
|
require 'json'
|
23
18
|
return JSON.parse(File.read(path), opts) if safe
|
@@ -34,6 +29,21 @@ module AbideDevUtils
|
|
34
29
|
File.read(path)
|
35
30
|
end
|
36
31
|
end
|
32
|
+
|
33
|
+
def self.read_yaml(path, safe: true, opts: { permitted_classes: [Symbol] })
|
34
|
+
permitted_classes = opts[:permitted_classes] || [Symbol]
|
35
|
+
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.0.0')
|
36
|
+
require 'psych'
|
37
|
+
return Psych.safe_load_file(path, permitted_classes: permitted_classes) if safe
|
38
|
+
|
39
|
+
Psych.load_file(path)
|
40
|
+
else
|
41
|
+
require 'yaml'
|
42
|
+
return YAML.safe_load(File.read(path), permitted_classes) if safe
|
43
|
+
|
44
|
+
YAML.load(File.read(path)) # rubocop:disable Security/YAMLLoad
|
45
|
+
end
|
46
|
+
end
|
37
47
|
end
|
38
48
|
|
39
49
|
class Writer
|
data/lib/abide_dev_utils/jira.rb
CHANGED
@@ -11,6 +11,7 @@ module AbideDevUtils
|
|
11
11
|
ERRORS = AbideDevUtils::Errors::Jira
|
12
12
|
COV_PARENT_SUMMARY_PREFIX = '::BENCHMARK:: '
|
13
13
|
COV_CHILD_SUMMARY_PREFIX = '::CONTROL:: '
|
14
|
+
UPD_EPIC_SUMMARY_PREFIX = '::BENCHMARK UPDATE::'
|
14
15
|
PROGRESS_BAR_FORMAT = '%a %e %P% Created: %c of %C'
|
15
16
|
|
16
17
|
def self.project(client, project)
|
@@ -58,7 +59,7 @@ module AbideDevUtils
|
|
58
59
|
iss.save
|
59
60
|
end
|
60
61
|
|
61
|
-
def self.new_issue(client, project, summary, labels: ['abide_dev_utils'], epic: nil, dry_run: false)
|
62
|
+
def self.new_issue(client, project, summary, description: nil, labels: ['abide_dev_utils'], epic: nil, dry_run: false)
|
62
63
|
if dry_run
|
63
64
|
sleep(0.2)
|
64
65
|
return Dummy.new(summary)
|
@@ -69,6 +70,7 @@ module AbideDevUtils
|
|
69
70
|
fields['reporter'] = myself(client)
|
70
71
|
fields['issuetype'] = issuetype(client, 'Task')
|
71
72
|
fields['priority'] = priority(client, '6')
|
73
|
+
fields['description'] = description if description
|
72
74
|
fields['labels'] = labels
|
73
75
|
epic = issue(client, epic) if epic && !epic.is_a?(JIRA::Resource::Issue)
|
74
76
|
fields['customfield_10006'] = epic.key if epic # Epic_Link
|
@@ -227,6 +229,72 @@ module AbideDevUtils
|
|
227
229
|
AbideDevUtils::Output.simple("#{dr_prefix(dry_run)}Done creating tasks in Epic '#{epic.summary}'")
|
228
230
|
end
|
229
231
|
|
232
|
+
def self.new_issues_from_xccdf_diff(client, project, xccdf1_path, xccdf2_path, epic: nil, dry_run: false, auto_approve: false, diff_opts: {})
|
233
|
+
require 'abide_dev_utils/xccdf/diff'
|
234
|
+
diff = AbideDevUtils::XCCDF::Diff::BenchmarkDiff.new(xccdf1_path, xccdf2_path, diff_opts)
|
235
|
+
i_attrs = all_project_issues_attrs(project)
|
236
|
+
# We need to get the actual epic Issue object, or create it if it doesn't exist
|
237
|
+
epic = if epic.nil?
|
238
|
+
new_epic_summary = "#{UPD_EPIC_SUMMARY_PREFIX}#{diff.this.title}: v#{diff.this.version} -> #{diff.other.version}"
|
239
|
+
if summary_exist?(new_epic_summary, i_attrs)
|
240
|
+
issue(client, new_epic_summary)
|
241
|
+
else
|
242
|
+
unless AbideDevUtils::Prompt.yes_no("#{dr_prefix(dry_run)}Create new epic '#{new_epic_summary}'?", auto_approve: auto_approve)
|
243
|
+
AbideDevUtils::Output.simple("#{dr_prefix(dry_run)}Aborting")
|
244
|
+
exit(0)
|
245
|
+
end
|
246
|
+
new_epic(client, project.key, new_epic_summary, dry_run: dry_run)
|
247
|
+
end
|
248
|
+
else
|
249
|
+
issue(client, epic)
|
250
|
+
end
|
251
|
+
to_create = {}
|
252
|
+
diff.diff[:rules].each do |key, val|
|
253
|
+
next if val.empty?
|
254
|
+
|
255
|
+
val.each do |v|
|
256
|
+
case key
|
257
|
+
when :added
|
258
|
+
sum = "Add rule #{v[:number]} - #{v[:title]}"
|
259
|
+
sum = "#{sum[0..60]}..." if sum.length > 60
|
260
|
+
to_create[sum] = <<~DESC
|
261
|
+
Rule #{v[:number]} - #{v[:title]} is added with #{diff.other.title} #{diff.other.version}
|
262
|
+
DESC
|
263
|
+
when :removed
|
264
|
+
sum = "Remove rule #{v[:number]} - #{v[:title]}"
|
265
|
+
sum = "#{sum[0..60]}..." if sum.length > 60
|
266
|
+
to_create[sum] = <<~DESC
|
267
|
+
Rule #{v[:number]} - #{v[:title]} is removed from #{diff.this.title} #{diff.this.version}
|
268
|
+
DESC
|
269
|
+
else
|
270
|
+
sum = "Update rule \"#{v[:from]}\""
|
271
|
+
sum = "#{sum[0..60]}..." if sum.length > 60
|
272
|
+
to_create[sum] = <<~DESC
|
273
|
+
Rule #{v[:from]} is updated in #{diff.other.title} #{diff.other.version}:
|
274
|
+
#{v[:changes].collect { |k, v| "#{k}: #{v}" }.join("\n")}
|
275
|
+
DESC
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
approved_create = {}
|
280
|
+
to_create.each do |summary, description|
|
281
|
+
if AbideDevUtils::Prompt.yes_no("#{dr_prefix(dry_run)}Create new issue '#{summary}' with description:\n#{description}", auto_approve: auto_approve)
|
282
|
+
approved_create[summary] = description
|
283
|
+
end
|
284
|
+
end
|
285
|
+
AbideDevUtils::Output.simple("#{dr_prefix(dry_run)}Creating #{approved_create.keys.count} new Jira issues")
|
286
|
+
progress = AbideDevUtils::Output.progress(title: "#{dr_prefix(dry_run)}Creating issues",
|
287
|
+
total: approved_create.keys.count,
|
288
|
+
format: PROGRESS_BAR_FORMAT)
|
289
|
+
approved_create.each do |summary, description|
|
290
|
+
progress.log("#{dr_prefix(dry_run)}Creating #{summary}...")
|
291
|
+
new_issue(client, project.key, summary, description: description, labels: [], epic: epic, dry_run: dry_run)
|
292
|
+
progress.increment
|
293
|
+
end
|
294
|
+
progress.finish
|
295
|
+
AbideDevUtils::Output.simple("#{dr_prefix(dry_run)}Done creating tasks in Epic '#{epic.summary}'")
|
296
|
+
end
|
297
|
+
|
230
298
|
def self.merge_options(options)
|
231
299
|
config.merge(options)
|
232
300
|
end
|