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" + )