simp-beaker-helpers 2.0.5 → 3.0.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: '01691b723cf1d20c20093a46cc90eaba1f0d3bd947e517388d963c86c086a406'
4
- data.tar.gz: 5cdc26846cbefaf342a15200542dd801c00947677b9e553ec741bc0bd62ae71b
3
+ metadata.gz: 4e51892c7f01f52c49e29840032a8e4b7d5f524a3c3160b3218d3839224bfaf6
4
+ data.tar.gz: abbce77cea4030bcc802eaa16359e5f53998fb1dda40cd8dbb5aa11e56fff768
5
5
  SHA512:
6
- metadata.gz: fcfbe6df23fe2fcb941349958cdd4d1645ffc61592c417ad52ce28975de51b44f795e6be786e297b9a8e6ca8a23aaf01898a0ef181f075dea6219ff5a595aa8d
7
- data.tar.gz: 1efc45ea2fb279ffa9795c4f31510be99ae565dcb36bdc5366bf8056d11a9d0bf8d6fd5dcbca1d18fc1d38c3a4912c965290ff88489f12bb1a55476fea08e4f0
6
+ metadata.gz: 3c0c3ef0740aef92c4dcb643b94ac228d5484a0ad524b7b419832f30e28caa63f4ba802bf48d721ae242af7a387cc291582e33e9ad23ef345f6bc88105161f67
7
+ data.tar.gz: 61829ea33bf1911ee6da64d46b29f270f907631c01b3e681b62ac4650716ccaeba4d3d8dababc07cfea1eb8400b1bd2ab72d8528940e296bf4e35f290f36ddac
@@ -17,14 +17,6 @@ jobs:
17
17
  strategy:
18
18
  matrix:
19
19
  puppet:
20
- - label: 'Puppet 7.x [SIMP 6.6/PE 2021.7]'
21
- puppet_version: '~> 7.0'
22
- ruby_version: '2.7'
23
- experimental: false
24
- - label: 'Puppet 8.x'
25
- puppet_version: '~> 8.0'
26
- ruby_version: '3.2'
27
- experimental: false
28
20
  - label: 'OpenVox 8.x'
29
21
  puppet_version: '~> 8.0'
30
22
  ruby_version: '3.2'
@@ -37,9 +29,6 @@ jobs:
37
29
  - label: beaker puppet_collections
38
30
  suite: puppet_collections
39
31
  allowed_to_fail: false
40
- - label: beaker ssg
41
- suite: ssg
42
- allowed_to_fail: false
43
32
  # The inspec suite fails for unclear reasons during an scp.
44
33
  # Sicura tests compliance at the framework level, so troubleshooting
45
34
  # inspec acceptance tests is not a priority at present.
@@ -51,7 +40,7 @@ jobs:
51
40
  PUPPET_VERSION: ${{matrix.puppet.puppet_version}}
52
41
  steps:
53
42
  - name: checkout repo
54
- uses: actions/checkout@v6
43
+ uses: actions/checkout@v7
55
44
  - name: setup ruby
56
45
  uses: ruby/setup-ruby@v1
57
46
  with:
@@ -32,7 +32,7 @@ jobs:
32
32
  runs-on: ubuntu-latest
33
33
  continue-on-error: true
34
34
  steps:
35
- - uses: actions/checkout@v6
35
+ - uses: actions/checkout@v7
36
36
  - name: "Install Ruby 3.2"
37
37
  uses: ruby/setup-ruby@v1
38
38
  with:
@@ -48,18 +48,20 @@ jobs:
48
48
  strategy:
49
49
  matrix:
50
50
  puppet:
51
- - label: 'Puppet 7.x [SIMP 6.6/PE 2021.7]'
52
- puppet_version: '~> 7.0'
53
- ruby_version: '2.7'
54
- experimental: false
55
- - label: 'Puppet 8.x'
51
+ - label: 'OpenVox 8.x'
56
52
  puppet_version: '~> 8.0'
57
53
  ruby_version: '3.2'
58
54
  experimental: false
55
+ # OpenVox 9 is unreleased; preview the future Ruby 4.0 / OpenVox 9
56
+ # combo by running the OpenVox 8 gem on Ruby 4.0.
57
+ - label: 'OpenVox 9.x preview (Ruby 4.0, OpenVox 8 gem)'
58
+ puppet_version: '~> 8.0'
59
+ ruby_version: '4.0'
60
+ experimental: false
59
61
  env:
60
62
  PUPPET_VERSION: ${{matrix.puppet.puppet_version}}
61
63
  steps:
62
- - uses: actions/checkout@v6
64
+ - uses: actions/checkout@v7
63
65
  - name: 'Install Ruby ${{matrix.puppet.ruby_version}}'
64
66
  uses: ruby/setup-ruby@v1
65
67
  with:
@@ -48,7 +48,7 @@ on:
48
48
  - '[0-9]+\.[0-9]+\.[0-9]+\-[a-z]+[0-9]+'
49
49
 
50
50
  env:
51
- PUPPET_VERSION: '~> 7'
51
+ PUPPET_VERSION: '~> 8'
52
52
  LOCAL_WORKFLOW_CONFIG_FILE: .github/workflows.local.json
53
53
 
54
54
  jobs:
@@ -63,7 +63,7 @@ jobs:
63
63
  steps:
64
64
  - name: "Assert '${{ github.ref }}' is a tag"
