feat: govern effective appearance defaults

This commit is contained in:
2026-08-20 07:03:28 +02:00
parent 6643c8fc1e
commit 8f642bd618
13 changed files with 429 additions and 61 deletions
+106
View File
@@ -6450,6 +6450,112 @@ class ApiSmokeTests(unittest.TestCase):
self.assertEqual(raw_test.status_code, 403, raw_test.text)
self.assertIn("manage_credentials", raw_test.json()["detail"])
def test_appearance_defaults_precedence_and_policy_lock(self) -> None:
headers, _ = self._login()
system = self.client.get("/api/v1/admin/system/settings", headers=headers)
self.assertEqual(system.status_code, 200, system.text)
system_payload = system.json()
system_saved = self.client.patch(
"/api/v1/admin/system/settings",
headers=headers,
json={
"default_locale": system_payload["default_locale"],
"allow_tenant_custom_groups": system_payload["allow_tenant_custom_groups"],
"allow_tenant_custom_roles": system_payload["allow_tenant_custom_roles"],
"allow_tenant_api_keys": system_payload["allow_tenant_api_keys"],
"appearance_palette": "civic_blue",
"appearance_palette_locked": False,
},
)
self.assertEqual(system_saved.status_code, 200, system_saved.text)
tenant = self.client.get("/api/v1/admin/tenant/settings", headers=headers)
self.assertEqual(tenant.status_code, 200, tenant.text)
tenant_payload = tenant.json()
tenant_saved = self.client.patch(
"/api/v1/admin/tenant/settings",
headers=headers,
json={
"default_locale": tenant_payload["default_locale"],
"appearance_palette": "forest",
"appearance_palette_locked": False,
},
)
self.assertEqual(tenant_saved.status_code, 200, tenant_saved.text)
self.assertEqual(tenant_saved.json()["effective_appearance_palette"], "forest")
inherited = self.client.patch(
"/api/v1/auth/profile",
headers=headers,
json={"ui_preferences": {"palette": None}},
)
self.assertEqual(inherited.status_code, 200, inherited.text)
self.assertEqual(inherited.json()["user"]["appearance"]["palette"], "forest")
self.assertEqual(inherited.json()["user"]["appearance"]["source"], "tenant")
explicit = self.client.patch(
"/api/v1/auth/profile",
headers=headers,
json={"ui_preferences": {"palette": "plum"}},
)
self.assertEqual(explicit.status_code, 200, explicit.text)
self.assertEqual(explicit.json()["user"]["appearance"]["source"], "user")
tenant_locked = self.client.patch(
"/api/v1/admin/tenant/settings",
headers=headers,
json={
"default_locale": tenant_payload["default_locale"],
"appearance_palette": "forest",
"appearance_palette_locked": True,
},
)
self.assertEqual(tenant_locked.status_code, 200, tenant_locked.text)
locked_profile = self.client.get("/api/v1/auth/profile", headers=headers)
self.assertEqual(locked_profile.json()["user"]["appearance"]["source"], "tenant_lock")
self.assertTrue(locked_profile.json()["user"]["appearance"]["locked"])
unchanged_palette = self.client.patch(
"/api/v1/auth/profile",
headers=headers,
json={"ui_preferences": {"palette": "plum", "theme": "dark"}},
)
self.assertEqual(unchanged_palette.status_code, 200, unchanged_palette.text)
self.assertEqual(unchanged_palette.json()["user"]["ui_preferences"]["theme"], "dark")
denied = self.client.patch(
"/api/v1/auth/profile",
headers=headers,
json={"ui_preferences": {"palette": "default"}},
)
self.assertEqual(denied.status_code, 422, denied.text)
system_locked = self.client.patch(
"/api/v1/admin/system/settings",
headers=headers,
json={
"default_locale": system_payload["default_locale"],
"allow_tenant_custom_groups": system_payload["allow_tenant_custom_groups"],
"allow_tenant_custom_roles": system_payload["allow_tenant_custom_roles"],
"allow_tenant_api_keys": system_payload["allow_tenant_api_keys"],
"appearance_palette": "civic_blue",
"appearance_palette_locked": True,
},
)
self.assertEqual(system_locked.status_code, 200, system_locked.text)
blocked_tenant_override = self.client.patch(
"/api/v1/admin/tenant/settings",
headers=headers,
json={
"default_locale": tenant_payload["default_locale"],
"appearance_palette": "plum",
"appearance_palette_locked": False,
},
)
self.assertEqual(blocked_tenant_override.status_code, 422, blocked_tenant_override.text)
final_profile = self.client.get("/api/v1/auth/profile", headers=headers)
self.assertEqual(final_profile.json()["user"]["appearance"]["palette"], "civic_blue")
self.assertEqual(final_profile.json()["user"]["appearance"]["source"], "system_lock")
def test_profile_refresh_and_system_role_protection_model(self) -> None:
headers, _ = self._login()
profile = self.client.patch(