abide_dev_utils 0.2.0 → 0.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 75678bc1c177a3187619cfec9d2c25e566b08d91439c3b46c578c4202f4d9a7c
4
- data.tar.gz: f9749e6c8ad3d5b0439a8fe0fd03ba3ea91e5c0052057eea43b3862c08b45fbd
3
+ metadata.gz: d9e993f8a435b4be58831bc98cf1658533c8c1084f14c96c1a12ecd73ff89da6
4
+ data.tar.gz: 1120b6cc91eac28ff8168e808f13c16cf6c6d844b5928f04f4f4bb6d7cda0bcb
5
5
  SHA512:
6
- metadata.gz: 97ba4b3b0898a40ed6df3facaf3aa03beb2d1375d61e1915c6566e107e6edffa083ab7af93827c2679c14a2503504cafd40d9275b12708f582c3723953b5c9c7
7
- data.tar.gz: 2680eb354112e27223d590a645318ea14c4988dd0e331bf5a5f3b347402ead6398c8c07c1b7ded55704d76011522ff790459cf40452ceba8ca15dc2a19a76a7a
6
+ metadata.gz: bcf0b6aa95f003e5402be98cc797202949368ceff62e6cdb778f4002e452716ef5ef833bc0bcd34bb797f628997e1c807d88f191048a5afec767bd8bcb7dc7a3
7
+ data.tar.gz: 2ca0b4fb33d0329f13e3ce04d317427b4ba67c9937b4df739d991a1692871d19c17d1eeb24d5035573a676560795ae466e6df65148693258718aeda115c9e1d8
data/README.md CHANGED
@@ -2,15 +2,48 @@
2
2
 
3
3
  Helper library and CLI app for Abide development.
4
4
 
5
+ ## Features
6
+
7
+ ### CLI
8
+
9
+ * Type `abide -h` to see the CLI help menu
10
+ * All commands have help menus
11
+ * Tested on MacOS, should also work on Linux
12
+
13
+ ### PDK-like manifest generation from local ERB templates
14
+
15
+ * Create a directory in your module called `object_templates` to hold ERB files
16
+ * Generate manifests from those ERB files
17
+
18
+ ### XCCDF to Hiera conversion
19
+
20
+ * Convert the contents of an XCCDF XML file to Hiera
21
+
22
+ ### Coverage Reporting
23
+
24
+ * Generate a coverage report (i.e. how many CIS controls are covered by classes in your module)
25
+
26
+ ### Jira Integration
27
+
28
+ * Create Jira issues in bulk from coverage reports
29
+
30
+ ### Supports Configuration via Local YAML file
31
+
32
+ * Fully configurable via the `~/.abide_dev.yaml` file
33
+
5
34
  ## Installation
6
35
 
7
36
  ### CLI app
8
37
 
9
- ```sh
10
- $ gem install abide_dev_utils
11
- ...
12
- $ abide -h
13
- ```
38
+ Install from RubyGems:
39
+
40
+ `gem install abide_dev_utils`
41
+
42
+ Then to access the help menu:
43
+
44
+ `abide -h`
45
+
46
+ ### As a dependency
14
47
 
15
48
  Add this line to your application's Gemfile:
16
49
 
@@ -26,9 +59,159 @@ Or install it yourself as:
26
59
 
27
60
  `$ gem install abide_dev_utils`
28
61
 
62
+ ### Build it yourself
63
+
64
+ Clone this repo:
65
+
66
+ `git clone <this repo>`
67
+
68
+ Build the gem:
69
+
70
+ `bundle exec rake build`
71
+
72
+ The gem will be located at `pkg/<gem file>`
73
+
74
+ Install the gem:
75
+
76
+ `gem install pkg/<gem file>`
77
+
29
78
  ## Usage
30
79
 
