From 93b2593e5214ea2e3c26280868a5d035543e1307 Mon Sep 17 00:00:00 2001 From: Tu2607 Date: Thu, 11 Jun 2026 19:48:27 +0000 Subject: [PATCH] (CEM-6541) Fix workstation profile appearing in sce_linux REFERENCE.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `Control#filtered_profiles_levels` used `.concat` (union) when both `--select-profile` and `--select-level` were given. This caused `profiles_levels_by_level` to return all profiles at the requested levels — including `workstation` — regardless of what was passed via `-p`. The fix changes `.concat` to `&` (intersection) so only entries matching both filters are returned. A second guard in `MarkdownGenerator#generate` defaults `select_profile` to `['server']` for `sce_linux` when no `-p` flag is provided at all, covering invocations that omit the flag entirely. The guard is extracted into a private `default_profile_for_sce_linux!` helper to avoid increasing the cyclomatic complexity of `generate`. Version bumped to 0.18.8. Co-authored-by: Claude Sonnet 4.6 --- .gitignore | 3 +- Gemfile.lock | 2 +- lib/abide_dev_utils/sce/benchmark.rb | 2 +- lib/abide_dev_utils/sce/generate/reference.rb | 8 ++ lib/abide_dev_utils/version.rb | 2 +- spec/abide_dev_utils/sce/benchmark_spec.rb | 10 ++ .../reference/markdown_generator_spec.rb | 36 ++++++ specifications/CEM-6541.md | 111 ++++++++++++++++++ 8 files changed, 170 insertions(+), 4 deletions(-) create mode 100644 spec/abide_dev_utils/sce/generate/reference/markdown_generator_spec.rb create mode 100644 specifications/CEM-6541.md diff --git a/.gitignore b/.gitignore index 005cc06..8999e09 100644 --- a/.gitignore +++ b/.gitignore @@ -9,5 +9,6 @@ /tmp/ w10_20h2.xml w10_2004.xml +.env # rspec failure tracking -.rspec_status +.rspec_status \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index 11aebf8..fb92f22 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - abide_dev_utils (0.18.7) + abide_dev_utils (0.18.8) cmdparse (~> 3.0) facterdb (~> 4.1.0) google-cloud-storage (~> 1.34) diff --git a/lib/abide_dev_utils/sce/benchmark.rb b/lib/abide_dev_utils/sce/benchmark.rb index 44cbf66..0cb65e3 100644 --- a/lib/abide_dev_utils/sce/benchmark.rb +++ b/lib/abide_dev_utils/sce/benchmark.rb @@ -222,7 +222,7 @@ def profiles_levels_by_profile(prof) def filtered_profiles_levels(prof: nil, lvl: nil) return profiles_levels if (prof.nil? || prof.empty?) && (lvl.nil? || lvl.empty?) if prof && lvl && !prof.empty? && !lvl.empty? - return profiles_levels_by_profile(prof).concat(profiles_levels_by_level(lvl)) + return profiles_levels_by_profile(prof) & profiles_levels_by_level(lvl) end return profiles_levels_by_profile(prof) unless prof&.empty? diff --git a/lib/abide_dev_utils/sce/generate/reference.rb b/lib/abide_dev_utils/sce/generate/reference.rb index 3dbd7be..8a1af99 100644 --- a/lib/abide_dev_utils/sce/generate/reference.rb +++ b/lib/abide_dev_utils/sce/generate/reference.rb @@ -78,6 +78,7 @@ def initialize(benchmarks, module_name, file: 'REFERENCE.md', opts: {}) end def generate(doc_title = 'Reference') + default_profile_for_sce_linux! @strings = Strings.new(opts: @opts) md.add_title(doc_title) benchmarks.each do |benchmark| @@ -121,6 +122,13 @@ def generate(doc_title = 'Reference') private attr_reader :benchmarks, :md + + def default_profile_for_sce_linux! + return unless @module_name.split('-').last == 'sce_linux' + return unless @opts[:select_profile].nil? || @opts[:select_profile].empty? + + @opts[:select_profile] = ['server'] + end end class ConfigExampleError < StandardError; end diff --git a/lib/abide_dev_utils/version.rb b/lib/abide_dev_utils/version.rb index 0f8ce9b..5d86bb3 100644 --- a/lib/abide_dev_utils/version.rb +++ b/lib/abide_dev_utils/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module AbideDevUtils - VERSION = "0.18.7" + VERSION = "0.18.8" end diff --git a/spec/abide_dev_utils/sce/benchmark_spec.rb b/spec/abide_dev_utils/sce/benchmark_spec.rb index 48ea0fb..d7051b3 100644 --- a/spec/abide_dev_utils/sce/benchmark_spec.rb +++ b/spec/abide_dev_utils/sce/benchmark_spec.rb @@ -15,6 +15,16 @@ ) end + context 'when filtering controls by profile and level' do + it 'excludes profiles not in the filter when both prof and lvl are given' do + ctrl = test_objs.last.flat_map(&:controls) + .find { |c| c.profiles_levels.any? { |pl| pl.start_with?('workstation;;;') } } + skip 'no control with workstation profile found in fixtures' unless ctrl + result = ctrl.filtered_profiles_levels(prof: %w[server], lvl: %w[level_1 level_2]) + expect(result.none? { |pl| pl.start_with?('workstation;;;') }).to be(true) + end + end + context 'when supplied a PuppetModule' do it 'creates benchmark objects correctly' do expect(test_objs.last.empty?).not_to be_truthy diff --git a/spec/abide_dev_utils/sce/generate/reference/markdown_generator_spec.rb b/spec/abide_dev_utils/sce/generate/reference/markdown_generator_spec.rb new file mode 100644 index 0000000..4da632c --- /dev/null +++ b/spec/abide_dev_utils/sce/generate/reference/markdown_generator_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'spec_helper' +require 'abide_dev_utils/sce/generate/reference' + +RSpec.describe(AbideDevUtils::Sce::Generate::Reference::MarkdownGenerator) do + before do + md_double = double('Markdown').as_null_object # rubocop:disable RSpec/VerifiedDoubles + allow(AbideDevUtils::Markdown).to receive(:new).and_return(md_double) + end + + context 'with puppetlabs-sce_linux and no select_profile' do + it 'defaults select_profile to server' do + gen = described_class.new([], 'puppetlabs-sce_linux', file: '/dev/null', opts: {}) + gen.generate + expect(gen.instance_variable_get(:@opts)[:select_profile]).to eq(['server']) + end + end + + context 'with puppetlabs-sce_linux and explicit select_profile' do + it 'does not override select_profile' do + gen = described_class.new([], 'puppetlabs-sce_linux', file: '/dev/null', + opts: { select_profile: ['server'] }) + gen.generate + expect(gen.instance_variable_get(:@opts)[:select_profile]).to eq(['server']) + end + end + + context 'with a non-sce_linux module and no select_profile' do + it 'does not set a default select_profile' do + gen = described_class.new([], 'puppetlabs-sce_windows', file: '/dev/null', opts: {}) + gen.generate + expect(gen.instance_variable_get(:@opts)[:select_profile].nil?).to be(true) + end + end +end diff --git a/specifications/CEM-6541.md b/specifications/CEM-6541.md new file mode 100644 index 0000000..982d2b6 --- /dev/null +++ b/specifications/CEM-6541.md @@ -0,0 +1,111 @@ +## Background + +The `REFERENCE.md` generated for `sce_linux` on the Forge lists `workstation` profile entries for +many controls. SCE documentation explicitly states that only the `server` profile is supported; +`workstation` is neither tested nor supported. + +Two bugs in `abide_dev_utils` cause this: + +**Bug 1 — `filtered_profiles_levels` uses OR logic instead of AND (`benchmark.rb:225`).** +When both `--select-profile` (`-p`) and `--select-level` (`-l`) are passed, the method returns +the *union* of profile-filtered and level-filtered entries: + +```ruby +return profiles_levels_by_profile(prof).concat(profiles_levels_by_level(lvl)) +``` + +`profiles_levels_by_level` returns every profile at the requested levels — including +`workstation` — regardless of what was passed via `-p`. So even when running: + +``` +bundle exec abide sce generate reference -p server,classified,public,sensitive -l level_1,level_2,... +``` + +`workstation` entries at `level_1` and `level_2` are included because they are matched by the +level filter and then concatenated in. + +**Bug 2 — No default profile filter for `sce_linux` when `-p` is omitted (`reference.rb`).** +When `abide sce generate reference` is run without `-p`, `@opts[:select_profile]` is `nil`. +`Control#filtered_profiles_levels` treats `nil` as "no filter", returning all profiles including +`workstation`. + +## Change + +**File:** `lib/abide_dev_utils/sce/benchmark.rb` (modified) + +Change `concat` to array intersection (`&`) in `Control#filtered_profiles_levels` so that when +both `prof` and `lvl` are given, only entries matching *both* filters are returned: + +```ruby +# before +return profiles_levels_by_profile(prof).concat(profiles_levels_by_level(lvl)) + +# after +return profiles_levels_by_profile(prof) & profiles_levels_by_level(lvl) +``` + +**File:** `lib/abide_dev_utils/sce/generate/reference.rb` (modified) + +In `MarkdownGenerator#generate`, default `@opts[:select_profile]` to `['server']` for `sce_linux` +when no profile was explicitly provided. This covers invocations that omit `-p` entirely: + +```ruby +def generate(doc_title = 'Reference') + if @module_name.split('-').last == 'sce_linux' && + (@opts[:select_profile].nil? || @opts[:select_profile].empty?) + @opts[:select_profile] = ['server'] + end + @strings = Strings.new(opts: @opts) + ... +``` + +**File:** `spec/abide_dev_utils/sce/benchmark_spec.rb` (modified) + +Add a test that verifies `filtered_profiles_levels` with both `prof` and `lvl` excludes profiles +not in the filter (i.e., does not include `workstation` when only `server` is requested). + +**File:** `spec/abide_dev_utils/sce/generate/reference/markdown_generator_spec.rb` (new) + +Unit tests for the `MarkdownGenerator` opts-defaulting behavior: + +```ruby +RSpec.describe(AbideDevUtils::Sce::Generate::Reference::MarkdownGenerator) do + context 'with puppetlabs-sce_linux and no select_profile' do + it 'defaults select_profile to server' do ... + end + context 'with puppetlabs-sce_linux and explicit select_profile' do + it 'does not override select_profile' do ... + end + context 'with a non-sce_linux module and no select_profile' do + it 'does not set a default select_profile' do ... + end +end +``` + +**File:** `lib/abide_dev_utils/version.rb` (modified) + +Bump version from `0.18.7` to `0.18.8`. + +## Functional behavior + +After these changes: + +- Running with both `-p server,...` and `-l level_1,...` returns only controls that match both + filters — `workstation` entries at the requested levels are no longer included. +- Running without `-p` against `sce_linux` defaults the profile filter to `['server']`, so + `workstation` entries are excluded in that case too. +- Passing `-p server,workstation` explicitly still includes `workstation` (escape hatch preserved). + +## Non-goals + +- Removing `workstation` profile data from the `sce_linux` mapping YAML files. +- Applying the `sce_linux` default profile to `sce_windows` (separate ticket if needed). + +## Acceptance criteria + +- [ ] Running `bundle exec abide sce generate reference -p server,classified,public,sensitive -l level_1,level_2,mac-1,mac-2,mac-3` against `sce_linux` produces a REFERENCE.md with no `workstation` entries. +- [ ] Running `bundle exec abide sce generate reference` against `sce_linux` without `-p` produces a REFERENCE.md with no `workstation` entries. +- [ ] Running with `-p server,workstation` still includes `workstation` entries (escape hatch not broken). +- [ ] `bundle exec rspec spec/abide_dev_utils/sce/benchmark_spec.rb` passes including the new `filtered_profiles_levels` intersection test. +- [ ] `bundle exec rspec spec/abide_dev_utils/sce/generate/reference/markdown_generator_spec.rb` passes with all three unit tests. +- [ ] `lib/abide_dev_utils/version.rb` reads `VERSION = "0.18.8"`.