From ba9e7fe315777babc14891c0e69ebee057b46ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simonyi=20Gerg=C5=91?= <28359278+gergosimonyi@users.noreply.github.com> Date: Mon, 5 Jan 2026 17:44:07 +0100 Subject: [PATCH] core: add prettier failure on duplicate group names (#18941) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * core: add prettier failure on duplicate group names * add db_alias Co-authored-by: Jens L. Signed-off-by: Simonyi Gergő <28359278+gergosimonyi@users.noreply.github.com> * lint * migrate to system migration Signed-off-by: Jens Langhammer * fix error on empty database Signed-off-by: Jens Langhammer * returning a count of 0 still takes 1 row :P --------- Signed-off-by: Simonyi Gergő <28359278+gergosimonyi@users.noreply.github.com> Signed-off-by: Jens Langhammer Co-authored-by: Jens L. --- lifecycle/migrate.py | 3 +- .../to_2025_12_group_duplicate.py | 41 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 lifecycle/system_migrations/to_2025_12_group_duplicate.py diff --git a/lifecycle/migrate.py b/lifecycle/migrate.py index 858cfd73b5..499bd5d911 100755 --- a/lifecycle/migrate.py +++ b/lifecycle/migrate.py @@ -30,10 +30,11 @@ class BaseMigration: def __init__(self, cur: Any, con: Any): self.cur = cur self.con = con + self.log = get_logger().bind() def system_crit(self, command: str): """Run system command""" - LOGGER.debug("Running system_crit command", command=command) + self.log.debug("Running system_crit command", command=command) retval = system(command) # nosec if retval != 0: raise CommandError("Migration error") diff --git a/lifecycle/system_migrations/to_2025_12_group_duplicate.py b/lifecycle/system_migrations/to_2025_12_group_duplicate.py new file mode 100644 index 0000000000..ec7ad4f892 --- /dev/null +++ b/lifecycle/system_migrations/to_2025_12_group_duplicate.py @@ -0,0 +1,41 @@ +# flake8: noqa +from lifecycle.migrate import BaseMigration + +SQL_STATEMENT = """ +SELECT "authentik_core_group"."name" AS "name", + Count("authentik_core_group"."name") AS "name__count" +FROM "authentik_core_group" GROUP BY 1 +HAVING Count("authentik_core_group"."name") > 1 +ORDER BY 2 DESC, + 1 ASC +""" + + +class DuplicateNameError(RuntimeError): + pass + + +class Migration(BaseMigration): + def needs_migration(self) -> bool: + self.cur.execute( + "select 1 from information_schema.tables where table_name = 'django_migrations';" + ) + if not bool(self.cur.rowcount): + # No django_migrations table, no data to check + return False + # migration that introduces the uniqueness + self.cur.execute( + "select 1 from django_migrations where app = 'authentik_core' and name = '0056_user_roles';" + ) + return not bool(self.cur.rowcount) + + def run(self): + rows = self.cur.execute(SQL_STATEMENT).fetchall() + if len(rows): + for row in rows: + self.log.error( + "Group with duplicate name detected", group_name=row[0], count=row[1] + ) + raise DuplicateNameError( + f"authentik 2025.12 forbids duplicate group names. For a list of duplicate groups, see logging output above. Please rename the offending groups and re-run the migration. For more information, see: https://version-2025-12.goauthentik.io/releases/2025.12/#group-name-uniqueness" + )