31
- Coming soon, in the mean time run `abide -h` and `abide [command] -h` for help.
80
+ * `abide -h` - CLI top-level help menu
81
+ * `abide <command> -h` - Command-specific help menu
82
+
83
+ ### Overview of Commands
84
+
85
+ * `abide jira` - Command namespace for Jira commands
86
+ * `abide jira auth` - Authenticate with Jira. Only useful as a stand-alone command to test authentication
87
+ * `abide jira from_coverage` - Creates a parent issue with subtasks from a Puppet coverage report
88
+ * `abide jira get_issue` - Gets a specific Jira issue
89
+ * `abide jira new_issue` - Creates a new Jira issue
90
+ * `abide puppet` - Command namespace for Puppet commands
91
+ * `abide puppet coverage` - Generate a "coverage" report. This examines how many manifests you have in your Puppet module versus how many CIS controls exist in the local Hiera data and gives you a breakdown of what percentage of the selected CIS benchmark / profile you have successfully covered.
92
+ * `abide puppet new` - Generate a new manifest from a local ERB template. Functions similar to `pdk new` except you can create arbitrary manifests.
93
+ * `abide test` - **BUGGED** Runs a module's test suite. Currently has issues with local gem environments.
94
+ * `abide xccdf` - Command namespace for XCCDF commands
95
+ * `abide xccdf to_hiera` - Converts a benchmark XCCDF file to a Hiera yaml file
96
+
97
+ ### Jira Command Reference
98
+
99
+ #### from_coverage
100
+
101
+ * Required positional parameters:
102
+ * `REPORT` - A path to a JSON file generated by the `abide puppet coverage` command
103
+ * `PROJECT` - A Jira project code. This is typically an all-caps abbreviation of a Jira project
104
+ * Options:
105
+ * `--dry-run`, `-d` - Prints the results of this command to the console instead of actually creating Jira issues
106
+
107
+ ### Puppet Command Reference
108
+
109
+ #### coverage
110
+
111
+ * Required positional parameters:
112
+ * `CLASS_DIR` - The path to the directory in your module that holds manifests named after the benchmark controls
113
+ * `HIERA_FILE` - The path to the Hiera file generated by the `abide xccdf to_hiera` command
114
+ * Options:
115
+ * `--out-file`, `-o` - The path to save the coverage report JSON file
116
+ * `--profile`, `-p` - A benchmark profile to generate the report for. By default, generates the report for all profiles
117
+
118
+ #### new
119
+
120
+ * Required positional parameters:
121
+ * `TYPE` - The type of object you would like to generate. This value is the name of an ERB template without `.erb` located in your template directory
122
+ * `NAME` - The fully namespaced name of the new object. Subdirectories will be automatically created within `manifests` based on the namespacing of this parameter if the directories do not exist.
123
+ * Options:
124
+ * `--template-dir`, `-t` - Name of the template directory relative to your module's root directory. Defaults to `object_templates`
125
+ * `--root-dir`, `-r` - Path to the root directory of your module. Defaults to the current working directory
126
+ * `--absolute-template-dir`, `-A` - Allows you to specify an absolute path with `--template-dir`. This is useful if your template directory is not relative to your module's root directory
127
+ * `--template-name`, `-n` - Allows you to specify a template name if it is different than the `TYPE` parameter
128
+ * `--vars`, `-v` - Comma-separated key=value pairs to pass in to the template renderer. This allows you to pass arbitrary values that can be used in your templates.
129
+
130
+ `abide puppet new` exposes a few variables for you to use in your templates by default:
131
+
132
+ * `@obj_name` - The value of the `NAME` parameter passed into the command
133
+ * `@vars` - A hash of any key=value pairs you passed into the command using `--vars`
134
+
135
+ Examples:
136
+
137
+ Lets assume we have a module at `~/test_module` and we have a directory in that module called `object_templates`. In the template directory, we have two ERB template files: `control_class.erb` and `util_class.erb`.
138
+
139
+ * control_class.erb
140
+
141
+ ```text
142
+ # @api private
143
+ class <%= @obj_name %> (
144
+ Boolean $enforce = true,
145
+ Hash $config = {},
146
+ ) {
147
+ if $enforce {
148
+ warning('Class not implemented yet')
149
+ }
150
+ }
151
+
152
+ ```
153
+
154
+ * util_class.erb
155
+
156
+ ```text
157
+ class <%= @obj_name %> (
158
+ <% if @vars.key?('testvar1') -%>
159
+ $testparam1 = '<%= @vars['testvar1'] %>',
160
+ <% else -%>
161
+ $testparam1 = undef,
162
+ <% end -%>
163
+ ) {
164
+ file { $testparam1:
165
+ ensure => file,
166
+ mode => '<%= @vars.fetch('testvar2', '0644') %>',
167
+ }
168
+ }
169
+
170
+ ```
171
+
172
+ ```text
173
+ $ cd ~/test_module
174
+ $ ls object_templates
175
+ control_class.erb util_class.erb
176
+ $ ls manifests
177
+ init.pp
178
+ $ abide puppet new control_class 'test_module::controls::test_new_control'
179
+ Created file /Users/the.dude/test_module/manifests/controls/test_new_control.pp
180
+ $ abide puppet new util_class 'test_module::utils::test_new_util' -v 'testvar1=dude,testvar2=sweet'
181
+ Created file /Users/the.dude/test_module/manifests/utils/test_new_util.pp
182
+ $ cat manifests/controls/test_new_control.pp
183
+ # @api private
184
+ class test_module::controls::test_new_control (
185
+ Boolean $enforce = true,
186
+ Hash $config = {},
187
+ ) {
188
+ if $enforce {
189
+ warning('Class not implemented yet')
190
+ }
191
+ }
192
+
193
+ $ cat manifests/utils/test_new_util.pp
194
+ class test_module::utils::test_new_util (
195
+ $testparam1 = 'dude',
196
+ ) {
197
+ file { 'dude':
198
+ ensure => file,
199
+ mode => 'sweet',
200
+ }
201
+ }
202
+
203
+ ```
204
+
205
+ ### XCCDF Command Reference
206
+
207
+ #### to_hiera
208
+
209
+ * Required positional parameters:
210
+ * `XCCDF_FILE` - Path to an XCCDF XML file
211
+ * Options:
212
+ * `--benchmark-type`, `-b` - The type of benchmark. Defaults to `cis`
213
+ * `--out-file`, `-o` - A path to a file where you would like to save the generated Hiera
214
+ * `--parent-key-prefix`, `-p` - Allows you to append a prefix to all top-level Hiera keys
32
215
 
