Decouple scopes from tenancy schema
Some checks failed
Dependency Audit / dependency-audit (push) Has been cancelled
Module Matrix / module-matrix (push) Has been cancelled

This commit is contained in:
2026-07-10 17:33:43 +02:00
parent 635d25c74c
commit 79af252e88
27 changed files with 529 additions and 75 deletions

View File

@@ -136,7 +136,7 @@ class DatabaseMigrationTests(unittest.TestCase):
job_indexes = {index["name"] for index in inspector.get_indexes("campaign_jobs")}
attempt_columns = {column["name"] for column in inspector.get_columns("send_attempts")}
tables = set(inspector.get_table_names())
tenant_columns = {column["name"] for column in inspector.get_columns("tenancy_tenants")}
tenant_columns = {column["name"] for column in inspector.get_columns("core_scopes")}
user_columns = {column["name"] for column in inspector.get_columns("access_users")}
session_columns = {column["name"] for column in inspector.get_columns("access_auth_sessions")}
group_columns = {column["name"] for column in inspector.get_columns("access_groups")}
@@ -186,6 +186,8 @@ class DatabaseMigrationTests(unittest.TestCase):
self.assertIn("claim_token", attempt_columns)
self.assertIn("access_accounts", tables)
self.assertIn("access_system_role_assignments", tables)
self.assertIn("core_scopes", tables)
self.assertNotIn("tenancy_tenants", tables)
self.assertIn("core_system_settings", tables)
self.assertIn("admin_governance_templates", tables)
self.assertIn("admin_governance_template_assignments", tables)
@@ -234,6 +236,34 @@ class DatabaseMigrationTests(unittest.TestCase):
finally:
engine.dispose()
def test_module_migrations_apply_after_core_scope_table_rename(self) -> None:
with tempfile.TemporaryDirectory(prefix="msm-late-module-migration-test-") as directory:
database = Path(directory) / "late-modules.db"
url = f"sqlite:///{database}"
command.upgrade(alembic_config(database_url=url, enabled_modules=()), "heads")
engine = create_engine(url)
try:
with engine.connect() as connection:
tables = set(inspect(connection).get_table_names())
self.assertIn("core_scopes", tables)
self.assertNotIn("tenancy_tenants", tables)
finally:
engine.dispose()
migrate_database(database_url=url)
engine = create_engine(url)
try:
with engine.connect() as connection:
inspector = inspect(connection)
mail_policy_fks = inspector.get_foreign_keys("mail_profile_policies")
referred_tables = {fk["referred_table"] for fk in mail_policy_fks}
self.assertIn("core_scopes", referred_tables)
self.assertNotIn("tenancy_tenants", referred_tables)
finally:
engine.dispose()
def test_repairs_current_schema_stamped_at_file_folders(self) -> None:
with tempfile.TemporaryDirectory(prefix="msm-current-schema-marker-test-") as directory:
database = Path(directory) / "current-schema-marker.db"
@@ -355,6 +385,7 @@ class DatabaseMigrationTests(unittest.TestCase):
engine = create_engine(url)
try:
with engine.connect() as connection:
tables = set(inspect(connection).get_table_names())
account = connection.execute(text(
"SELECT id, normalized_email, password_hash FROM access_accounts"
)).mappings().one()
@@ -389,8 +420,14 @@ class DatabaseMigrationTests(unittest.TestCase):
"SELECT slug, is_builtin FROM access_roles WHERE tenant_id IS NULL AND slug IN ('system_owner', 'system_admin', 'system_auditor')"
)).mappings().all()
}
scope_slug = connection.execute(text(
"SELECT slug FROM core_scopes WHERE id = 'tenant-1'"
)).scalar_one()
self.assertIn("core_scopes", tables)
self.assertNotIn("tenancy_tenants", tables)
self.assertEqual(account["normalized_email"], "owner@example.local")
self.assertEqual(account["password_hash"], "legacy-password-hash")
self.assertEqual(scope_slug, "legacy")
self.assertEqual(membership["account_id"], account["id"])
self.assertEqual(migrated_session["account_id"], account["id"])
self.assertEqual(owner_assignment, "owner")