From 482f12256e89998a8f6bd0b993bdee1a2c8570ed Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Tue, 26 May 2026 21:51:24 -0400 Subject: [PATCH] test(fusion_login_audit): view-visibility checks for admin vs non-admin Asserts the smart-button and Login Activity tab fields are stripped from res.users get_view() for non-admin users, and present for Settings admins. Locks down the contract behind the groups="base.group_system" XML attributes on the form-inheritance view (the inherited view record cannot carry groups itself per CLAUDE.md rule #11; the gate must live on the inner nodes). Co-Authored-By: Claude Opus 4.7 (1M context) --- fusion_login_audit/tests/test_security.py | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/fusion_login_audit/tests/test_security.py b/fusion_login_audit/tests/test_security.py index 0b6321ec..9f9c74cd 100644 --- a/fusion_login_audit/tests/test_security.py +++ b/fusion_login_audit/tests/test_security.py @@ -94,3 +94,36 @@ class TestFusionLoginAuditSecurity(TransactionCase): # we would need a global rule (groups=[]) with domain [(0,'=',1)] paired # with the admin grant. That is a security-model redesign and out of # scope for T3. The ACL already provides the actual gate. + + # ───────────────────────────────────────────────────────────────────── + # T14: view-level visibility checks. The smart button and the "Login + # Activity" tab on res.users are gated by groups="base.group_system" + # on the inner XML nodes (the inherited view record itself cannot + # carry groups — CLAUDE.md rule #11). Verify the gate works by asking + # for the form view as a non-admin and confirming the x_fc_* fields + # are stripped from the arch. + # ───────────────────────────────────────────────────────────────────── + + def test_view_hides_button_and_tab_for_non_admin(self): + """A regular user's get_view() does not contain the x_fc_login_audit_* + fields — they live behind groups="base.group_system" XML attributes.""" + view = self.env['res.users'].with_user(self.regular_user).get_view( + view_id=self.env.ref('base.view_users_form').id, + view_type='form', + ) + arch = view['arch'] + self.assertNotIn('x_fc_login_audit_count', arch, + "Smart-button field must not leak into non-admin view") + self.assertNotIn('x_fc_login_audit_ids', arch, + "Login Activity tab must not leak into non-admin view") + + def test_view_shows_button_and_tab_for_admin(self): + """A Settings admin DOES see both nodes.""" + admin = self.env.ref('base.user_admin') + view = self.env['res.users'].with_user(admin).get_view( + view_id=self.env.ref('base.view_users_form').id, + view_type='form', + ) + arch = view['arch'] + self.assertIn('x_fc_login_audit_count', arch) + self.assertIn('x_fc_login_audit_ids', arch)