abide_dev_utils 0.9.7 → 0.11.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/.gitignore +1 -0
- data/.rubocop.yml +7 -1
- data/Gemfile.lock +82 -64
- data/Rakefile +28 -0
- data/abide_dev_utils.gemspec +3 -1
- data/lib/abide_dev_utils/cem/benchmark.rb +291 -0
- data/lib/abide_dev_utils/cem/coverage_report.rb +348 -0
- data/lib/abide_dev_utils/cem/generate/reference.rb +116 -0
- data/lib/abide_dev_utils/cem/generate.rb +10 -0
- data/lib/abide_dev_utils/cem/mapping/mapper.rb +155 -0
- data/lib/abide_dev_utils/cem.rb +74 -0
- data/lib/abide_dev_utils/cli/cem.rb +153 -0
- data/lib/abide_dev_utils/cli/jira.rb +1 -1
- data/lib/abide_dev_utils/cli/xccdf.rb +15 -1
- data/lib/abide_dev_utils/cli.rb +2 -0
- data/lib/abide_dev_utils/errors/cem.rb +22 -0
- data/lib/abide_dev_utils/errors/general.rb +8 -2
- data/lib/abide_dev_utils/errors/ppt.rb +4 -0
- data/lib/abide_dev_utils/errors.rb +6 -0
- data/lib/abide_dev_utils/files.rb +34 -0
- data/lib/abide_dev_utils/markdown.rb +104 -0
- data/lib/abide_dev_utils/ppt/facter_utils.rb +140 -0
- data/lib/abide_dev_utils/ppt/hiera.rb +297 -0
- data/lib/abide_dev_utils/ppt/puppet_module.rb +74 -0
- data/lib/abide_dev_utils/ppt.rb +3 -5
- data/lib/abide_dev_utils/validate.rb +14 -0
- data/lib/abide_dev_utils/version.rb +1 -1
- data/lib/abide_dev_utils/xccdf/diff/benchmark/number_title.rb +270 -0
- data/lib/abide_dev_utils/xccdf/diff/benchmark/profile.rb +104 -0
- data/lib/abide_dev_utils/xccdf/diff/benchmark/property.rb +127 -0
- data/lib/abide_dev_utils/xccdf/diff/benchmark/property_existence.rb +47 -0
- data/lib/abide_dev_utils/xccdf/diff/benchmark.rb +267 -0
- data/lib/abide_dev_utils/xccdf/diff/utils.rb +30 -0
- data/lib/abide_dev_utils/xccdf/diff.rb +233 -0
- data/lib/abide_dev_utils/xccdf/parser/objects/digest_object.rb +118 -0
- data/lib/abide_dev_utils/xccdf/parser/objects/numbered_object.rb +104 -0
- data/lib/abide_dev_utils/xccdf/parser/objects.rb +741 -0
- data/lib/abide_dev_utils/xccdf/parser.rb +52 -0
- data/lib/abide_dev_utils/xccdf.rb +14 -124
- data/new_diff.rb +48 -0
- metadata +60 -9
- data/lib/abide_dev_utils/ppt/coverage.rb +0 -86
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'yaml'
|
5
|
+
require 'abide_dev_utils/markdown'
|
6
|
+
require 'abide_dev_utils/ppt'
|
7
|
+
require 'abide_dev_utils/cem/benchmark'
|
8
|
+
|
9
|
+
module AbideDevUtils
|
10
|
+
module CEM
|
11
|
+
module Generate
|
12
|
+
# Holds objects and methods for generating a reference doc
|
13
|
+
module Reference
|
14
|
+
MAPPING_PATH_KEY = 'Mapping Data'
|
15
|
+
RESOURCE_DATA_PATH_KEY = 'Resource Data'
|
16
|
+
|
17
|
+
def self.generate(data = {})
|
18
|
+
pupmod = AbideDevUtils::Ppt::PuppetModule.new
|
19
|
+
doc_title = case pupmod.name
|
20
|
+
when 'puppetlabs-cem_linux'
|
21
|
+
'CEM Linux Reference'
|
22
|
+
when 'puppetlabs-cem_windows'
|
23
|
+
'CEM Windows Reference'
|
24
|
+
else
|
25
|
+
'Reference'
|
26
|
+
end
|
27
|
+
benchmarks = AbideDevUtils::CEM::Benchmark.benchmarks_from_puppet_module(pupmod)
|
28
|
+
case data.fetch(:format, 'markdown')
|
29
|
+
when 'markdown'
|
30
|
+
MarkdownGenerator.new(benchmarks).generate(doc_title)
|
31
|
+
else
|
32
|
+
raise "Format #{data[:format]} is unsupported! Only `markdown` format supported"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.generate_markdown
|
37
|
+
AbideDevUtils::Markdown.new('REFERENCE.md').generate
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.config_example(control, params_array)
|
41
|
+
out_str = ['cem_windows::config:', ' control_configs:', " \"#{control}\":"]
|
42
|
+
indent = ' '
|
43
|
+
params_array.each do |param_hash|
|
44
|
+
val = case param_hash[:type]
|
45
|
+
when 'String'
|
46
|
+
"'#{param_hash[:default]}'"
|
47
|
+
else
|
48
|
+
param_hash[:default]
|
49
|
+
end
|
50
|
+
|
51
|
+
out_str << "#{indent}#{param_hash[:name]}: #{val}"
|
52
|
+
end
|
53
|
+
out_str.join("\n")
|
54
|
+
end
|
55
|
+
|
56
|
+
# Generates a markdown reference doc
|
57
|
+
class MarkdownGenerator
|
58
|
+
def initialize(benchmarks)
|
59
|
+
@benchmarks = benchmarks
|
60
|
+
@md = AbideDevUtils::Markdown.new('REFERENCE.md')
|
61
|
+
end
|
62
|
+
|
63
|
+
def generate(doc_title = 'Reference')
|
64
|
+
md.add_title(doc_title)
|
65
|
+
benchmarks.each do |benchmark|
|
66
|
+
md.add_h1(benchmark.title_key)
|
67
|
+
benchmark.rules.each do |title, rule|
|
68
|
+
md.add_h2("#{rule['number']} #{title}")
|
69
|
+
md.add_ul('Parameters:')
|
70
|
+
rule['params'].each do |p|
|
71
|
+
md.add_ul("#{md.code(p[:name])} - [ #{md.code(p[:type])} ] - #{md.italic('Default:')} #{md.code(p[:default])}", indent: 1)
|
72
|
+
end
|
73
|
+
md.add_ul('Config Example:')
|
74
|
+
example = config_example(benchmark.module_name, title, rule['params'])
|
75
|
+
md.add_code_block(example, language: 'yaml')
|
76
|
+
md.add_ul('Supported Levels:')
|
77
|
+
rule['level'].each do |l|
|
78
|
+
md.add_ul(md.code(l), indent: 1)
|
79
|
+
end
|
80
|
+
md.add_ul('Supported Profiles:')
|
81
|
+
rule['profile'].each do |l|
|
82
|
+
md.add_ul(md.code(l), indent: 1)
|
83
|
+
end
|
84
|
+
md.add_ul('Alternate Config IDs:')
|
85
|
+
rule['alternate_ids'].each do |l|
|
86
|
+
md.add_ul(md.code(l), indent: 1)
|
87
|
+
end
|
88
|
+
md.add_ul("Resource: #{md.code(rule['resource'].capitalize)}")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
md.to_file
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
attr_reader :benchmarks, :md
|
97
|
+
|
98
|
+
def config_example(module_name, control, params_array)
|
99
|
+
out_str = ["#{module_name}::config:", ' control_configs:', " \"#{control}\":"]
|
100
|
+
indent = ' '
|
101
|
+
params_array.each do |param_hash|
|
102
|
+
val = case param_hash[:type]
|
103
|
+
when 'String'
|
104
|
+
"'#{param_hash[:default]}'"
|
105
|
+
else
|
106
|
+
param_hash[:default]
|
107
|
+
end
|
108
|
+
out_str << "#{indent}#{param_hash[:name]}: #{val}"
|
109
|
+
end
|
110
|
+
out_str.join("\n")
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AbideDevUtils
|
4
|
+
module CEM
|
5
|
+
module Mapping
|
6
|
+
# Handles interacting with mapping data
|
7
|
+
class Mapper
|
8
|
+
MAP_TYPES = %w[hiera_title_num number hiera_title vulnid title].freeze
|
9
|
+
|
10
|
+
attr_reader :module_name, :framework, :map_data
|
11
|
+
|
12
|
+
def initialize(module_name, framework, map_data)
|
13
|
+
@module_name = module_name
|
14
|
+
@framework = framework
|
15
|
+
load_framework(@framework)
|
16
|
+
@map_data = map_data
|
17
|
+
@cache = {}
|
18
|
+
@rule_cache = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def title
|
22
|
+
@title ||= benchmark_data['title']
|
23
|
+
end
|
24
|
+
|
25
|
+
def version
|
26
|
+
@version ||= benchmark_data['version']
|
27
|
+
end
|
28
|
+
|
29
|
+
def each_like(identifier)
|
30
|
+
mtype, mtop = map_type_and_top_key(identifier)
|
31
|
+
map_data[mtype][mtop].each { |key, val| yield key, val }
|
32
|
+
end
|
33
|
+
|
34
|
+
def each_with_array_like(identifier)
|
35
|
+
mtype, mtop = map_type_and_top_key(identifier)
|
36
|
+
map_data[mtype][mtop].each_with_object([]) { |(key, val), ary| yield [key, val], ary }
|
37
|
+
end
|
38
|
+
|
39
|
+
def get(control_id, level: nil, profile: nil)
|
40
|
+
return cache_get(control_id, level, profile) if cached?(control_id, level, profile)
|
41
|
+
|
42
|
+
value = get_map(control_id, level: level, profile: profile)
|
43
|
+
return if value.nil? || value.empty?
|
44
|
+
|
45
|
+
cache_set(value, control_id, level, profile)
|
46
|
+
value
|
47
|
+
end
|
48
|
+
|
49
|
+
def map_type(control_id)
|
50
|
+
return control_id if MAP_TYPES.include?(control_id)
|
51
|
+
|
52
|
+
case control_id
|
53
|
+
when %r{^c[0-9_]+$}
|
54
|
+
'hiera_title_num'
|
55
|
+
when %r{^[0-9][0-9.]*$}
|
56
|
+
'number'
|
57
|
+
when %r{^[a-z][a-z0-9_]+$}
|
58
|
+
'hiera_title'
|
59
|
+
when %r{^V-[0-9]{6}$}
|
60
|
+
'vulnid'
|
61
|
+
else
|
62
|
+
'title'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def load_framework(framework)
|
69
|
+
case framework.downcase
|
70
|
+
when 'cis'
|
71
|
+
self.class.include AbideDevUtils::CEM::Mapping::MixinCIS
|
72
|
+
extend AbideDevUtils::CEM::Mapping::MixinCIS
|
73
|
+
when 'stig'
|
74
|
+
self.class.include AbideDevUtils::CEM::Mapping::MixinSTIG
|
75
|
+
extend AbideDevUtils::CEM::Mapping::MixinSTIG
|
76
|
+
else
|
77
|
+
raise "Invalid framework: #{framework}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def map_type_and_top_key(identifier)
|
82
|
+
mtype = MAP_TYPES.include?(identifier) ? identifier : map_type(identifier)
|
83
|
+
[mtype, map_top_key(mtype)]
|
84
|
+
end
|
85
|
+
|
86
|
+
def cached?(control_id, *args)
|
87
|
+
@cache.key?(cache_key(control_id, *args))
|
88
|
+
end
|
89
|
+
|
90
|
+
def cache_get(control_id, *args)
|
91
|
+
ckey = cache_key(control_id, *args)
|
92
|
+
@cache[ckey] if cached?(control_id, *args)
|
93
|
+
end
|
94
|
+
|
95
|
+
def cache_set(value, control_id, *args)
|
96
|
+
@cache[cache_key(control_id, *args)] = value unless value.nil?
|
97
|
+
end
|
98
|
+
|
99
|
+
def default_map_type
|
100
|
+
@default_map_type ||= (framework == 'stig' ? 'vulnid' : map_data.keys.first)
|
101
|
+
end
|
102
|
+
|
103
|
+
def benchmark_data
|
104
|
+
@benchmark_data ||= map_data[default_map_type][map_top_key(default_map_type)]['benchmark']
|
105
|
+
end
|
106
|
+
|
107
|
+
def cache_key(control_id, *args)
|
108
|
+
args.unshift(control_id).compact.join('-')
|
109
|
+
end
|
110
|
+
|
111
|
+
def map_top_key(mtype)
|
112
|
+
[module_name, 'mappings', framework, mtype].join('::')
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Mixin module used by Mapper to implement CIS-specific mapping behavior
|
117
|
+
module MixinCIS
|
118
|
+
def get_map(control_id, level: nil, profile: nil, **_)
|
119
|
+
mtype, mtop = map_type_and_top_key(control_id)
|
120
|
+
return if mtype == 'vulnid'
|
121
|
+
|
122
|
+
return map_data[mtype][mtop][level][profile][control_id] unless level.nil? || profile.nil?
|
123
|
+
|
124
|
+
map_data[mtype][mtop].each do |lvl, profile_hash|
|
125
|
+
next if lvl == 'benchmark'
|
126
|
+
|
127
|
+
profile_hash.each do |prof, control_hash|
|
128
|
+
return map_data[mtype][mtop][lvl][prof][control_id] if control_hash.key?(control_id)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Mixin module used by Mapper to implement STIG-specific mapping behavior
|
135
|
+
module MixinSTIG
|
136
|
+
def get_map(control_id, level: nil, **_)
|
137
|
+
mtype, mtop = map_type_and_top_key(control_id)
|
138
|
+
return map_data[mtype][mtop][level][control_id] unless level.nil?
|
139
|
+
|
140
|
+
begin
|
141
|
+
map_data[mtype][mtop].each do |lvl, control_hash|
|
142
|
+
next if lvl == 'benchmark'
|
143
|
+
|
144
|
+
return control_hash[control_id] if control_hash.key?(control_id)
|
145
|
+
end
|
146
|
+
rescue NoMethodError => e
|
147
|
+
require 'pry'
|
148
|
+
binding.pry
|
149
|
+
#raise "Control ID: #{control_id}, Level: #{level}, #{e.message}"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'abide_dev_utils/xccdf'
|
4
|
+
require 'abide_dev_utils/cem/coverage_report'
|
5
|
+
require 'abide_dev_utils/cem/generate'
|
6
|
+
|
7
|
+
module AbideDevUtils
|
8
|
+
# Methods for working with Compliance Enforcement Modules (CEM)
|
9
|
+
module CEM
|
10
|
+
def self.xccdf
|
11
|
+
return @xccdf if defined?(@xccdf)
|
12
|
+
|
13
|
+
xccdf = Object.new
|
14
|
+
xccdf.extend AbideDevUtils::XCCDF::Common
|
15
|
+
@xccdf = xccdf
|
16
|
+
@xccdf
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.rule_id_format(rule_id)
|
20
|
+
case rule_id
|
21
|
+
when /^c[0-9_]+$/
|
22
|
+
:hiera_title_num
|
23
|
+
when /^[a-z][a-z0-9_]+$/
|
24
|
+
:hiera_title
|
25
|
+
when /^[0-9.]+$/
|
26
|
+
:number
|
27
|
+
else
|
28
|
+
:title
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.rule_identifiers(rule_id)
|
33
|
+
{
|
34
|
+
number: xccdf.control_parts(rule_id).first,
|
35
|
+
hiera_title: xccdf.name_normalize_control(rule_id),
|
36
|
+
hiera_title_num: xccdf.number_normalize_control(rule_id),
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.update_legacy_config_from_diff(config_hiera, diff)
|
41
|
+
new_config_hiera = config_hiera.dup
|
42
|
+
new_control_configs = {}
|
43
|
+
change_report = []
|
44
|
+
changes = diff.select { |d| d[:type][0] == :number }
|
45
|
+
config_hiera['config']['control_configs'].each do |key, val_hash|
|
46
|
+
key_id_format = rule_id_format(key)
|
47
|
+
changed = false
|
48
|
+
changes.each do |change|
|
49
|
+
if key_id_format == :title
|
50
|
+
next unless change[:title] == key
|
51
|
+
else
|
52
|
+
next unless rule_identifiers(change[:self].id)[key_id_format] == key
|
53
|
+
end
|
54
|
+
|
55
|
+
changed = true
|
56
|
+
new_key = if key_id_format == :title
|
57
|
+
change[:other_title]
|
58
|
+
else
|
59
|
+
rule_identifiers(change[:other].id)[key_id_format]
|
60
|
+
end
|
61
|
+
new_control_configs[new_key] = val_hash
|
62
|
+
change_report << {
|
63
|
+
type: :identifier_update,
|
64
|
+
from: key,
|
65
|
+
to: new_key,
|
66
|
+
}
|
67
|
+
end
|
68
|
+
new_control_configs[key] = val_hash unless changed
|
69
|
+
end
|
70
|
+
new_config_hiera['config']['control_configs'] = new_control_configs
|
71
|
+
[new_config_hiera, change_report]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'abide_dev_utils/cem'
|
4
|
+
require 'abide_dev_utils/files'
|
5
|
+
require 'abide_dev_utils/output'
|
6
|
+
require 'abide_dev_utils/validate'
|
7
|
+
require 'abide_dev_utils/xccdf/diff/benchmark'
|
8
|
+
require 'abide_dev_utils/cli/abstract'
|
9
|
+
|
10
|
+
module Abide
|
11
|
+
module CLI
|
12
|
+
class CemCommand < AbideCommand
|
13
|
+
CMD_NAME = 'cem'
|
14
|
+
CMD_SHORT = 'Commands related to Puppet CEM'
|
15
|
+
CMD_LONG = 'Namespace for commands related to Puppet CEM'
|
16
|
+
def initialize
|
17
|
+
super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: true)
|
18
|
+
add_command(CemGenerate.new)
|
19
|
+
add_command(CemUpdateConfig.new)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class CemGenerate < AbideCommand
|
24
|
+
CMD_NAME = 'generate'
|
25
|
+
CMD_SHORT = 'Holds subcommands for generating objects / files'
|
26
|
+
CMD_LONG = 'Holds subcommands for generating objects / files'
|
27
|
+
def initialize
|
28
|
+
super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: true)
|
29
|
+
add_command(CemGenerateCoverageReport.new)
|
30
|
+
add_command(CemGenerateReference.new)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class CemGenerateCoverageReport < AbideCommand
|
35
|
+
CMD_NAME = 'coverage-report'
|
36
|
+
CMD_SHORT = 'Generates control coverage report'
|
37
|
+
CMD_LONG = <<-EOLC.chomp
|
38
|
+
Generates report of resources that are associated with controls in mapping data. This command must
|
39
|
+
be run from a module directory.
|
40
|
+
EOLC
|
41
|
+
def initialize
|
42
|
+
super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: false)
|
43
|
+
options.on('-o [FILE]', '--out-file [FILE]', 'Path to save the coverage report') { |f| @data[:file] = f }
|
44
|
+
options.on('-f [FORMAT]', '--format [FORMAT]', 'The format to output the report in (hash, json, yaml)') do |f|
|
45
|
+
@data[:format] = f
|
46
|
+
end
|
47
|
+
options.on('-I', '--ignore-benchmark-errors', 'Ignores errors while generating benchmark reports') do
|
48
|
+
@data[:ignore_all] = true
|
49
|
+
end
|
50
|
+
options.on('-v', '--verbose', 'Will output the report to the console') { @data[:verbose] = true }
|
51
|
+
options.on('-q', '--quiet', 'Will not output anything to the console') { @data[:quiet] = true }
|
52
|
+
end
|
53
|
+
|
54
|
+
def execute
|
55
|
+
file_name = @data.fetch(:file, 'coverage_report')
|
56
|
+
out_format = @data.fetch(:format, 'yaml')
|
57
|
+
quiet = @data.fetch(:quiet, false)
|
58
|
+
console = @data.fetch(:verbose, false) && !quiet
|
59
|
+
ignore_all = @data.fetch(:ignore_all, false)
|
60
|
+
AbideDevUtils::Output.simple('Generating coverage report...') unless quiet
|
61
|
+
coverage = AbideDevUtils::CEM::CoverageReport.basic_coverage(format_func: :to_h, ignore_benchmark_errors: ignore_all)
|
62
|
+
AbideDevUtils::Output.simple("Saving coverage report to #{file_name}...")
|
63
|
+
case out_format
|
64
|
+
when /yaml/i
|
65
|
+
AbideDevUtils::Output.yaml(coverage, console: console, file: file_name)
|
66
|
+
when /json/i
|
67
|
+
AbideDevUtils::Output.json(coverage, console: console, file: file_name)
|
68
|
+
else
|
69
|
+
File.open(file_name, 'w') do |f|
|
70
|
+
AbideDevUtils::Output.simple(coverage.to_s, stream: f)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class CemGenerateReference < AbideCommand
|
77
|
+
CMD_NAME = 'reference'
|
78
|
+
CMD_SHORT = 'Generates a reference doc for the module'
|
79
|
+
CMD_LONG = 'Generates a reference doc for the module'
|
80
|
+
def initialize
|
81
|
+
super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: false)
|
82
|
+
options.on('-o [FILE]', '--out-file [FILE]', 'Path to save the updated config file') do |o|
|
83
|
+
@data[:out_file] = o
|
84
|
+
end
|
85
|
+
options.on('-f [FORMAT]', '--format [FORMAT]', 'Format to save reference as') do |f|
|
86
|
+
@data[:format] = f
|
87
|
+
end
|
88
|
+
options.on('-v', '--verbose', 'Verbose output') do
|
89
|
+
@data[:verbose] = true
|
90
|
+
end
|
91
|
+
options.on('-q', '--quiet', 'Quiet output') do
|
92
|
+
@data[:quiet] = true
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def execute
|
97
|
+
AbideDevUtils::Validate.puppet_module_directory
|
98
|
+
AbideDevUtils::CEM::Generate::Reference.generate(@data)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class CemUpdateConfig < AbideCommand
|
103
|
+
CMD_NAME = 'update-config'
|
104
|
+
CMD_SHORT = 'Updates the Puppet CEM config'
|
105
|
+
CMD_LONG = 'Updates the Puppet CEM config'
|
106
|
+
def initialize
|
107
|
+
super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: true)
|
108
|
+
add_command(CemUpdateConfigFromDiff.new)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
class CemUpdateConfigFromDiff < AbideCommand
|
113
|
+
CMD_NAME = 'from-diff'
|
114
|
+
CMD_SHORT = 'Update by diffing two XCCDF files'
|
115
|
+
CMD_LONG = 'Update by diffing two XCCDF files'
|
116
|
+
CMD_CONFIG_FILE = 'Path to the Puppet CEM config file'
|
117
|
+
CMD_CURRENT_XCCDF = 'Path to the current XCCDF file'
|
118
|
+
CMD_NEW_XCCDF = 'Path to the new XCCDF file'
|
119
|
+
def initialize
|
120
|
+
super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: false)
|
121
|
+
argument_desc(CONFIG_FILE: CMD_CONFIG_FILE, CURRENT_XCCDF: CMD_CURRENT_XCCDF, NEW_XCCDF: CMD_NEW_XCCDF)
|
122
|
+
options.on('-o [FILE]', '--out-file [FILE]', 'Path to save the updated config file') do |o|
|
123
|
+
@data[:out_file] = o
|
124
|
+
end
|
125
|
+
options.on('-v', '--verbose', 'Verbose output') do
|
126
|
+
@data[:verbose] = true
|
127
|
+
end
|
128
|
+
options.on('-q', '--quiet', 'Quiet output') do
|
129
|
+
@data[:quiet] = true
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def help_arguments
|
134
|
+
<<~ARGHELP
|
135
|
+
Arguments:
|
136
|
+
CONFIG_FILE: #{CMD_CONFIG_FILE}
|
137
|
+
CURRENT_XCCDF: #{CMD_CURRENT_XCCDF}
|
138
|
+
NEW_XCCDF: #{CMD_NEW_XCCDF}
|
139
|
+
ARGHELP
|
140
|
+
end
|
141
|
+
|
142
|
+
def execute(config_file, cur_xccdf, new_xccdf)
|
143
|
+
AbideDevUtils::Validate.file(config_file, extension: 'yaml')
|
144
|
+
AbideDevUtils::Validate.file(cur_xccdf, extension: 'xml')
|
145
|
+
config_hiera = AbideDevUtils::Files::Reader.read(config_file, safe: true)
|
146
|
+
diff = AbideDevUtils::XCCDF::Diff::BenchmarkDiff.new(cur_xccdf, new_xccdf).diff[:diff][:number_title]
|
147
|
+
new_config_hiera, change_report = AbideDevUtils::CEM.update_legacy_config_from_diff(config_hiera, diff)
|
148
|
+
AbideDevUtils::Output.yaml(new_config_hiera, console: @data[:verbose], file: @data[:out_file])
|
149
|
+
AbideDevUtils::Output.simple(change_report) unless @data[:quiet]
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -34,6 +34,9 @@ module Abide
|
|
34
34
|
options.on('-d [DIR]', '--files-output-directory [DIR]', 'Directory to save files data/mappings by default') do |d|
|
35
35
|
@data[:dir] = d
|
36
36
|
end
|
37
|
+
options.on('-V', '--version-output-dir', 'If saving to a directory, version the output directory') do
|
38
|
+
@data[:version_output_dir] = true
|
39
|
+
end
|
37
40
|
options.on('-q', '--quiet', 'Show no output in the terminal') { @data[:quiet] = true }
|
38
41
|
options.on('-p [PREFIX]', '--parent-key-prefix [PREFIX]', 'A prefix to append to the parent key') do |p|
|
39
42
|
@data[:parent_key_prefix] = p
|
@@ -104,13 +107,24 @@ module Abide
|
|
104
107
|
options.on('-p [PROFILE]', '--profile', 'Only diff and specific profile in the benchmarks') do |x|
|
105
108
|
@data[:profile] = x
|
106
109
|
end
|
110
|
+
options.on('-l [LEVEL]', '--level', 'Only diff the specific level in the benchmarks') do |x|
|
111
|
+
@data[:level] = x
|
112
|
+
end
|
113
|
+
options.on('-r', '--raw', 'Output the diff in raw hash format') { @data[:raw] = true }
|
107
114
|
options.on('-q', '--quiet', 'Show no output in the terminal') { @data[:quiet] = false }
|
108
115
|
options.on('--no-diff-profiles', 'Do not diff the profiles in the XCCDF files') { @data[:diff_profiles] = false }
|
109
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 }
|
110
118
|
end
|
111
119
|
|
112
120
|
def execute(file1, file2)
|
113
|
-
diffreport =
|
121
|
+
diffreport = if @data[:old_style]
|
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
|
114
128
|
AbideDevUtils::Output.yaml(diffreport, console: @data.fetch(:quiet, true), file: @data.fetch(:outfile, nil))
|
115
129
|
end
|
116
130
|
end
|
data/lib/abide_dev_utils/cli.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'cmdparse'
|
4
4
|
require 'abide_dev_utils/version'
|
5
|
+
require 'abide_dev_utils/cli/cem'
|
5
6
|
require 'abide_dev_utils/constants'
|
6
7
|
require 'abide_dev_utils/cli/comply'
|
7
8
|
require 'abide_dev_utils/cli/puppet'
|
@@ -22,6 +23,7 @@ module Abide
|
|
22
23
|
parser.main_options.banner = ROOT_CMD_BANNER
|
23
24
|
parser.add_command(CmdParse::HelpCommand.new, default: true)
|
24
25
|
parser.add_command(CmdParse::VersionCommand.new(add_switches: true))
|
26
|
+
parser.add_command(CemCommand.new)
|
25
27
|
parser.add_command(ComplyCommand.new)
|
26
28
|
parser.add_command(PuppetCommand.new)
|
27
29
|
parser.add_command(XccdfCommand.new)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'abide_dev_utils/errors/base'
|
4
|
+
|
5
|
+
module AbideDevUtils
|
6
|
+
module Errors
|
7
|
+
# Raised by Benchmark when mapping data cannot be loaded
|
8
|
+
class MappingFilesNotFoundError < GenericError
|
9
|
+
@default = 'Mapping files not found using facts:'
|
10
|
+
end
|
11
|
+
|
12
|
+
# Raised by Benchmark when mapping files are not found for the specified framework
|
13
|
+
class MappingDataFrameworkMismatchError < GenericError
|
14
|
+
@default = 'Mapping data could not be found for the specified framework:'
|
15
|
+
end
|
16
|
+
|
17
|
+
# Raised by Benchmark when resource data cannot be loaded
|
18
|
+
class ResourceDataNotFoundError < GenericError
|
19
|
+
@default = 'Resource data not found using facts:'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -9,7 +9,12 @@ module AbideDevUtils
|
|
9
9
|
@default = 'Object is empty and should not be:'
|
10
10
|
end
|
11
11
|
|
12
|
-
# Raised when a
|
12
|
+
# Raised when something is not a string, or is an empty string
|
13
|
+
class NotPopulatedStringError < GenericError
|
14
|
+
@default = 'Object is either not a String or is empty:'
|
15
|
+
end
|
16
|
+
|
17
|
+
# Raised when an object is initialized with a nil param
|
13
18
|
class NewObjectParamNilError < GenericError
|
14
19
|
@default = 'Object init parameter is nil and should not be:'
|
15
20
|
end
|
@@ -54,8 +59,9 @@ module AbideDevUtils
|
|
54
59
|
@default = 'Object does not respond to #to_hash or #to_h:'
|
55
60
|
end
|
56
61
|
|
62
|
+
# Raised when conflicting CLI options are specified for a command
|
57
63
|
class CliOptionsConflict < GenericError
|
58
|
-
@default =
|
64
|
+
@default = 'Console options conflict:'
|
59
65
|
end
|
60
66
|
end
|
61
67
|
end
|
@@ -5,6 +5,10 @@ require 'abide_dev_utils/errors/base'
|
|
5
5
|
module AbideDevUtils
|
6
6
|
module Errors
|
7
7
|
module Ppt
|
8
|
+
class NotModuleDirError < GenericError
|
9
|
+
@default = 'Path is not a Puppet module directory:'
|
10
|
+
end
|
11
|
+
|
8
12
|
class ObjClassPathError < GenericError
|
9
13
|
@default = 'Invalid path for class:'
|
10
14
|
end
|
@@ -1,9 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'abide_dev_utils/errors/base'
|
4
|
+
require 'abide_dev_utils/errors/cem'
|
4
5
|
require 'abide_dev_utils/errors/comply'
|
5
6
|
require 'abide_dev_utils/errors/gcloud'
|
6
7
|
require 'abide_dev_utils/errors/general'
|
7
8
|
require 'abide_dev_utils/errors/jira'
|
8
9
|
require 'abide_dev_utils/errors/xccdf'
|
9
10
|
require 'abide_dev_utils/errors/ppt'
|
11
|
+
|
12
|
+
module AbideDevUtils
|
13
|
+
# Namespace for Error objects
|
14
|
+
module Errors; end
|
15
|
+
end
|