Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package rubygem-d-installer for openSUSE:Factory checked in at 2022-12-23 10:21:29 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/rubygem-d-installer (Old) and /work/SRC/openSUSE:Factory/.rubygem-d-installer.new.1563 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rubygem-d-installer" Fri Dec 23 10:21:29 2022 rev:2 rq:1044303 version:0.6.2 Changes: -------- --- /work/SRC/openSUSE:Factory/rubygem-d-installer/rubygem-d-installer.changes 2022-12-07 17:36:53.517172191 +0100 +++ /work/SRC/openSUSE:Factory/.rubygem-d-installer.new.1563/rubygem-d-installer.changes 2022-12-23 10:21:38.511528438 +0100 @@ -1,0 +2,30 @@ +Thu Dec 15 13:15:10 UTC 2022 - Imobach Gonzalez Sosa <igonzalezs...@suse.com> + +- Implement the ImportGpgKey libzypp callback + (gh#yast/d-installer#371) +- Version 0.6.2 + +------------------------------------------------------------------- +Wed Dec 14 22:38:24 UTC 2022 - Imobach Gonzalez Sosa <igonzalezs...@suse.com> + +- Implement AcceptUnsignedFile and MediaChange libzypp callbacks + (gh#yast/d-installer#369). + +------------------------------------------------------------------- +Wed Dec 14 15:29:12 UTC 2022 - Imobach Gonzalez Sosa <igonzalezs...@suse.com> + +- Switch the SELinux policy for ALP to "enforcing" + (gh#yast/d-installer#360). +- Fix generic questions handling (gh#yast/d-installer#362) +- Version 0.6.1 + +------------------------------------------------------------------- +Wed Dec 14 13:25:22 UTC 2022 - Ancor Gonzalez Sosa <an...@suse.com> + +- Removed previous temporary setting "olaf_luks2_password" and all + the code supporting it. +- Added new temporary setting "tpm_luks_open" to try to configure + TPM-based unlocking of the LUKS devices during the first system + boot (gh#yast/d-installer#363). + +------------------------------------------------------------------- Old: ---- d-installer-0.6.gem New: ---- d-installer-0.6.2.gem ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ rubygem-d-installer.spec ++++++ --- /var/tmp/diff_new_pack.I0RFIC/_old 2022-12-23 10:21:39.051531524 +0100 +++ /var/tmp/diff_new_pack.I0RFIC/_new 2022-12-23 10:21:39.055531547 +0100 @@ -1,7 +1,7 @@ # # spec file for package rubygem-d-installer # -# Copyright (c) 2022 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2022 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -12,7 +12,7 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# Please submit bugfixes or comments via https://bugs.opensuse.org/ # @@ -24,7 +24,7 @@ # Name: rubygem-d-installer -Version: 0.6 +Version: 0.6.2 Release: 0 %define mod_name d-installer %define mod_full_name %{mod_name}-%{version} @@ -44,11 +44,11 @@ Requires: yast2 >= 4.5.20 # /MANUAL BuildRoot: %{_tmppath}/%{name}-%{version}-build -BuildRequires: ruby-macros >= 5 BuildRequires: %{ruby >= 2.5.0} BuildRequires: %{rubygem gem2rpm} +BuildRequires: ruby-macros >= 5 BuildRequires: update-alternatives -Url: https://github.com/yast/d-installer +URL: https://github.com/yast/d-installer Source: %{mod_full_name}.gem Source1: gem2rpm.yml Summary: D-Installer Service @@ -75,7 +75,6 @@ install -D -m 0644 %{buildroot}%{gem_base}/gems/%{mod_full_name}/etc/d-installer.yaml %{buildroot}%{_sysconfdir}/d-installer.yaml # /MANUAL - %gem_packages %changelog ++++++ d-installer-0.6.gem -> d-installer-0.6.2.gem ++++++ Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/etc/d-installer.yaml new/etc/d-installer.yaml --- old/etc/d-installer.yaml 2022-12-05 16:56:00.000000000 +0100 +++ new/etc/d-installer.yaml 2022-12-22 16:38:27.000000000 +0100 @@ -161,10 +161,13 @@ optional_patterns: null # no optional pattern shared mandatory_packages: - device-mapper # Apparently needed if devices at /dev/mapper are used at boot (eg. FDE) + - fde-tools # Needed for FDE with TPM, hardcoded here temporarily + - libtss2-tcti-device0 # Same than fde-tools optional_packages: null base_product: ALP security: + tpm_luks_open: true lsm: selinux available_lsms: # apparmor: @@ -173,7 +176,7 @@ selinux: patterns: - alp_selinux - policy: permissive + policy: enforcing none: patterns: null diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/dinstaller/dbus/clients/question.rb new/lib/dinstaller/dbus/clients/question.rb --- old/lib/dinstaller/dbus/clients/question.rb 2022-12-05 16:56:00.000000000 +0100 +++ new/lib/dinstaller/dbus/clients/question.rb 2022-12-22 16:38:27.000000000 +0100 @@ -28,6 +28,9 @@ # Its interface is a subset of {DInstaller::Question} # so it can be used in the block of {DInstaller::CanAskQuestion#ask}. class Question < Base + LUKS_ACTIVATION_IFACE = "org.opensuse.DInstaller.Question.LuksActivation1" + private_constant :LUKS_ACTIVATION_IFACE + # @return [::DBus::ProxyObject] attr_reader :dbus_object @@ -38,7 +41,9 @@ @dbus_object = service[object_path] @dbus_iface = @dbus_object["org.opensuse.DInstaller.Question1"] # one D-Bus client for all kinds of questions - @luks_iface = @dbus_object["org.opensuse.DInstaller.Question.LuksActivation1"] + return unless @dbus_object.has_iface?(LUKS_ACTIVATION_IFACE) + + @luks_iface = @dbus_object[LUKS_ACTIVATION_IFACE] end # @return [String] @@ -58,8 +63,10 @@ @dbus_iface["Answer"].to_sym end - # @return [String] + # @return [String,nil] Password or nil if there is no LUKS interface def password + return nil unless @luks_iface + @luks_iface["Password"] end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/dinstaller/dbus/clients/questions_manager.rb new/lib/dinstaller/dbus/clients/questions_manager.rb --- old/lib/dinstaller/dbus/clients/questions_manager.rb 2022-12-05 16:56:00.000000000 +0100 +++ new/lib/dinstaller/dbus/clients/questions_manager.rb 2022-12-22 16:38:27.000000000 +0100 @@ -21,6 +21,7 @@ require "dinstaller/dbus/clients/base" require "dinstaller/dbus/clients/question" +require "dinstaller/luks_activation_question" module DInstaller module DBus diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/dinstaller/dbus/software_service.rb new/lib/dinstaller/dbus/software_service.rb --- old/lib/dinstaller/dbus/software_service.rb 2022-12-05 16:56:00.000000000 +0100 +++ new/lib/dinstaller/dbus/software_service.rb 2022-12-22 16:38:27.000000000 +0100 @@ -43,7 +43,7 @@ def initialize(config, logger = nil) @logger = logger || Logger.new($stdout) @bus = ::DBus::SystemBus.instance - @backend = DInstaller::Software.new(config, logger) + @backend = DInstaller::Software::Manager.new(config, logger) @backend.on_progress_change { dispatch } end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/dinstaller/dbus/storage/proposal.rb new/lib/dinstaller/dbus/storage/proposal.rb --- old/lib/dinstaller/dbus/storage/proposal.rb 2022-12-05 16:56:00.000000000 +0100 +++ new/lib/dinstaller/dbus/storage/proposal.rb 2022-12-22 16:38:27.000000000 +0100 @@ -144,6 +144,8 @@ # # @param dbus_settings [DInstaller::Storage::ProposalSettings] def calculate(dbus_settings) + logger.info("Calculating storage proposal from D-Bus settings: #{dbus_settings}") + backend.calculate(to_proposal_settings(dbus_settings)) end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/dinstaller/dbus/y2dir/software/modules/PackageCallbacks.rb new/lib/dinstaller/dbus/y2dir/software/modules/PackageCallbacks.rb --- old/lib/dinstaller/dbus/y2dir/software/modules/PackageCallbacks.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/dinstaller/dbus/y2dir/software/modules/PackageCallbacks.rb 2022-12-22 16:38:27.000000000 +0100 @@ -0,0 +1,52 @@ +# Copyright (c) [2022] SUSE LLC +# +# All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as published +# by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, contact SUSE LLC. +# +# To contact SUSE LLC about this file by physical or electronic mail, you may +# find current contact information at www.suse.com. + +require "yast" +require "logger" +require "dinstaller/software/callbacks" +require "dinstaller/dbus/clients/questions_manager" + +# :nodoc: +module Yast + # Replacement for the Yast::PackageCallbacks module. + class PackageCallbacksClass < Module + def main + puts "Loading mocked module #{__FILE__}" + end + + # @see https://github.com/yast/yast-yast2/blob/19180445ab935a25edd4ae0243aa7a3bcd09c9de/library/packages/src/modules/PackageCallbacks.rb#L183 + def InitPackageCallbacks(logger = ::Logger.new($stdout)) + DInstaller::Software::Callbacks::Signature.new( + questions_manager, logger + ).setup + + DInstaller::Software::Callbacks::Media.new( + questions_manager, logger + ).setup + end + + def questions_manager + @questions_manager ||= DInstaller::DBus::Clients::QuestionsManager.new + end + end + + PackageCallbacks = PackageCallbacksClass.new + PackageCallbacks.main +end + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/dinstaller/manager.rb new/lib/dinstaller/manager.rb --- old/lib/dinstaller/manager.rb 2022-12-05 16:56:00.000000000 +0100 +++ new/lib/dinstaller/manager.rb 2022-12-22 16:38:27.000000000 +0100 @@ -86,7 +86,7 @@ def install_phase installation_phase.install - start_progress(9) + start_progress(8) progress.step("Reading software repositories") do software.probe @@ -107,7 +107,6 @@ progress.step("Writing Network Configuration") { network.install } progress.step("Saving Language Settings") { language.finish } progress.step("Writing repositories information") { software.finish } - progress.step("Copying logs") { copy_logs } progress.step("Finishing storage configuration") { storage.finish } end @@ -191,10 +190,5 @@ # @return [ServiceStatusRecorder] attr_reader :service_status_recorder - - # Copy the logs to the target system - def copy_logs - Yast::WFM.CallFunction("copy_logs_finish", ["Write"]) - end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/dinstaller/package_callbacks.rb new/lib/dinstaller/package_callbacks.rb --- old/lib/dinstaller/package_callbacks.rb 2022-12-05 16:56:00.000000000 +0100 +++ new/lib/dinstaller/package_callbacks.rb 1970-01-01 01:00:00.000000000 +0100 @@ -1,69 +0,0 @@ -# frozen_string_literal: true - -# Copyright (c) [2021] SUSE LLC -# -# All Rights Reserved. -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of version 2 of the GNU General Public License as published -# by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -# more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, contact SUSE LLC. -# -# To contact SUSE LLC about this file by physical or electronic mail, you may -# find current contact information at www.suse.com. - -require "yast" - -Yast.import "Pkg" - -# YaST specific code lives under this namespace -module DInstaller - # This class represents the installer status - class PackageCallbacks - class << self - def setup(pkg_count, progress) - new(pkg_count, progress).setup - end - end - - def initialize(pkg_count, progress) - @total = pkg_count - @installed = 0 - @progress = progress - end - - def setup - Yast::Pkg.CallbackDonePackage( - fun_ref(method(:package_installed), "string (integer, string)") - ) - end - - private - - # @return [DInstaller::Progress] - attr_reader :progress - - def fun_ref(method, signature) - Yast::FunRef.new(method, signature) - end - - # TODO: error handling - def package_installed(_error, _reason) - @installed += 1 - progress.step(msg) - - "" - end - - def msg - "Installing packages (#{@total - @installed} remains)" - end - end -end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/dinstaller/software/callbacks/media.rb new/lib/dinstaller/software/callbacks/media.rb --- old/lib/dinstaller/software/callbacks/media.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/dinstaller/software/callbacks/media.rb 2022-12-22 16:38:27.000000000 +0100 @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +# Copyright (c) [2021] SUSE LLC +# +# All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as published +# by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, contact SUSE LLC. +# +# To contact SUSE LLC about this file by physical or electronic mail, you may +# find current contact information at www.suse.com. + +require "yast" +require "dinstaller/can_ask_question" +require "dinstaller/question" + +Yast.import "Pkg" + +module DInstaller + module Software + module Callbacks + # Callbacks related to media handling + class Media + include CanAskQuestion + + # @param questions_manager [DBus::Clients::QuestionsManager] + # @param logger [Logger] + def initialize(questions_manager, logger) + @questions_manager = questions_manager + @logger = logger + end + + # Register the callbacks + def setup + Yast::Pkg.CallbackMediaChange( + Yast::FunRef.new( + method(:media_change), + "string (string, string, string, string, integer, string, integer, string, " \ + "boolean, list <string>, integer)" + ) + ) + end + + # Media change callback + # + # @return [String] + # @see https://github.com/yast/yast-yast2/blob/19180445ab935a25edd4ae0243aa7a3bcd09c9de/library/packages/src/modules/PackageCallbacks.rb#L620 + # rubocop:disable Metrics/ParameterLists + def media_change(_error_code, error, _url, _product, _current, _current_label, _wanted, + _wanted_label, _double_sided, _devices, _current_device) + question = DInstaller::Question.new( + error, options: [:Retry, :Skip], default_option: :Retry + ) + ask(question) do |q| + logger.info "#{q.text}: #{q.answer}" + + (q.answer == :Retry) ? "" : "S" + end + end + # rubocop:enable Metrics/ParameterLists + + private + + # @return [DBus::Clients::QuestionsManager] + attr_reader :questions_manager + + # @return [Logger] + attr_reader :logger + end + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/dinstaller/software/callbacks/progress.rb new/lib/dinstaller/software/callbacks/progress.rb --- old/lib/dinstaller/software/callbacks/progress.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/dinstaller/software/callbacks/progress.rb 2022-12-22 16:38:27.000000000 +0100 @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +# Copyright (c) [2021] SUSE LLC +# +# All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as published +# by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, contact SUSE LLC. +# +# To contact SUSE LLC about this file by physical or electronic mail, you may +# find current contact information at www.suse.com. + +require "yast" + +Yast.import "Pkg" + +module DInstaller + module Software + module Callbacks + # This class represents the installer status + class Progress + class << self + def setup(pkg_count, progress) + new(pkg_count, progress).setup + end + end + + def initialize(pkg_count, progress) + @total = pkg_count + @installed = 0 + @progress = progress + end + + def setup + Yast::Pkg.CallbackDonePackage( + fun_ref(method(:package_installed), "string (integer, string)") + ) + end + + private + + # @return [DInstaller::Progress] + attr_reader :progress + + def fun_ref(method, signature) + Yast::FunRef.new(method, signature) + end + + # TODO: error handling + def package_installed(_error, _reason) + @installed += 1 + progress.step(msg) + + "" + end + + def msg + "Installing packages (#{@total - @installed} remains)" + end + end + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/dinstaller/software/callbacks/signature.rb new/lib/dinstaller/software/callbacks/signature.rb --- old/lib/dinstaller/software/callbacks/signature.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/dinstaller/software/callbacks/signature.rb 2022-12-22 16:38:27.000000000 +0100 @@ -0,0 +1,113 @@ +# frozen_string_literal: true + +# Copyright (c) [2022] SUSE LLC +# +# All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as published +# by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, contact SUSE LLC. +# +# To contact SUSE LLC about this file by physical or electronic mail, you may +# find current contact information at www.suse.com. + +require "yast" +require "dinstaller/can_ask_question" +require "dinstaller/question" + +Yast.import "Pkg" + +module DInstaller + module Software + module Callbacks + # Callbacks related to signatures handling + class Signature + include CanAskQuestion + + # @param questions_manager [DBus::Clients::QuestionsManager] + # @param logger [Logger] + def initialize(questions_manager, logger) + @questions_manager = questions_manager + @logger = logger + end + + # Register the callbacks + def setup + Yast::Pkg.CallbackAcceptUnsignedFile( + Yast::FunRef.new(method(:accept_unsigned_file), "boolean (string, integer)") + ) + Yast::Pkg.CallbackImportGpgKey( + Yast::FunRef.new(method(:import_gpg_key), "boolean (map <string, any>, integer)") + ) + end + + # Callback to handle unsigned files + # + # @param filename [String] File name + # @param repo_id [Integer] Repository ID. It might be -1 if there is not an associated repo. + def accept_unsigned_file(filename, repo_id) + repo = Yast::Pkg.SourceGeneralData(repo_id) + source = if repo + format( + "The file %{filename} from repository %{repo_name} (%{repo_url})", + filename: filename, repo_name: repo["name"], repo_url: repo["url"] + ) + else + format("The file %{filename}", filename: filename) + end + + message = format( + "%{source} is not digitally signed. The origin and integrity of the file cannot be " \ + "verified. Use it anyway?", source: source + ) + + question = DInstaller::Question.new( + message, options: [:Yes, :No], default_option: :No + ) + ask(question) do |q| + logger.info "#{q.text} #{q.answer}" + q.answer == :Yes + end + end + + # Callback to handle signature verification failures + # + # @param key [Hash] GPG key data (id, name, fingerprint, etc.) + # @param _repo_id [Integer] Repository ID + def import_gpg_key(key, _repo_id) + fingerprint = key["fingerprint"].scan(/.{4}/).join(" ") + message = format( + "The key %{id} (%{name}) with fingerprint %{fingerprint} is unknown. " \ + "Do you want to trust this key?", + id: key["id"], name: key["name"], fingerprint: fingerprint + ) + + question = DInstaller::Question.new( + message, options: [:Trust, :Skip], default_option: :Skip + ) + + ask(question) do |q| + logger.info "#{q.text} #{q.answer}" + q.answer == :Trust + end + end + + private + + # @return [DBus::Clients::QuestionsManager] + attr_reader :questions_manager + + # @return [Logger] + attr_reader :logger + end + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/dinstaller/software/callbacks.rb new/lib/dinstaller/software/callbacks.rb --- old/lib/dinstaller/software/callbacks.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/dinstaller/software/callbacks.rb 2022-12-22 16:38:27.000000000 +0100 @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +# Copyright (c) [2022] SUSE LLC +# +# All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as published +# by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, contact SUSE LLC. +# +# To contact SUSE LLC about this file by physical or electronic mail, you may +# find current contact information at www.suse.com. + +module DInstaller + module Software + # Namespace for software callbacks + module Callbacks + end + end +end + +require "dinstaller/software/callbacks/media" +require "dinstaller/software/callbacks/progress" +require "dinstaller/software/callbacks/signature" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/dinstaller/software/manager.rb new/lib/dinstaller/software/manager.rb --- old/lib/dinstaller/software/manager.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/dinstaller/software/manager.rb 2022-12-22 16:38:27.000000000 +0100 @@ -0,0 +1,262 @@ +# frozen_string_literal: true + +# Copyright (c) [2021] SUSE LLC +# +# All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as published +# by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, contact SUSE LLC. +# +# To contact SUSE LLC about this file by physical or electronic mail, you may +# find current contact information at www.suse.com. + +require "yast" +require "fileutils" +require "dinstaller/config" +require "dinstaller/with_progress" +require "y2packager/product" +require "yast2/arch_filter" +require "dinstaller/software/callbacks" + +Yast.import "Package" +Yast.import "Packages" +Yast.import "PackageCallbacks" +Yast.import "Pkg" +Yast.import "Stage" + +module DInstaller + module Software + # This class is responsible for software handling + class Manager + include WithProgress + + GPG_KEYS_GLOB = "/usr/lib/rpm/gnupg/keys/gpg-*" + private_constant :GPG_KEYS_GLOB + + attr_reader :product + + DEFAULT_LANGUAGES = ["en_US"].freeze + private_constant :DEFAULT_LANGUAGES + + attr_accessor :languages + + # FIXME: what about defining a Product class? + # @return [Array<Array<String,Hash>>] An array containing the product ID and + # additional information in a hash + attr_reader :products + + def initialize(config, logger) + @config = config + @logger = logger + @languages = DEFAULT_LANGUAGES + @products = @config.products + if @config.multi_product? + @product = nil + else + @product = @products.keys.first # use the available product as default + @config.pick_product(@product) + end + end + + def select_product(name) + return if name == @product + raise ArgumentError unless @products[name] + + @config.pick_product(name) + @product = name + end + + def probe + logger.info "Probing software" + + store_original_repos + Yast::Pkg.SetSolverFlags("ignoreAlreadyRecommended" => false, "onlyRequires" => true) + + # as we use liveDVD with normal like ENV, lets temporary switch to normal to use its repos + Yast::Stage.Set("normal") + + start_progress(3) + Yast::PackageCallbacks.InitPackageCallbacks(logger) + progress.step("Initialize target repositories") { initialize_target_repos } + progress.step("Initialize sources") { add_base_repo } + progress.step("Making the initial proposal") do + proposal = Yast::Packages.Proposal(force_reset = true, reinit = false, _simple = true) + logger.info "proposal #{proposal["raw_proposal"]}" + end + + Yast::Stage.Set("initial") + end + + def initialize_target_repos + Yast::Pkg.TargetInitialize("/") + import_gpg_keys + end + + def propose + Yast::Pkg.TargetFinish # ensure that previous target is closed + Yast::Pkg.TargetInitialize(Yast::Installation.destdir) + Yast::Pkg.TargetLoad + Yast::Pkg.SetAdditionalLocales(languages) + select_base_product(@config.data["software"]["base_product"]) + + add_resolvables + proposal = Yast::Packages.Proposal(force_reset = false, reinit = false, _simple = true) + logger.info "proposal #{proposal["raw_proposal"]}" + + solve_dependencies + + # do not return proposal hash, so intentional nil here + nil + end + + def install + start_progress(count_packages) + Callbacks::Progress.setup(count_packages, progress) + + # TODO: error handling + commit_result = Yast::Pkg.Commit({}) + + if commit_result.nil? || commit_result.empty? + logger.error("Commit failed") + raise Yast::Pkg.LastError + end + + logger.info "Commit result #{commit_result}" + rescue DInstaller::WithProgress::NotFinishedProgress => e + logger.error "There is an unfinished progress: #{e.inspect}" + finish_progress + end + + # Writes the repositories information to the installed system + def finish + start_progress(2) + progress.step("Writing repositories to the target system") do + Yast::Pkg.SourceSaveAll + Yast::Pkg.TargetFinish + Yast::Pkg.SourceCacheCopyTo(Yast::Installation.destdir) + end + progress.step("Restoring original repositories") { restore_original_repos } + end + + # Determine whether the given tag is provided by the selected packages + # + # @param tag [String] Tag to search for (package names, requires/provides, or file + # names) + # @return [Boolean] true if it is provided; false otherwise + def provision_selected?(tag) + Yast::Pkg.IsSelected(tag) || Yast::Pkg.IsProvided(tag) + end + + # Determines whether a package is installed + # + # @param name [String] Package name + # @return [Boolean] true if it is installed; false otherwise + def package_installed?(name) + Yast::Package.Installed(name, target: :system) + end + + private + + # adds resolvables from yaml config for given product + def add_resolvables + mandatory_patterns = @config.data["software"]["mandatory_patterns"] || [] + Yast::PackagesProposal.SetResolvables("d-installer", :pattern, mandatory_patterns) + + optional_patterns = @config.data["software"]["optional_patterns"] || [] + Yast::PackagesProposal.SetResolvables("d-installer", :pattern, optional_patterns, + optional: true) + + mandatory_packages = @config.data["software"]["mandatory_packages"] || [] + Yast::PackagesProposal.SetResolvables("d-installer", :package, mandatory_packages) + + optional_packages = @config.data["software"]["optional_packages"] || [] + Yast::PackagesProposal.SetResolvables("d-installer", :package, optional_packages, + optional: true) + end + + # call solver to satisfy dependency or log error + def solve_dependencies + res = Yast::Pkg.PkgSolve(unused = true) + logger.info "solver run #{res.inspect}" + + return if res + + logger.error "Solver failed: #{Yast::Pkg.LastError}" + logger.error "Details: #{Yast::Pkg.LastErrorDetails}" + logger.error "Solving issues: #{Yast::Pkg.PkgSolveErrors}" + end + + # @return [Logger] + attr_reader :logger + + def count_packages + Yast::Pkg.PkgMediaCount.reduce(0) { |sum, res| sum + res.reduce(0, :+) } + end + + def import_gpg_keys + gpg_keys = Dir.glob(GPG_KEYS_GLOB).map(&:to_s) + logger.info "Importing GPG keys: #{gpg_keys}" + gpg_keys.each do |path| + Yast::Pkg.ImportGPGKey(path, true) + end + end + + def add_base_repo + @config.data["software"]["installation_repositories"].each do |repo| + if repo.is_a?(Hash) + url = repo["url"] + # skip if repo is not for current arch + next if repo["archs"] && !Yast2::ArchFilter.from_string(repo["archs"]).match? + else + url = repo + end + Yast::Pkg.SourceCreate(url, "/") # TODO: having that dir also in config? + end + + Yast::Pkg.SourceSaveAll + end + + def select_base_product(name) + base_product = Y2Packager::Product.available_base_products.find do |product| + product.name == name + end + logger.info "Base product to select: #{base_product&.name}" + base_product&.select + end + + REPOS_BACKUP = "/etc/zypp/repos.d.dinstaller.backup" + private_constant :REPOS_BACKUP + + REPOS_DIR = "/etc/zypp/repos.d" + private_constant :REPOS_DIR + + # ensure that repos backup is there and repos.d is empty + def store_original_repos + # Backup was already created, so just remove all repos + if File.directory?(REPOS_BACKUP) + logger.info "removing #{REPOS_DIR}" + FileUtils.rm_rf(REPOS_DIR) + else # move repos to backup + logger.info "moving #{REPOS_DIR} to #{REPOS_BACKUP}" + FileUtils.mv(REPOS_DIR, REPOS_BACKUP) + end + end + + def restore_original_repos + logger.info "removing #{REPOS_DIR}" + FileUtils.rm_rf(REPOS_DIR) + logger.info "moving #{REPOS_BACKUP} to #{REPOS_DIR}" + FileUtils.mv(REPOS_BACKUP, REPOS_DIR) + end + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/dinstaller/software.rb new/lib/dinstaller/software.rb --- old/lib/dinstaller/software.rb 2022-12-05 16:56:00.000000000 +0100 +++ new/lib/dinstaller/software.rb 2022-12-22 16:38:27.000000000 +0100 @@ -1,6 +1,6 @@ # frozen_string_literal: true -# Copyright (c) [2021] SUSE LLC +# Copyright (c) [2022] SUSE LLC # # All Rights Reserved. # @@ -19,238 +19,10 @@ # To contact SUSE LLC about this file by physical or electronic mail, you may # find current contact information at www.suse.com. -require "yast" -require "fileutils" -require "dinstaller/package_callbacks" -require "dinstaller/config" -require "dinstaller/with_progress" -require "y2packager/product" -require "yast2/arch_filter" - -Yast.import "Package" -Yast.import "Packages" -Yast.import "Pkg" -Yast.import "Stage" - -# YaST specific code lives under this namespace module DInstaller - # This class is responsible for software handling - class Software - include WithProgress - - GPG_KEYS_GLOB = "/usr/lib/rpm/gnupg/keys/gpg-*" - private_constant :GPG_KEYS_GLOB - - attr_reader :product - - DEFAULT_LANGUAGES = ["en_US"].freeze - private_constant :DEFAULT_LANGUAGES - - attr_accessor :languages - - # FIXME: what about defining a Product class? - # @return [Array<Array<String,Hash>>] An array containing the product ID and - # additional information in a hash - attr_reader :products - - def initialize(config, logger) - @config = config - @logger = logger - @languages = DEFAULT_LANGUAGES - @products = @config.products - if @config.multi_product? - @product = nil - else - @product = @products.keys.first # use the available product as default - @config.pick_product(@product) - end - end - - def select_product(name) - return if name == @product - raise ArgumentError unless @products[name] - - @config.pick_product(name) - @product = name - end - - def probe - logger.info "Probing software" - - store_original_repos - Yast::Pkg.SetSolverFlags("ignoreAlreadyRecommended" => false, "onlyRequires" => true) - - # as we use liveDVD with normal like ENV, lets temporary switch to normal to use its repos - Yast::Stage.Set("normal") - - start_progress(3) - progress.step("Initialize target repositories") { initialize_target_repos } - progress.step("Initialize sources") { add_base_repo } - progress.step("Making the initial proposal") do - proposal = Yast::Packages.Proposal(force_reset = true, reinit = false, _simple = true) - logger.info "proposal #{proposal["raw_proposal"]}" - end - - Yast::Stage.Set("initial") - end - - def initialize_target_repos - Yast::Pkg.TargetInitialize("/") - import_gpg_keys - end - - def propose - Yast::Pkg.TargetFinish # ensure that previous target is closed - Yast::Pkg.TargetInitialize(Yast::Installation.destdir) - Yast::Pkg.TargetLoad - Yast::Pkg.SetAdditionalLocales(languages) - select_base_product(@config.data["software"]["base_product"]) - - add_resolvables - proposal = Yast::Packages.Proposal(force_reset = false, reinit = false, _simple = true) - logger.info "proposal #{proposal["raw_proposal"]}" - - solve_dependencies - - # do not return proposal hash, so intentional nil here - nil - end - - def install - start_progress(count_packages) - PackageCallbacks.setup(count_packages, progress) - - # TODO: error handling - commit_result = Yast::Pkg.Commit({}) - - if commit_result.nil? || commit_result.empty? - logger.error("Commit failed") - raise Yast::Pkg.LastError - end - - logger.info "Commit result #{commit_result}" - end - - # Writes the repositories information to the installed system - def finish - start_progress(2) - progress.step("Writing repositories to the target system") do - Yast::Pkg.SourceSaveAll - Yast::Pkg.TargetFinish - Yast::Pkg.SourceCacheCopyTo(Yast::Installation.destdir) - end - progress.step("Restoring original repositories") { restore_original_repos } - end - - # Determine whether the given tag is provided by the selected packages - # - # @param tag [String] Tag to search for (package names, requires/provides, or file - # names) - # @return [Boolean] true if it is provided; false otherwise - def provision_selected?(tag) - Yast::Pkg.IsSelected(tag) || Yast::Pkg.IsProvided(tag) - end - - # Determines whether a package is installed - # - # @param name [String] Package name - # @return [Boolean] true if it is installed; false otherwise - def package_installed?(name) - Yast::Package.Installed(name, target: :system) - end - - private - - # adds resolvables from yaml config for given product - def add_resolvables - mandatory_patterns = @config.data["software"]["mandatory_patterns"] || [] - Yast::PackagesProposal.SetResolvables("d-installer", :pattern, mandatory_patterns) - - optional_patterns = @config.data["software"]["optional_patterns"] || [] - Yast::PackagesProposal.SetResolvables("d-installer", :pattern, optional_patterns, - optional: true) - - mandatory_packages = @config.data["software"]["mandatory_packages"] || [] - Yast::PackagesProposal.SetResolvables("d-installer", :package, mandatory_packages) - - optional_packages = @config.data["software"]["optional_packages"] || [] - Yast::PackagesProposal.SetResolvables("d-installer", :package, optional_packages, - optional: true) - end - - # call solver to satisfy dependency or log error - def solve_dependencies - res = Yast::Pkg.PkgSolve(unused = true) - logger.info "solver run #{res.inspect}" - - return if res - - logger.error "Solver failed: #{Yast::Pkg.LastError}" - logger.error "Details: #{Yast::Pkg.LastErrorDetails}" - logger.error "Solving issues: #{Yast::Pkg.PkgSolveErrors}" - end - - # @return [Logger] - attr_reader :logger - - def count_packages - Yast::Pkg.PkgMediaCount.reduce(0) { |sum, res| sum + res.reduce(0, :+) } - end - - def import_gpg_keys - gpg_keys = Dir.glob(GPG_KEYS_GLOB).map(&:to_s) - logger.info "Importing GPG keys: #{gpg_keys}" - gpg_keys.each do |path| - Yast::Pkg.ImportGPGKey(path, true) - end - end - - def add_base_repo - @config.data["software"]["installation_repositories"].each do |repo| - if repo.is_a?(Hash) - url = repo["url"] - # skip if repo is not for current arch - next if repo["archs"] && !Yast2::ArchFilter.from_string(repo["archs"]).match? - else - url = repo - end - Yast::Pkg.SourceCreate(url, "/") # TODO: having that dir also in config? - end - - Yast::Pkg.SourceSaveAll - end - - def select_base_product(name) - base_product = Y2Packager::Product.available_base_products.find do |product| - product.name == name - end - logger.info "Base product to select: #{base_product&.name}" - base_product&.select - end - - REPOS_BACKUP = "/etc/zypp/repos.d.dinstaller.backup" - private_constant :REPOS_BACKUP - - REPOS_DIR = "/etc/zypp/repos.d" - private_constant :REPOS_DIR - - # ensure that repos backup is there and repos.d is empty - def store_original_repos - # Backup was already created, so just remove all repos - if File.directory?(REPOS_BACKUP) - logger.info "removing #{REPOS_DIR}" - FileUtils.rm_rf(REPOS_DIR) - else # move repos to backup - logger.info "moving #{REPOS_DIR} to #{REPOS_BACKUP}" - FileUtils.mv(REPOS_DIR, REPOS_BACKUP) - end - end - - def restore_original_repos - logger.info "removing #{REPOS_DIR}" - FileUtils.rm_rf(REPOS_DIR) - logger.info "moving #{REPOS_BACKUP} to #{REPOS_DIR}" - FileUtils.mv(REPOS_BACKUP, REPOS_DIR) - end + # Namespace for software backend + module Software end end + +require "dinstaller/software/manager" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/dinstaller/storage/manager.rb new/lib/dinstaller/storage/manager.rb --- old/lib/dinstaller/storage/manager.rb 2022-12-05 16:56:00.000000000 +0100 +++ new/lib/dinstaller/storage/manager.rb 2022-12-22 16:38:27.000000000 +0100 @@ -20,6 +20,8 @@ # find current contact information at www.suse.com. require "yast" +require "yast2/execute" +require "yast2/systemd/service" require "bootloader/proposal_client" require "bootloader/finish_client" require "y2storage/storage_manager" @@ -79,17 +81,25 @@ # Unmounts the target file system def finish - start_progress(4) + steps = tpm_key? ? 6 : 5 + start_progress(steps) on_target do progress.step("Writing Linux Security Modules configuration") { security.write } progress.step("Installing bootloader") do - hack_olaf_password ::Bootloader::FinishClient.new.write end + if tpm_key? + progress.step("Preparing the system to unlock the encryption using the TPM") do + prepare_tpm_key + end + end progress.step("Configuring file systems snapshots") do Yast::WFM.CallFunction("snapshots_finish", ["Write"]) end + progress.step("Copying logs") do + Yast::WFM.CallFunction("copy_logs_finish", ["Write"]) + end progress.step("Unmounting storage devices") do Yast::WFM.CallFunction("umount_finish", ["Write"]) end @@ -175,38 +185,60 @@ @software ||= DBus::Clients::Software.new end - # Temporary method for testing FDE during early development - def hack_olaf_password - password = config.data.fetch("security", {})["olaf_luks2_password"] - return if password.nil? || password.empty? - - grub_path = File.join(Yast::Installation.destdir, "etc", "default", "grub") - File.open(grub_path, "a") do |file| - file.puts "GRUB_CRYPTODISK_PASSWORD=\"#{password}\"" - end + def tpm_key? + tpm_product? && tpm_proposal? && tpm_system? + end - hack_jeos_firstboot + def tpm_proposal? + settings = proposal.calculated_settings + settings.encrypt? && !settings.lvm end - # @see #hack_olaf_password - # - # This assumes the package jeos-firstboot has been installed - def hack_jeos_firstboot - require "yast2/systemd/service" - require "fileutils" - destdir = Yast::Installation.destdir + def tpm_system? + Y2Storage::Arch.new.efiboot? && tpm_present? + end + + def tpm_present? + return @tpm_present unless @tpm_present.nil? + + @tpm_present = + begin + execute_fdectl("tpm-present") + logger.info "FDE: TPMv2 detected" + true + rescue Cheetah::ExecutionFailed + logger.info "FDE: TPMv2 not detected" + false + end + end + + def tpm_product? + config.data.fetch("security", {}).fetch("tpm_luks_open", false) + end + + def prepare_tpm_key + keyfile_path = File.join(Yast::Installation.destdir, "root", ".root.keyfile") + execute_fdectl( + "add-secondary-key", "--keyfile", keyfile_path, + stdin: "#{proposal.calculated_settings.encryption_password}\n", + recorder: Yast::ReducedRecorder.new(skip: :stdin) + ) - service = Yast2::Systemd::Service.find("jeos-firstboot") + service = Yast2::Systemd::Service.find("fde-tpm-enroll.service") + logger.info "FDE: TPM enroll service: #{service}" service&.enable + rescue Cheetah::ExecutionFailed + false + end - reconfig_path = File.join(destdir, "var", "lib", "YaST2") - FileUtils.mkdir_p(reconfig_path) - FileUtils.touch(File.join(reconfig_path, "reconfig_system")) - - jeos_path = File.join(destdir, "etc", "jeos-firstboot.conf") - File.open(jeos_path, "a") do |file| - file.puts "JEOS_PASSWORD_ALREADY_SET='yes'" - end + def execute_fdectl(*args) + # Some subcommands like "tpm-present" should not require a --device argument, but they + # currently do. Let's always us until the problem at fdectl is fully fixed. + Yast::Execute.locally!("fdectl", "--device", fdectl_device, *args) + end + + def fdectl_device + Yast::Installation.destdir end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/dinstaller/storage/proposal.rb new/lib/dinstaller/storage/proposal.rb --- old/lib/dinstaller/storage/proposal.rb 2022-12-05 16:56:00.000000000 +0100 +++ new/lib/dinstaller/storage/proposal.rb 2022-12-22 16:38:27.000000000 +0100 @@ -123,7 +123,6 @@ settings ||= ProposalSettings.new settings.freeze proposal_settings = to_y2storage_settings(settings) - hack_olaf_password(proposal_settings) @proposal = new_proposal(proposal_settings) storage_manager.proposal = proposal @@ -296,16 +295,6 @@ # Setting #linux_delete_mode to :all is not enough to prevent VG reusing in all cases settings.lvm_vg_reuse = false end - - # Temporary method for testing FDE during early development - # - # @param settings [Y2Storage::ProposalSettings] - def hack_olaf_password(settings) - password = config.data.fetch("security", {})["olaf_luks2_password"] - return if password.nil? || password.empty? - - settings.encryption_password = password - end end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/dinstaller/storage/proposal_settings.rb new/lib/dinstaller/storage/proposal_settings.rb --- old/lib/dinstaller/storage/proposal_settings.rb 2022-12-05 16:56:00.000000000 +0100 +++ new/lib/dinstaller/storage/proposal_settings.rb 2022-12-22 16:38:27.000000000 +0100 @@ -55,6 +55,13 @@ @candidate_devices = [] @volumes = [] end + + # Whether the proposal must create encrypted devices + # + # @return [Boolean] + def encrypt? + !(encryption_password.nil? || encryption_password.empty?) + end end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/dinstaller/with_progress.rb new/lib/dinstaller/with_progress.rb --- old/lib/dinstaller/with_progress.rb 2022-12-05 16:56:00.000000000 +0100 +++ new/lib/dinstaller/with_progress.rb 2022-12-22 16:38:27.000000000 +0100 @@ -24,6 +24,9 @@ module DInstaller # Mixin that allows to start a progress and configure callbacks module WithProgress + # There is an unfinished progress + class NotFinishedProgress < StandardError; end + # @return [Progress, nil] attr_reader :progress @@ -33,7 +36,7 @@ # # @param total_steps [Integer] total number of the steps for the progress. def start_progress(total_steps) - raise "There already is an unfinished progress" if progress && !progress.finished? + raise NotFinishedProgress if progress && !progress.finished? on_change_callbacks = @on_progress_change_callbacks || [] on_finish_callbacks = @on_progress_finish_callbacks || [] @@ -44,6 +47,13 @@ end end + # Finishes the current progress + def finish_progress + return if progress.nil? || progress.finished? + + progress.finish + end + # Registers an on_change callback to be added to the progress # # @param block [Proc] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/metadata new/metadata --- old/metadata 2022-12-05 16:56:00.000000000 +0100 +++ new/metadata 2022-12-22 16:38:27.000000000 +0100 @@ -1,14 +1,14 @@ --- !ruby/object:Gem::Specification name: d-installer version: !ruby/object:Gem::Version - version: '0.6' + version: 0.6.2 platform: ruby authors: - YaST Team autorequire: bindir: bin cert_chain: [] -date: 2022-12-05 00:00:00.000000000 Z +date: 2022-12-22 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: packaging_rake_tasks @@ -261,6 +261,7 @@ - lib/dinstaller/dbus/y2dir/manager/modules/Package.rb - lib/dinstaller/dbus/y2dir/manager/modules/PackagesProposal.rb - lib/dinstaller/dbus/y2dir/modules/Autologin.rb +- lib/dinstaller/dbus/y2dir/software/modules/PackageCallbacks.rb - lib/dinstaller/dbus/y2dir/software/modules/SpaceCalculation.rb - lib/dinstaller/dbus/y2dir/storage/modules/Package.rb - lib/dinstaller/dbus/y2dir/storage/modules/PackagesProposal.rb @@ -271,13 +272,17 @@ - lib/dinstaller/luks_activation_question.rb - lib/dinstaller/manager.rb - lib/dinstaller/network.rb -- lib/dinstaller/package_callbacks.rb - lib/dinstaller/progress.rb - lib/dinstaller/question.rb - lib/dinstaller/questions_manager.rb - lib/dinstaller/security.rb - lib/dinstaller/service_status_recorder.rb - lib/dinstaller/software.rb +- lib/dinstaller/software/callbacks.rb +- lib/dinstaller/software/callbacks/media.rb +- lib/dinstaller/software/callbacks/progress.rb +- lib/dinstaller/software/callbacks/signature.rb +- lib/dinstaller/software/manager.rb - lib/dinstaller/storage.rb - lib/dinstaller/storage/actions.rb - lib/dinstaller/storage/callbacks.rb ++++++ gem2rpm.yml ++++++ --- /var/tmp/diff_new_pack.I0RFIC/_old 2022-12-23 10:21:39.231532553 +0100 +++ /var/tmp/diff_new_pack.I0RFIC/_new 2022-12-23 10:21:39.235532576 +0100 @@ -1,8 +1,8 @@ --- :sourceurl: "%{mod_full_name}.gem" :preamble: |- - BuildRequires: pkgconfig(dbus-1) - Requires: pkgconfig(dbus-1) + BuildRequires: dbus-1-common + Requires: dbus-1-common Requires: snapper Requires: yast2-bootloader Requires: yast2-country