From ecda300e5ba2a628a2764b12860ac416bdaab4d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20V=C3=A1vra?= Date: Wed, 9 Sep 2026 10:10:56 +0000 Subject: [PATCH] fix: use gpasswd instead of removed groupmems for local groups groupmems was dropped from recent Fedora; manage /etc/group membership with gpasswd -a/-d for users and gpasswd -M for nested group members. Assisted-by: Cursor --- sssd_test_framework/utils/local_users.py | 35 ++++++++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/sssd_test_framework/utils/local_users.py b/sssd_test_framework/utils/local_users.py index b0d5849d..7c85d7e9 100644 --- a/sssd_test_framework/utils/local_users.py +++ b/sssd_test_framework/utils/local_users.py @@ -655,6 +655,33 @@ def add_member(self, member: GroupMemberField) -> LocalGroup: """ return self.add_members([member]) + def _group_member_add_cmd(self, member: GroupMemberField) -> str: + """Build shell to add one member; groupmems was removed from recent Fedora.""" + name = self._member_principal_name(member) + group = self._name + if isinstance(member, LocalGroup): + return ( + f"current=$(getent group '{group}' | cut -d: -f4); " + f'case ",$current," in *,"{name}",*) ;; ' + f"*) " + f'if [ -n "$current" ]; then gpasswd -M "$current,{name}" \'{group}\'; ' + f"else gpasswd -M '{name}' '{group}'; fi ;; " + f"esac" + ) + return f"gpasswd -a '{name}' '{group}'" + + def _group_member_remove_cmd(self, member: GroupMemberField) -> str: + """Build shell to remove one member; groupmems was removed from recent Fedora.""" + name = self._member_principal_name(member) + group = self._name + if isinstance(member, LocalGroup): + return ( + f"current=$(getent group '{group}' | cut -d: -f4); " + f"new=$(printf '%s\\n' \"${{current//,/ }}\" | grep -vxF '{name}' | paste -sd,); " + f"gpasswd -M \"$new\" '{group}'" + ) + return f"gpasswd -d '{name}' '{group}'" + def add_members(self, members: list[GroupMemberField]) -> LocalGroup: """ Add multiple group members. @@ -669,9 +696,7 @@ def add_members(self, members: list[GroupMemberField]) -> LocalGroup: if not members: return self - cmd = "\n".join( - [f"groupmems --group '{self._name}' --add '{self._member_principal_name(x)}'" for x in members] - ) + cmd = "\n".join([self._group_member_add_cmd(x) for x in members]) self.util.host.conn.run("set -ex\n" + cmd, log_level=ProcessLogLevel.Error) return self @@ -701,9 +726,7 @@ def remove_members(self, members: list[GroupMemberField]) -> LocalGroup: if not members: return self - cmd = "\n".join( - [f"groupmems --group '{self._name}' --delete '{self._member_principal_name(x)}'" for x in members] - ) + cmd = "\n".join([self._group_member_remove_cmd(x) for x in members]) self.util.host.conn.run("set -ex\n" + cmd, log_level=ProcessLogLevel.Error) return self