abide_dev_utils 0.6.0 → 0.8.0

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: cf0d6affedd8f13f06af7f1f0db11666b9df2707d87a7685a4bd39ecd3e1519d
4
- data.tar.gz: 0f20af443ff1e13f9e854daa5e7cf5ec45213dfe9a2f0390c250dac92a8cc8d3
3
+ metadata.gz: 3978f655b9053e54d4fd63d456d3d65b9079c7684c6fcc88a3f764ead1aa012a
4
+ data.tar.gz: 746265daf86c8095a0f4ddbf9909d85a30ba2495b2b449e19896584c6e88da2b
5
5
  SHA512:
6
- metadata.gz: '097e88fb6b19170c2b727fd8873fa3dbb766ace25a7538ab8cfbd0a35083cb11654b58fb7f45ee7130d7c4f4cb48b8b241de4849b0cb406de8f7eb62cf09ce68'
7
- data.tar.gz: 4c0bc197da434b0ee25c9854b4b2af98a6ad9600733b734f9be21022ce312d7e8f0aea4f27c2217c3f56f7d2df26fedfe228f80b60fcd04da4ec08877a86bc54
6
+ metadata.gz: a6bbb36782aff2d06e4fd55ea66582cf64c4414c2e13f1c3cca76c8b1c33c420f76474b058c2e2ce49bb294efc01b677588957fa8f745d3b2fa022683253281f
7
+ data.tar.gz: 78f92a917f547ba04f17610e0bca9cc5816efaadf7b066645cc75e40c303173a9b0d3e27ea0d7a741219f88c5e479810e14f180fc813cd5a31e3d6f0ee4bf65e
data/.gitignore CHANGED
@@ -6,7 +6,8 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
-
9
+ w10_20h2.xml
10
+ w10_2004.xml
10
11
  # rspec failure tracking
11
12
  .rspec_status
12
13
  Gemfile.lock
data/.rubocop.yml CHANGED
@@ -12,7 +12,7 @@ AllCops:
12
12
  - 'tmp/**/*'
13
13
  - '.git/**/*'
14
14
  - 'bin/*'
15
- TargetRubyVersion: 2.5
15
+ TargetRubyVersion: 2.7
16
16
  SuggestExtensions: false
17
17
 
18
18
  Naming/PredicateName:
data/CODEOWNERS ADDED
@@ -0,0 +1 @@
1
+ * @puppetlabs/abide-team
@@ -7,14 +7,14 @@ require "abide_dev_utils/version"
7
7
  Gem::Specification.new do |spec|
8
8
  spec.name = "abide_dev_utils"
9
9
  spec.version = AbideDevUtils::VERSION
10
- spec.authors = ["Heston Snodgrass"]
11
- spec.email = ["hsnodgrass3@gmail.com"]
10
+ spec.authors = ["abide-team"]
11
+ spec.email = ["abide-team@puppet.com"]
12
12
 
13
- spec.summary = "Helper utilities for developing Abide"
14
- spec.description = "Provides a CLI with helpful utilities for developing Abide"
15
- spec.homepage = "https://github.com/hsnodgrass/abide_dev_utils"
13
+ spec.summary = "Helper utilities for developing compliance Puppet code"
14
+ spec.description = "Provides a CLI with helpful utilities for developing compliance Puppet code"
15
+ spec.homepage = "https://github.com/puppetlabs/abide_dev_utils"
16
16
  spec.license = "MIT"
17
- spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
17
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
18
18
 
19
19
  # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
20
20
 
@@ -39,6 +39,7 @@ Gem::Specification.new do |spec|
39
39
  spec.add_dependency 'ruby-progressbar', '~> 1.11'
40
40
  spec.add_dependency 'selenium-webdriver', '~> 4.0.0.beta4'
41
41
  spec.add_dependency 'google-cloud-storage', '~> 1.34'
42
+ spec.add_dependency 'hashdiff', '~> 1.0'
42
43
 
43
44
  # Dev dependencies
44
45
  spec.add_development_dependency 'bundler'
