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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ecd985f39afeac37bf8f2305dc65c782f34722f95a655249d7219b975952012f
4
- data.tar.gz: 9123b33054f39149ba2deb34464b56bcac404438ac161f64a02e93fc1d33b340
3
+ metadata.gz: cf0d6affedd8f13f06af7f1f0db11666b9df2707d87a7685a4bd39ecd3e1519d
4
+ data.tar.gz: 0f20af443ff1e13f9e854daa5e7cf5ec45213dfe9a2f0390c250dac92a8cc8d3
5
5
  SHA512:
6
- metadata.gz: 595556633f91088d8b34ac1d17d5f012c9d84ca7c03d45ef31bd59ccc45278b008f967b5e096909fa625c8eac7911163584ac7d0d4cc46caa1bd062b14eb1f7c
7
- data.tar.gz: 0dc612075817afeae37820a7c2d097a29af5ed3ee491b7ab2c61743e209b0345e5fd5fff6f5aab53b3d85b9f0e5b9c07cf16cefff5092ec981c679523fd141e2
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
@@ -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.19'
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'
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'abide_dev_utils/config'
4
+
3
5
  module Abide
4
6
  module CLI
5
7
  # @abstract
@@ -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? ? true : false
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::CoverageReport.generate(class_dir, hiera_file, @data[:profile])
50
+ coverage = AbideDevUtils::Ppt.generate_coverage_report(class_dir, hiera_file, @data[:profile])
45
51
  coverage.each do |k, v|
46
- next if ['classes', 'benchmark'].include?(k)
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
- require 'abide_dev_utils/ppt/new_obj'
104
- builder = AbideDevUtils::Ppt::NewObjectBuilder.new(
105
- type,
106
- name,
107
- opts: @data,
108
- vars: @data.fetch(:vars, '').split(',').map { |i| i.split('=') }.to_h # makes the str a hash
109
- )
110
- builder.build
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
@@ -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)