33
216
  ## Development
34
217
 
@@ -3,7 +3,7 @@
3
3
  module Abide
4
4
  module CLI
5
5
  # @abstract
6
- class Command < CmdParse::Command
6
+ class AbideCommand < CmdParse::Command
7
7
  include AbideDevUtils::Config
8
8
  def initialize(cmd_name, cmd_short, cmd_long, **opts)
9
9
  super(cmd_name, **opts)
@@ -4,7 +4,7 @@ require 'abide_dev_utils/cli/abstract'
4
4
 
5
5
  module Abide
6
6
  module CLI
7
- class PuppetCommand < Command
7
+ class PuppetCommand < AbideCommand
8
8
  CMD_NAME = 'puppet'
9
9
  CMD_SHORT = 'Commands related to Puppet code'
10
10
  CMD_LONG = 'Namespace for commands related to Puppet code'
@@ -15,7 +15,7 @@ module Abide
15
15
  end
16
16
  end
17
17
 
18
- class PuppetCoverageCommand < Command
18
+ class PuppetCoverageCommand < AbideCommand
19
19
  CMD_NAME = 'coverage'
20
20
  CMD_SHORT = 'Generates control coverage report'
21
21
  CMD_LONG = 'Generates report of valid Puppet classes that match with Hiera controls'
@@ -53,7 +53,7 @@ module Abide
53
53
  end
54
54
  end
55
55
 
56
- class PuppetNewCommand < Command
56
+ class PuppetNewCommand < AbideCommand
57
57
  CMD_NAME = 'new'
58
58
  CMD_SHORT = 'Generates a new Puppet object from templates'
59
59
  CMD_LONG = 'Generates a new Puppet object (class, test, etc.) from templates stored in the module repo'
@@ -12,36 +12,16 @@ module AbideDevUtils
12
12
 
13
13
  def initialize(obj_type, obj_name, opts: {}, vars: {})
14
14
  @obj_type = obj_type
15
- @obj_name = obj_name.split(':').reject(&:empty?).join('::') # removes
16
- @obj_basename = obj_name.split('::')[-1]
17
- @root_dir = Pathname.new(opts.fetch(:root_dir, Dir.pwd))
18
- @tmpl_dir = if opts.fetch(:absolute_template_dir, false)
19
- opts.fetch(:tmpl_dir)
20
- else
21
- "#{@root_dir}/#{opts.fetch(:tmpl_dir, 'object_templates')}"
22
- end
23
- @tmpl_name = opts.fetch(:tmpl_name, "#{@obj_type}.erb")
24
- @tmpl_path = Pathname.new("#{@tmpl_dir}/#{@tmpl_name}")
25
- @type_path_map = opts.fetch(:type_path_map, {})
15
+ @obj_name = namespace_format(obj_name)
16
+ @opts = opts
26
17
  @vars = vars
18
+ class_vars
19
+ validate_class_vars
27
20
  end
28
21
 
29
- def obj_path
30
- case @obj_type
31
- when 'class'
32
- obj_path_from_name
33
- else
34
- custom_obj_path
35
- end
36
- end
37
-
38
- def template?
39
- @tmpl_path.file?
40
- end
22
+ attr_reader :obj_type, :obj_name, :tmpl_name, :root_dir, :tmpl_dir, :tmpl_path, :type_path_map, :obj_path, :vars
41
23
 
42
24
  def render
43
- raise AbideDevUtils::Errors::Ppt::TemplateNotFoundError, @tmpl_path.to_s unless template?
44
-
45
25
  ERB.new(File.read(@tmpl_path.to_s), 0, '<>-').result(binding)
46
26
  end
47
27
 
@@ -79,34 +59,69 @@ module AbideDevUtils
79
59
 
80
60
  private
81
61
 
62
+ def class_vars
63
+ @tmpl_name = @opts.fetch(:tmpl_name, "#{@obj_type}.erb")
64
+ @root_dir = Pathname.new(@opts.fetch(:root_dir, Dir.pwd))
65
+ @tmpl_dir = if @opts.fetch(:absolute_template_dir, false)
66
+ @opts.fetch(:tmpl_dir)
67
+ else
68
+ "#{@opts.fetch(:root_dir, Dir.pwd)}/#{@opts.fetch(:tmpl_dir, 'object_templates')}"
69
+ end
70
+ @tmpl_path = Pathname.new("#{@tmpl_dir}/#{@opts.fetch(:tmpl_name, "#{@obj_type}.erb")}")
71
+ @type_path_map = @opts.fetch(:type_path_map, {})
72
+ @obj_path = new_obj_path
73
+ end
74
+
75
+ def validate_class_vars
76
+ raise AbideDevUtils::Errors::PathNotDirectoryError, @root_dir unless Dir.exist? @root_dir
77
+ raise AbideDevUtils::Errors::PathNotDirectoryError, @tmpl_dir unless Dir.exist? @tmpl_dir
78
+ raise AbideDevUtils::Errors::Ppt::TemplateNotFoundError, @tmpl_path.to_s unless @tmpl_path.file?
79
+ end
80
+
81
+ def basename(obj_name)
82
+ obj_name.split('::')[-1]
83
+ end
84
+
85
+ def new_obj_path
86
+ if obj_type == 'class'
87
+ obj_path_from_name
88
+ else
89
+ custom_obj_path
90
+ end
91
+ end
92
+
93
+ def namespace_format(name)
94
+ name.split(':').reject(&:empty?).join('::')
95
+ end
96
+
82
97
  def obj_path_from_name
83
98
  parts = @obj_name.split('::')[1..-2]
84
99
  parts.insert(0, 'manifests')
85
- parts.insert(-1, "#{@obj_basename}#{DEFAULT_EXT}")
100
+ parts.insert(-1, "#{basename(@obj_name)}#{DEFAULT_EXT}")
86
101
  path = @root_dir + Pathname.new(parts.join('/'))
87
102
  path.to_s
88
103
  end
89
104
 
90
105
  def custom_obj_path
91
- map_val = @type_path_map.fetch(@obj_type.to_sym, nil)
106
+ map_val = type_path_map.fetch(@obj_type.to_sym, nil)
92
107
  return obj_path_from_name if map_val.nil?
93
108
 
94
109
  if map_val.respond_to?(:key?)
95
- custom_obj_path_from_hash(map_val)
110
+ custom_obj_path_from_hash(map_val, @obj_name)
96
111
  else
97
112
  abs_path = Pathname.new(map_val).absolute? ? map_val : "#{Dir.pwd}/#{map_val}"
98
- "#{abs_path}/#{@obj_basename}#{DEFAULT_EXT}"
113
+ "#{abs_path}/#{basename(@obj_name)}#{DEFAULT_EXT}"
99
114
  end
100
115
  end
101
116
 
102
- def custom_obj_path_from_hash(map_val)
117
+ def custom_obj_path_from_hash(map_val, obj_name)
103
118
  raise AbideDevUtils::Errors::Ppt::CustomObjPathKeyError, map_val unless map_val.key?(:path)
104
119
 
105
120
  abs_path = Pathname.new(map_val[:path]).absolute? ? map_val[:path] : "#{Dir.pwd}/#{map_val[:path]}"
106
121
  if map_val.key?(:extension)
107
- "#{abs_path}/#{@obj_basename}#{map_val[:extension]}"
122
+ "#{abs_path}/#{basename(obj_name)}#{map_val[:extension]}"
108
123
  else
109
- "#{abs_path}/#{@obj_basename}#{DEFAULT_EXT}"
124
+ "#{abs_path}/#{basename(obj_name)}#{DEFAULT_EXT}"
110
125
  end
111
126
  end
112
127
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AbideDevUtils
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.1"
5
5
  end
@@ -25,6 +25,7 @@ module AbideDevUtils
25
25
  relative_select: './xccdf:select'
26
26
  }
27
27
  }.freeze
28
+ NEXT_GEN_WINDOWS = /(next_generation_windows_security)/.freeze
28
29
 
29
30
  attr_reader :title, :version
30
31
 
@@ -111,11 +112,19 @@ module AbideDevUtils
111
112
  end
112
113
 
113
114
  def normalize_str(str)
114
- str.delete('-').gsub(/\s/, '_').downcase
115
+ nstr = str.downcase
116
+ nstr.gsub!(/[^a-z]$/, '')
117
+ nstr.gsub!(/^[^a-z]/, '')
118
+ nstr.gsub!(/^(l1_|l2_|ng_)/, '')
119
+ nstr.delete!('-')
120
+ nstr.gsub!(/(\s|\(|\))/, '_')
121
+ nstr
115
122
  end
116
123
 
117
124
  def normalize_profile_name(prof)
118
- normalize_str("profile_#{prof}")
125
+ prof_name = normalize_str("profile_#{prof}")
126
+ prof_name.gsub!(NEXT_GEN_WINDOWS, 'ngws')
127
+ prof_name
119
128
  end
120
129
 
121
130
  def normalize_ctrl_name(ctrl)
@@ -125,12 +134,10 @@ module AbideDevUtils
125
134
 
126
135
  def make_parent_key(doc, prefix)
127
136
  doc_title = normalize_str(doc.xpath(XPATHS[:benchmark][:title]).children.to_s)
128
- if prefix.nil?
129
- doc_title
130
- else
131
- sepped_prefix = prefix.end_with?('::') ? prefix : "#{prefix}::"
132
- "#{sepped_prefix.chomp}#{doc_title}"
133
- end
137
+ return doc_title if prefix.nil?
138
+
139
+ sepped_prefix = prefix.end_with?('::') ? prefix : "#{prefix}::"
140
+ "#{sepped_prefix.chomp}#{doc_title}"
134
141
  end
135
142
  end
136
143
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: abide_dev_utils
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Heston Snodgrass
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-16 00:00:00.000000000 Z
11
+ date: 2021-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri