Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package yast2-users for openSUSE:Factory 
checked in at 2023-06-14 16:28:33
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/yast2-users (Old)
 and      /work/SRC/openSUSE:Factory/.yast2-users.new.15902 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "yast2-users"

Wed Jun 14 16:28:33 2023 rev:256 rq:1092599 version:4.6.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/yast2-users/yast2-users.changes  2023-04-04 
21:17:16.067984403 +0200
+++ /work/SRC/openSUSE:Factory/.yast2-users.new.15902/yast2-users.changes       
2023-06-14 16:28:35.130190183 +0200
@@ -1,0 +2,10 @@
+Wed Jun  7 16:22:59 UTC 2023 - Imobach Gonzalez Sosa <[email protected]>
+
+- Write the users when using AutoYaST on an installed system
+  (bsc#1211753).
+- Move Ruby classes in Yast::Users (SSHAuthorizedKeysFile and
+  SSHAuthorizedKeyring) to the Y2Users module to remove duplication
+  Yast::Users Perl module.
+- 4.6.2
+
+-------------------------------------------------------------------

Old:
----
  yast2-users-4.6.1.tar.bz2

New:
----
  yast2-users-4.6.2.tar.bz2

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ yast2-users.spec ++++++
--- /var/tmp/diff_new_pack.egPkCR/_old  2023-06-14 16:28:37.658205723 +0200
+++ /var/tmp/diff_new_pack.egPkCR/_new  2023-06-14 16:28:37.710206042 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           yast2-users
-Version:        4.6.1
+Version:        4.6.2
 Release:        0
 Summary:        YaST2 - User and Group Configuration
 License:        GPL-2.0-only

++++++ yast2-users-4.6.1.tar.bz2 -> yast2-users-4.6.2.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-users-4.6.1/package/yast2-users.changes 
new/yast2-users-4.6.2/package/yast2-users.changes
--- old/yast2-users-4.6.1/package/yast2-users.changes   2023-04-03 
13:48:38.000000000 +0200
+++ new/yast2-users-4.6.2/package/yast2-users.changes   2023-06-12 
16:19:35.000000000 +0200
@@ -1,4 +1,14 @@
 -------------------------------------------------------------------
+Wed Jun  7 16:22:59 UTC 2023 - Imobach Gonzalez Sosa <[email protected]>
+
+- Write the users when using AutoYaST on an installed system
+  (bsc#1211753).
+- Move Ruby classes in Yast::Users (SSHAuthorizedKeysFile and
+  SSHAuthorizedKeyring) to the Y2Users module to remove duplication
+  Yast::Users Perl module.
+- 4.6.2
+
+-------------------------------------------------------------------
 Thu Mar 23 14:04:54 UTC 2023 - Ancor Gonzalez Sosa <[email protected]>
 
 - Stop mangling the value of "Create as Btrfs Subvolume" for new
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-users-4.6.1/package/yast2-users.spec 
new/yast2-users-4.6.2/package/yast2-users.spec
--- old/yast2-users-4.6.1/package/yast2-users.spec      2023-04-03 
13:48:38.000000000 +0200
+++ new/yast2-users-4.6.2/package/yast2-users.spec      2023-06-12 
16:19:35.000000000 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           yast2-users
-Version:        4.6.1
+Version:        4.6.2
 Release:        0
 Summary:        YaST2 - User and Group Configuration
 License:        GPL-2.0-only
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-users-4.6.1/src/lib/users/clients/auto.rb 
new/yast2-users-4.6.2/src/lib/users/clients/auto.rb
--- old/yast2-users-4.6.1/src/lib/users/clients/auto.rb 2023-04-03 
13:48:38.000000000 +0200
+++ new/yast2-users-4.6.2/src/lib/users/clients/auto.rb 2023-06-12 
16:19:35.000000000 +0200
@@ -22,6 +22,11 @@
 require "y2users"
 require "y2users/autoinst/reader"
 require "y2issues"
+require "y2users/config_merger"
+require "y2users/config_manager"
+require "y2users/autoinst/reader"
+require "y2users/users_module/reader"
+require "y2users/linux/writer"
 
 Yast.import "Users"
 Yast.import "Linuxrc"
@@ -90,15 +95,33 @@
       end
 
       # @note This code is not executed during autoinstallation (instead, the
-      # users_finish is used). However, it is used when running ayast_setup.
+      # users_finish is used). However, it is used when running ayast_setup
+      # or using the AutoYaST UI.
+      #
+      # When working on an already installed system, the process of detecting
+      # which users/groups changed is tricky:
+      #
+      # * The approach followed by 
[Y2Users::UsersModule::Reader](https://github.com/yast/yast-users/blob/414b6c7373068c367c0a01be20a1399fbd0ef470/src/lib/y2users/users_module/reader.rb#L103),
+      #   checking the content of `org_user`, does not work because it is 
defined
+      #   only if the user was modified using the AutoYaST UI.
+      # * Directly comparing the users/groups from `system_config` and
+      #   `target_config` does not work because passwords are missing from the
+      #   `target_config` users.
+      #
+      # To overcome these limitations, we only consider those users/groups
+      # which 'modified' property is not nil, although it does not guarantee
+      # that they changed at all.
       #
       # @return [Boolean] true if configuration was changed; false otherwise.
       def write
-        Yast::Users.SetWriteOnly(true)
-        progress_orig = Yast::Progress.set(false)
-        ret = Yast::Users.Write == ""
-        Yast::Progress.set(progress_orig)
-        ret
+        system_config = Y2Users::ConfigManager.instance.system(force_read: 
true)
+        new_config = system_config.copy
+        _, target_config = Y2Users::UsersModule::Reader.new.read
+        remove_unchanged_elements(target_config)
+        Y2Users::ConfigMerger.new(new_config, target_config).merge
+        writer = Y2Users::Linux::Writer.new(new_config, system_config)
+        issues = writer.write
+        issues.empty?
       end
 
       def modified?
@@ -149,6 +172,23 @@
 
         root_user
       end
+
+      # Clean users and groups that have not changed according to the 
'modified' attributes
+      #
+      # @param config [Y2Users::Config] Configuration to clean
+      def remove_unchanged_elements(config)
+        all_users = Yast::Users.GetUsers("uid", "local").values +
+          Yast::Users.GetUsers("uid", "system").values
+        uids = all_users.select { |u| u["modified"] }.map { |u| u["uid"] }
+        users = config.users.reject { |u| uids.include?(u.name) }
+
+        all_groups = Yast::Users.GetGroups("cn", "local").values +
+          Yast::Users.GetGroups("cn", "system").values
+        gids = all_groups.select { |g| g["modified"] }.map { |g| g["cn"] }
+        groups = config.groups.reject { |g| gids.include?(g.name) }
+
+        (users + groups).each { |e| config.detach(e) }
+      end
     end
   end
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-users-4.6.1/src/lib/users/ssh_authorized_keyring.rb 
new/yast2-users-4.6.2/src/lib/users/ssh_authorized_keyring.rb
--- old/yast2-users-4.6.1/src/lib/users/ssh_authorized_keyring.rb       
2023-04-03 13:48:38.000000000 +0200
+++ new/yast2-users-4.6.2/src/lib/users/ssh_authorized_keyring.rb       
2023-06-12 16:19:35.000000000 +0200
@@ -19,220 +19,218 @@
 require "yast"
 require "users/ssh_authorized_keys_file"
 
-module Yast
-  module Users
-    # Read, write and store SSH authorized keys.
-    #
-    # This class manages authorized keys for a home directory in the system.
-    class SSHAuthorizedKeyring
-      include Logger
-
-      # @return [Array<String>] List of authorized keys
-      attr_reader :keys
-      # @return [String] Home directory path
-      attr_reader :home
-
-      # Base class to use in file/directory problems
-      class PathError < StandardError
-        # @return [String] Path
-        attr_reader :path
-
-        # Constructor
-        #
-        # @param path [String] Path
-        def initialize(path)
-          @path = path
-          super(default_message)
-        end
-
-        # @return [String] Error message
-        def message
-          "#{super}: #{path}"
-        end
-
-        # Returns the default message to be used
-        #
-        # Derived classes should implement it.
-        #
-        # @return [String] Default message
-        def default_message
-          "Path error"
-        end
-      end
-
-      # The home directory does not exist.
-      class HomeDoesNotExist < PathError
-        # @return [String] Default error message
-        def default_message
-          "Home directory does not exist"
-        end
-      end
-
-      # The user's SSH configuration directory could not be created.
-      class CouldNotCreateSSHDirectory < PathError
-        # @return [String] Default error message
-        def default_message
-          "SSH directory could not be created"
-        end
-      end
-
-      # The user's SSH configuration directory is a link (potentially 
insecure).
-      class NotRegularSSHDirectory < PathError
-        # @return [String] Default error message
-        def default_message
-          "SSH directory is not a regular directory"
-        end
-      end
-
-      # The authorized_keys is not a regular file (potentially insecure).
-      class NotRegularAuthorizedKeysFile < PathError
-        # @return [String] Default error message
-        def default_message
-          "authorized_keys is not a regular file"
-        end
-      end
+module Y2Users
+  # Read, write and store SSH authorized keys.
+  #
+  # This class manages authorized keys for a home directory in the system.
+  class SSHAuthorizedKeyring
+    include Yast::Logger
+
+    # @return [Array<String>] List of authorized keys
+    attr_reader :keys
+    # @return [String] Home directory path
+    attr_reader :home
+
+    # Base class to use in file/directory problems
+    class PathError < StandardError
+      # @return [String] Yast::Path
+      attr_reader :path
 
       # Constructor
       #
-      # @param home [String] path to the user home where keys will be written
-      # @param keys [Array<String>] List of authorized keys, empty by default
-      def initialize(home, keys = [])
-        @keys = keys
-        @old_keys = keys
-        @home = home
+      # @param path [String] Yast::Path
+      def initialize(path)
+        @path = path
+        super(default_message)
+      end
+
+      # @return [String] Error message
+      def message
+        "#{super}: #{path}"
       end
 
-      # Add/register a keys
+      # Returns the default message to be used
       #
-      # This method does not make any change to the system. For that,
-      # see #write_keys.
+      # Derived classes should implement it.
       #
-      # @return [Array<String>] Registered authorized keys
-      def add_keys(new_keys)
-        @keys |= new_keys.compact
+      # @return [String] Default message
+      def default_message
+        "Yast::Path error"
       end
+    end
 
-      # Determines if the keyring is empty
-      #
-      # @return [Boolean] +true+ if it's empty; +false+ otherwise
-      def empty?
-        keys.empty?
+    # The home directory does not exist.
+    class HomeDoesNotExist < PathError
+      # @return [String] Default error message
+      def default_message
+        "Home directory does not exist"
       end
+    end
 
-      # Determines if the keyring has changed
-      #
-      # @return [Boolean] +true+ if it has changed; +false+ otherwise
-      def changed?
-        @keys != @old_keys
+    # The user's SSH configuration directory could not be created.
+    class CouldNotCreateSSHDirectory < PathError
+      # @return [String] Default error message
+      def default_message
+        "SSH directory could not be created"
       end
+    end
 
-      # Read keys from a given home directory and add them to the keyring
-      #
-      # @return [Array<String>] List of authorized keys
-      def read_keys
-        path = authorized_keys_path
-        @old_keys = FileUtils::Exists(path) ? 
SSHAuthorizedKeysFile.new(path).keys : []
-        log.info "Read #{@old_keys.size} keys from #{path}"
-        @keys = @old_keys.dup
+    # The user's SSH configuration directory is a link (potentially insecure).
+    class NotRegularSSHDirectory < PathError
+      # @return [String] Default error message
+      def default_message
+        "SSH directory is not a regular directory"
       end
+    end
 
-      # Write user keys to the given file
-      #
-      # If SSH_DIR does not exist in the given directory, it will be
-      # created inheriting owner/group and setting permissions to SSH_DIR_PERM.
-      def write_keys
-        return unless changed?
+    # The authorized_keys is not a regular file (potentially insecure).
+    class NotRegularAuthorizedKeysFile < PathError
+      # @return [String] Default error message
+      def default_message
+        "authorized_keys is not a regular file"
+      end
+    end
 
-        remove_authorized_keys_file
+    # Constructor
+    #
+    # @param home [String] path to the user home where keys will be written
+    # @param keys [Array<String>] List of authorized keys, empty by default
+    def initialize(home, keys = [])
+      @keys = keys
+      @old_keys = keys
+      @home = home
+    end
 
-        return if keys.empty?
+    # Add/register a keys
+    #
+    # This method does not make any change to the system. For that,
+    # see #write_keys.
+    #
+    # @return [Array<String>] Registered authorized keys
+    def add_keys(new_keys)
+      @keys |= new_keys.compact
+    end
 
-        if !FileUtils::Exists(home)
-          log.error("Home directory '#{home}' does not exist!")
-          raise HomeDoesNotExist, home
-        end
+    # Determines if the keyring is empty
+    #
+    # @return [Boolean] +true+ if it's empty; +false+ otherwise
+    def empty?
+      keys.empty?
+    end
 
-        user = FileUtils::GetOwnerUserID(home)
-        group = FileUtils::GetOwnerGroupID(home)
-        create_ssh_dir(user, group)
-        write_file(user, group)
-      end
+    # Determines if the keyring has changed
+    #
+    # @return [Boolean] +true+ if it has changed; +false+ otherwise
+    def changed?
+      @keys != @old_keys
+    end
 
-    private
+    # Read keys from a given home directory and add them to the keyring
+    #
+    # @return [Array<String>] List of authorized keys
+    def read_keys
+      path = authorized_keys_path
+      @old_keys = Yast::FileUtils::Exists(path) ? 
Y2Users::SSHAuthorizedKeysFile.new(path).keys : []
+      log.info "Read #{@old_keys.size} keys from #{path}"
+      @keys = @old_keys.dup
+    end
 
-      # @return [String] Relative path to the SSH directory inside users' home
-      SSH_DIR = ".ssh".freeze
-      # @return [String] Authorized keys file name
-      AUTHORIZED_KEYS_FILE = "authorized_keys".freeze
-      # @return [String] Permissions to be set on SSH_DIR directory
-      SSH_DIR_PERMS = "0700".freeze
+    # Write user keys to the given file
+    #
+    # If SSH_DIR does not exist in the given directory, it will be
+    # created inheriting owner/group and setting permissions to SSH_DIR_PERM.
+    def write_keys
+      return unless changed?
 
-      # Determine the path to the user's SSH directory
-      #
-      # @return [String] Path to the user's SSH directory
-      #
-      # @see SSH_DIR
-      def ssh_dir_path
-        @ssh_dir_path ||= File.join(home, SSH_DIR)
-      end
+      remove_authorized_keys_file
 
-      # Determine the path to the user's authorized keys file
-      #
-      # @return [String] Path to authorized keys file
-      #
-      # @see SSH_DIR
-      # @see AUTHORIZED_KEYS_FILE
-      #
-      # @see #ssh_dir_path
-      def authorized_keys_path
-        @authorized_keys_path ||= File.join(ssh_dir_path, AUTHORIZED_KEYS_FILE)
+      return if keys.empty?
+
+      if !Yast::FileUtils::Exists(home)
+        log.error("Home directory '#{home}' does not exist!")
+        raise HomeDoesNotExist, home
       end
 
-      # Find or creates the SSH directory
-      #
-      # This method sets up the SSH directory (usually .ssh). Although only 1
-      # level is needed (as SSH directory lives under $HOME/.ssh), this code
-      # should support changing SSH_DIR to something like `.config/ssh`.
-      #
-      # @param user  [Fixnum] Users's UID
-      # @param group [Fixnum] Group's GID
-      # @return [String] Returns the path to the first created directory
-      #
-      # @raise NotRegularSSHDirectory
-      # @raise CouldNotCreateSSHDirectory
-      def create_ssh_dir(user, group)
-        if FileUtils::Exists(ssh_dir_path)
-          raise NotRegularSSHDirectory, ssh_dir_path unless 
FileUtils::IsDirectory(ssh_dir_path)
-
-          return ssh_dir_path
-        end
-        ret = SCR.Execute(Path.new(".target.mkdir"), ssh_dir_path)
-        log.info("Creating SSH directory: #{ret}")
-        raise CouldNotCreateSSHDirectory, ssh_dir_path unless ret
+      user = Yast::FileUtils::GetOwnerUserID(home)
+      group = Yast::FileUtils::GetOwnerGroupID(home)
+      create_ssh_dir(user, group)
+      write_file(user, group)
+    end
 
-        FileUtils::Chown("#{user}:#{group}", ssh_dir_path, false) &&
-          FileUtils::Chmod(SSH_DIR_PERMS, ssh_dir_path, false)
-      end
+  private
 
-      # Write authorized keys file
-      #
-      # @param owner [Fixnum] Users's UID
-      # @param group [Fixnum] Group's GID
-      def write_file(owner, group)
-        file = SSHAuthorizedKeysFile.new(authorized_keys_path)
-        file.keys = keys
-        log.info "Writing #{keys.size} keys in #{authorized_keys_path}"
-        file.save && FileUtils::Chown("#{owner}:#{group}", 
authorized_keys_path, false)
-      rescue SSHAuthorizedKeysFile::NotRegularFile
-        raise NotRegularAuthorizedKeysFile, authorized_keys_path
-      end
-
-      # Remove the authorized keys file
-      def remove_authorized_keys_file
-        return unless FileUtils::Exists(authorized_keys_path)
+    # @return [String] Relative path to the SSH directory inside users' home
+    SSH_DIR = ".ssh".freeze
+    # @return [String] Authorized keys file name
+    AUTHORIZED_KEYS_FILE = "authorized_keys".freeze
+    # @return [String] Permissions to be set on SSH_DIR directory
+    SSH_DIR_PERMS = "0700".freeze
 
-        SCR.Execute(Path.new(".target.remove"), authorized_keys_path)
-      end
+    # Determine the path to the user's SSH directory
+    #
+    # @return [String] Yast::Path to the user's SSH directory
+    #
+    # @see SSH_DIR
+    def ssh_dir_path
+      @ssh_dir_path ||= File.join(home, SSH_DIR)
+    end
+
+    # Determine the path to the user's authorized keys file
+    #
+    # @return [String] Yast::Path to authorized keys file
+    #
+    # @see SSH_DIR
+    # @see AUTHORIZED_KEYS_FILE
+    #
+    # @see #ssh_dir_path
+    def authorized_keys_path
+      @authorized_keys_path ||= File.join(ssh_dir_path, AUTHORIZED_KEYS_FILE)
+    end
+
+    # Find or creates the SSH directory
+    #
+    # This method sets up the SSH directory (usually .ssh). Although only 1
+    # level is needed (as SSH directory lives under $HOME/.ssh), this code
+    # should support changing SSH_DIR to something like `.config/ssh`.
+    #
+    # @param user  [Fixnum] Users's UID
+    # @param group [Fixnum] Group's GID
+    # @return [String] Returns the path to the first created directory
+    #
+    # @raise NotRegularSSHDirectory
+    # @raise CouldNotCreateSSHDirectory
+    def create_ssh_dir(user, group)
+      if Yast::FileUtils::Exists(ssh_dir_path)
+        raise NotRegularSSHDirectory, ssh_dir_path unless 
Yast::FileUtils::IsDirectory(ssh_dir_path)
+
+        return ssh_dir_path
+      end
+      ret = Yast::SCR.Execute(Yast::Path.new(".target.mkdir"), ssh_dir_path)
+      log.info("Creating SSH directory: #{ret}")
+      raise CouldNotCreateSSHDirectory, ssh_dir_path unless ret
+
+      Yast::FileUtils::Chown("#{user}:#{group}", ssh_dir_path, false) &&
+        Yast::FileUtils::Chmod(SSH_DIR_PERMS, ssh_dir_path, false)
+    end
+
+    # Write authorized keys file
+    #
+    # @param owner [Fixnum] Users's UID
+    # @param group [Fixnum] Group's GID
+    def write_file(owner, group)
+      file = Y2Users::SSHAuthorizedKeysFile.new(authorized_keys_path)
+      file.keys = keys
+      log.info "Writing #{keys.size} keys in #{authorized_keys_path}"
+      file.save && Yast::FileUtils::Chown("#{owner}:#{group}", 
authorized_keys_path, false)
+    rescue Y2Users::SSHAuthorizedKeysFile::NotRegularFile
+      raise NotRegularAuthorizedKeysFile, authorized_keys_path
+    end
+
+    # Remove the authorized keys file
+    def remove_authorized_keys_file
+      return unless Yast::FileUtils::Exists(authorized_keys_path)
+
+      Yast::SCR.Execute(Yast::Path.new(".target.remove"), authorized_keys_path)
     end
   end
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-users-4.6.1/src/lib/users/ssh_authorized_keys_file.rb 
new/yast2-users-4.6.2/src/lib/users/ssh_authorized_keys_file.rb
--- old/yast2-users-4.6.1/src/lib/users/ssh_authorized_keys_file.rb     
2023-04-03 13:48:38.000000000 +0200
+++ new/yast2-users-4.6.2/src/lib/users/ssh_authorized_keys_file.rb     
2023-06-12 16:19:35.000000000 +0200
@@ -20,111 +20,111 @@
 
 Yast.import "FileUtils"
 
-module Yast
-  module Users
-    # Represents a `authorized_keys` SSH file.
-    #
-    # @example Adding a key to a file
-    #   path = "/home/user/.ssh/authorized_keys"
-    #   file = SSHAuthorizedKeysFile.new(path) #=> #<SSHAuthorizedKeysFile:...>
-    #   file.add_key("ssh-rsa 123ABC") #=> true
-    #   file.save #=> true
-    #
-    # @example Creating a new authorized_keys file
-    #   path = "/home/user/.ssh/authorized_keys2"
-    #   file = SSHAuthorizedKeysFile.new(path) #=> #<SSHAuthorizedKeysFile:...>
-    #   file.keys = ["ssh-rsa 123ABC"] #=> true
-    #   file.save #=> true
-    #
-    # @see man sshd(8)
-    class SSHAuthorizedKeysFile
-      include Logger
-
-      # @return [Pathname,String] Path to the file
-      attr_reader :path
-
-      # authorized_keys exists but it's not a regular file
-      class NotRegularFile < StandardError; end
-
-      # Constructor
-      #
-      # @param path [Pathname,String] Path to the file
-      def initialize(path)
-        @path = path.to_s
-      end
+module Y2Users
+  # Represents a `authorized_keys` SSH file.
+  #
+  # @example Adding a key to a file
+  #   path = "/home/user/.ssh/authorized_keys"
+  #   file = SSHAuthorizedKeysFile.new(path) #=> #<SSHAuthorizedKeysFile:...>
+  #   file.add_key("ssh-rsa 123ABC") #=> true
+  #   file.save #=> true
+  #
+  # @example Creating a new authorized_keys file
+  #   path = "/home/user/.ssh/authorized_keys2"
+  #   file = SSHAuthorizedKeysFile.new(path) #=> #<SSHAuthorizedKeysFile:...>
+  #   file.keys = ["ssh-rsa 123ABC"] #=> true
+  #   file.save #=> true
+  #
+  # @see man sshd(8)
+  class SSHAuthorizedKeysFile
+    include Yast::Logger
 
-      # Return the authorized keys present in the file
-      #
-      # @return [Array<String>] Array of keys
-      def keys
-        return @keys if @keys
-
-        content = SCR.Read(Path.new(".target.string"), path)
-        self.keys = content.nil? ? [] : content.split("\n")
-        @keys
-      end
+    # @return [Pathname,String] Path to the file
+    attr_reader :path
 
-      # Validate and add a key to the keyring
-      #
-      # The key is validated before adding it to the keyring.
-      #
-      # @param key [String] String that represents the key
-      # @return [Boolean] +true+ if the key was added; +false+ otherwise
-      def add_key(key)
-        new_key = key.strip
-
-        # Ignores comments or empty lines given as key
-        return if new_key.empty? || new_key.start_with?("#")
-
-        if valid_key?(new_key)
-          keys << new_key
-          true
-        else
-          log.warn("The key '#{key}' does not look like a valid SSH key")
-          false
-        end
-      end
+    # authorized_keys exists but it's not a regular file
+    class NotRegularFile < StandardError; end
 
-      # Set the authorized keys in the file
-      #
-      # It won't write the new keys to the file. For that, check the #save
-      # method.
-      #
-      # @param new_keys [Array<String>] SSH authorized keys
-      # @return [Array<String>] SSH authorized keys
-      #
-      # @see #save
-      # @see #keys
-      def keys=(new_keys)
-        @keys = []
-        new_keys.each { |k| add_key(k) }
-        keys
-      end
+    # Constructor
+    #
+    # @param path [Pathname,String] Path to the file
+    def initialize(path)
+      @path = path.to_s
+    end
 
-      # 
https://github.com/puppetlabs/puppet/blob/master/lib/puppet/type/ssh_authorized_key.rb#L138
-      AUTHORIZED_KEYS_REGEX =
-        /\A(?<env>(.+)\s+)?(?<type>(ssh|ecdsa)-\S+)\s+(?<key>[^ 
]+)\s*(?<comment>.*)\z/.freeze
-
-      # Determine is a string qualifies like a valid key
-      #
-      # @param key [String] SSH authorized keys
-      # @return [Boolean] +true+ if it's valid; +false+ otherwise
-      def valid_key?(key)
-        AUTHORIZED_KEYS_REGEX.match(key)
+    # Return the authorized keys present in the file
+    #
+    # @return [Array<String>] Array of keys
+    def keys
+      return @keys if @keys
+
+      content = Yast::SCR.Read(Yast::Path.new(".target.string"), path)
+      self.keys = content.nil? ? [] : content.split("\n")
+      @keys
+    end
+
+    # Validate and add a key to the keyring
+    #
+    # The key is validated before adding it to the keyring.
+    #
+    # @param key [String] String that represents the key
+    # @return [Boolean] +true+ if the key was added; +false+ otherwise
+    def add_key(key)
+      new_key = key.strip
+
+      # Ignores comments or empty lines given as key
+      return if new_key.empty? || new_key.start_with?("#")
+
+      if valid_key?(new_key)
+        keys << new_key
+        true
+      else
+        log.warn("The key '#{key}' does not look like a valid SSH key")
+        false
       end
+    end
+
+    # Set the authorized keys in the file
+    #
+    # It won't write the new keys to the file. For that, check the #save
+    # method.
+    #
+    # @param new_keys [Array<String>] SSH authorized keys
+    # @return [Array<String>] SSH authorized keys
+    #
+    # @see #save
+    # @see #keys
+    def keys=(new_keys)
+      @keys = []
+      new_keys.each { |k| add_key(k) }
+      keys
+    end
 
-      # Write keys to the file
-      #
-      # @return [Boolean] +true+ if file was written; +false+ otherwise.
-      def save
-        if FileUtils::Exists(path)
-          raise NotRegularFile unless FileUtils::IsFile(path)
-        else
-          SCR.Execute(Path.new(".target.bash"), "umask 0077 && /usr/bin/touch 
#{path.shellescape}")
-        end
-        content = keys.join("\n") + "\n"
-        SCR.Write(Path.new(".target.string"), path, content)
+    # 
https://github.com/puppetlabs/puppet/blob/master/lib/puppet/type/ssh_authorized_key.rb#L138
+    AUTHORIZED_KEYS_REGEX =
+      /\A(?<env>(.+)\s+)?(?<type>(ssh|ecdsa)-\S+)\s+(?<key>[^ 
]+)\s*(?<comment>.*)\z/.freeze
+
+    # Determine is a string qualifies like a valid key
+    #
+    # @param key [String] SSH authorized keys
+    # @return [Boolean] +true+ if it's valid; +false+ otherwise
+    def valid_key?(key)
+      AUTHORIZED_KEYS_REGEX.match(key)
+    end
+
+    # Write keys to the file
+    #
+    # @return [Boolean] +true+ if file was written; +false+ otherwise.
+    def save
+      if Yast::FileUtils::Exists(path)
+        raise NotRegularFile unless Yast::FileUtils::IsFile(path)
+      else
+        Yast::SCR.Execute(
+          Yast::Path.new(".target.bash"), "umask 0077 && /usr/bin/touch 
#{path.shellescape}"
+        )
       end
+      content = keys.join("\n") + "\n"
+      Yast::SCR.Write(Yast::Path.new(".target.string"), path, content)
     end
   end
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-users-4.6.1/src/lib/y2users/linux/reader.rb 
new/yast2-users-4.6.2/src/lib/y2users/linux/reader.rb
--- old/yast2-users-4.6.1/src/lib/y2users/linux/reader.rb       2023-04-03 
13:48:38.000000000 +0200
+++ new/yast2-users-4.6.2/src/lib/y2users/linux/reader.rb       2023-06-12 
16:19:35.000000000 +0200
@@ -82,13 +82,13 @@
 
       # Reads users authorized keys
       #
-      # @see Yast::Users::SSHAuthorizedKeyring#read_keys
+      # @see Y2Users::SSHAuthorizedKeyring#read_keys
       # @return [Array<Y2Users::User>]
       def read_authorized_keys(config)
         config.users.each do |user|
           next unless user.home
 
-          user.authorized_keys = 
Yast::Users::SSHAuthorizedKeyring.new(user.home.path).read_keys
+          user.authorized_keys = 
Y2Users::SSHAuthorizedKeyring.new(user.home.path).read_keys
         end
       end
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-users-4.6.1/src/lib/y2users/linux/set_auth_keys_action.rb 
new/yast2-users-4.6.2/src/lib/y2users/linux/set_auth_keys_action.rb
--- old/yast2-users-4.6.1/src/lib/y2users/linux/set_auth_keys_action.rb 
2023-04-03 13:48:38.000000000 +0200
+++ new/yast2-users-4.6.2/src/lib/y2users/linux/set_auth_keys_action.rb 
2023-06-12 16:19:35.000000000 +0200
@@ -54,11 +54,11 @@
       #
       # Issues are generated when the authorized keys cannot be set.
       def run_action
-        keyring = Yast::Users::SSHAuthorizedKeyring.new(user.home.path, 
previous_keys)
+        keyring = Y2Users::SSHAuthorizedKeyring.new(user.home.path, 
previous_keys)
         keyring.add_keys(user.authorized_keys)
         keyring.write_keys
         true
-      rescue Yast::Users::SSHAuthorizedKeyring::PathError => e
+      rescue Y2Users::SSHAuthorizedKeyring::PathError => e
         issues << Y2Issues::Issue.new(
           # TRANSLATORS: %s is a placeholder for a username
           format(_("Error writing authorized keys for '%s'"), user.name)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-users-4.6.1/src/modules/SSHAuthorizedKeys.rb 
new/yast2-users-4.6.2/src/modules/SSHAuthorizedKeys.rb
--- old/yast2-users-4.6.1/src/modules/SSHAuthorizedKeys.rb      2023-04-03 
13:48:38.000000000 +0200
+++ new/yast2-users-4.6.2/src/modules/SSHAuthorizedKeys.rb      2023-06-12 
16:19:35.000000000 +0200
@@ -35,27 +35,27 @@
 
     # Read keys from a given home directory
     #
-    # @see Yast::Users::SSHAuthorizedKeyring#read_keys
+    # @see Y2Y2Users::SSHAuthorizedKeyring#read_keys
     def read_keys(home)
-      keyring = Users::SSHAuthorizedKeyring.new(home)
+      keyring = Y2Users::SSHAuthorizedKeyring.new(home)
       keyring.read_keys
     end
 
     # Write keys to a given home directory
     #
-    # @see Yast::Users::SSHAuthorizedKeyring#write_keys
+    # @see Y2Y2Users::SSHAuthorizedKeyring#write_keys
     def write_keys(home, keys)
-      keyring = Users::SSHAuthorizedKeyring.new(home)
+      keyring = Y2Users::SSHAuthorizedKeyring.new(home)
       keyring.add_keys(keys)
       keyring.write_keys
-    rescue Users::SSHAuthorizedKeyring::HomeDoesNotExist => e
+    rescue Y2Users::SSHAuthorizedKeyring::HomeDoesNotExist => e
       log.warn(e.message)
       Report.Warning(
         # TRANSLATORS: '%s' is a directory path
         format(_("Home directory '%s' does not exist\n" \
                  "so authorized keys will not be written."), e.path)
       )
-    rescue Users::SSHAuthorizedKeyring::NotRegularSSHDirectory => e
+    rescue Y2Users::SSHAuthorizedKeyring::NotRegularSSHDirectory => e
       log.warn(e.message)
       Report.Warning(
         # TRANSLATORS: '%s' is a directory path
@@ -63,7 +63,7 @@
                  "a security issue so authorized keys will not\n" \
                  "be written."), e.path)
       )
-    rescue Users::SSHAuthorizedKeyring::NotRegularAuthorizedKeysFile => e
+    rescue Y2Users::SSHAuthorizedKeyring::NotRegularAuthorizedKeysFile => e
       log.warn(e.message)
       Report.Warning(
         # TRANSLATORS: '%s' is a directory path
@@ -71,7 +71,7 @@
                  "a security issue so authorized keys will not\n" \
                  "be written."), e.path)
       )
-    rescue Users::SSHAuthorizedKeyring::CouldNotCreateSSHDirectory => e
+    rescue Y2Users::SSHAuthorizedKeyring::CouldNotCreateSSHDirectory => e
       log.warn(e.message)
       Report.Warning(
         Message.UnableToCreateDirectory(e.path) + "\n" +
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-users-4.6.1/test/lib/users/clients/auto_test.rb 
new/yast2-users-4.6.2/test/lib/users/clients/auto_test.rb
--- old/yast2-users-4.6.1/test/lib/users/clients/auto_test.rb   2023-04-03 
13:48:38.000000000 +0200
+++ new/yast2-users-4.6.2/test/lib/users/clients/auto_test.rb   2023-06-12 
16:19:35.000000000 +0200
@@ -208,5 +208,79 @@
         subject.run
       end
     end
+
+    context "Write" do
+      let(:func) { "Write" }
+      let(:reader) do
+        instance_double(
+          Y2Users::UsersModule::Reader, read: [Y2Users::Config.new, 
target_config]
+        )
+      end
+      let(:writer) { instance_double(Y2Users::Linux::Writer, write: []) }
+      let(:system_config) { Y2Users::Config.new }
+      let(:target_config) do
+        Y2Users::Config.new.tap do |config|
+          config.attach(user)
+          config.attach(root)
+          config.attach(users_group)
+          config.attach(others_group)
+        end
+      end
+      let(:root) { Y2Users::User.new("root").tap { |u| u.uid = 0 } }
+      let(:user) { Y2Users::User.new("foo") }
+      let(:users_group) { Y2Users::Group.new("users") }
+      let(:others_group) { Y2Users::Group.new("others") }
+
+      before do
+        allow(Y2Users::ConfigManager.instance).to receive(:system)
+          .and_return(system_config)
+        allow(Y2Users::Linux::Writer).to receive(:new).and_return(writer)
+        allow(Y2Users::UsersModule::Reader).to receive(:new).and_return(reader)
+        allow(Yast::Users).to receive(:GetUsers).with("uid", "local")
+          .and_return("foo" => { "uid" => "foo", "modified" => true })
+        allow(Yast::Users).to receive(:GetUsers).with("uid", "system")
+          .and_return("root" => { "uid" => "root", "modified" => false })
+        allow(Yast::Users).to receive(:GetGroups).with("cn", "local")
+          .and_return("foo" => { "cn" => "users", "modified" => true })
+        allow(Yast::Users).to receive(:GetGroups).with("cn", "system")
+          .and_return("root" => { "cn" => "others", "modified" => false })
+      end
+
+      it "writes the users defined in the Users module" do
+        expect(Y2Users::Linux::Writer).to receive(:new) do |new_config, _|
+          names = new_config.users.map(&:name)
+          expect(names).to include("foo")
+          expect(names).to_not include("root")
+          writer
+        end
+        subject.run
+      end
+
+      it "writes the groups defined in the Users module" do
+        expect(Y2Users::Linux::Writer).to receive(:new) do |new_config, _|
+          names = new_config.groups.map(&:name)
+          expect(names).to include("users")
+          expect(names).to_not include("others")
+          writer
+        end
+        subject.run
+      end
+
+      context "when there are not issues" do
+        it "returns true" do
+          expect(subject.run).to eq(true)
+        end
+      end
+
+      context "when any issue was found" do
+        before do
+          allow(writer).to receive(:write).and_return([double("issue")])
+        end
+
+        it "returns false" do
+          expect(subject.run).to eq(false)
+        end
+      end
+    end
   end
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-users-4.6.1/test/lib/users/ssh_authorized_keyring_test.rb 
new/yast2-users-4.6.2/test/lib/users/ssh_authorized_keyring_test.rb
--- old/yast2-users-4.6.1/test/lib/users/ssh_authorized_keyring_test.rb 
2023-04-03 13:48:38.000000000 +0200
+++ new/yast2-users-4.6.2/test/lib/users/ssh_authorized_keyring_test.rb 
2023-06-12 16:19:35.000000000 +0200
@@ -21,8 +21,8 @@
 require "users/ssh_authorized_keyring"
 require "tmpdir"
 
-describe Yast::Users::SSHAuthorizedKeyring do
-  subject(:keyring) { Yast::Users::SSHAuthorizedKeyring.new(home) }
+describe Y2Users::SSHAuthorizedKeyring do
+  subject(:keyring) { Y2Users::SSHAuthorizedKeyring.new(home) }
   let(:home) { FIXTURES_PATH.join("home", "user1").to_s }
 
   def authorized_keys_from_home(path)
@@ -130,7 +130,7 @@
   describe "#write_keys" do
     let(:tmpdir) { Dir.mktmpdir }
     let(:home) { File.join(tmpdir, "/home/user") }
-    let(:file) { Yast::Users::SSHAuthorizedKeysFile.new(authorized_keys_path) }
+    let(:file) { Y2Users::SSHAuthorizedKeysFile.new(authorized_keys_path) }
     let(:ssh_dir) { File.join(home, ".ssh") }
     let(:key) { "ssh-rsa 123ABC" }
     let(:authorized_keys_path) { File.join(home, ".ssh", "authorized_keys") }
@@ -138,7 +138,7 @@
     before do
       FileUtils.mkdir_p(ssh_dir)
 
-      allow(Yast::Users::SSHAuthorizedKeysFile).to 
receive(:new).and_return(file)
+      allow(Y2Users::SSHAuthorizedKeysFile).to receive(:new).and_return(file)
     end
 
     after { FileUtils.rm_rf(tmpdir) if File.exist?(tmpdir) }
@@ -211,20 +211,20 @@
           let(:home_dir_exists) { false }
 
           it "raises a HomeDoesNotExist exception and does not write 
authorized_keys" do
-            expect(Yast::Users::SSHAuthorizedKeysFile).to_not receive(:new)
+            expect(Y2Users::SSHAuthorizedKeysFile).to_not receive(:new)
             expect { keyring.write_keys }
-              .to 
raise_error(Yast::Users::SSHAuthorizedKeyring::HomeDoesNotExist)
+              .to raise_error(Y2Users::SSHAuthorizedKeyring::HomeDoesNotExist)
           end
         end
 
         context "when SSH directory could not be created" do
           it "raises a CouldNotCreateSSHDirectory exception and does not write 
authorized_keys" do
-            expect(Yast::Users::SSHAuthorizedKeysFile).to_not receive(:new)
+            expect(Y2Users::SSHAuthorizedKeysFile).to_not receive(:new)
             expect(Yast::SCR).to receive(:Execute)
               .with(Yast::Path.new(".target.mkdir"), anything)
               .and_return(false)
             expect { keyring.write_keys }
-              .to 
raise_error(Yast::Users::SSHAuthorizedKeyring::CouldNotCreateSSHDirectory)
+              .to 
raise_error(Y2Users::SSHAuthorizedKeyring::CouldNotCreateSSHDirectory)
           end
         end
 
@@ -234,9 +234,9 @@
           it "raises a NotRegularSSHDirectory and does not write 
authorized_keys" do
             allow(Yast::FileUtils).to receive(:IsDirectory).with(ssh_dir)
               .and_return(false)
-            expect(Yast::Users::SSHAuthorizedKeysFile).to_not receive(:new)
+            expect(Y2Users::SSHAuthorizedKeysFile).to_not receive(:new)
             expect { keyring.write_keys }
-              .to 
raise_error(Yast::Users::SSHAuthorizedKeyring::NotRegularSSHDirectory)
+              .to 
raise_error(Y2Users::SSHAuthorizedKeyring::NotRegularSSHDirectory)
           end
         end
 
@@ -282,10 +282,10 @@
 
           it "raises a NotRegularAuthorizedKeysFile" do
             allow(file).to receive(:save)
-              .and_raise(Yast::Users::SSHAuthorizedKeysFile::NotRegularFile)
+              .and_raise(Y2Users::SSHAuthorizedKeysFile::NotRegularFile)
 
             expect { keyring.write_keys }
-              .to 
raise_error(Yast::Users::SSHAuthorizedKeyring::NotRegularAuthorizedKeysFile)
+              .to 
raise_error(Y2Users::SSHAuthorizedKeyring::NotRegularAuthorizedKeysFile)
           end
         end
       end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-users-4.6.1/test/lib/users/ssh_authorized_keys_file_test.rb 
new/yast2-users-4.6.2/test/lib/users/ssh_authorized_keys_file_test.rb
--- old/yast2-users-4.6.1/test/lib/users/ssh_authorized_keys_file_test.rb       
2023-04-03 13:48:38.000000000 +0200
+++ new/yast2-users-4.6.2/test/lib/users/ssh_authorized_keys_file_test.rb       
2023-06-12 16:19:35.000000000 +0200
@@ -20,8 +20,8 @@
 require "users/ssh_authorized_keys_file"
 require "tmpdir"
 
-describe Yast::Users::SSHAuthorizedKeysFile do
-  subject(:file) { Yast::Users::SSHAuthorizedKeysFile.new(path) }
+describe Y2Users::SSHAuthorizedKeysFile do
+  subject(:file) { described_class.new(path) }
   let(:path) { FIXTURES_PATH.join("home", "user1", ".ssh", "authorized_keys") }
 
   describe "#keys" do
@@ -117,7 +117,7 @@
           expect(Yast::SCR).to_not receive(:Write)
             .with(Yast::Path.new(".target.string"), anything)
           file.keys = [key0, key1]
-          expect { file.save }.to 
raise_error(Yast::Users::SSHAuthorizedKeysFile::NotRegularFile)
+          expect { file.save }.to 
raise_error(Y2Users::SSHAuthorizedKeysFile::NotRegularFile)
         end
       end
     end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-users-4.6.1/test/lib/y2users/linux/set_auth_keys_action_test.rb 
new/yast2-users-4.6.2/test/lib/y2users/linux/set_auth_keys_action_test.rb
--- old/yast2-users-4.6.1/test/lib/y2users/linux/set_auth_keys_action_test.rb   
2023-04-03 13:48:38.000000000 +0200
+++ new/yast2-users-4.6.2/test/lib/y2users/linux/set_auth_keys_action_test.rb   
2023-06-12 16:19:35.000000000 +0200
@@ -37,21 +37,21 @@
 
   describe "#perform" do
     it "calls SSHAuthorizedKeyring#write_keys" do
-      obj = double(Yast::Users::SSHAuthorizedKeyring)
+      obj = double(Y2Users::SSHAuthorizedKeyring)
       expect(obj).to receive(:write_keys)
       expect(obj).to receive(:add_keys).with(["test"])
-      expect(Yast::Users::SSHAuthorizedKeyring).to 
receive(:new).with("/home/test", [])
+      expect(Y2Users::SSHAuthorizedKeyring).to 
receive(:new).with("/home/test", [])
         .and_return(obj)
 
       subject.perform
     end
 
     it "returns result without success and with issues if cmd failed" do
-      obj = double(Yast::Users::SSHAuthorizedKeyring)
+      obj = double(Y2Users::SSHAuthorizedKeyring)
       expect(obj).to receive(:add_keys).with(["test"])
       expect(obj).to receive(:write_keys)
-        .and_raise(Yast::Users::SSHAuthorizedKeyring::PathError, "/home/test")
-      expect(Yast::Users::SSHAuthorizedKeyring).to 
receive(:new).with("/home/test", [])
+        .and_raise(Y2Users::SSHAuthorizedKeyring::PathError, "/home/test")
+      expect(Y2Users::SSHAuthorizedKeyring).to 
receive(:new).with("/home/test", [])
         .and_return(obj)
 
       result = action.perform
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-users-4.6.1/test/ssh_authorized_keys_test.rb 
new/yast2-users-4.6.2/test/ssh_authorized_keys_test.rb
--- old/yast2-users-4.6.1/test/ssh_authorized_keys_test.rb      2023-04-03 
13:48:38.000000000 +0200
+++ new/yast2-users-4.6.2/test/ssh_authorized_keys_test.rb      2023-06-12 
16:19:35.000000000 +0200
@@ -34,16 +34,16 @@
   let(:authorized_keys_path) { File.join("ssh_dir", ".authorized_keys") }
   let(:key) { double("key") }
   let(:keys) { [key] }
-  let(:keyring) { instance_double(Yast::Users::SSHAuthorizedKeyring, add_keys: 
[]) }
+  let(:keyring) { instance_double(Y2Users::SSHAuthorizedKeyring, add_keys: []) 
}
 
   before do
-    allow(Yast::Users::SSHAuthorizedKeyring).to 
receive(:new).and_return(keyring)
+    allow(Y2Users::SSHAuthorizedKeyring).to receive(:new).and_return(keyring)
   end
 
   describe "#write_keys" do
     context "when home directory does not exists" do
       let(:exception) do
-        Yast::Users::SSHAuthorizedKeyring::HomeDoesNotExist.new(home)
+        Y2Users::SSHAuthorizedKeyring::HomeDoesNotExist.new(home)
       end
 
       it "shows an error message" do
@@ -56,7 +56,7 @@
 
     context "SSH directory is not a directory" do
       let(:exception) do
-        Yast::Users::SSHAuthorizedKeyring::NotRegularSSHDirectory.new(ssh_dir)
+        Y2Users::SSHAuthorizedKeyring::NotRegularSSHDirectory.new(ssh_dir)
       end
 
       it "shows an error message" do
@@ -69,7 +69,7 @@
 
     context "SSH directory could not be created" do
       let(:exception) do
-        
Yast::Users::SSHAuthorizedKeyring::CouldNotCreateSSHDirectory.new(ssh_dir)
+        Y2Users::SSHAuthorizedKeyring::CouldNotCreateSSHDirectory.new(ssh_dir)
       end
 
       it "shows an error message" do
@@ -82,7 +82,7 @@
 
     context "authorized_keys exists but it's not a regular file" do
       let(:exception) do
-        
Yast::Users::SSHAuthorizedKeyring::NotRegularAuthorizedKeysFile.new(authorized_keys_path)
+        
Y2Users::SSHAuthorizedKeyring::NotRegularAuthorizedKeysFile.new(authorized_keys_path)
       end
 
       it "shows an error message" do

Reply via email to