data/itests.rb ADDED
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'json'
5
+ require 'yaml'
6
+ require 'abide_dev_utils/comply'
7
+ require 'abide_dev_utils/ppt/api'
8
+
9
+ OS_BENCHMARK_MAP = {
10
+ 'centos-7' => 'CIS_CentOS_Linux_7_Benchmark_v3.1.1-xccdf.xml',
11
+ 'centos-8' => 'CIS_CentOS_Linux_8_Benchmark_v1.0.1-xccdf.xml',
12
+ 'rhel-7' => 'CIS_Red_Hat_Enterprise_Linux_7_Benchmark_v3.1.1-xccdf.xml',
13
+ 'rhel-8' => 'CIS_Red_Hat_Enterprise_Linux_8_Benchmark_v1.0.1-xccdf.xml',
14
+ 'serv-2016' => 'CIS_Microsoft_Windows_Server_2016_RTM_(Release_1607)_Benchmark_v1.3.0-xccdf.xml',
15
+ 'serv-2019' => 'CIS_Microsoft_Windows_Server_2019_Benchmark_v1.2.1-xccdf.xml'
16
+ }
17
+ EL_PROFILE_1_SERVER = 'xccdf_org.cisecurity.benchmarks_profile_Level_1_-_Server'
18
+ WIN_PROFILE_1_MS = 'xccdf_org.cisecurity.benchmarks_profile_Level_1_-_Member_Server'
19
+ NIX_SCAN_HASH = {
20
+ 'nix-centos-7.c.team-sse.internal' => {
21
+ 'benchmark' => OS_BENCHMARK_MAP['centos-7'],
22
+ 'profile' => EL_PROFILE_1_SERVER
23
+ },
24
+ 'nix-centos-8.c.team-sse.internal' => {
25
+ 'benchmark' => OS_BENCHMARK_MAP['centos-8'],
26
+ 'profile' => EL_PROFILE_1_SERVER
27
+ },
28
+ 'nix-rhel-7.c.team-sse.internal' => {
29
+ 'benchmark' => OS_BENCHMARK_MAP['rhel-7'],
30
+ 'profile' => EL_PROFILE_1_SERVER
31
+ },
32
+ 'nix-rhel-8.c.team-sse.internal' => {
33
+ 'benchmark' => OS_BENCHMARK_MAP['rhel-8'],
34
+ 'profile' => EL_PROFILE_1_SERVER
35
+ }
36
+ }.freeze
37
+ WIN_SCAN_HASH = {
38
+ 'win-server-2016.c.team-sse.internal' => {
39
+ 'benchmark' => OS_BENCHMARK_MAP['serv-2016'],
40
+ 'profile' => EL_PROFILE_1_SERVER
41
+ },
42
+ 'win-serv-2019.c.team-sse.internal' => {
43
+ 'benchmark' => OS_BENCHMARK_MAP['serv-2019'],
44
+ 'profile' => WIN_PROFILE_1_MS
45
+ }
46
+ }.freeze
47
+
48
+ scan_hash = ENV['ABIDE_OS'] == 'nix' ? NIX_SCAN_HASH : WIN_SCAN_HASH
49
+ node_group_name = ENV['ABIDE_OS'] == 'nix' ? 'CEM Linux Nodes' : 'CEM Windows Nodes'
50
+
51
+ puts 'Creating client...'
52
+ client = AbideDevUtils::Ppt::ApiClient.new(ENV['PUPPET_HOST'], auth_token: ENV['PE_ACCESS_TOKEN'])
53
+ puts 'Starting code deploy...'
54
+ code_manager_deploy = client.post_codemanager_deploys('environments' => ['production'], 'wait' => true)
55
+ raise 'Code manager deployment failed!' unless code_manager_deploy['status'] == 'complete'
56
+
57
+ puts 'Code deploy successful...'
58
+ puts 'Gathering node group ID...'
59
+ node_groups = client.get_classifier1_groups
60
+ node_group_id = nil
61
+ node_groups.each { |x| node_group_id = x['id'] if x['name'] == node_group_name }
62
+ raise 'Failed to find requested node group!' if node_group_id.nil?
63
+
64
+ puts 'Running Puppet on nodes...'
65
+ puppet_run = client.post_orchestrator_command_deploy('environment' => 'production', 'scope' => { 'node_group' => node_group_id })
66
+ puts "Started job #{puppet_run['job']['name']}..."
67
+ timeout = 0
68
+ run_complete = false
69
+ until run_complete || timeout >= 30
70
+ puts "Waiting on job #{puppet_run['job']['name']} to complete..."
71
+ status = client.get_orchestrator_jobs(puppet_run['job']['name'])
72
+ case status['state']
73
+ when 'failed'
74
+ raise "Job #{puppet_run['job']['name']} finished with failures!"
75
+ when 'finished'
76
+ run_complete = true
77
+ break
78
+ else
79
+ timeout += 1
80
+ sleep(10)
81
+ end
82
+ end
83
+ raise 'Job timed out waiting for completion' unless run_complete
84
+
85
+ puts 'Starting node scans...'
86
+ scan_job = client.post_orchestrator_command_task(
87
+ 'environment' => 'production',
88
+ 'task' => 'comply::ciscat_scan',
89
+ 'params' => {
90
+ 'comply_port' => '443',
91
+ 'comply_server' => ENV['COMPLY_FQDN'],
92
+ 'ssl_verify_mode' => 'none',
93
+ 'scan_type' => 'desired',
94
+ 'scan_hash' => JSON.generate(scan_hash)
95
+ },
96
+ 'scope' => {
97
+ 'node_group' => node_group_id
98
+ }
99
+ )
100
+ puts "Started scan #{scan_job['job']['name']}..."
101
+ timeout = 0
102
+ scan_complete = false
103
+ until scan_complete || timeout >= 30
104
+ puts "Waiting on scan #{scan_job['job']['name']} to complete..."
105
+ status = client.get_orchestrator_jobs(scan_job['job']['name'])
106
+ case status['state']
107
+ when 'failed'
108
+ raise "Task #{scan_job['job']['name']} finished with failures!"
109
+ when 'finished'
110
+ scan_complete = true
111
+ break
112
+ else
113
+ timeout += 1
114
+ sleep(10)
115
+ end
116
+ end
117
+ raise 'Job timed out waiting for completion' unless scan_complete
118
+
119
+ puts 'Collecting scan report from Comply...'
120
+ onlylist = scan_hash.keys
121
+ scan_report = AbideDevUtils::Comply.build_report("https://#{ENV['COMPLY_FQDN']}", ENV['COMPLY_PASSWORD'], nil, onlylist: onlylist)
122
+ puts 'Saving report to nix_report.yaml...'
123
+ File.open('nix_report.yaml', 'w') { |f| f.write(scan_report.to_yaml) }
124
+
125
+ puts 'Comparing current report to last report...'
126
+ opts = {
127
+ report_name: 'nix_report.yaml',
128
+ remote_storage: 'gcloud',
129
+ upload: true
130
+ }
131
+ result = AbideDevUtils::Comply.compare_reports(File.expand_path('./nix_report.yaml'), 'nix_report.yaml', opts)
132
+ if result
133
+ puts 'Success!'
134
+ exit(0)
135
+ else
136
+ puts 'Failure!'
137
+ exit(1)
138
+ end
@@ -12,6 +12,7 @@ module Abide
12
12
  def initialize
