simp-beaker-helpers 2.0.5 → 3.1.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 +4 -4
- data/.github/workflows/pr_acceptance.yml +1 -12
- data/.github/workflows/pr_tests.yml +9 -7
- data/.github/workflows/tag_deploy_rubygem.yml +4 -4
- data/CHANGELOG.md +33 -1
- data/Gemfile +4 -5
- data/lib/simp/beaker_helpers/constants.rb +0 -2
- data/lib/simp/beaker_helpers/version.rb +1 -1
- data/lib/simp/beaker_helpers.rb +79 -9
- data/lib/simp/rake/beaker.rb +2 -2
- data/simp-beaker-helpers.gemspec +1 -0
- data/spec/acceptance/suites/inspec/00_default_spec.rb +1 -1
- data/spec/lib/simp/beaker_helpers_spec.rb +46 -0
- metadata +22 -6
- data/lib/simp/beaker_helpers/ssg.rb +0 -479
- data/spec/acceptance/suites/ssg/00_default_spec.rb +0 -49
- data/spec/acceptance/suites/ssg/metadata.yml +0 -2
- data/spec/acceptance/suites/ssg/nodesets +0 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 249a3f841428c2b28cbe7961183d25344edc726652e3ae5bb66c084e9a30b2d9
|
|
4
|
+
data.tar.gz: 29fb61f0eb9dd16251d1389dd5b68457b93e3bbd81946e52a153dc82ace40fbd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d42a18f587b5c613a0ce1d4af8946be6f070e258e1012e8b1811dd63d93caa0fe967205b545ddc3462b87d37d3df58902bb5aca8705528750e08eb80166b80ab
|
|
7
|
+
data.tar.gz: 5ddf2f564b29b9eb93e8d02c5bb5670d3019cf2ed2950c8083cbbc5d0a29ddca349b5009e1ec81242292af0d80b84149c0afcda54c97dc443cbe1b50584bbc9f
|
|
@@ -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@
|
|
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@
|
|
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: '
|
|
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@
|
|
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: '~>
|
|
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@
|
|
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@
|
|
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@
|
|
181
|
+
uses: actions/checkout@v7
|
|
182
182
|
with:
|
|
183
183
|
ref: ${{ github.ref }}
|
|
184
184
|
clean: true
|
data/CHANGELOG.md
CHANGED
|
@@ -1,7 +1,39 @@
|
|
|
1
|
+
### 3.1.0 / 2026-07-02
|
|
2
|
+
* Added:
|
|
3
|
+
* `ensure_beaker_ip_on`: detect SUTs whose recorded `host[:ip]` was never
|
|
4
|
+
actually applied (e.g. EL10 under Vagrant, where the legacy ifcfg files
|
|
5
|
+
Vagrant writes for static private-network IPs are no longer supported and
|
|
6
|
+
the interface silently falls back to DHCP) and (re-)apply the expected
|
|
7
|
+
address via NetworkManager (reboot-safe), falling back to `ip addr add`.
|
|
8
|
+
Runs automatically alongside `activate_interfaces` in the global
|
|
9
|
+
`before(:all)` hook; disable with `BEAKER_no_fix_interfaces`.
|
|
10
|
+
|
|
11
|
+
### 3.0.0 / 2026-06-24
|
|
12
|
+
* Changed (**Breaking**):
|
|
13
|
+
* Dropped support for Puppet 7 / Ruby 2.7. CI now tests Puppet/OpenVox 8 only,
|
|
14
|
+
and the default OpenVox gem floor is raised to `>= 8.0.0`.
|
|
15
|
+
* Replaced the `puppetlabs_spec_helper/tasks/fixtures` dependency with
|
|
16
|
+
`puppet_fixtures`, enabling Ruby 4.0 support. `puppetlabs_spec_helper` pulls
|
|
17
|
+
in `puppet-syntax` < 5, which depends on the `puppet` gem and its `facter`
|
|
18
|
+
dependency that does not support Ruby >= 4.0; `puppet_fixtures` is the
|
|
19
|
+
OpenVox-ecosystem replacement and supports Ruby 4.0.
|
|
20
|
+
* The `beaker:suites` task now depends on `fixtures:prep` (from
|
|
21
|
+
`puppet_fixtures`) instead of `spec_prep`, and `ensure_fixture_modules` now
|
|
22
|
+
runs `rake fixtures:prep`.
|
|
23
|
+
* Removed (**Breaking**):
|
|
24
|
+
* Removed the unsupported `Simp::BeakerHelpers::SSG` helpers, the `ssg`
|
|
25
|
+
acceptance suite, and the `SSG_REPO_URL` constant (#268)
|
|
26
|
+
* Added:
|
|
27
|
+
* `puppet_fixtures` runtime dependency
|
|
28
|
+
* OpenVox-named environment variables for `get_puppet_install_info`, taking
|
|
29
|
+
precedence over the Puppet-named equivalents (which remain as fallbacks):
|
|
30
|
+
`OPENVOX_VERSION`, `OPENVOX_INSTALL_VERSION`, `OPENVOX_INSTALL_TYPE`,
|
|
31
|
+
`BEAKER_OPENVOX_AGENT_VERSION`, `BEAKER_OPENVOX_COLLECTION`,
|
|
32
|
+
`BEAKER_OPENVOX_PACKAGE_NAME`
|
|
33
|
+
|
|
1
34
|
### 2.0.5 / 2026-06-06
|
|
2
35
|
* Fixed:
|
|
3
36
|
* Additional cleanup for rubocop
|
|
4
|
-
|
|
5
37
|
### 2.0.4 / 2025-10-16
|
|
6
38
|
* Fixed:
|
|
7
39
|
* `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', ['>=
|
|
45
|
-
gem 'pry-byebug', '~> 3.
|
|
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.
|
|
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.
|
|
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'])
|
data/lib/simp/beaker_helpers.rb
CHANGED
|
@@ -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
|
|
371
|
-
puts " -- running
|
|
369
|
+
cmd = 'bundle exec rake fixtures:prep'
|
|
370
|
+
puts " -- running fixtures:prep: '#{cmd}'"
|
|
372
371
|
`#{cmd}`
|
|
373
372
|
end
|
|
374
373
|
end
|
|
@@ -1139,6 +1138,64 @@ module Simp::BeakerHelpers # rubocop:disable Style/OneClassPerFile
|
|
|
1139
1138
|
end
|
|
1140
1139
|
end
|
|
1141
1140
|
|
|
1141
|
+
# Ensure that the IP address that Beaker has recorded for each SUT is
|
|
1142
|
+
# actually present on the system and (re-)apply it if it is not.
|
|
1143
|
+
#
|
|
1144
|
+
# Some OS/hypervisor combinations silently fail to configure the static IP
|
|
1145
|
+
# for secondary (private) networks. In particular, Vagrant configures
|
|
1146
|
+
# static IPs on RedHat-family guests by writing legacy ifcfg files, which
|
|
1147
|
+
# EL10 no longer supports at all. The interface falls back to NetworkManager
|
|
1148
|
+
# DHCP and receives an arbitrary address, so everything that targets the
|
|
1149
|
+
# recorded `host[:ip]` (cross-SUT traffic, direct Net::SSH logins, etc.)
|
|
1150
|
+
# fails with 'No route to host'.
|
|
1151
|
+
#
|
|
1152
|
+
# This detects the mismatch and applies the expected address to the
|
|
1153
|
+
# interface that is attached to the same network, using NetworkManager so
|
|
1154
|
+
# that the address survives reboots, and falling back to a runtime-only
|
|
1155
|
+
# `ip addr add` when NetworkManager is not in use.
|
|
1156
|
+
def ensure_beaker_ip_on(hosts)
|
|
1157
|
+
return if ENV['BEAKER_no_fix_interfaces']
|
|
1158
|
+
|
|
1159
|
+
block_on(hosts, run_in_parallel: @run_in_parallel) do |host|
|
|
1160
|
+
expected_ip = host[:ip]
|
|
1161
|
+
next unless expected_ip
|
|
1162
|
+
next if host[:platform].include?('windows')
|
|
1163
|
+
|
|
1164
|
+
# All currently assigned IPv4 addresses ('<iface> <address>/<prefix>')
|
|
1165
|
+
addrs = on(host, %(ip -o -4 addr show), accept_all_exit_codes: true).stdout.lines.map { |line|
|
|
1166
|
+
next unless line =~ %r{^\d+:\s+(\S+)\s+inet\s+(\S+)/(\d+)}
|
|
1167
|
+
{ iface: Regexp.last_match(1), ip: Regexp.last_match(2), prefix: Regexp.last_match(3) }
|
|
1168
|
+
}.compact
|
|
1169
|
+
|
|
1170
|
+
next if addrs.any? { |a| a[:ip] == expected_ip }
|
|
1171
|
+
|
|
1172
|
+
require 'ipaddr'
|
|
1173
|
+
target = addrs.find do |a|
|
|
1174
|
+
IPAddr.new("#{a[:ip]}/#{a[:prefix]}").include?(expected_ip)
|
|
1175
|
+
rescue IPAddr::Error
|
|
1176
|
+
false
|
|
1177
|
+
end
|
|
1178
|
+
|
|
1179
|
+
unless target
|
|
1180
|
+
puts " -- WARNING: #{host} does not have expected IP #{expected_ip} and no interface on that network could be found"
|
|
1181
|
+
next
|
|
1182
|
+
end
|
|
1183
|
+
|
|
1184
|
+
puts " -- FIXING: #{host} expected IP #{expected_ip} but '#{target[:iface]}' has #{target[:ip]}"
|
|
1185
|
+
|
|
1186
|
+
nm_connection = on(host, %(nmcli -g GENERAL.CONNECTION device show #{target[:iface]}), accept_all_exit_codes: true).stdout.strip
|
|
1187
|
+
if nm_connection.empty?
|
|
1188
|
+
# Not NetworkManager-managed => runtime-only fallback
|
|
1189
|
+
on(host, %(ip addr add #{expected_ip}/#{target[:prefix]} dev #{target[:iface]}), accept_all_exit_codes: true)
|
|
1190
|
+
else
|
|
1191
|
+
# Match Vagrant's static network behavior: fixed address, no gateway,
|
|
1192
|
+
# and never a default route on the private interface
|
|
1193
|
+
on(host, %(nmcli connection modify "#{nm_connection}" ipv4.method manual ipv4.addresses "#{expected_ip}/#{target[:prefix]}" ipv4.gateway "" ipv4.never-default yes))
|
|
1194
|
+
on(host, %(nmcli connection up "#{nm_connection}"))
|
|
1195
|
+
end
|
|
1196
|
+
end
|
|
1197
|
+
end
|
|
1198
|
+
|
|
1142
1199
|
## Inline Hiera Helpers ##
|
|
1143
1200
|
## These will be integrated into core Beaker at some point ##
|
|
1144
1201
|
|
|
@@ -1153,6 +1210,10 @@ module Simp::BeakerHelpers # rubocop:disable Style/OneClassPerFile
|
|
|
1153
1210
|
|
|
1154
1211
|
# We can't guarantee that the upstream vendor isn't disabling interfaces
|
|
1155
1212
|
activate_interfaces(hosts)
|
|
1213
|
+
|
|
1214
|
+
# Some OS/hypervisor combinations (e.g. EL10 under Vagrant) fail to
|
|
1215
|
+
# apply the static IP that Beaker expects for private networks
|
|
1216
|
+
ensure_beaker_ip_on(hosts)
|
|
1156
1217
|
end
|
|
1157
1218
|
|
|
1158
1219
|
c.after(:all) do
|
|
@@ -1426,16 +1487,25 @@ module Simp::BeakerHelpers # rubocop:disable Style/OneClassPerFile
|
|
|
1426
1487
|
# install version and a puppet collection are specified. This is
|
|
1427
1488
|
# because the puppet install version can specify more precise
|
|
1428
1489
|
# version information than is available from a puppet collection.
|
|
1490
|
+
#
|
|
1491
|
+
# Each Puppet-named environment variable has an OpenVox-named
|
|
1492
|
+
# equivalent (e.g. OPENVOX_VERSION, BEAKER_OPENVOX_COLLECTION) that
|
|
1493
|
+
# takes precedence; the Puppet-named variables are kept as fallbacks
|
|
1494
|
+
# for backwards compatibility.
|
|
1429
1495
|
def get_puppet_install_info
|
|
1430
|
-
#
|
|
1431
|
-
|
|
1496
|
+
# OpenVox-named variables win; the Puppet-named ones remain as fallbacks.
|
|
1497
|
+
# Within each pair the first match is internal Beaker, the second legacy SIMP.
|
|
1498
|
+
puppet_install_version =
|
|
1499
|
+
ENV['BEAKER_OPENVOX_AGENT_VERSION'] || ENV['BEAKER_PUPPET_AGENT_VERSION'] ||
|
|
1500
|
+
ENV['OPENVOX_INSTALL_VERSION'] || ENV['PUPPET_INSTALL_VERSION'] ||
|
|
1501
|
+
ENV['OPENVOX_VERSION'] || ENV['PUPPET_VERSION']
|
|
1432
1502
|
|
|
1433
1503
|
if puppet_install_version && !puppet_install_version.strip.empty?
|
|
1434
1504
|
puppet_agent_version = latest_puppet_agent_version_for(puppet_install_version.strip)
|
|
1435
1505
|
end
|
|
1436
1506
|
|
|
1437
1507
|
if puppet_agent_version.nil?
|
|
1438
|
-
if (puppet_collection = ENV['BEAKER_PUPPET_COLLECTION'] || host.options['puppet_collection'])
|
|
1508
|
+
if (puppet_collection = ENV['BEAKER_OPENVOX_COLLECTION'] || ENV['BEAKER_PUPPET_COLLECTION'] || host.options['puppet_collection'])
|
|
1439
1509
|
raise("Error: Puppet Collection '#{puppet_collection}' must match /(puppet|openvox)(\\d+)/") unless puppet_collection =~ %r{(puppet|openvox)(\d+)}
|
|
1440
1510
|
puppet_collection_name = ::Regexp.last_match(1)
|
|
1441
1511
|
puppet_install_version = "~> #{::Regexp.last_match(2)}"
|
|
@@ -1453,18 +1523,18 @@ module Simp::BeakerHelpers # rubocop:disable Style/OneClassPerFile
|
|
|
1453
1523
|
{
|
|
1454
1524
|
puppet_install_version: puppet_agent_version,
|
|
1455
1525
|
puppet_collection: puppet_collection,
|
|
1456
|
-
puppet_install_type: ENV.fetch('PUPPET_INSTALL_TYPE', 'agent')
|
|
1526
|
+
puppet_install_type: ENV['OPENVOX_INSTALL_TYPE'] || ENV.fetch('PUPPET_INSTALL_TYPE', 'agent')
|
|
1457
1527
|
}
|
|
1458
1528
|
end
|
|
1459
1529
|
|
|
1460
1530
|
def run_puppet_install_helper_on(hosts)
|
|
1461
1531
|
block_on hosts, run_in_parallel: true do |host|
|
|
1462
|
-
puppet_collection = ENV.fetch('BEAKER_PUPPET_COLLECTION', nil) || host.options['puppet_collection']
|
|
1532
|
+
puppet_collection = ENV['BEAKER_OPENVOX_COLLECTION'] || ENV.fetch('BEAKER_PUPPET_COLLECTION', nil) || host.options['puppet_collection']
|
|
1463
1533
|
if is_windows?(host)
|
|
1464
1534
|
install_msi_on(host, puppet_collection)
|
|
1465
1535
|
else
|
|
1466
1536
|
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))
|
|
1537
|
+
package_name = ENV['BEAKER_OPENVOX_PACKAGE_NAME'] || ENV.fetch('BEAKER_PUPPET_PACKAGE_NAME', BeakerPuppetHelpers::InstallUtils.collection2packagename(host, puppet_collection))
|
|
1468
1538
|
host.install_package(package_name)
|
|
1469
1539
|
end
|
|
1470
1540
|
end
|
data/lib/simp/rake/beaker.rb
CHANGED
|
@@ -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 '
|
|
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] => ['
|
|
114
|
+
task :suites, [:suite, :nodeset] => ['fixtures:prep'] do |_t, args|
|
|
115
115
|
suite = args[:suite]
|
|
116
116
|
nodeset = args[:nodeset]
|
|
117
117
|
|
data/simp-beaker-helpers.gemspec
CHANGED
|
@@ -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
|
|
@@ -4,6 +4,7 @@ require 'simp/beaker_helpers'
|
|
|
4
4
|
# redefine methods used in RSpec.configure withing Simp::BeakerHelpers
|
|
5
5
|
def hosts; end
|
|
6
6
|
def activate_interfaces(hosts); end
|
|
7
|
+
def ensure_beaker_ip_on(hosts); end
|
|
7
8
|
def clear_temp_hieradata; end
|
|
8
9
|
|
|
9
10
|
class MyTestClass
|
|
@@ -131,10 +132,15 @@ describe 'Simp::BeakerHelpers' do
|
|
|
131
132
|
|
|
132
133
|
context '#get_puppet_install_info' do
|
|
133
134
|
after(:each) do
|
|
135
|
+
ENV['BEAKER_OPENVOX_AGENT_VERSION'] = nil
|
|
134
136
|
ENV['BEAKER_PUPPET_AGENT_VERSION'] = nil
|
|
137
|
+
ENV['OPENVOX_INSTALL_VERSION'] = nil
|
|
135
138
|
ENV['PUPPET_INSTALL_VERSION'] = nil
|
|
139
|
+
ENV['OPENVOX_VERSION'] = nil
|
|
136
140
|
ENV['PUPPET_VERSION'] = nil
|
|
141
|
+
ENV['BEAKER_OPENVOX_COLLECTION'] = nil
|
|
137
142
|
ENV['BEAKER_PUPPET_COLLECTION'] = nil
|
|
143
|
+
ENV['OPENVOX_INSTALL_TYPE'] = nil
|
|
138
144
|
ENV['PUPPET_INSTALL_TYPE'] = nil
|
|
139
145
|
end
|
|
140
146
|
|
|
@@ -222,6 +228,46 @@ describe 'Simp::BeakerHelpers' do
|
|
|
222
228
|
expect(helper.get_puppet_install_info).to eq expected
|
|
223
229
|
end
|
|
224
230
|
|
|
231
|
+
it 'extracts info from OPENVOX_VERSION' do
|
|
232
|
+
allow(helper).to receive(:`).with('gem search -ra -e puppet').and_return(gem_search_results)
|
|
233
|
+
ENV['OPENVOX_VERSION'] = '5.5.0'
|
|
234
|
+
expected = {
|
|
235
|
+
puppet_install_version: '5.5.0',
|
|
236
|
+
puppet_collection: 'puppet5',
|
|
237
|
+
puppet_install_type: 'agent'
|
|
238
|
+
}
|
|
239
|
+
expect(helper.get_puppet_install_info).to eq expected
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
it 'extracts openvox info from BEAKER_OPENVOX_COLLECTION' do
|
|
243
|
+
allow(helper).to receive(:`).with('gem search -ra -e openvox').and_return(openvox_gem_search_results)
|
|
244
|
+
ENV['BEAKER_OPENVOX_COLLECTION'] = 'openvox8'
|
|
245
|
+
expected = {
|
|
246
|
+
puppet_install_version: '8.19.2',
|
|
247
|
+
puppet_collection: 'openvox8',
|
|
248
|
+
puppet_install_type: 'agent'
|
|
249
|
+
}
|
|
250
|
+
expect(helper.get_puppet_install_info).to eq expected
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
it 'prefers BEAKER_OPENVOX_COLLECTION over BEAKER_PUPPET_COLLECTION' do
|
|
254
|
+
allow(helper).to receive(:`).with('gem search -ra -e openvox').and_return(openvox_gem_search_results)
|
|
255
|
+
ENV['BEAKER_OPENVOX_COLLECTION'] = 'openvox8'
|
|
256
|
+
ENV['BEAKER_PUPPET_COLLECTION'] = 'puppet5'
|
|
257
|
+
expected = {
|
|
258
|
+
puppet_install_version: '8.19.2',
|
|
259
|
+
puppet_collection: 'openvox8',
|
|
260
|
+
puppet_install_type: 'agent'
|
|
261
|
+
}
|
|
262
|
+
expect(helper.get_puppet_install_info).to eq expected
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
it 'extracts info from OPENVOX_INSTALL_TYPE' do
|
|
266
|
+
ENV['OPENVOX_INSTALL_TYPE'] = 'pe'
|
|
267
|
+
|
|
268
|
+
expect(helper.get_puppet_install_info[:puppet_install_type]).to eq('pe')
|
|
269
|
+
end
|
|
270
|
+
|
|
225
271
|
it 'extracts info from PUPPET_INSTALL_TYPE' do
|
|
226
272
|
ENV['PUPPET_INSTALL_TYPE'] = 'pe'
|
|
227
273
|
|
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:
|
|
4
|
+
version: 3.1.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-
|
|
11
|
+
date: 2026-07-03 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 +0,0 @@
|
|
|
1
|
-
../../nodesets
|