details:   https://code.tryton.org/tryton/commit/1ba9f0091db6
branch:    7.8
user:      Cédric Krier <[email protected]>
date:      Thu Nov 05 18:53:11 2026 +0100
description:
        Only permit administrators to execute wizards without models or groups

        Closes #15205
        (grafted from 22897711abb09d83f972c6a2b850cccbfa877021)
diffstat:

 trytond/CHANGELOG                    |   1 +
 trytond/trytond/tests/test_wizard.py |  53 +++++++++++++++++++++++++++++++++--
 trytond/trytond/tests/wizard.py      |   5 +++
 trytond/trytond/tests/wizard.xml     |   6 ++++
 trytond/trytond/wizard/wizard.py     |  14 ++++++++-
 5 files changed, 73 insertions(+), 6 deletions(-)

diffs (156 lines):

diff -r 5b51cf0a8fc9 -r 1ba9f0091db6 trytond/CHANGELOG
--- a/trytond/CHANGELOG Wed Nov 04 10:06:28 2026 +0100
+++ b/trytond/CHANGELOG Thu Nov 05 18:53:11 2026 +0100
@@ -1,3 +1,4 @@
+* Only permit administrators to execute wizards without models or groups 
(issue15205)
 
 Version 7.8.18 - 2026-10-15
 ---------------------------
diff -r 5b51cf0a8fc9 -r 1ba9f0091db6 trytond/trytond/tests/test_wizard.py
--- a/trytond/trytond/tests/test_wizard.py      Wed Nov 04 10:06:28 2026 +0100
+++ b/trytond/trytond/tests/test_wizard.py      Thu Nov 05 18:53:11 2026 +0100
@@ -183,10 +183,55 @@
         "Execute wizard on wrong model"
         pool = Pool()
         Wizard = pool.get('test.test_wizard', type='wizard')
+        User = pool.get('res.user')
+
+        user = User(login='foo')
+        user.save()
+        session_id, start_state, end_state = Wizard.create()
+
+        with Transaction().set_user(user.id):
+            with self.assertRaises(AccessError):
+                with Transaction().set_context(
+                        active_model='test.test_wizard.start'):
+                    Wizard.execute(session_id, {}, start_state)
+
+    @with_transaction(context={'_check_access': True})
+    def test_execute_without_model(self):
+        "Execute wizard without model"
+        pool = Pool()
+        Wizard = pool.get('test.test_wizard_no_model', type='wizard')
+        User = pool.get('res.user')
+
+        user = User(login='foo')
+        user.save()
+        session_id, start_state, end_state = Wizard.create()
+
+        with Transaction().set_user(user.id):
+            with self.assertRaises(AccessError):
+                Wizard.execute(session_id, {}, start_state)
+
+    @with_transaction(context={'_check_access': True})
+    def test_execute_without_model_with_group(self):
+        "Execute wizard without model and groups"
+        pool = Pool()
+        Wizard = pool.get('test.test_wizard_no_model', type='wizard')
+        User = pool.get('res.user')
+        Group = pool.get('res.group')
+
+        user = User(login='foo', groups=[Group(name="Group")])
+        user.save()
+        session_id, start_state, end_state = Wizard.create()
+
+        with Transaction().set_user(user.id):
+            with self.assertRaises(AccessError):
+                Wizard.execute(session_id, {}, start_state)
+
+    @with_transaction(context={'_check_access': True})
+    def test_execute_without_model_with_admin(self):
+        "Execute wizard without model"
+        pool = Pool()
+        Wizard = pool.get('test.test_wizard_no_model', type='wizard')
 
         session_id, start_state, end_state = Wizard.create()
 
-        with self.assertRaises(AccessError):
-            with Transaction().set_context(
-                    active_model='test.test_wizard.start'):
-                Wizard.execute(session_id, {}, start_state)
+        Wizard.execute(session_id, {}, start_state)
diff -r 5b51cf0a8fc9 -r 1ba9f0091db6 trytond/trytond/tests/wizard.py
--- a/trytond/trytond/tests/wizard.py   Wed Nov 04 10:06:28 2026 +0100
+++ b/trytond/trytond/tests/wizard.py   Thu Nov 05 18:53:11 2026 +0100
@@ -47,10 +47,15 @@
         return 'end'
 
 
+class TestWizardNoModel(TestWizard):
+    __name__ = 'test.test_wizard_no_model'
+
+
 def register(module):
     Pool.register(
         TestWizardStart,
         module=module, type_='model')
     Pool.register(
         TestWizard,
+        TestWizardNoModel,
         module=module, type_='wizard')
diff -r 5b51cf0a8fc9 -r 1ba9f0091db6 trytond/trytond/tests/wizard.xml
--- a/trytond/trytond/tests/wizard.xml  Wed Nov 04 10:06:28 2026 +0100
+++ b/trytond/trytond/tests/wizard.xml  Thu Nov 05 18:53:11 2026 +0100
@@ -21,5 +21,11 @@
             <field name="wiz_name">test.test_wizard</field>
             <field name="model">test.access</field>
         </record>
+
+        <record model="ir.action.wizard" id="test_wizard_no_model">
+            <field name="name">Test Wizard</field>
+            <field name="wiz_name">test.test_wizard_no_model</field>
+            <field name="model" eval="None"/>
+        </record>
     </data>
 </tryton>
diff -r 5b51cf0a8fc9 -r 1ba9f0091db6 trytond/trytond/wizard/wizard.py
--- a/trytond/trytond/wizard/wizard.py  Wed Nov 04 10:06:28 2026 +0100
+++ b/trytond/trytond/wizard/wizard.py  Thu Nov 05 18:53:11 2026 +0100
@@ -249,12 +249,17 @@
         ActionWizard = pool.get('ir.action.wizard')
         User = pool.get('res.user')
         Group = pool.get('res.group')
+        ModelData = pool.get('ir.model.data')
         transaction = Transaction()
         context = transaction.context
 
         if transaction.user == 0:
             return
 
+        admin_group = ModelData.get_id('res.group_admin')
+        groups = set(User.get_groups())
+        is_admin = admin_group in groups
+
         with check_access():
             model = context.get('active_model')
             if model:
@@ -263,7 +268,7 @@
                 ModelAccess.check(model, 'read')
             models = ActionWizard.get_models(
                 cls.__name__, action_id=context.get('action_id'))
-            if model and models and model not in models:
+            if not is_admin and models and (not model or model not in models):
                 groups = Group.browse(User.get_groups())
                 raise AccessError(
                     gettext(
@@ -273,7 +278,6 @@
                     gettext(
                         'ir.msg_context_groups',
                         groups=', '.join(g.rec_name for g in groups)))
-            groups = set(User.get_groups())
             wizard_groups = ActionWizard.get_groups(cls.__name__,
                 action_id=context.get('action_id'))
             if wizard_groups:
@@ -291,6 +295,12 @@
                         or Model.write.__func__ != ModelSQL.write.__func__):
                     ModelAccess.check(model, 'write')
 
+            if not is_admin and not models and not wizard_groups:
+                raise AccessError(
+                    gettext(
+                        'ir.msg_access_wizard_error',
+                        wizard=cls.__name__))
+
             if model:
                 ids = context.get('active_ids') or []
                 id_ = context.get('active_id')

Reply via email to