13
13
  super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: true)
14
14
  add_command(ComplyReportCommand.new)
15
+ add_command(ComplyCompareReportCommand.new)
15
16
  end
16
17
  end
17
18
 
@@ -57,23 +58,19 @@ module Abide
57
58
  options.on('-t [SECONDS]', '--timeout [SECONDS]', OPT_TIMEOUT_DESC) do |t|
58
59
  @data[:timeout] = t
59
60
  end
60
- options.on('-s x,y,z', '--status x,y,x',
61
+ options.on('-s [X,Y,Z]', '--status [X,Y,Z]',
61
62
  %w[pass fail error notapplicable notchecked unknown informational],
62
63
  Array,
63
64
  OPT_STATUS_DESC) do |s|
64
65
  s&.map! { |i| i == 'notchecked' ? 'not checked' : i }
65
66
  @data[:status] = s
66
67
  end
67
- options.on('--only x,y,z', Array, OPT_ONLY_NODES) do |o|
68
+ options.on('--only [X,Y,Z]', Array, OPT_ONLY_NODES) do |o|
68
69
  @data[:onlylist] = o
69
70
  end
70
- options.on('--ignore x,y,z', Array, OPT_IGNORE_NODES) do |i|
71
+ options.on('--ignore [X,Y,Z]', Array, OPT_IGNORE_NODES) do |i|
71
72
  @data[:ignorelist] = i
72
73
  end
73
- # options.on('-R', '--[no-]regression-test', OPT_REGRESSION_TEST) do |r|
74
- # @data[:regression] = r
75
- # end
76
- # options.on('--')
77
74
  end
78
75
 
79
76
  def help_arguments
@@ -95,5 +92,24 @@ module Abide
95
92
  Abide::CLI::OUTPUT.yaml(report, file: outfile)
96
93
  end
97
94
  end
95
+
96
+ class ComplyCompareReportCommand < AbideCommand
97
+ CMD_NAME = 'compare-report'
98
+ CMD_SHORT = 'Compare two Comply reports and get the differences.'
99
+ CMD_LONG = 'Compare two Comply reports and get the differences. Report A is compared to report B, showing what changes it would take for A to equal B.'
100
+ CMD_REPORT_A = 'The current Comply report yaml file'
101
+ CMD_REPORT_B = 'The old Comply report yaml file name or full path'
102
+ def initialize
103
+ super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: false)
104
+ argument_desc(REPORT_A: CMD_REPORT_A, REPORT_B: CMD_REPORT_B)
105
+ options.on('-u', '--upload-new', 'If you want to upload the new scan report') { @data[:upload] = true }
106
+ options.on('-s [STORAGE]', '--remote-storage [STORAGE]', 'Remote storage to upload the report to. (Only supports "gcloud")') { |x| @data[:remote_storage] = x }
107
+ options.on('-r [NAME]', '--name [NAME]', 'The name to upload the report as') { |x| @data[:report_name] = x }
108
+ end
109
+
110
+ def execute(report_a, report_b)
111
+ AbideDevUtils::Comply.compare_reports(report_a, report_b, @data)
112
+ end
113
+ end
98
114
  end
