diff --git a/package/yast2-bootloader.changes b/package/yast2-bootloader.changes
index 6801308d3..9edde4f58 100644
--- a/package/yast2-bootloader.changes
+++ b/package/yast2-bootloader.changes
@@ -1,3 +1,9 @@
+-------------------------------------------------------------------
+Fri Apr 26 13:07:51 UTC 2024 - Stefan Schubert
+
+- Creating kernel options for systemd-boot. (bsc#1220892)
+- 5.0.9
+
-------------------------------------------------------------------
Fri Apr 5 08:08:09 UTC 2024 - Josef Reidinger
diff --git a/package/yast2-bootloader.spec b/package/yast2-bootloader.spec
index c6f1f2203..bf26c4a40 100644
--- a/package/yast2-bootloader.spec
+++ b/package/yast2-bootloader.spec
@@ -17,7 +17,7 @@
Name: yast2-bootloader
-Version: 5.0.8
+Version: 5.0.9
Release: 0
Summary: YaST2 - Bootloader Configuration
License: GPL-2.0-or-later
diff --git a/src/lib/bootloader/generic_widgets.rb b/src/lib/bootloader/generic_widgets.rb
index 55c3aa94a..f3c938124 100644
--- a/src/lib/bootloader/generic_widgets.rb
+++ b/src/lib/bootloader/generic_widgets.rb
@@ -3,6 +3,7 @@
require "yast"
require "bootloader/bootloader_factory"
+require "bootloader/cpu_mitigations"
require "cwm/widget"
@@ -110,4 +111,109 @@ def help
)
end
end
+
+ # Represents decision if smt is enabled
+ class CpuMitigationsWidget < CWM::ComboBox
+ def initialize
+ textdomain "bootloader"
+
+ super
+ end
+
+ def label
+ _("CPU Mitigations")
+ end
+
+ def items
+ ::Bootloader::CpuMitigations::ALL.map do |m|
+ [m.value.to_s, m.to_human_string]
+ end
+ end
+
+ def help
+ _(
+ "CPU Mitigations
\n" \
+ "The option selects which default settings should be used for CPU \n" \
+ "side channels mitigations. A highlevel description is on our Technical Information \n" \
+ "Document TID 7023836. Following options are available:
\n" \
+ "- Auto: This option enables all the mitigations needed for your CPU model. \n" \
+ "This setting can impact performance to some degree, depending on CPU model and \n" \
+ "workload. It provides all security mitigations, but it does not protect against \n" \
+ "cross-CPU thread attacks.
\n" \
+ "- Auto + No SMT: This option enables all the above mitigations in \n" \
+ "\"Auto\", and also disables Simultaneous Multithreading to avoid \n" \
+ "side channel attacks across multiple CPU threads. This setting can \n" \
+ "further impact performance, depending on your \n" \
+ "workload. This setting provides the full set of available security mitigations.
\n" \
+ "- Off: All CPU Mitigations are disabled. This setting has no performance \n" \
+ "impact, but side channel attacks against your CPU are possible, depending on CPU \n" \
+ "model.
\n" \
+ "- Manual: This setting does not specify a mitigation level and leaves \n" \
+ "this to be the kernel default. The administrator can add other mitigations options \n" \
+ "in the kernel command line widget.\n" \
+ "All CPU mitigation specific options can be set manually.
"
+ )
+ end
+
+ def init
+ if Bootloader::BootloaderFactory.current.respond_to?(:cpu_mitigations)
+ self.value = Bootloader::BootloaderFactory.current.cpu_mitigations.value.to_s
+ else
+ disable
+ end
+ end
+
+ def store
+ return unless enabled?
+
+ Bootloader::BootloaderFactory.current.cpu_mitigations =
+ ::Bootloader::CpuMitigations.new(value.to_sym)
+ end
+ end
+
+ # represents kernel command line
+ class KernelAppendWidget < CWM::InputField
+ def initialize
+ textdomain "bootloader"
+
+ super
+ end
+
+ def label
+ _("O&ptional Kernel Command Line Parameter")
+ end
+
+ def help
+ _(
+ "Optional Kernel Command Line Parameter lets you define " \
+ "additional parameters to pass to the kernel.
"
+ )
+ end
+
+ def init
+ current_bl = ::Bootloader::BootloaderFactory.current
+ case current_bl
+ when ::Bootloader::SystemdBoot
+ self.value = current_bl.kernel_params.serialize.gsub(/mitigations=\S+/, "")
+ when ::Bootloader::Grub2Base
+ self.value = current_bl.grub_default.kernel_params.serialize.gsub(/mitigations=\S+/, "")
+ else
+ disable
+ end
+ end
+
+ def store
+ return unless enabled?
+
+ current_bl = ::Bootloader::BootloaderFactory.current
+ case current_bl
+ when ::Bootloader::SystemdBoot
+ current_bl.kernel_params.replace(value)
+ when ::Bootloader::Grub2Base
+ current_bl.grub_default.kernel_params.replace(value)
+ else
+ log.error("Bootloader type #{current_bl} not found.")
+ end
+ end
+ end
end
diff --git a/src/lib/bootloader/grub2_widgets.rb b/src/lib/bootloader/grub2_widgets.rb
index 6669245bc..c676618c3 100644
--- a/src/lib/bootloader/grub2_widgets.rb
+++ b/src/lib/bootloader/grub2_widgets.rb
@@ -122,66 +122,6 @@ def store
end
end
- # Represents decision if smt is enabled
- class CpuMitigationsWidget < CWM::ComboBox
- include Grub2Helper
-
- def initialize
- textdomain "bootloader"
-
- super
- end
-
- def label
- _("CPU Mitigations")
- end
-
- def items
- ::Bootloader::CpuMitigations::ALL.map do |m|
- [m.value.to_s, m.to_human_string]
- end
- end
-
- def help
- _(
- "CPU Mitigations
\n" \
- "The option selects which default settings should be used for CPU \n" \
- "side channels mitigations. A highlevel description is on our Technical Information \n" \
- "Document TID 7023836. Following options are available:
\n" \
- "- Auto: This option enables all the mitigations needed for your CPU model. \n" \
- "This setting can impact performance to some degree, depending on CPU model and \n" \
- "workload. It provides all security mitigations, but it does not protect against \n" \
- "cross-CPU thread attacks.
\n" \
- "- Auto + No SMT: This option enables all the above mitigations in \n" \
- "\"Auto\", and also disables Simultaneous Multithreading to avoid \n" \
- "side channel attacks across multiple CPU threads. This setting can \n" \
- "further impact performance, depending on your \n" \
- "workload. This setting provides the full set of available security mitigations.
\n" \
- "- Off: All CPU Mitigations are disabled. This setting has no performance \n" \
- "impact, but side channel attacks against your CPU are possible, depending on CPU \n" \
- "model.
\n" \
- "- Manual: This setting does not specify a mitigation level and leaves \n" \
- "this to be the kernel default. The administrator can add other mitigations options \n" \
- "in the kernel command line widget.\n" \
- "All CPU mitigation specific options can be set manually.
"
- )
- end
-
- def init
- if grub2.respond_to?(:cpu_mitigations)
- self.value = grub2.cpu_mitigations.value.to_s
- else
- # do not crash when use no bootloader. This widget is also used in security dialog.
- # (bsc#1184968)
- disable
- end
- end
-
- def store
- grub2.cpu_mitigations = ::Bootloader::CpuMitigations.new(value.to_sym) if enabled?
- end
- end
-
# Represents decision if generic MBR have to be installed on disk
class GenericMBRWidget < CWM::CheckBox
include Grub2Helper
@@ -268,36 +208,6 @@ def store
end
end
- # represents kernel command line
- class KernelAppendWidget < CWM::InputField
- include Grub2Helper
-
- def initialize
- textdomain "bootloader"
-
- super
- end
-
- def label
- _("O&ptional Kernel Command Line Parameter")
- end
-
- def help
- _(
- "Optional Kernel Command Line Parameter lets you define " \
- "additional parameters to pass to the kernel.
"
- )
- end
-
- def init
- self.value = grub_default.kernel_params.serialize.gsub(/mitigations=\S+/, "")
- end
-
- def store
- grub_default.kernel_params.replace(value)
- end
- end
-
# Represents Protective MBR action
class PMBRWidget < CWM::ComboBox
include Grub2Helper
diff --git a/src/lib/bootloader/grub2base.rb b/src/lib/bootloader/grub2base.rb
index 866152959..788b95120 100644
--- a/src/lib/bootloader/grub2base.rb
+++ b/src/lib/bootloader/grub2base.rb
@@ -21,7 +21,6 @@
Yast.import "BootStorage"
Yast.import "HTML"
Yast.import "Initrd"
-Yast.import "Kernel"
Yast.import "Mode"
Yast.import "Pkg"
Yast.import "Product"
@@ -381,31 +380,13 @@ def propose_xen_hypervisor
grub_default.xen_hypervisor_params.add_parameter("vga", "gfx-1024x768x16", placer)
end
- def propose_resume
- swap_parts = Yast::BootStorage.available_swap_partitions
- largest_swap_name, lagest_swap_size = (swap_parts.max_by { |_part, size| size } || [])
-
- propose = Yast::Kernel.propose_hibernation? && largest_swap_name
-
- return "" unless propose
-
- if lagest_swap_size < Yast::BootStorage.ram_size
- log.info "resume parameter is not added because swap (#{largest_swap_name}) is too small"
-
- return ""
- end
-
- # try to use label or udev id for device name... FATE #302219
- UdevMapping.to_mountby_device(largest_swap_name)
- end
-
def propose_encrypted
grub_default.cryptodisk.value = !!Yast::BootStorage.encrypted_boot?
end
def propose_grub_default
if grub_default.kernel_params.empty?
- kernel_line = Yast::BootArch.DefaultKernelParams(propose_resume)
+ kernel_line = Yast::BootArch.DefaultKernelParams(Yast::BootStorage.propose_resume)
grub_default.kernel_params.replace(kernel_line)
end
grub_default.gfxmode ||= "auto"
diff --git a/src/lib/bootloader/systemdboot.rb b/src/lib/bootloader/systemdboot.rb
index 56c1c81e5..7bbe53fd0 100644
--- a/src/lib/bootloader/systemdboot.rb
+++ b/src/lib/bootloader/systemdboot.rb
@@ -5,6 +5,7 @@
require "bootloader/sysconfig"
require "bootloader/cpu_mitigations"
require "cfa/systemd_boot"
+require "cfa/grub2/default"
Yast.import "Report"
Yast.import "Arch"
@@ -18,6 +19,8 @@ class SystemdBoot < BootloaderBase
include Yast::Logger
include Yast::I18n
+ CMDLINE = "/etc/kernel/cmdline"
+
# @!attribute menue_timeout
# @return [Integer] menue timeout
attr_accessor :menue_timeout
@@ -30,14 +33,63 @@ def initialize
super
textdomain "bootloader"
+ # For kernel parameters we are using the same data structure
+ # like grub2 in order to be compatible with all calls.
+ @kernel_container = ::CFA::Grub2::Default.new
+ @explicit_cpu_mitigations = false
+ end
+
+ def kernel_params
+ @kernel_container.kernel_params
end
+ # rubocop:disable Metrics/AbcSize
def merge(other)
- log.info "merging with system: timeout=#{other.menue_timeout} " \
- "secure_boot=#{other.secure_boot}"
+ log.info "merging: timeout: #{menue_timeout}=>#{other.menue_timeout}"
+ log.info " secure_boot: #{secure_boot}=>#{other.secure_boot}"
+ log.info " mitigations: #{cpu_mitigations.to_human_string}=>" \
+ "#{other.cpu_mitigations.to_human_string}"
+ log.info " kernel_params: #{kernel_params.serialize}=>" \
+ "#{other.kernel_params.serialize}"
super
self.menue_timeout = other.menue_timeout unless other.menue_timeout.nil?
self.secure_boot = other.secure_boot unless other.secure_boot.nil?
+
+ kernel_serialize = kernel_params.serialize
+ # handle specially noresume as it should lead to remove all other resume
+ kernel_serialize.gsub!(/resume=\S+/, "") if other.kernel_params.parameter("noresume")
+
+ # prevent double cpu_mitigations params
+ kernel_serialize.gsub!(/mitigations=\S+/, "") if other.kernel_params.parameter("mitigations")
+
+ new_kernel_params = "#{kernel_serialize} #{other.kernel_params.serialize}"
+ # deduplicate identicatel parameter. Keep always the last one ( so reverse is needed ).
+ new_params = new_kernel_params.split.reverse.uniq.reverse.join(" ")
+
+ @kernel_container.kernel_params.replace(new_params)
+
+ # explicitly set mitigations means overwrite of our
+ self.cpu_mitigations = other.cpu_mitigations if other.explicit_cpu_mitigations
+
+ log.info "merging result: timeout: #{menue_timeout}"
+ log.info " secure_boot: #{secure_boot}"
+ log.info " mitigations: #{cpu_mitigations.to_human_string}"
+ log.info " kernel_params: #{kernel_params.serialize}"
+ end
+ # rubocop:enable Metrics/AbcSize
+
+ def cpu_mitigations
+ CpuMitigations.from_kernel_params(kernel_params)
+ end
+
+ def explicit_cpu_mitigations
+ @explicit_cpu_mitigations ? cpu_mitigations : nil
+ end
+
+ def cpu_mitigations=(value)
+ log.info "set mitigations to #{value.to_human_string}"
+ @explicit_cpu_mitigations = true
+ value.modify_kernel_params(kernel_params)
end
def read
@@ -45,6 +97,15 @@ def read
read_menue_timeout
self.secure_boot = Systeminfo.secure_boot_active?
+
+ lines = ""
+ filename = File.join(Yast::Installation.destdir, CMDLINE)
+ if File.exist?(filename)
+ File.open(filename).each do |line|
+ lines = + line
+ end
+ end
+ @kernel_container.kernel_params.replace(lines)
end
# Write bootloader settings to disk
@@ -57,12 +118,19 @@ def write(etc_only: false)
end
write_menue_timeout
+ File.open(File.join(Yast::Installation.destdir, CMDLINE), "w+") do |fw|
+ fw.puts(kernel_params.serialize)
+ end
true
end
def propose
super
log.info("Propose settings...")
+ if @kernel_container.kernel_params.empty?
+ kernel_line = Yast::BootArch.DefaultKernelParams(Yast::BootStorage.propose_resume)
+ @kernel_container.kernel_params.replace(kernel_line)
+ end
self.menue_timeout = Yast::ProductFeatures.GetIntegerFeature("globals", "boot_timeout").to_i
self.secure_boot = Systeminfo.secure_boot_supported?
end
@@ -137,10 +205,10 @@ def write_sysconfig(prewrite: false)
SDBOOTUTIL = "/usr/bin/sdbootutil"
def create_menue_entries
- cmdline_file = File.join(Yast::Installation.destdir, "/etc/kernel/cmdline")
+ cmdline_file = File.join(Yast::Installation.destdir, CMDLINE)
if Yast::Stage.initial
# sdbootutil script needs the "root=" entry in kernel parameters.
- # This will be written to /etc/kernel/cmdline which will be used in an
+ # This will be written to CMDLINE which will be used in an
# installed system by the administrator only. So we can use it because
# the system will be installed new. This file will be deleted after
# calling sdbootutil.
diff --git a/src/lib/bootloader/systemdboot_widgets.rb b/src/lib/bootloader/systemdboot_widgets.rb
index 0877bea6e..66ee98755 100644
--- a/src/lib/bootloader/systemdboot_widgets.rb
+++ b/src/lib/bootloader/systemdboot_widgets.rb
@@ -116,10 +116,8 @@ def label
def contents
VBox(
VSpacing(1),
- HBox(
- HSpacing(1),
- HStretch()
- ),
+ MarginBox(1, 0.5, KernelAppendWidget.new),
+ MarginBox(1, 0.5, Left(CpuMitigationsWidget.new)),
VStretch()
)
end
diff --git a/src/modules/BootStorage.rb b/src/modules/BootStorage.rb
index 414a2a815..a4b4251f6 100644
--- a/src/modules/BootStorage.rb
+++ b/src/modules/BootStorage.rb
@@ -48,6 +48,7 @@ def main
Yast.import "Arch"
Yast.import "Mode"
+ Yast.import "Kernel"
# FATE#305008: Failover boot configurations for md arrays with redundancy
# list includes physical disks used for md raid
@@ -254,6 +255,24 @@ def root_partitions
stage1_partitions_for(root_filesystem)
end
+ def propose_resume
+ swap_parts = Yast::BootStorage.available_swap_partitions
+ largest_swap_name, largest_swap_size = (swap_parts.max_by { |_part, size| size } || [])
+
+ propose = Yast::Kernel.propose_hibernation? && largest_swap_name
+
+ return "" unless propose
+
+ if largest_swap_size < Yast::BootStorage.ram_size
+ log.info "resume parameter is not added because swap (#{largest_swap_name}) is too small"
+
+ return ""
+ end
+
+ # try to use label or udev id for device name... FATE #302219
+ ::Bootloader::UdevMapping.to_mountby_device(largest_swap_name)
+ end
+
private
def detect_disks
diff --git a/src/modules/Bootloader.rb b/src/modules/Bootloader.rb
index cdb6a18c8..160c3107a 100644
--- a/src/modules/Bootloader.rb
+++ b/src/modules/Bootloader.rb
@@ -22,6 +22,7 @@
require "bootloader/bootloader_factory"
require "bootloader/autoyast_converter"
require "bootloader/autoinst_profile/bootloader_section"
+require "bootloader/systemdboot"
require "installation/autoinst_issues/invalid_value"
require "cfa/matcher"
@@ -336,21 +337,26 @@ def kernel_param(flavor, key)
return :missing
end
- ReadOrProposeIfNeeded() # ensure we have some data
-
current_bl = ::Bootloader::BootloaderFactory.current
- # currently only grub2 bootloader supported
- return :missing unless current_bl.respond_to?(:grub_default)
-
- grub_default = current_bl.grub_default
- params = case flavor
- when :common then grub_default.kernel_params
- when :xen_guest then grub_default.xen_kernel_params
- when :xen_host then grub_default.xen_hypervisor_params
- else raise ArgumentError, "Unknown flavor #{flavor}"
+ if current_bl.is_a?(::Bootloader::SystemdBoot)
+ # systemd-boot
+ kernel_params = current_bl.kernel_params
+ elsif current_bl.respond_to?(:grub_default)
+ # all grub bootloader types
+ grub_default = current_bl.grub_default
+ kernel_params = case flavor
+ when :common then grub_default.kernel_params
+ when :xen_guest then grub_default.xen_kernel_params
+ when :xen_host then grub_default.xen_hypervisor_params
+ else raise ArgumentError, "Unknown flavor #{flavor}"
+ end
+ else
+ return :missing
end
- res = params.parameter(key)
+ ReadOrProposeIfNeeded() # ensure we have some data
+
+ res = kernel_params.parameter(key)
BOOLEAN_MAPPING[res] || res
end
@@ -382,10 +388,10 @@ def kernel_param(flavor, key)
def modify_kernel_params(*args)
ReadOrProposeIfNeeded() # ensure we have data to modify
current_bl = ::Bootloader::BootloaderFactory.current
- # currently only grub2 bootloader supported
- return :missing unless current_bl.respond_to?(:grub_default)
-
- grub_default = current_bl.grub_default
+ # currently only grub2 bootloader and systemd-boot supported
+ if !current_bl.respond_to?(:grub_default) && !current_bl.is_a?(::Bootloader::SystemdBoot)
+ return :missing
+ end
values = args.pop
raise ArgumentError, "Missing parameters to modify #{args.inspect}" if !values.is_a? Hash
@@ -403,12 +409,17 @@ def modify_kernel_params(*args)
values[key] = remap_values[values[key]] if remap_values.key?(values[key])
end
- params = args.map do |flavor|
- case flavor
- when :common then grub_default.kernel_params
- when :xen_guest then grub_default.xen_kernel_params
- when :xen_host then grub_default.xen_hypervisor_params
- else raise ArgumentError, "Unknown flavor #{flavor}"
+ if current_bl.is_a?(::Bootloader::SystemdBoot)
+ params = [current_bl.kernel_params]
+ else
+ grub_default = current_bl.grub_default
+ params = args.map do |flavor|
+ case flavor
+ when :common then grub_default.kernel_params
+ when :xen_guest then grub_default.xen_kernel_params
+ when :xen_host then grub_default.xen_hypervisor_params
+ else raise ArgumentError, "Unknown flavor #{flavor}"
+ end
end
end
diff --git a/test/data/etc/kernel/cmdline b/test/data/etc/kernel/cmdline
new file mode 100644
index 000000000..3535cd4cd
--- /dev/null
+++ b/test/data/etc/kernel/cmdline
@@ -0,0 +1 @@
+splash=silent quiet security=apparmor mitigations=off
diff --git a/test/grub2_widgets_test.rb b/test/grub2_widgets_test.rb
index 5a6565990..7f40371ac 100644
--- a/test/grub2_widgets_test.rb
+++ b/test/grub2_widgets_test.rb
@@ -102,7 +102,7 @@ def stub_widget_value(id, value)
end
end
-describe Bootloader::Grub2Widget::CpuMitigationsWidget do
+describe Bootloader::CpuMitigationsWidget do
before do
assign_bootloader
end
@@ -215,7 +215,7 @@ def stub_widget_value(id, value)
end
end
-describe Bootloader::Grub2Widget::KernelAppendWidget do
+describe Bootloader::KernelAppendWidget do
before do
assign_bootloader
end
@@ -231,6 +231,7 @@ def stub_widget_value(id, value)
it "stores text as kernel command line option" do
expect(subject).to receive(:value).and_return("showopts quiet")
+ expect(subject).to receive(:enabled?).and_return(true)
subject.store
expect(bootloader.grub_default.kernel_params.serialize).to eq "showopts quiet"
diff --git a/test/systemdboot_test.rb b/test/systemdboot_test.rb
index 7810fd980..c860ffd6c 100644
--- a/test/systemdboot_test.rb
+++ b/test/systemdboot_test.rb
@@ -11,46 +11,90 @@
end
let(:destdir) { File.expand_path("data/", __dir__) }
- let(:kerneldir) { File.join(destdir, "etc", "kernel") }
+ let(:cmdline_content) { "splash=silent quiet security=apparmor mitigations=off" }
before do
allow(Yast::BootStorage).to receive(:available_swap_partitions).and_return([])
allow(Yast::Arch).to receive(:architecture).and_return("x86_64")
allow(Yast::Package).to receive(:Available).and_return(true)
- FileUtils.mkdir_p(kerneldir)
- end
-
- after do
- FileUtils.remove_entry(kerneldir) if Dir.exist?(kerneldir)
end
describe "#read" do
- it "reads bootloader flags from sysconfig" do
+ before do
expect(Bootloader::Systeminfo).to receive(:secure_boot_active?).and_return(true)
- allow(Yast::Installation).to receive(:destdir).and_return(File.expand_path("data/", __dir__))
+ allow(Yast::Installation).to receive(:destdir).and_return(destdir)
+ end
+ it "reads bootloader flags from sysconfig" do
subject.read
expect(subject.secure_boot).to eq true
end
+
+ it "reads entries from /etc/kernel/cmdline" do
+ subject.read
+
+ expect(subject.cpu_mitigations.to_human_string).to eq "Off"
+ expect(subject.kernel_params.serialize).to eq cmdline_content
+ end
end
describe "#write" do
- it "installs bootloader and creates menue entries" do
+ before do
allow(subject).to receive(:secure_boot).and_return(false)
allow(Yast::Stage).to receive(:initial).and_return(true)
+ allow(Yast::Installation).to receive(:destdir).and_return(destdir)
+ subject.kernel_params.replace(cmdline_content)
+ subject.menue_timeout = 10
+ end
+
+ it "installs the bootloader" do
+ allow(Yast::Execute).to receive(:on_target!)
+ .with("/usr/bin/sdbootutil", "--verbose", "add-all-kernels")
+ allow_any_instance_of(CFA::SystemdBoot).to receive(:save)
# install bootloader
expect(Yast::Execute).to receive(:on_target!)
.with("/usr/bin/sdbootutil", "--verbose", "install")
+
+ subject.write
+ end
+
+ it "writes kernel cmdline" do
+ allow(Yast::Execute).to receive(:on_target!)
+ .with("/usr/bin/sdbootutil", "--verbose", "install")
+ allow(Yast::Execute).to receive(:on_target!)
+ .with("/usr/bin/sdbootutil", "--verbose", "add-all-kernels")
+ allow_any_instance_of(CFA::SystemdBoot).to receive(:save)
+
+ subject.write
+ # Checking written kernel parameters
+ subject.read
+ expect(subject.cpu_mitigations.to_human_string).to eq "Off"
+ expect(subject.kernel_params.serialize).to eq cmdline_content
+ end
+
+ it "creates menue entries" do
+ allow(Yast::Execute).to receive(:on_target!)
+ .with("/usr/bin/sdbootutil", "--verbose", "install")
+ allow_any_instance_of(CFA::SystemdBoot).to receive(:save)
+
# create menue entries
- allow(Yast::Installation).to receive(:destdir).and_return(destdir)
expect(Yast::Execute).to receive(:on_target!)
.with("/usr/bin/sdbootutil", "--verbose", "add-all-kernels")
+
+ subject.write
+ end
+
+ it "saves menue timeout" do
+ allow(Yast::Execute).to receive(:on_target!)
+ .with("/usr/bin/sdbootutil", "--verbose", "install")
+ allow(Yast::Execute).to receive(:on_target!)
+ .with("/usr/bin/sdbootutil", "--verbose", "add-all-kernels")
+
# Saving menue timeout
expect_any_instance_of(CFA::SystemdBoot).to receive(:save)
- subject.menue_timeout = 10
subject.write
end
end
@@ -77,18 +121,47 @@
end
describe "#merge" do
- it "overwrite secure boot and menue timeout if specified in merged one" do
+ it "overwrite secure boot, mitigations and menue timeout if specified in merged one" do
+ other_cmdline = "splash=silent quiet mitigations=auto"
other = described_class.new
other.secure_boot = true
other.menue_timeout = 12
+ other.kernel_params.replace(other_cmdline)
subject.secure_boot = false
subject.menue_timeout = 10
+ subject.kernel_params.replace(cmdline_content)
subject.merge(other)
expect(subject.secure_boot).to eq true
expect(subject.menue_timeout).to eq 12
+ expect(subject.cpu_mitigations.to_human_string).to eq "Auto"
+ expect(subject.kernel_params.serialize).to eq "security=apparmor splash=silent quiet mitigations=auto"
+ end
+ end
+
+ describe "#propose" do
+ it "proposes timeout to product/role default" do
+ allow(Yast::ProductFeatures).to receive(:GetIntegerFeature)
+ .with("globals", "boot_timeout").and_return(2)
+ subject.propose
+
+ expect(subject.menue_timeout).to eq 2
+ end
+
+ it "proposes secure boot" do
+ allow(Bootloader::Systeminfo).to receive(:secure_boot_supported?).and_return(true)
+ subject.propose
+
+ expect(subject.secure_boot).to eq true
+ end
+
+ it "proposes kernel cmdline" do
+ expect(Yast::BootArch).to receive(:DefaultKernelParams).and_return(cmdline_content)
+
+ subject.propose
+ expect(subject.kernel_params.serialize).to eq cmdline_content
end
end
end
diff --git a/test/systemdboot_widgets_test.rb b/test/systemdboot_widgets_test.rb
index 80260ac4d..24333cbeb 100644
--- a/test/systemdboot_widgets_test.rb
+++ b/test/systemdboot_widgets_test.rb
@@ -85,6 +85,61 @@ def stub_widget_value(id, value)
end
end
+describe Bootloader::CpuMitigationsWidget do
+ before do
+ assign_systemd_bootloader
+ end
+
+ it_behaves_like "labeled widget"
+ it_behaves_like "CWM::ComboBox"
+
+ context "when none bootloader is selected" do
+ before do
+ assign_bootloader("none")
+ end
+
+ describe "#init" do
+ it "disables widget" do
+ expect(subject).to receive(:disable)
+
+ subject.init
+ end
+ end
+
+ describe "#store" do
+ it "does nothing on disabled widget" do
+ expect(subject).to receive(:enabled?).and_return(false)
+ expect(subject).to_not receive(:value)
+
+ subject.store
+ end
+ end
+ end
+end
+
+describe Bootloader::KernelAppendWidget do
+ before do
+ assign_systemd_bootloader
+ end
+
+ it_behaves_like "labeled widget"
+
+ it "is initialized to kernel command line option" do
+ bootloader.kernel_params.replace("verbose showopts")
+ expect(subject).to receive(:value=).with("verbose showopts")
+
+ subject.init
+ end
+
+ it "stores text as kernel command line option" do
+ expect(subject).to receive(:value).and_return("showopts quiet")
+ expect(subject).to receive(:enabled?).and_return(true)
+ subject.store
+
+ expect(bootloader.kernel_params.serialize).to eq "showopts quiet"
+ end
+end
+
describe Bootloader::SystemdBootWidget::KernelTab do
before do
assign_systemd_bootloader