This is an automated email from the ASF dual-hosted git repository.

hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin.git


The following commit(s) were added to refs/heads/master by this push:
     new d3e9928  fix: preserve policy order in Model.RemovePolicy
d3e9928 is described below

commit d3e9928ab07b200efa0132f99fa095c084597897
Author: Yang Luo <[email protected]>
AuthorDate: Tue Aug 4 16:11:57 2026 +0800

    fix: preserve policy order in Model.RemovePolicy
---
 model/policy.go | 15 ++++++++-------
 model_test.go   | 20 ++++++++++++++++++++
 2 files changed, 28 insertions(+), 7 deletions(-)

diff --git a/model/policy.go b/model/policy.go
index d4e4899..7669dfe 100644
--- a/model/policy.go
+++ b/model/policy.go
@@ -267,14 +267,15 @@ func (model Model) RemovePolicy(sec string, ptype string, 
rule []string) (bool,
                return false, nil
        }
 
-       lastIdx := len(ast.Policy) - 1
-       if index != lastIdx {
-               ast.Policy[index] = ast.Policy[lastIdx]
-               lastPolicyKey := strings.Join(ast.Policy[index], DefaultSep)
-               ast.PolicyMap[lastPolicyKey] = index
-       }
-       ast.Policy = ast.Policy[:lastIdx]
+       // The order of Policy is significant: it carries the priority 
semantics of
+       // the "priority(p_eft)" effector, both for explicit priority models 
and for
+       // implicit ones where the priority is the policy order itself. So the 
rule
+       // has to be shifted out instead of being swapped with the last one.
+       ast.Policy = append(ast.Policy[:index], ast.Policy[index+1:]...)
        delete(ast.PolicyMap, key)
+       for i := index; i < len(ast.Policy); i++ {
+               ast.PolicyMap[strings.Join(ast.Policy[i], DefaultSep)] = i
+       }
        return true, nil
 }
 
diff --git a/model_test.go b/model_test.go
index 2cb155b..bd0a293 100644
--- a/model_test.go
+++ b/model_test.go
@@ -639,6 +639,26 @@ func TestPriorityModel(t *testing.T) {
        testEnforce(t, e, "bob", "data2", "write", false)
 }
 
+func TestPriorityExplicitRemovePolicyKeepsOrder(t *testing.T) {
+       e, _ := NewEnforcer("examples/priority_model_explicit.conf")
+
+       if _, err := e.AddPolicies([][]string{
+               {"1", "carol", "data9", "read", "allow"},
+               {"2", "alice", "data1", "read", "deny"},
+               {"3", "alice", "data1", "read", "allow"},
+       }); err != nil {
+               t.Fatalf("AddPolicies: %v", err)
+       }
+       testEnforce(t, e, "alice", "data1", "read", false)
+
+       // Removing an unrelated rule must not reorder the remaining ones, 
otherwise
+       // the priority 3 rule would take precedence over the priority 2 one.
+       if _, err := e.RemovePolicy("1", "carol", "data9", "read", "allow"); 
err != nil {
+               t.Fatalf("RemovePolicy: %v", err)
+       }
+       testEnforce(t, e, "alice", "data1", "read", false)
+}
+
 func TestPriorityModelIndeterminate(t *testing.T) {
        e, _ := NewEnforcer("examples/priority_model.conf", 
"examples/priority_indeterminate_policy.csv")
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to