65
65
  run: '[[ "$GITHUB_REF" =~ ^refs/tags/ ]] || { echo "::error ::GITHUB_REF is not a tag: ${GITHUB_REF}"; exit 1 ; }'
66
- - uses: actions/checkout@v6
66
+ - uses: actions/checkout@v7
67
67
  with:
68
68
  ref: ${{ github.ref }}
69
69
  clean: true
@@ -116,7 +116,7 @@ jobs:
116
116
  tag: ${{ steps.tag-check.outputs.tag }}
117
117
  steps:
118
118
  - name: Checkout code
119
- uses: actions/checkout@v6
119
+ uses: actions/checkout@v7
120
120
  with:
121
121
  ref: ${{ github.ref }}
122
122
  clean: true
@@ -178,7 +178,7 @@ jobs:
178
178
  PKG_DIR: ${{ needs.releng-checks.outputs.pkg_dir }}
179
179
  steps:
180
180
  - name: Checkout code
181
- uses: actions/checkout@v6
181
+ uses: actions/checkout@v7
182
182
  with:
183
183
  ref: ${{ github.ref }}
184
184
  clean: true
data/CHANGELOG.md CHANGED
@@ -1,7 +1,29 @@
1
+ ### 3.0.0 / 2026-06-24
2
+ * Changed (**Breaking**):
3
+ * Dropped support for Puppet 7 / Ruby 2.7. CI now tests Puppet/OpenVox 8 only,
4
+ and the default OpenVox gem floor is raised to `>= 8.0.0`.
5
+ * Replaced the `puppetlabs_spec_helper/tasks/fixtures` dependency with
6
+ `puppet_fixtures`, enabling Ruby 4.0 support. `puppetlabs_spec_helper` pulls
7
+ in `puppet-syntax` < 5, which depends on the `puppet` gem and its `facter`
8
+ dependency that does not support Ruby >= 4.0; `puppet_fixtures` is the
9
+ OpenVox-ecosystem replacement and supports Ruby 4.0.
10
+ * The `beaker:suites` task now depends on `fixtures:prep` (from
11
+ `puppet_fixtures`) instead of `spec_prep`, and `ensure_fixture_modules` now
12
+ runs `rake fixtures:prep`.
13
+ * Removed (**Breaking**):
14
+ * Removed the unsupported `Simp::BeakerHelpers::SSG` helpers, the `ssg`
15
+ acceptance suite, and the `SSG_REPO_URL` constant (#268)
16
+ * Added:
17
+ * `puppet_fixtures` runtime dependency
18
+ * OpenVox-named environment variables for `get_puppet_install_info`, taking
19
+ precedence over the Puppet-named equivalents (which remain as fallbacks):
20
+ `OPENVOX_VERSION`, `OPENVOX_INSTALL_VERSION`, `OPENVOX_INSTALL_TYPE`,
21
+ `BEAKER_OPENVOX_AGENT_VERSION`, `BEAKER_OPENVOX_COLLECTION`,
22
+ `BEAKER_OPENVOX_PACKAGE_NAME`
23
+
1
24
  ### 2.0.5 / 2026-06-06
2
25
  * Fixed:
3
26
  * Additional cleanup for rubocop
4
-
5
27
  ### 2.0.4 / 2025-10-16
6
28
  * Fixed:
7
29
  * `install_puppet` failure on Windows (#266)
data/Gemfile CHANGED
@@ -41,15 +41,14 @@ group :system_tests do
41
41
  gem 'ed25519'
42
42
  gem 'net-ssh'
43
43
  # renovate: datasource=rubygems versioning=ruby
44
- gem 'openvox', ENV.fetch('OPENVOX_VERSION', ENV.fetch('PUPPET_VERSION', ['>= 7.0.0', '< 9.0.0']))
45
- gem 'pry-byebug', '~> 3.10.0'
46
- gem 'puppetlabs_spec_helper', '>= 4.0.0', '< 9.0.0'
44
+ gem 'openvox', ENV.fetch('OPENVOX_VERSION', ENV.fetch('PUPPET_VERSION', ['>= 8.0.0', '< 9.0.0']))
45
+ gem 'pry-byebug', '~> 3.12.0'
47
46
  gem 'syslog' # Required for Ruby >= 3.4
48
47
  end
49
48
 
50
49
  group :tests do
51
- gem 'rubocop', '~> 1.87.0'
50
+ gem 'rubocop', '~> 1.88.0'
52
51
  gem 'rubocop-performance', '~> 1.26.0'
53
52
  gem 'rubocop-rake', '~> 0.7.0'
54
- gem 'rubocop-rspec', '~> 3.8.0'
53
+ gem 'rubocop-rspec', '~> 3.10.0'
55
54
  end
@@ -9,8 +9,6 @@ module Simp::BeakerHelpers # rubocop:disable Style/OneClassPerFile
9
9
  # oldest system that we support
10
10
  DEFAULT_PUPPET_AGENT_VERSION = '~> 8.0'.freeze
11
11
 
12
- SSG_REPO_URL = ENV['BEAKER_ssg_repo'] || 'https://github.com/ComplianceAsCode/content.git'
13
-
14
12
  if ['true', 'yes'].include?(ENV['BEAKER_online'])
15
13
  ONLINE = true
16
14
  elsif ['false', 'no'].include?(ENV['BEAKER_online'])
@@ -4,5 +4,5 @@
4
4
  module Simp; end
5
5
 
6
6
  module Simp::BeakerHelpers # rubocop:disable Style/OneClassPerFile
7
- VERSION = '2.0.5'
7
+ VERSION = '3.0.0'
8
8
  end
@@ -14,7 +14,6 @@ module Simp::BeakerHelpers # rubocop:disable Style/OneClassPerFile
14
14
  require 'simp/beaker_helpers/constants'
15
15
  require 'simp/beaker_helpers/inspec'
16
16
  require 'simp/beaker_helpers/snapshot'
17
- require 'simp/beaker_helpers/ssg'
18
17
  require 'simp/beaker_helpers/version'
19
18
  require 'find'
20
19
 
@@ -367,8 +366,8 @@ module Simp::BeakerHelpers # rubocop:disable Style/OneClassPerFile
367
366
  if missing_modules.empty?
368
367
  puts ' == all fixture modules present'
369
368
  else
370
- cmd = 'bundle exec rake spec_prep'
371
- puts " -- running spec_prep: '#{cmd}'"
369
+ cmd = 'bundle exec rake fixtures:prep'
370
+ puts " -- running fixtures:prep: '#{cmd}'"
372
371
  `#{cmd}`
373
372
  end
374
373
  end
@@ -1426,16 +1425,25 @@ module Simp::BeakerHelpers # rubocop:disable Style/OneClassPerFile
1426
1425
  # install version and a puppet collection are specified. This is
1427
1426
  # because the puppet install version can specify more precise
1428
1427
  # version information than is available from a puppet collection.
1428
+ #
1429
+ # Each Puppet-named environment variable has an OpenVox-named
1430
+ # equivalent (e.g. OPENVOX_VERSION, BEAKER_OPENVOX_COLLECTION) that
1431
+ # takes precedence; the Puppet-named variables are kept as fallbacks
1432
+ # for backwards compatibility.
1429
1433
  def get_puppet_install_info
1430
- # The first match is internal Beaker and the second is legacy SIMP
1431
- puppet_install_version = ENV['BEAKER_PUPPET_AGENT_VERSION'] || ENV['PUPPET_INSTALL_VERSION'] || ENV['PUPPET_VERSION']
1434
+ # OpenVox-named variables win; the Puppet-named ones remain as fallbacks.
1435
+ # Within each pair the first match is internal Beaker, the second legacy SIMP.
1436
+ puppet_install_version =
1437
+ ENV['BEAKER_OPENVOX_AGENT_VERSION'] || ENV['BEAKER_PUPPET_AGENT_VERSION'] ||
1438
+ ENV['OPENVOX_INSTALL_VERSION'] || ENV['PUPPET_INSTALL_VERSION'] ||
1439
+ ENV['OPENVOX_VERSION'] || ENV['PUPPET_VERSION']
1432
1440
 
1433
1441
  if puppet_install_version && !puppet_install_version.strip.empty?
1434
1442
  puppet_agent_version = latest_puppet_agent_version_for(puppet_install_version.strip)
1435
1443
  end
1436
1444
 
1437
1445
  if puppet_agent_version.nil?
1438
- if (puppet_collection = ENV['BEAKER_PUPPET_COLLECTION'] || host.options['puppet_collection'])
1446
+ if (puppet_collection = ENV['BEAKER_OPENVOX_COLLECTION'] || ENV['BEAKER_PUPPET_COLLECTION'] || host.options['puppet_collection'])
1439
1447
  raise("Error: Puppet Collection '#{puppet_collection}' must match /(puppet|openvox)(\\d+)/") unless puppet_collection =~ %r{(puppet|openvox)(\d+)}
1440
1448
  puppet_collection_name = ::Regexp.last_match(1)
1441
1449
  puppet_install_version = "~> #{::Regexp.last_match(2)}"
@@ -1453,18 +1461,18 @@ module Simp::BeakerHelpers # rubocop:disable Style/OneClassPerFile
1453
1461
  {
1454
1462
  puppet_install_version: puppet_agent_version,
1455
1463
  puppet_collection: puppet_collection,
1456
- puppet_install_type: ENV.fetch('PUPPET_INSTALL_TYPE', 'agent')
1464
+ puppet_install_type: ENV['OPENVOX_INSTALL_TYPE'] || ENV.fetch('PUPPET_INSTALL_TYPE', 'agent')
1457
1465
  }
1458
1466
  end
1459
1467
 
1460
1468
  def run_puppet_install_helper_on(hosts)
1461
1469
  block_on hosts, run_in_parallel: true do |host|
1462
- puppet_collection = ENV.fetch('BEAKER_PUPPET_COLLECTION', nil) || host.options['puppet_collection']
1470
+ puppet_collection = ENV['BEAKER_OPENVOX_COLLECTION'] || ENV.fetch('BEAKER_PUPPET_COLLECTION', nil) || host.options['puppet_collection']
1463
1471
  if is_windows?(host)
1464
1472
  install_msi_on(host, puppet_collection)
1465
1473
  else
1466
1474
  BeakerPuppetHelpers::InstallUtils.install_puppet_release_repo_on(host, puppet_collection)
1467
- package_name = ENV.fetch('BEAKER_PUPPET_PACKAGE_NAME', BeakerPuppetHelpers::InstallUtils.collection2packagename(host, puppet_collection))
1475
+ package_name = ENV['BEAKER_OPENVOX_PACKAGE_NAME'] || ENV.fetch('BEAKER_PUPPET_PACKAGE_NAME', BeakerPuppetHelpers::InstallUtils.collection2packagename(host, puppet_collection))
1468
1476
  host.install_package(package_name)
1469
1477
  end
1470
1478
  end
@@ -4,7 +4,7 @@ require 'rake/tasklib'
4
4
  require 'fileutils'
5
5
  require 'beaker/tasks/rake_task'
6
6
  require 'beaker-rspec/rake_task'
7
- require 'puppetlabs_spec_helper/tasks/fixtures'
7
+ require 'puppet_fixtures/tasks'
8
8
 
9
9
  # Simp namespace
10
10
  module Simp; end
@@ -111,7 +111,7 @@ class Simp::Rake::Beaker < ::Rake::TaskLib # rubocop:disable Style/OneClassPerFi
111
111
  'default_run' : <true|false> => Default: false
112
112
  ```
113
113
  EOM
114
- task :suites, [:suite, :nodeset] => ['spec_prep'] do |_t, args|
114
+ task :suites, [:suite, :nodeset] => ['fixtures:prep'] do |_t, args|
115
115
  suite = args[:suite]
116
116
  nodeset = args[:nodeset]
117
117
 
@@ -30,6 +30,7 @@ Gem::Specification.new do |s|
30
30
  s.add_runtime_dependency 'docker-api', ['>= 2.1.0', '< 3.0.0']
31
31
  s.add_runtime_dependency 'highline', ['>= 2.0', '< 4.0.0']
32
32
  s.add_runtime_dependency 'nokogiri', '~> 1.8'
33
+ s.add_runtime_dependency 'puppet_fixtures', ['>= 0.1', '< 3.0.0']
33
34
 
34
35
  ### s.files = Dir['Rakefile', '{bin,lib,spec}/**/*', 'README*', 'LICENSE*'] & `git ls-files -z .`.split("\0")
35
36
  s.files = %x(git ls-files).split("\n")
@@ -38,7 +38,7 @@ describe 'Inspec STIG Profile' do
38
38
 
39
39
  it 'has a report' do
40
40
  expect(inspec_report_data[:report]).not_to be_nil
41
- puts inspec_report_data[:report]
41
+ puts inspec_report_data[:report] # rubocop:disable RSpec/Output
42
42
  end
43
43
  else
44
44
  # rubocop:disable RSpec/RepeatedDescription
@@ -131,10 +131,15 @@ describe 'Simp::BeakerHelpers' do
131
131
 
132
132
  context '#get_puppet_install_info' do
133
133
  after(:each) do
134
+ ENV['BEAKER_OPENVOX_AGENT_VERSION'] = nil
134
135
  ENV['BEAKER_PUPPET_AGENT_VERSION'] = nil
136
+ ENV['OPENVOX_INSTALL_VERSION'] = nil
135
137
  ENV['PUPPET_INSTALL_VERSION'] = nil
138
+ ENV['OPENVOX_VERSION'] = nil
136
139
  ENV['PUPPET_VERSION'] = nil
140
+ ENV['BEAKER_OPENVOX_COLLECTION'] = nil
137
141
  ENV['BEAKER_PUPPET_COLLECTION'] = nil
142
+ ENV['OPENVOX_INSTALL_TYPE'] = nil
138
143
  ENV['PUPPET_INSTALL_TYPE'] = nil
139
144
  end
140
145
 
@@ -222,6 +227,46 @@ describe 'Simp::BeakerHelpers' do
222
227
  expect(helper.get_puppet_install_info).to eq expected
223
228
  end
224
229
 
230
+ it 'extracts info from OPENVOX_VERSION' do
231
+ allow(helper).to receive(:`).with('gem search -ra -e puppet').and_return(gem_search_results)
232
+ ENV['OPENVOX_VERSION'] = '5.5.0'
233
+ expected = {
234
+ puppet_install_version: '5.5.0',
235
+ puppet_collection: 'puppet5',
236
+ puppet_install_type: 'agent'
237
+ }
238
+ expect(helper.get_puppet_install_info).to eq expected
239
+ end
240
+
241
+ it 'extracts openvox info from BEAKER_OPENVOX_COLLECTION' do
242
+ allow(helper).to receive(:`).with('gem search -ra -e openvox').and_return(openvox_gem_search_results)
243
+ ENV['BEAKER_OPENVOX_COLLECTION'] = 'openvox8'
244
+ expected = {
245
+ puppet_install_version: '8.19.2',
246
+ puppet_collection: 'openvox8',
247
+ puppet_install_type: 'agent'
248
+ }
249
+ expect(helper.get_puppet_install_info).to eq expected
250
+ end
251
+
252
+ it 'prefers BEAKER_OPENVOX_COLLECTION over BEAKER_PUPPET_COLLECTION' do
253
+ allow(helper).to receive(:`).with('gem search -ra -e openvox').and_return(openvox_gem_search_results)
254
+ ENV['BEAKER_OPENVOX_COLLECTION'] = 'openvox8'
255
+ ENV['BEAKER_PUPPET_COLLECTION'] = 'puppet5'
256
+ expected = {
257
+ puppet_install_version: '8.19.2',
258
+ puppet_collection: 'openvox8',
259
+ puppet_install_type: 'agent'
260
+ }
261
+ expect(helper.get_puppet_install_info).to eq expected
262
+ end
263
+
264
+ it 'extracts info from OPENVOX_INSTALL_TYPE' do
265
+ ENV['OPENVOX_INSTALL_TYPE'] = 'pe'
266
+
267
+ expect(helper.get_puppet_install_info[:puppet_install_type]).to eq('pe')
268
+ end
269
+
225
270
  it 'extracts info from PUPPET_INSTALL_TYPE' do
226
271
  ENV['PUPPET_INSTALL_TYPE'] = 'pe'
227
272
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simp-beaker-helpers
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.5
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Tessmer
8
8
  - Trevor Vaughan
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-06-07 00:00:00.000000000 Z
11
+ date: 2026-06-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: beaker
@@ -164,6 +164,26 @@ dependencies:
164
164
  - - "~>"
165
165
  - !ruby/object:Gem::Version
166
166
  version: '1.8'
167
+ - !ruby/object:Gem::Dependency
168
+ name: puppet_fixtures
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0.1'
174
+ - - "<"
175
+ - !ruby/object:Gem::Version
176
+ version: 3.0.0
177
+ type: :runtime
178
+ prerelease: false
179
+ version_requirements: !ruby/object:Gem::Requirement
180
+ requirements:
181
+ - - ">="
182
+ - !ruby/object:Gem::Version
183
+ version: '0.1'
184
+ - - "<"
185
+ - !ruby/object:Gem::Version
186
+ version: 3.0.0
167
187
  description: 'Beaker helper methods to help scaffold SIMP acceptance tests
168
188
 
169
189
  '
@@ -196,7 +216,6 @@ files:
196
216
  - lib/simp/beaker_helpers/constants.rb
197
217
  - lib/simp/beaker_helpers/inspec.rb
198
218
  - lib/simp/beaker_helpers/snapshot.rb
199
- - lib/simp/beaker_helpers/ssg.rb
200
219
  - lib/simp/beaker_helpers/version.rb
201
220
  - lib/simp/beaker_helpers/windows.rb
202
221
  - lib/simp/rake/beaker.rb
@@ -229,9 +248,6 @@ files:
229
248
  - spec/acceptance/suites/snapshot/00_snapshot_test_spec.rb
230
249
  - spec/acceptance/suites/snapshot/10_general_usage_spec.rb
231
250
  - spec/acceptance/suites/snapshot/nodesets
232
- - spec/acceptance/suites/ssg/00_default_spec.rb
233
- - spec/acceptance/suites/ssg/metadata.yml
234
- - spec/acceptance/suites/ssg/nodesets
235
251
  - spec/acceptance/suites/windows/00_default_spec.rb
236
252
  - spec/acceptance/suites/windows/metadata.yml
237
253
  - spec/acceptance/suites/windows/nodesets/default.yml
@@ -1,479 +0,0 @@
1
- # SIMP Beaker helper methods for testing
2
- module Simp::BeakerHelpers
3
- require 'simp/beaker_helpers/constants'
4
-
5
- # Helpers for working with the SCAP Security Guide
6
- class SSG
7
- if ENV['BEAKER_ssg_repo']
8
- GIT_REPO = ENV['BEAKER_ssg_repo']
9
- else
10
- raise('You are offline: Set BEAKER_ssg_repo to point to the git repo that hosts the SSG content') unless ONLINE
11
-
12
- GIT_REPO = 'https://github.com/ComplianceAsCode/content.git'.freeze
13
- end
14
-
15
- # If this is not set, the highest numeric tag will be used
16
- GIT_BRANCH = nil
17
-
18
- if ENV['BEAKER_ssg_branch']
19
- GIT_BRANCH = ENV['BEAKER_ssg_branch']
20
- end
21
-
22
- EL7_PACKAGES = [
23
- 'PyYAML',
24
- 'cmake',
25
- 'git',
26
- 'openscap-python',
27
- 'openscap-scanner',
28
- 'openscap-utils',
29
- 'python-jinja2',
30
- 'python-lxml',
31
- 'python-setuptools',
32
- ].freeze
33
-
34
- EL8_PACKAGES = [
35
- 'cmake',
36
- 'git',
37
- 'make',
38
- 'openscap-python3',
39
- 'openscap-utils',
40
- 'openscap-scanner',
41
- 'python3',
42
- 'python3-jinja2',
43
- 'python3-lxml',
44
- 'python3-pyyaml',
45
- 'python3-setuptools',
46
- 'libarchive',
47
- ].freeze
48
-
49
- EL9_PACKAGES = [
50
- 'cmake',
51
- 'git',
52
- 'make',
53
- 'openscap-python3',
54
- 'openscap-utils',
55
- 'openscap-scanner',
56
- 'python3',
57
- 'python3-jinja2',
58
- 'python3-lxml',
59
- 'python3-pyyaml',
60
- 'python3-setuptools',
61
- 'libarchive',
62
- ].freeze
63
-
64
- OS_INFO = {
65
- 'RedHat' => {
66
- '6' => {
67
- 'required_packages' => EL7_PACKAGES,
68
- 'ssg' => {
69
- 'profile_target' => 'rhel6',
70
- 'build_target' => 'rhel6',
71
- 'datastream' => 'ssg-rhel6-ds.xml'
72
- }
73
- },
74
- '7' => {
75
- 'required_packages' => EL7_PACKAGES,
76
- 'ssg' => {
77
- 'profile_target' => 'rhel7',
78
- 'build_target' => 'rhel7',
79
- 'datastream' => 'ssg-rhel7-ds.xml'
80
- }
81
- },
82
- '8' => {
83
- 'required_packages' => EL8_PACKAGES,
84
- 'ssg' => {
85
- 'profile_target' => 'rhel8',
86
- 'build_target' => 'rhel8',
87
- 'datastream' => 'ssg-rhel8-ds.xml'
88
- }
89
- },
90
- '9' => {
91
- 'required_packages' => EL9_PACKAGES,
92
- 'ssg' => {
93
- 'profile_target' => 'rhel9',
94
- 'build_target' => 'rhel9',
95
- 'datastream' => 'ssg-rhel9-ds.xml'
96
- }
97
- }
98
- },
99
- 'CentOS' => {
100
- '6' => {
101
- 'required_packages' => EL7_PACKAGES,
102
- 'ssg' => {
103
- 'profile_target' => 'rhel6',
104
- 'build_target' => 'centos6',
105
- 'datastream' => 'ssg-centos6-ds.xml'
106
- }
107
- },
108
- '7' => {
109
- 'required_packages' => EL7_PACKAGES,
110
- 'ssg' => {
111
- 'profile_target' => 'centos7',
112
- 'build_target' => 'centos7',
113
- 'datastream' => 'ssg-centos7-ds.xml'
114
- }
115
- },
116
- '8' => {
117
- 'required_packages' => EL8_PACKAGES,
118
- 'ssg' => {
119
- 'profile_target' => 'centos8',
120
- 'build_target' => 'centos8',
121
- 'datastream' => 'ssg-centos8-ds.xml'
122
- }
123
- },
124
- '9' => {
125
- 'required_packages' => EL9_PACKAGES,
126
- 'ssg' => {
127
- 'profile_target' => 'cs9',
128
- 'build_target' => 'cs9',
129
- 'datastream' => 'ssg-cs9-ds.xml'
130
- }
131
- }
132
- },
133
- 'Rocky' => {
134
- '8' => {
135
- 'required_packages' => EL8_PACKAGES,
136
- 'ssg' => {
137
- 'profile_target' => 'centos8',
138
- 'build_target' => 'centos8',
139
- 'datastream' => 'ssg-centos8-ds.xml'
140
- }
141
- },
142
- '9' => {
143
- 'required_packages' => EL9_PACKAGES,
144
- 'ssg' => {
145
- 'profile_target' => 'cs9',
146
- 'build_target' => 'cs9',
147
- 'datastream' => 'ssg-cs9-ds.xml'
148
- }
149
- }
150
- },
151
- 'OracleLinux' => {
152
- '7' => {
153
- 'required_packages' => EL7_PACKAGES,
154
- 'ssg' => {
155
- 'profile_target' => 'ol7',
156
- 'build_target' => 'ol7',
157
- 'datastream' => 'ssg-ol7-ds.xml'
158
- },
159
- },
160
- '8' => {
161
- 'required_packages' => EL8_PACKAGES,
162
- 'ssg' => {
163
- 'profile_target' => 'ol8',
164
- 'build_target' => 'ol8',
165
- 'datastream' => 'ssg-ol8-ds.xml'
166
- }
167
- },
168
- '9' => {
169
- 'required_packages' => EL9_PACKAGES,
170
- 'ssg' => {
171
- 'profile_target' => 'ol9',
172
- 'build_target' => 'ol9',
173
- 'datastream' => 'ssg-ol9-ds.xml'
174
- }
175
- }
176
- }
177
- }.freeze
178
-
179
- attr_accessor :scap_working_dir
180
-
181
- # Create a new SSG helper for the specified host
182
- #
183
- # @param sut
184
- # The SUT against which to run
185
- #
186
- def initialize(sut)
187
- @sut = sut
188
-
189
- @os = pfact_on(@sut, 'os.name')
190
- @os_rel = pfact_on(@sut, 'os.release.major')
191
-
192
- sut.mkdir_p('scap_working_dir')
193
-
194
- @scap_working_dir = on(sut, 'cd scap_working_dir && pwd').stdout.strip
195
-
196
- unless OS_INFO[@os]
197
- raise("Error: The '#{@os}' Operating System is not supported")
198
- end
199
-
200
- OS_INFO[@os][@os_rel]['required_packages'].each do |pkg|
201
- install_latest_package_on(@sut, pkg)
202
- end
203
-
204
- @output_dir = File.absolute_path('sec_results/ssg')
205
-
206
- unless File.directory?(@output_dir)
207
- FileUtils.mkdir_p(@output_dir)
208
- end
209
-
210
- @result_file = "#{@sut.hostname}-ssg-#{Time.now.to_i}"
211
-
212
- get_ssg_datastream
213
- end
214
-
215
- def profile_target
216
- OS_INFO[@os][@os_rel]['ssg']['profile_target']
217
- end
218
-
219
- def get_profiles
220
- cmd = "cd #{@scap_working_dir}; oscap info --profiles"
221
- on(@sut, "#{cmd} #{OS_INFO[@os][@os_rel]['ssg']['datastream']}")
222
- .stdout
223
- .strip
224
- .lines
225
- .map { |x| x.split(':').first }
226
- end
227
-
228
- def remediate(profile)
229
- evaluate(profile, true)
230
- end
231
-
232
- def evaluate(profile, remediate = false)
233
- cmd = "cd #{@scap_working_dir}; oscap xccdf eval"
234
-
235
- if remediate
236
- cmd += ' --remediate'
237
- end
238
-
239
- cmd += %( --profile #{profile} --results #{@result_file}.xml --report #{@result_file}.html #{OS_INFO[@os][@os_rel]['ssg']['datastream']})
240
-
241
- # We accept all exit codes here because there have occasionally been
242
- # failures in the SSG content and we're not testing that.
243
-
244
- on(@sut, cmd, accept_all_exit_codes: true)
245
-
246
- ['xml', 'html'].each do |ext|
247
- path = "#{@scap_working_dir}/#{@result_file}.#{ext}"
248
- scp_from(@sut, path, @output_dir)
249
-
250
- raise("Could not retrieve #{path} from #{@sut}") unless File.exist?(File.join(@output_dir, "#{@result_file}.#{ext}"))
251
- end
252
- end
253
-
254
- # Output the report
255
- #
256
- # @param report
257
- # The results Hash
258
- #
259
- def write_report(report)
260
- File.open(File.join(@output_dir, @result_file) + '.report', 'w') do |fh|
261
- fh.puts(report[:report].uncolor)
262
- end
263
- end
264
-
265
- # Retrieve a subset of test results based on a match to filter
266
- #
267
- # @param filter [String, Array[String]]
268
- # A 'short name' filter that will be matched against the rule ID name
269
- #
270
- # @param exclusions [String, Array[String]]
271
- # A 'short name' filter of items that will be removed from the `filter`
272
- # matches
273
- #
274
- # @return [Hash] A Hash of statistics and a formatted report
275
- #
276
- # FIXME:
277
- # - This is a hack! Should be searching for rules based on a set
278
- # set of STIG ids, but don't see those ids in the oscap results xml.
279
- # Further mapping is required...
280
- # - Create the same report structure as inspec
281
- def process_ssg_results(filter = nil, exclusions = nil)
282
- self.class.process_ssg_results(
283
- File.join(@output_dir, @result_file) + '.xml',
284
- filter,
285
- exclusions,
286
- )
287
- end
288
-
289
- # Process the results of an SSG run
290
- #
291
- # @param result_file [String]
292
- # The oscap result XML file to process
293
- #
294
- # @param filter [String, Array[String]]
295
- # A 'short name' filter that will be matched against the rule ID name
296
- #
297
- # @param exclusions [String, Array[String]]
298
- # A 'short name' filter of items that will be removed from the `filter`
299
- # matches
300
- #
301
- # @return [Hash] A Hash of statistics and a formatted report
302
- #
303
- def self.process_ssg_results(result_file, filter = nil, exclusions = nil)
304
- require 'highline'
305
- require 'nokogiri'
306
-
307
- HighLine.colorize_strings
308
-
309
- raise("Could not find results XML file '#{result_file}'") unless File.exist?(result_file)
310
-
311
- puts "Processing #{result_file}"
312
- doc = Nokogiri::XML(File.open(result_file))
313
-
314
- # because I'm lazy
315
- doc.remove_namespaces!
316
-
317
- if filter
318
- filter = Array(filter)
319
-
320
- xpath_query = [
321
- '//rule-result[(',
322
- ]
323
-
324
- xpath_query << filter.map { |flt|
325
- "contains(@idref,'#{flt}')"
326
- }.join(' or ')
327
-
328
- xpath_query << ')' if filter.size > 1
329
-
330
- exclusions = Array(exclusions)
331
- unless exclusions.empty?
332
- xpath_query << 'and not('
333
-
334
- xpath_query << exclusions.map { |exl|
335
- "contains(@idref,'#{exl}')"
336
- }.join(' or ')
337
-
338
- xpath_query << ')' unless exclusions.empty?
339
- end
340
-
341
- xpath_query << ')]'
342
-
343
- xpath_query = xpath_query.join(' ')
344
-
345
- # XPATH to get the pertinent test results:
346
- # Any node named 'rule-result' for which the attribute 'idref'
347
- # contains any of the `filter` Strings and does not contain any of the
348
- # `exclusions` Strings
349
- result_nodes = doc.xpath(xpath_query)
350
- else
351
- result_nodes = doc.xpath('//rule-result')
352
- end
353
-
354
- stats = {
355
- failed: [],
356
- passed: [],
357
- skipped: [],
358
- filter: filter.nil? ? 'No Filter' : filter,
359
- report: nil,
360
- score: 0
361
- }
362
-
363
- result_nodes.each do |rule_result|
364
- # Results are recorded in a child node named 'result'.
365
- # Within the 'result' node, the actual result string is
366
- # the content of that node's (only) child node.
367
-
368
- result = rule_result.element_children.at('result')
369
- result_id = rule_result.attributes['idref'].value.to_s
370
- result_value = [
371
- 'Title: ' + doc.xpath("//Rule[@id='#{result_id}']/title/text()").first.to_s,
372
- ' ID: ' + result_id,
373
- ]
374
-
375
- if result.child.content == 'fail'
376
- references = {}
377
-
378
- doc.xpath("//Rule[@id='#{result_id}']/reference").each do |ref|
379
- references[ref['href']] ||= []
380
- references[ref['href']] << ref.text
381
- end
382
-
383
- result_value << ' References:'
384
- references.each_pair do |src, items|
385
- result_value << " * #{src}"
386
- result_value << " * #{items.join(', ')}"
387
- end
388
- result_value << ' Description: ' + doc.xpath("//Rule[@id='#{result_id}']/description").text.gsub("\n", "\n ")
389
- end
390
-
391
- result_value = result_value.join("\n")
392
-
393
- if result.child.content == 'fail'
394
- stats[:failed] << result_value.red
395
- elsif result.child.content == 'pass'
396
- stats[:passed] << result_value.green
397
- else
398
- stats[:skipped] << result_value.yellow
399
- end
400
- end
401
-
402
- report = []
403
-
404
- report << '== Skipped =='
405
- report << stats[:skipped].join("\n")
406
-
407
- report << '== Passed =='
408
- report << stats[:passed].join("\n")
409
-
410
- report << '== Failed =='
411
- report << stats[:failed].join("\n")
412
-
413
- report << 'OSCAP Statistics:'
414
-
415
- if filter
416
- report << " * Used Filter: 'idref' ~= '#{stats[:filter]}'"
417
- end
418
-
419
- report << " * Passed: #{stats[:passed].count.to_s.green}"
420
- report << " * Failed: #{stats[:failed].count.to_s.red}"
421
- report << " * Skipped: #{stats[:skipped].count.to_s.yellow}"
422
-
423
- score = 0
424
-
425
- if (stats[:passed].count + stats[:failed].count) > 0
426
- score = ((stats[:passed].count.to_f / (stats[:passed].count + stats[:failed].count)) * 100.0).round(0)
427
- end
428
-
429
- report << "\n Score: #{score}%"
430
-
431
- stats[:score] = score
432
- stats[:report] = report.join("\n")
433
-
434
- stats
435
- end
436
-
437
- private
438
-
439
- def get_ssg_datastream
440
- # Allow users to point at a specific SSG release 'tar.bz2' file
441
- ssg_release = ENV['BEAKER_ssg_release']
442
-
443
- # Grab the latest SSG release in fixtures if it exists
444
- ssg_release ||= Dir.glob('spec/fixtures/ssg_releases/*.bz2').last
445
-
446
- if ssg_release
447
- copy_to(@sut, ssg_release, @scap_working_dir)
448
-
449
- on(@sut, %(mkdir -p scap-content && tar -xj -C scap-content --strip-components 1 -f #{ssg_release} && cp scap-content/*ds.xml #{@scap_working_dir}))
450
- else
451
- on(@sut, %(git clone #{GIT_REPO} scap-content))
452
- if GIT_BRANCH
453
- on(@sut, %(cd scap-content; git checkout #{GIT_BRANCH}))
454
- else
455
- tags = on(@sut, %(cd scap-content; git tag -l)).output
456
- target_tag = tags.lines.map(&:strip)
457
- .select { |x| x.match?(%r{^v(\d+\.)+\d+$}) }
458
- .sort.last
459
-
460
- on(@sut, %(cd scap-content; git checkout #{target_tag}))
461
- end
462
-
463
- # Work around the issue where the profiles now strip out derivative
464
- # content that isn't explicitlly approved for that OS. This means that
465
- # we are unable to test CentOS builds against the STIG, etc...
466
- #
467
- # This isn't 100% correct but it's "good enough" for an automated CI
468
- # environment to tell us if something is critically out of alignment.
469
- safe_sed(
470
- @sut,
471
- 's/ssg.build_derivatives.profile_handling/__simp_dontcare__ = None #ssg.build_derivatives.profile_handling/g',
472
- 'scap-content/build-scripts/enable_derivatives.py',
473
- )
474
-
475
- on(@sut, %(cd scap-content/build; cmake ../; make -j4 #{OS_INFO[@os][@os_rel]['ssg']['build_target']}-content && cp *ds.xml #{@scap_working_dir}))
476
- end
477
- end
478
- end
479
- end
@@ -1,49 +0,0 @@
1
- require 'spec_helper_acceptance'
2
-
3
- test_name 'SSG Functionality Validation'
4
-
5
- describe 'run the SSG against an SCAP profile' do
6
- hosts.each do |host|
7
- context "on #{host}" do
8
- ssg = nil
9
- ssg_report = nil
10
-
11
- before(:all) do
12
- ssg = Simp::BeakerHelpers::SSG.new(host)
13
-
14
- # If we don't do this, the variable gets reset
15
- ssg_report = { data: nil }
16
- end
17
-
18
- it 'runs the SSG' do
19
- profiles = ssg.get_profiles
20
-
21
- profile = profiles.find { |x| x.include?('_stig') } ||
22
- profiles.find { |x| x.include?('_cui') } ||
23
- profiles.find { |x| x.include?('_ospp') } ||
24
- profiles.find { |x| x.include?('_standard') } ||
25
- profiles.last
26
-
27
- expect(profile).not_to be_nil
28
- ssg.evaluate(profile)
29
- end
30
-
31
- it 'has an SSG report' do
32
- # Validate that the filter works
33
- filter = '_rule_audit'
34
- host_exclusions = ['ssh_']
35
-
36
- ssg_report[:data] = ssg.process_ssg_results(filter, host_exclusions)
37
-
38
- expect(ssg_report[:data]).not_to be_nil
39
-
40
- ssg.write_report(ssg_report[:data])
41
- end
42
-
43
- it 'has a report' do
44
- expect(ssg_report[:data][:report]).not_to be_nil
45
- puts ssg_report[:data][:report]
46
- end
47
- end
48
- end
49
- end
@@ -1,2 +0,0 @@
1
- ---
2
- 'default_run': true
@@ -1 +0,0 @@
1
- ../../nodesets