From 5674ab3eba0647c94fceb674c054b2e5eb2c163b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 11:51:14 +0000 Subject: [PATCH 1/3] Initial plan From 14c1a9f3081e1262f7612a52c862de664650c040 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 11:58:23 +0000 Subject: [PATCH 2/3] Fix enforce_ex to return explanations for allow rules in deny models Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com> --- casbin/core_enforcer.py | 4 +++- tests/test_enforcer.py | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/casbin/core_enforcer.py b/casbin/core_enforcer.py index 0800fb2..2538aa7 100644 --- a/casbin/core_enforcer.py +++ b/casbin/core_enforcer.py @@ -481,8 +481,10 @@ def enforce_ex(self, *rvals): else: policy_effects.add(Effector.ALLOW) + # Update explain_index for any matching policy + explain_index = i + if self.eft.intermediate_effect(policy_effects) != Effector.INDETERMINATE: - explain_index = i break else: diff --git a/tests/test_enforcer.py b/tests/test_enforcer.py index 11af386..5ad0626 100644 --- a/tests/test_enforcer.py +++ b/tests/test_enforcer.py @@ -285,6 +285,15 @@ def test_enforce_rbac_with_deny(self): self.assertTrue(e.enforce("alice", "data2", "read")) self.assertFalse(e.enforce("alice", "data2", "write")) + def test_enforce_ex_rbac_with_deny(self): + e = self.get_enforcer( + get_examples("rbac_with_deny_model.conf"), + get_examples("rbac_with_deny_policy.csv"), + ) + # Test that enforce_ex returns explanations for both allow and deny cases + self.assertTupleEqual(e.enforce_ex("alice", "data2", "read"), (True, ["data2_admin", "data2", "read", "allow"])) + self.assertTupleEqual(e.enforce_ex("alice", "data2", "write"), (False, ["alice", "data2", "write", "deny"])) + def test_enforce_rbac_with_domains(self): e = self.get_enforcer( get_examples("rbac_with_domains_model.conf"), From 4531cf335884cf89c3ce336a58423e38906a21c2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 12:00:25 +0000 Subject: [PATCH 3/3] Improve comment clarity for explain_index update Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com> --- casbin/core_enforcer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/casbin/core_enforcer.py b/casbin/core_enforcer.py index 2538aa7..4ffcef2 100644 --- a/casbin/core_enforcer.py +++ b/casbin/core_enforcer.py @@ -481,7 +481,8 @@ def enforce_ex(self, *rvals): else: policy_effects.add(Effector.ALLOW) - # Update explain_index for any matching policy + # Update explain_index for any matching policy before checking early break condition + # to ensure explanations are captured for allow rules in deny models explain_index = i if self.eft.intermediate_effect(policy_effects) != Effector.INDETERMINATE: