abide_dev_utils 0.2.0 → 0.2.1

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: 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