abide_dev_utils 0.4.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +34 -0
- data/abide_dev_utils.gemspec +4 -1
- data/lib/abide_dev_utils/cli/abstract.rb +2 -0
- data/lib/abide_dev_utils/cli/comply.rb +99 -0
- data/lib/abide_dev_utils/cli/jira.rb +4 -2
- data/lib/abide_dev_utils/cli/puppet.rb +118 -11
- data/lib/abide_dev_utils/cli.rb +2 -0
- data/lib/abide_dev_utils/comply.rb +441 -0
- data/lib/abide_dev_utils/config.rb +24 -1
- data/lib/abide_dev_utils/errors/comply.rb +13 -0
- data/lib/abide_dev_utils/errors/gcloud.rb +27 -0
- data/lib/abide_dev_utils/errors/ppt.rb +12 -0
- data/lib/abide_dev_utils/errors.rb +2 -0
- data/lib/abide_dev_utils/gcloud.rb +21 -0
- data/lib/abide_dev_utils/jira.rb +17 -0
- data/lib/abide_dev_utils/mixins.rb +16 -0
- data/lib/abide_dev_utils/ppt/class_utils.rb +184 -0
- data/lib/abide_dev_utils/ppt/coverage.rb +2 -3
- data/lib/abide_dev_utils/ppt.rb +135 -49
- data/lib/abide_dev_utils/version.rb +1 -1
- data/lib/abide_dev_utils/xccdf/cis/hiera.rb +71 -66
- data/lib/abide_dev_utils/xccdf/utils.rb +85 -0
- data/lib/abide_dev_utils/xccdf.rb +5 -0
- data/lib/abide_dev_utils.rb +1 -0
- metadata +55 -6
- data/lib/abide_dev_utils/utils/general.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cf0d6affedd8f13f06af7f1f0db11666b9df2707d87a7685a4bd39ecd3e1519d
|
4
|
+
data.tar.gz: 0f20af443ff1e13f9e854daa5e7cf5ec45213dfe9a2f0390c250dac92a8cc8d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '097e88fb6b19170c2b727fd8873fa3dbb766ace25a7538ab8cfbd0a35083cb11654b58fb7f45ee7130d7c4f4cb48b8b241de4849b0cb406de8f7eb62cf09ce68'
|
7
|
+
data.tar.gz: 4c0bc197da434b0ee25c9854b4b2af98a6ad9600733b734f9be21022ce312d7e8f0aea4f27c2217c3f56f7d2df26fedfe228f80b60fcd04da4ec08877a86bc54
|
data/README.md
CHANGED
@@ -29,6 +29,10 @@ Issues and pull requests are welcome!
|
|
29
29
|
|
30
30
|
* Create Jira issues in bulk from coverage reports
|
31
31
|
|
32
|
+
### Puppet Comply Report Generation
|
33
|
+
|
34
|
+
* Allows you ot programatically generate compliance reports from Puppet Comply
|
35
|
+
|
32
36
|
### Supports Configuration via Local YAML file
|
33
37
|
|
34
38
|
* Fully configurable via the `~/.abide_dev.yaml` file
|
@@ -84,6 +88,8 @@ Install the gem:
|
|
84
88
|
|
85
89
|
### Overview of Commands
|
86
90
|
|
91
|
+
* `abide comply` - Command namespace for Puppet Comply commands
|
92
|
+
* `abide comply report` - Creates a scan report in YAML format by scraping Puppet Comply
|
87
93
|
* `abide jira` - Command namespace for Jira commands
|
88
94
|
* `abide jira auth` - Authenticate with Jira. Only useful as a stand-alone command to test authentication
|
89
95
|
* `abide jira from_coverage` - Creates a parent issue with subtasks from a Puppet coverage report
|
@@ -96,6 +102,34 @@ Install the gem:
|
|
96
102
|
* `abide xccdf` - Command namespace for XCCDF commands
|
97
103
|
* `abide xccdf to_hiera` - Converts a benchmark XCCDF file to a Hiera yaml file
|
98
104
|
|
105
|
+
### Comply Command Reference
|
106
|
+
|
107
|
+
#### report
|
108
|
+
|
109
|
+
* Required positional parameters:
|
110
|
+
* `COMPLY_URL` - The URL of Puppet Comply
|
111
|
+
* `COMPLY_PASSWORD` - The password for the Puppet Comply user
|
112
|
+
* Options:
|
113
|
+
* `--out-file`, `-o` - The path to save the scan report. Defaults to `./comply_scan_report.yaml`
|
114
|
+
* `--username`, `-u` - The Puppet Comply username. Defaults to `comply`
|
115
|
+
* `--status`, `-s` - A comma-separated list of check statuses to ONLY include in the report. Valid statuses are: `pass`, `fail`, `error`, `notapplicable`, `notchecked`, `unknown`, `informational`
|
116
|
+
* `--only`, `-O` - A comma-separated list of node certnames to ONLY build reports for. No other nodes will have reports built for them except the ones specified. This option is mutually exclusive with `--ignore` and, if both are set, this options will take precedence over `--ignore`.
|
117
|
+
* `--ignore`, `-I` - A comma-separated list of node certnames to ignore building reports for. This options is mutually exclusive with `--only` and, if both are set, `--only` will take precedence over this option.
|
118
|
+
|
119
|
+
Examples:
|
120
|
+
|
121
|
+
Generating a report of all failed and err'd scan checks
|
122
|
+
|
123
|
+
```sh
|
124
|
+
abide comply report https://comply.my.instance 'my_comply_password!' -s fail,error
|
125
|
+
```
|
126
|
+
|
127
|
+
Generating a report for certain nodes only
|
128
|
+
|
129
|
+
```sh
|
130
|
+
abide comply report https://comply.my.instance 'my_comply_password!' -O specific-node.my.instance
|
131
|
+
```
|
132
|
+
|
99
133
|
### Jira Command Reference
|
100
134
|
|
101
135
|
#### from_coverage
|
data/abide_dev_utils.gemspec
CHANGED
@@ -34,9 +34,11 @@ Gem::Specification.new do |spec|
|
|
34
34
|
# Prod dependencies
|
35
35
|
spec.add_dependency 'nokogiri', '~> 1.11'
|
36
36
|
spec.add_dependency 'cmdparse', '~> 3.0'
|
37
|
-
spec.add_dependency 'puppet', '>= 6.
|
37
|
+
spec.add_dependency 'puppet', '>= 6.23'
|
38
38
|
spec.add_dependency 'jira-ruby', '~> 2.1'
|
39
39
|
spec.add_dependency 'ruby-progressbar', '~> 1.11'
|
40
|
+
spec.add_dependency 'selenium-webdriver', '~> 4.0.0.beta4'
|
41
|
+
spec.add_dependency 'google-cloud-storage', '~> 1.34'
|
40
42
|
|
41
43
|
# Dev dependencies
|
42
44
|
spec.add_development_dependency 'bundler'
|
@@ -44,6 +46,7 @@ Gem::Specification.new do |spec|
|
|
44
46
|
spec.add_development_dependency 'console'
|
45
47
|
spec.add_development_dependency 'github_changelog_generator'
|
46
48
|
spec.add_development_dependency 'gem-release'
|
49
|
+
spec.add_development_dependency 'pry'
|
47
50
|
spec.add_development_dependency 'rspec', '~> 3.10'
|
48
51
|
spec.add_development_dependency 'rubocop', '~> 1.8'
|
49
52
|
spec.add_development_dependency 'rubocop-rspec', '~> 2.1'
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'abide_dev_utils/comply'
|
4
|
+
require 'abide_dev_utils/cli/abstract'
|
5
|
+
|
6
|
+
module Abide
|
7
|
+
module CLI
|
8
|
+
class ComplyCommand < AbideCommand
|
9
|
+
CMD_NAME = 'comply'
|
10
|
+
CMD_SHORT = 'Commands related to Puppet Comply'
|
11
|
+
CMD_LONG = 'Namespace for commands related to Puppet Comply'
|
12
|
+
def initialize
|
13
|
+
super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: true)
|
14
|
+
add_command(ComplyReportCommand.new)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class ComplyReportCommand < AbideCommand
|
19
|
+
CMD_NAME = 'report'
|
20
|
+
CMD_SHORT = 'Generates a yaml report of Puppet Comply scan results'
|
21
|
+
CMD_LONG = <<~LONGCMD
|
22
|
+
Generates a yaml file that shows the scan results of all nodes in Puppet Comply.
|
23
|
+
This command utilizes Selenium WebDriver and the Google Chrome browser to automate
|
24
|
+
clicking through the Comply UI and building a report. In order to use this command,
|
25
|
+
you MUST have Google Chrome installed and you MUST install the chromedriver binary.
|
26
|
+
More info and instructions can be found here:
|
27
|
+
https://www.selenium.dev/documentation/en/getting_started_with_webdriver/.
|
28
|
+
LONGCMD
|
29
|
+
CMD_COMPLY_URL = 'The URL (including https://) of Puppet Comply'
|
30
|
+
CMD_COMPLY_PASSWORD = 'The password for Puppet Comply'
|
31
|
+
OPT_TIMEOUT_DESC = <<~EOTO
|
32
|
+
The number of seconds you would like requests to wait before timing out. Defaults
|
33
|
+
to 10 seconds.
|
34
|
+
EOTO
|
35
|
+
OPT_STATUS_DESC = <<~EODESC
|
36
|
+
A comma-separated list of check statuses to ONLY include in the report.
|
37
|
+
Valid statuses are: pass, fail, error, notapplicable, notchecked, unknown, informational
|
38
|
+
EODESC
|
39
|
+
OPT_IGNORE_NODES = <<~EOIGN
|
40
|
+
A comma-separated list of node certnames to ignore building reports for. This
|
41
|
+
options is mutually exclusive with --only and, if both are set, --only will take precedence
|
42
|
+
over this option.
|
43
|
+
EOIGN
|
44
|
+
OPT_ONLY_NODES = <<~EOONLY
|
45
|
+
A comma-separated list of node certnames to ONLY build reports for. No other
|
46
|
+
nodes will have reports built for them except the ones specified. This option
|
47
|
+
is mutually exclusive with --ignore and, if both are set, this options will
|
48
|
+
take precedence over --ignore.
|
49
|
+
EOONLY
|
50
|
+
def initialize
|
51
|
+
super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: false)
|
52
|
+
argument_desc(COMPLY_URL: CMD_COMPLY_URL, COMPLY_PASSWORD: CMD_COMPLY_PASSWORD)
|
53
|
+
options.on('-o [FILE]', '--out-file [FILE]', 'Path to save the report') { |f| @data[:file] = f }
|
54
|
+
options.on('-u [USERNAME]', '--username [USERNAME]', 'The username for Comply (defaults to comply)') do |u|
|
55
|
+
@data[:username] = u
|
56
|
+
end
|
57
|
+
options.on('-t [SECONDS]', '--timeout [SECONDS]', OPT_TIMEOUT_DESC) do |t|
|
58
|
+
@data[:timeout] = t
|
59
|
+
end
|
60
|
+
options.on('-s x,y,z', '--status x,y,x',
|
61
|
+
%w[pass fail error notapplicable notchecked unknown informational],
|
62
|
+
Array,
|
63
|
+
OPT_STATUS_DESC) do |s|
|
64
|
+
s&.map! { |i| i == 'notchecked' ? 'not checked' : i }
|
65
|
+
@data[:status] = s
|
66
|
+
end
|
67
|
+
options.on('--only x,y,z', Array, OPT_ONLY_NODES) do |o|
|
68
|
+
@data[:onlylist] = o
|
69
|
+
end
|
70
|
+
options.on('--ignore x,y,z', Array, OPT_IGNORE_NODES) do |i|
|
71
|
+
@data[:ignorelist] = i
|
72
|
+
end
|
73
|
+
# options.on('-R', '--[no-]regression-test', OPT_REGRESSION_TEST) do |r|
|
74
|
+
# @data[:regression] = r
|
75
|
+
# end
|
76
|
+
# options.on('--')
|
77
|
+
end
|
78
|
+
|
79
|
+
def help_arguments
|
80
|
+
<<~ARGHELP
|
81
|
+
Arguments:
|
82
|
+
COMPLY_URL #{CMD_COMPLY_URL}
|
83
|
+
COMPLY_PASSWORD #{CMD_COMPLY_PASSWORD}
|
84
|
+
|
85
|
+
ARGHELP
|
86
|
+
end
|
87
|
+
|
88
|
+
def execute(comply_url = nil, comply_password = nil)
|
89
|
+
Abide::CLI::VALIDATE.filesystem_path(`command -v chromedriver`.strip)
|
90
|
+
conf = config_section('comply')
|
91
|
+
comply_url = conf.fetch(:url) if comply_url.nil?
|
92
|
+
comply_password = comply_password.nil? ? conf.fetch(:password, Abide::CLI::PROMPT.password) : comply_password
|
93
|
+
report = AbideDevUtils::Comply.build_report(comply_url, comply_password, conf, **@data)
|
94
|
+
outfile = @data.fetch(:file, nil).nil? ? conf.fetch(:report_path, 'comply_scan_report.yaml') : @data[:file]
|
95
|
+
Abide::CLI::OUTPUT.yaml(report, file: outfile)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'json'
|
4
|
+
require 'abide_dev_utils/config'
|
4
5
|
require 'abide_dev_utils/jira'
|
5
6
|
|
6
7
|
module Abide
|
7
8
|
module CLI
|
9
|
+
CONFIG = AbideDevUtils::Config
|
8
10
|
JIRA = AbideDevUtils::Jira
|
9
11
|
|
10
12
|
class JiraCommand < CmdParse::Command
|
@@ -57,8 +59,8 @@ module Abide
|
|
57
59
|
def execute(issue)
|
58
60
|
client = JIRA.client(options: {})
|
59
61
|
issue = client.Issue.find(issue)
|
60
|
-
console = @data[:file].nil?
|
61
|
-
out_json = issue.attrs.select { |_,v| !v.nil? || !v.empty? }
|
62
|
+
console = @data[:file].nil?
|
63
|
+
out_json = issue.attrs.select { |_, v| !v.nil? || !v.empty? }
|
62
64
|
Abide::CLI::OUTPUT.json(out_json, console: console, file: @data[:file])
|
63
65
|
end
|
64
66
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'abide_dev_utils/cli/abstract'
|
4
|
+
require 'abide_dev_utils/output'
|
5
|
+
require 'abide_dev_utils/ppt'
|
4
6
|
|
5
7
|
module Abide
|
6
8
|
module CLI
|
@@ -12,6 +14,10 @@ module Abide
|
|
12
14
|
super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: true)
|
13
15
|
add_command(PuppetCoverageCommand.new)
|
14
16
|
add_command(PuppetNewCommand.new)
|
17
|
+
add_command(PuppetRenameCommand.new)
|
18
|
+
add_command(PuppetFixClassNamesCommand.new)
|
19
|
+
add_command(PuppetAuditClassNamesCommand.new)
|
20
|
+
add_command(PuppetAddCISCommentCommand.new)
|
15
21
|
end
|
16
22
|
end
|
17
23
|
|
@@ -38,12 +44,12 @@ module Abide
|
|
38
44
|
end
|
39
45
|
|
40
46
|
def execute(class_dir, hiera_file)
|
41
|
-
require 'abide_dev_utils/ppt'
|
47
|
+
require 'abide_dev_utils/ppt/coverage'
|
42
48
|
Abide::CLI::VALIDATE.directory(class_dir)
|
43
49
|
Abide::CLI::VALIDATE.file(hiera_file)
|
44
|
-
coverage = AbideDevUtils::Ppt
|
50
|
+
coverage = AbideDevUtils::Ppt.generate_coverage_report(class_dir, hiera_file, @data[:profile])
|
45
51
|
coverage.each do |k, v|
|
46
|
-
next if
|
52
|
+
next if k.match?(/classes|benchmark/)
|
47
53
|
|
48
54
|
Abide::CLI::OUTPUT.simple("#{k} coverage: #{v[:coverage]}%")
|
49
55
|
end
|
@@ -100,14 +106,115 @@ module Abide
|
|
100
106
|
end
|
101
107
|
|
102
108
|
def execute(type, name)
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
109
|
+
AbideDevUtils::Ppt.build_new_object(type, name, @data)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
class PuppetRenameCommand < AbideCommand
|
114
|
+
CMD_NAME = 'rename'
|
115
|
+
CMD_SHORT = 'Renames a Puppet class'
|
116
|
+
CMD_LONG = 'Renames a Puppet class. It does this by renaming the file and also the class name in the file. This command can also move class files based on the new class name.'
|
117
|
+
CMD_FROM_ARG = 'The current full class name'
|
118
|
+
CMD_TO_ARG = 'The new full class name'
|
119
|
+
def initialize
|
120
|
+
super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: false)
|
121
|
+
argument_desc(FROM: CMD_FROM_ARG, TO: CMD_TO_ARG)
|
122
|
+
options.on(
|
123
|
+
'-d',
|
124
|
+
'--declaration-only',
|
125
|
+
'Will not rename the class file, only the class declaration in the file'
|
126
|
+
) { @data[:declaration_only] = true }
|
127
|
+
options.on(
|
128
|
+
'-t',
|
129
|
+
'--declaration-in-to-file',
|
130
|
+
'Use the path derived from the TO class name as the existing file path when renaming class declaration'
|
131
|
+
) { @data[:declaration_in_to_file] = true }
|
132
|
+
options.on(
|
133
|
+
'-f',
|
134
|
+
'--force',
|
135
|
+
'Forces file move operations'
|
136
|
+
) { @data[:force] = true }
|
137
|
+
options.on(
|
138
|
+
'-v',
|
139
|
+
'--verbose',
|
140
|
+
'Sets verbose mode on file operations'
|
141
|
+
) { @data[:verbose] = true }
|
142
|
+
end
|
143
|
+
|
144
|
+
def execute(from, to)
|
145
|
+
AbideDevUtils::Ppt.rename_puppet_class(from, to, **@data)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
class PuppetFixClassNamesCommand < AbideCommand
|
150
|
+
CMD_NAME = 'fix-class-names'
|
151
|
+
CMD_SHORT = 'Fixes Puppet class names that are mismatched'
|
152
|
+
CMD_LONG = 'Fixes Puppet class names that are mismatched'
|
153
|
+
CMD_MODE_ARG = '"file" or "class". If "file", the file names will be changed to match their class declarations. If "class", the class declarations will be changed to match the file names.'
|
154
|
+
CMD_DIR_ARG = 'The directory containing the Puppet class files'
|
155
|
+
def initialize
|
156
|
+
super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: false)
|
157
|
+
argument_desc(MODE: CMD_MODE_ARG, DIR: CMD_DIR_ARG)
|
158
|
+
options.on(
|
159
|
+
'-f',
|
160
|
+
'--force',
|
161
|
+
'Forces file move operations'
|
162
|
+
) { @data[:force] = true }
|
163
|
+
options.on(
|
164
|
+
'-v',
|
165
|
+
'--verbose',
|
166
|
+
'Sets verbose mode on file operations'
|
167
|
+
) { @data[:verbose] = true }
|
168
|
+
end
|
169
|
+
|
170
|
+
def execute(mode, dir)
|
171
|
+
case mode
|
172
|
+
when /^f.*/
|
173
|
+
AbideDevUtils::Ppt.fix_class_names_file_rename(dir, **@data)
|
174
|
+
when /^c.*/
|
175
|
+
AbideDevUtils::Ppt.fix_class_names_class_rename(dir, **@data)
|
176
|
+
else
|
177
|
+
raise ::ArgumentError, "Invalid mode. Mode:#{mode}"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
class PuppetAuditClassNamesCommand < AbideCommand
|
183
|
+
CMD_NAME = 'audit-class-names'
|
184
|
+
CMD_SHORT = 'Finds Puppet classes in a directory that have names that do not match their path'
|
185
|
+
CMD_LONG = 'Finds Puppet classes in a directory that have names that do not match their path. This is helpful because class names that do not match their path structure break Puppet autoloading.'
|
186
|
+
CMD_DIR_ARG = 'The directory containing the Puppet class files'
|
187
|
+
def initialize
|
188
|
+
super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: false)
|
189
|
+
argument_desc(DIR: CMD_DIR_ARG)
|
190
|
+
options.on('-o [FILE]', '--out-file [FILE]', 'Save results to a file') { |f| @data[:file] = f }
|
191
|
+
options.on('-q', '--quiet', 'Do not print results to console') { @data[:quiet] = true }
|
192
|
+
end
|
193
|
+
|
194
|
+
def execute(dir)
|
195
|
+
if @data.fetch(:quiet, false) && !@data.key?(:file)
|
196
|
+
AbideDevUtils::Output.simple('ERROR: Specifying --quiet without --out-file is useless.', stream: $stderr)
|
197
|
+
exit 1
|
198
|
+
end
|
199
|
+
|
200
|
+
AbideDevUtils::Ppt.audit_class_names(dir, **@data)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
class PuppetAddCISCommentCommand < AbideCommand
|
205
|
+
CMD_NAME = 'add-cis-comment'
|
206
|
+
CMD_SHORT = 'Adds the CIS recommendation name to the top of a .pp file'
|
207
|
+
CMD_LONG = 'Adds the CIS recommendation name to the top of a .pp file. Finds CIS recommendation by pattern-matching the class name against XCCDF recommendations.'
|
208
|
+
CMD_PATH_ARG = 'Path to a .pp file or to a directory containing .pp files'
|
209
|
+
CMD_XCCDF_ARG = 'Path to XCCDF file to source recommendation names from'
|
210
|
+
def initialize
|
211
|
+
super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: false)
|
212
|
+
argument_desc(PATH: CMD_PATH_ARG, XCCDF: CMD_XCCDF_ARG)
|
213
|
+
options.on('-N', '--number-format', 'Matches based on number-formatted control class names') { @data[:number_format] = true }
|
214
|
+
end
|
215
|
+
|
216
|
+
def execute(path, xccdf)
|
217
|
+
AbideDevUtils::Ppt.add_cis_comment(path, xccdf, number_format: @data.fetch(:number_format, false))
|
111
218
|
end
|
112
219
|
end
|
113
220
|
end
|
data/lib/abide_dev_utils/cli.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'cmdparse'
|
4
4
|
require 'abide_dev_utils/version'
|
5
5
|
require 'abide_dev_utils/constants'
|
6
|
+
require 'abide_dev_utils/cli/comply'
|
6
7
|
require 'abide_dev_utils/cli/puppet'
|
7
8
|
require 'abide_dev_utils/cli/xccdf'
|
8
9
|
require 'abide_dev_utils/cli/test'
|
@@ -21,6 +22,7 @@ module Abide
|
|
21
22
|
parser.main_options.banner = ROOT_CMD_BANNER
|
22
23
|
parser.add_command(CmdParse::HelpCommand.new, default: true)
|
23
24
|
parser.add_command(CmdParse::VersionCommand.new(add_switches: true))
|
25
|
+
parser.add_command(ComplyCommand.new)
|
24
26
|
parser.add_command(PuppetCommand.new)
|
25
27
|
parser.add_command(XccdfCommand.new)
|
26
28
|
parser.add_command(TestCommand.new)
|