abide_dev_utils 0.9.7 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|