99
115
  end
@@ -217,5 +217,23 @@ module Abide
217
217
  AbideDevUtils::Ppt.add_cis_comment(path, xccdf, number_format: @data.fetch(:number_format, false))
218
218
  end
219
219
  end
220
+
221
+ class PuppetScoreModuleCommand < AbideCommand
222
+ CMD_NAME = 'score'
223
+ CMD_SHORT = 'Scores a Puppet module just like Puppet Forge'
224
+ CMD_LONG = 'Scores a Puppet module just like Puppet Forge. This is a useful quality-check before publishing a module.'
225
+ def initialize
226
+ super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: false)
227
+ options.on('-o [PATH]', '--outfile [PATH]', 'Save results to a file') { |x| @data[:outfile] = x }
228
+ options.on('-q', '--quiet', FalseClass, 'Do not print results to console') { |x| @data[:quiet] = x }
229
+ options.on('-c', '--checks', Array, 'Comma-separated list of individual checks to run. Defaults to running all checks.') { |x| @data[:check] = x }
230
+ options.on('-m [PATH]', '--module [PATH]', 'Path to a Puppet module to score. Defaults to using the current directory.') { |x| @data[:module] = x }
231
+ end
232
+
233
+ def execute
234
+ module_path = @data.fetch(:module, nil)
235
+ AbideDevUtils::Ppt.score_module(module_path, **@data)
236
+ end
237
+ end
220
238
  end
221
239
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'abide_dev_utils/cli/abstract'
3
4
  require 'abide_dev_utils/xccdf'
4
5
 
5
6
  module Abide
@@ -14,11 +15,12 @@ module Abide
14
15
  long_desc(CMD_LONG)
15
16
  add_command(CmdParse::HelpCommand.new, default: true)
16
17
  add_command(XccdfToHieraCommand.new)
18
+ add_command(XccdfDiffCommand.new)
17
19
  end
18
20
  end
19
21
 
20
22
  class XccdfToHieraCommand < CmdParse::Command
21
- CMD_NAME = 'to_hiera'
23
+ CMD_NAME = 'to-hiera'
22
24
  CMD_SHORT = 'Generates control coverage report'
23
25
  CMD_LONG = 'Generates report of valid Puppet classes that match with Hiera controls'
24
26
  def initialize
@@ -37,15 +39,32 @@ module Abide
37
39
 
38
40
  def execute(xccdf_file)
39
41
  @data[:type] = 'cis' if @data[:type].nil?
40
-
41
- to_hiera(xccdf_file)
42
+ hfile = AbideDevUtils::XCCDF.to_hiera(xccdf_file, @data)
43
+ AbideDevUtils::Output.yaml(hfile, console: @data[:file].nil?, file: @data[:file])
42
44
  end
45
+ end
43
46
 
44
- private
47
+ class XccdfDiffCommand < AbideCommand
48
+ CMD_NAME = 'diff'
49
+ CMD_SHORT = 'Generates a diff report between two XCCDF files'
50
+ CMD_LONG = 'Generates a diff report between two XCCDF files'
51
+ CMD_FILE1_ARG = 'path to first XCCDF file'
52
+ CMD_FILE2_ARG = 'path to second XCCDF file'
53
+ def initialize
54
+ super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: false)
55
+ argument_desc(FILE1: CMD_FILE1_ARG, FILE2: CMD_FILE2_ARG)
56
+ options.on('-o [PATH]', '--out-file', 'Save the report as a yaml file') { |x| @data[:outfile] = x }
57
+ options.on('-p [PROFILE]', '--profile', 'Only diff and specific profile in the benchmarks') do |x|
58
+ @data[:profile] = x
59
+ end
60
+ options.on('-q', '--quiet', 'Show no output in the terminal') { @data[:quiet] = false }
61
+ options.on('--no-diff-profiles', 'Do not diff the profiles in the XCCDF files') { @data[:diff_profiles] = false }
62
+ options.on('--no-diff-controls', 'Do not diff the controls in the XCCDF files') { @data[:diff_controls] = false }
63
+ end
45
64
 
46
- def to_hiera(xccdf_file)
47
- xfile = AbideDevUtils::XCCDF.to_hiera(xccdf_file, @data)
48
- Abide::CLI::OUTPUT.yaml(xfile, console: @data[:file].nil?, file: @data[:file])
65
+ def execute(file1, file2)
66
+ diffreport = AbideDevUtils::XCCDF.diff(file1, file2, @data)
67
+ AbideDevUtils::Output.yaml(diffreport, console: @data.fetch(:quiet, true), file: @data.fetch(:outfile, nil))
49
68
  end
50
69
  end
51
70
  end