From d07d9c18d9f6578c49fd7c1c5e01503969bf11c8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 13 Jan 2026 18:00:22 +0000 Subject: [PATCH 01/11] Initial plan From d968473bb14d82d55272a6e43575dc8efa9ed0a3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 13 Jan 2026 18:29:38 +0000 Subject: [PATCH 02/11] Replace govaluate with expr - basic implementation complete Co-authored-by: nomeguy <85475922+nomeguy@users.noreply.github.com> --- enforcer.go | 85 +++++++++++++++++++++++++++++++++------ enforcer_interface.go | 3 +- enforcer_synced.go | 4 +- go.mod | 2 +- go.sum | 4 +- management_api.go | 22 +++++++--- model/function.go | 11 ++--- util/builtin_operators.go | 10 ++--- 8 files changed, 102 insertions(+), 39 deletions(-) diff --git a/enforcer.go b/enforcer.go index ff8c5431f..5cc9a6b97 100644 --- a/enforcer.go +++ b/enforcer.go @@ -31,7 +31,8 @@ import ( defaultrolemanager "github.com/casbin/casbin/v3/rbac/default-role-manager" "github.com/casbin/casbin/v3/util" - "github.com/casbin/govaluate" + "github.com/expr-lang/expr" + "github.com/expr-lang/expr/vm" ) // Enforcer is the main interface for authorization enforcement and policy management. @@ -777,8 +778,8 @@ func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interfac if hasEval { functions["eval"] = generateEvalFunction(functions, ¶meters) } - var expression *govaluate.EvaluableExpression - expression, err = e.getAndStoreMatcherExpression(hasEval, expString, functions) + var expression *vm.Program + expression, err = e.getAndStoreMatcherExpression(hasEval, expString, functions, rTokens, pTokens) if err != nil { return false, err } @@ -813,7 +814,13 @@ func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interfac parameters.pVals = pvals - result, err := expression.Eval(parameters) + // Create environment with functions and parameters + env := parameters.ToMap() + for k, v := range functions { + env[k] = v + } + + result, err := expr.Run(expression, env) // log.LogPrint("Result: ", result) if err != nil { @@ -871,7 +878,13 @@ func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interfac parameters.pVals = make([]string, len(parameters.pTokens)) - result, err := expression.Eval(parameters) + // Create environment with functions and parameters + env := parameters.ToMap() + for k, v := range functions { + env[k] = v + } + + result, err := expr.Run(expression, env) if err != nil { return false, err @@ -904,15 +917,27 @@ func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interfac return result, nil } -func (e *Enforcer) getAndStoreMatcherExpression(hasEval bool, expString string, functions map[string]govaluate.ExpressionFunction) (*govaluate.EvaluableExpression, error) { - var expression *govaluate.EvaluableExpression +func (e *Enforcer) getAndStoreMatcherExpression(hasEval bool, expString string, functions map[string]interface{}, rTokens, pTokens map[string]int) (*vm.Program, error) { + var expression *vm.Program var err error var cachedExpression, isPresent = e.matcherMap.Load(expString) if !hasEval && isPresent { - expression = cachedExpression.(*govaluate.EvaluableExpression) + expression = cachedExpression.(*vm.Program) } else { - expression, err = govaluate.NewEvaluableExpressionWithFunctions(expString, functions) + // Create environment with functions and parameter names (with dummy values for type checking) + env := make(map[string]interface{}) + for k, v := range functions { + env[k] = v + } + // Add all r and p parameter names with string type for compilation + for token := range rTokens { + env[token] = "" + } + for token := range pTokens { + env[token] = "" + } + expression, err = expr.Compile(expString, expr.Env(env)) if err != nil { return nil, err } @@ -1041,7 +1066,24 @@ type enforceParameters struct { pVals []string } -// implements govaluate.Parameters. +// ToMap converts enforceParameters to a map suitable for expr evaluation. +func (p enforceParameters) ToMap() map[string]interface{} { + env := make(map[string]interface{}) + + // Add r parameters + for token, index := range p.rTokens { + env[token] = p.rVals[index] + } + + // Add p parameters + for token, index := range p.pTokens { + env[token] = p.pVals[index] + } + + return env +} + +// Get implements parameter access for backward compatibility. func (p enforceParameters) Get(name string) (interface{}, error) { if name == "" { return nil, nil @@ -1065,7 +1107,7 @@ func (p enforceParameters) Get(name string) (interface{}, error) { } } -func generateEvalFunction(functions map[string]govaluate.ExpressionFunction, parameters *enforceParameters) govaluate.ExpressionFunction { +func generateEvalFunction(functions map[string]interface{}, parameters *enforceParameters) func(args ...interface{}) (interface{}, error) { return func(args ...interface{}) (interface{}, error) { if len(args) != 1 { return nil, fmt.Errorf("function eval(subrule string) expected %d arguments, but got %d", 1, len(args)) @@ -1076,10 +1118,27 @@ func generateEvalFunction(functions map[string]govaluate.ExpressionFunction, par return nil, errors.New("argument of eval(subrule string) must be a string") } expression = util.EscapeAssertion(expression) - expr, err := govaluate.NewEvaluableExpressionWithFunctions(expression, functions) + // Create environment with functions and parameter tokens for compilation + env := make(map[string]interface{}) + for k, v := range functions { + env[k] = v + } + // Add all r and p parameter names with empty string for type checking + for token := range parameters.rTokens { + env[token] = "" + } + for token := range parameters.pTokens { + env[token] = "" + } + program, err := expr.Compile(expression, expr.Env(env)) if err != nil { return nil, fmt.Errorf("error while parsing eval parameter: %s, %s", expression, err.Error()) } - return expr.Eval(parameters) + // Create environment with parameters and functions for evaluation + evalEnv := parameters.ToMap() + for k, v := range functions { + evalEnv[k] = v + } + return expr.Run(program, evalEnv) } } diff --git a/enforcer_interface.go b/enforcer_interface.go index 733653187..cea7dab49 100644 --- a/enforcer_interface.go +++ b/enforcer_interface.go @@ -19,7 +19,6 @@ import ( "github.com/casbin/casbin/v3/model" "github.com/casbin/casbin/v3/persist" "github.com/casbin/casbin/v3/rbac" - "github.com/casbin/govaluate" ) var _ IEnforcer = &Enforcer{} @@ -138,7 +137,7 @@ type IEnforcer interface { RemoveNamedGroupingPolicy(ptype string, params ...interface{}) (bool, error) RemoveNamedGroupingPolicies(ptype string, rules [][]string) (bool, error) RemoveFilteredNamedGroupingPolicy(ptype string, fieldIndex int, fieldValues ...string) (bool, error) - AddFunction(name string, function govaluate.ExpressionFunction) + AddFunction(name string, function interface{}) UpdatePolicy(oldPolicy []string, newPolicy []string) (bool, error) UpdatePolicies(oldPolicies [][]string, newPolicies [][]string) (bool, error) diff --git a/enforcer_synced.go b/enforcer_synced.go index 89bbe5dae..6263c3f58 100644 --- a/enforcer_synced.go +++ b/enforcer_synced.go @@ -19,8 +19,6 @@ import ( "sync/atomic" "time" - "github.com/casbin/govaluate" - "github.com/casbin/casbin/v3/persist" "github.com/casbin/casbin/v3/rbac" ) @@ -631,7 +629,7 @@ func (e *SyncedEnforcer) RemoveFilteredNamedGroupingPolicy(ptype string, fieldIn } // AddFunction adds a customized function. -func (e *SyncedEnforcer) AddFunction(name string, function govaluate.ExpressionFunction) { +func (e *SyncedEnforcer) AddFunction(name string, function interface{}) { e.m.Lock() defer e.m.Unlock() e.Enforcer.AddFunction(name, function) diff --git a/go.mod b/go.mod index c46f727d3..331183102 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/casbin/casbin/v3 require ( github.com/bmatcuk/doublestar/v4 v4.6.1 - github.com/casbin/govaluate v1.3.0 + github.com/expr-lang/expr v1.17.7 github.com/google/uuid v1.6.0 ) diff --git a/go.sum b/go.sum index 2f3a1c775..3c2d6b86f 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,6 @@ github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I= github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= -github.com/casbin/govaluate v1.3.0 h1:VA0eSY0M2lA86dYd5kPPuNZMUD9QkWnOCnavGrw9myc= -github.com/casbin/govaluate v1.3.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A= +github.com/expr-lang/expr v1.17.7 h1:Q0xY/e/2aCIp8g9s/LGvMDCC5PxYlvHgDZRQ4y16JX8= +github.com/expr-lang/expr v1.17.7/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= diff --git a/management_api.go b/management_api.go index 7a8f768ee..42d6c1556 100644 --- a/management_api.go +++ b/management_api.go @@ -21,7 +21,8 @@ import ( "github.com/casbin/casbin/v3/constant" "github.com/casbin/casbin/v3/util" - "github.com/casbin/govaluate" + "github.com/expr-lang/expr" + "github.com/expr-lang/expr/vm" ) // GetAllSubjects gets the list of subjects that show up in the current policy. @@ -160,9 +161,14 @@ func (e *Enforcer) GetFilteredNamedPolicyWithMatcher(ptype string, matcher strin expString = util.RemoveComments(util.EscapeAssertion(matcher)) } - var expression *govaluate.EvaluableExpression + var expression *vm.Program - expression, err = govaluate.NewEvaluableExpressionWithFunctions(expString, functions) + // Create environment with functions + env := make(map[string]interface{}) + for k, v := range functions { + env[k] = v + } + expression, err = expr.Compile(expString, expr.Env(env)) if err != nil { return res, err } @@ -188,7 +194,13 @@ func (e *Enforcer) GetFilteredNamedPolicyWithMatcher(ptype string, matcher strin parameters.pVals = pvals - result, err := expression.Eval(parameters) + // Create environment with functions and parameters + evalEnv := parameters.ToMap() + for k, v := range functions { + evalEnv[k] = v + } + + result, err := expr.Run(expression, evalEnv) if err != nil { return res, err @@ -480,7 +492,7 @@ func (e *Enforcer) RemoveFilteredNamedGroupingPolicy(ptype string, fieldIndex in } // AddFunction adds a customized function. -func (e *Enforcer) AddFunction(name string, function govaluate.ExpressionFunction) { +func (e *Enforcer) AddFunction(name string, function interface{}) { e.fm.AddFunction(name, function) } diff --git a/model/function.go b/model/function.go index 956c94b9d..a1db70f42 100644 --- a/model/function.go +++ b/model/function.go @@ -18,7 +18,6 @@ import ( "sync" "github.com/casbin/casbin/v3/util" - "github.com/casbin/govaluate" ) // FunctionMap represents the collection of Function. @@ -26,10 +25,8 @@ type FunctionMap struct { fns *sync.Map } -// [string]govaluate.ExpressionFunction - // AddFunction adds an expression function. -func (fm *FunctionMap) AddFunction(name string, function govaluate.ExpressionFunction) { +func (fm *FunctionMap) AddFunction(name string, function interface{}) { fm.fns.LoadOrStore(name, function) } @@ -54,11 +51,11 @@ func LoadFunctionMap() FunctionMap { } // GetFunctions return a map with all the functions. -func (fm *FunctionMap) GetFunctions() map[string]govaluate.ExpressionFunction { - ret := make(map[string]govaluate.ExpressionFunction) +func (fm *FunctionMap) GetFunctions() map[string]interface{} { + ret := make(map[string]interface{}) fm.fns.Range(func(k interface{}, v interface{}) bool { - ret[k.(string)] = v.(govaluate.ExpressionFunction) + ret[k.(string)] = v return true }) diff --git a/util/builtin_operators.go b/util/builtin_operators.go index 37d9cb5bf..6a99cf774 100644 --- a/util/builtin_operators.go +++ b/util/builtin_operators.go @@ -26,8 +26,6 @@ import ( "github.com/bmatcuk/doublestar/v4" "github.com/casbin/casbin/v3/rbac" - - "github.com/casbin/govaluate" ) var ( @@ -402,10 +400,10 @@ func GlobMatchFunc(args ...interface{}) (interface{}, error) { } // GenerateGFunction is the factory method of the g(_, _[, _]) function. -func GenerateGFunction(rm rbac.RoleManager) govaluate.ExpressionFunction { +func GenerateGFunction(rm rbac.RoleManager) func(args ...interface{}) (interface{}, error) { memorized := sync.Map{} return func(args ...interface{}) (interface{}, error) { - // Like all our other govaluate functions, all args are strings. + // Like all our other expression functions, all args are strings. // Allocate and generate a cache key from the arguments... total := len(args) @@ -445,9 +443,9 @@ func GenerateGFunction(rm rbac.RoleManager) govaluate.ExpressionFunction { } // GenerateConditionalGFunction is the factory method of the g(_, _[, _]) function with conditions. -func GenerateConditionalGFunction(crm rbac.ConditionalRoleManager) govaluate.ExpressionFunction { +func GenerateConditionalGFunction(crm rbac.ConditionalRoleManager) func(args ...interface{}) (interface{}, error) { return func(args ...interface{}) (interface{}, error) { - // Like all our other govaluate functions, all args are strings. + // Like all our other expression functions, all args are strings. var hasLink bool name1, name2 := args[0].(string), args[1].(string) From 066e918d1e958cb8bcfa67bbe8f1418c6581effc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 13 Jan 2026 18:44:14 +0000 Subject: [PATCH 03/11] Complete migration from govaluate to expr - all tests passing Co-authored-by: nomeguy <85475922+nomeguy@users.noreply.github.com> --- enforcer.go | 26 ++++++++------------------ management_api.go | 5 ++++- util/util.go | 15 +++++++++++++++ 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/enforcer.go b/enforcer.go index 5cc9a6b97..9fdd6d0a5 100644 --- a/enforcer.go +++ b/enforcer.go @@ -738,6 +738,8 @@ func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interfac // For custom matchers provided at runtime, escape backslashes in string literals expString = util.EscapeStringLiterals(util.RemoveComments(util.EscapeAssertion(matcher))) } + // Convert govaluate IN operator syntax to expr syntax + expString = util.ConvertInOperatorSyntax(expString) rTokens := make(map[string]int, len(e.model["r"][rType].Tokens)) for i, token := range e.model["r"][rType].Tokens { @@ -925,19 +927,13 @@ func (e *Enforcer) getAndStoreMatcherExpression(hasEval bool, expString string, if !hasEval && isPresent { expression = cachedExpression.(*vm.Program) } else { - // Create environment with functions and parameter names (with dummy values for type checking) + // Create environment with functions env := make(map[string]interface{}) for k, v := range functions { env[k] = v } - // Add all r and p parameter names with string type for compilation - for token := range rTokens { - env[token] = "" - } - for token := range pTokens { - env[token] = "" - } - expression, err = expr.Compile(expString, expr.Env(env)) + // Compile with AllowUndefinedVariables to support ABAC and dynamic parameter access + expression, err = expr.Compile(expString, expr.Env(env), expr.AllowUndefinedVariables()) if err != nil { return nil, err } @@ -1118,19 +1114,13 @@ func generateEvalFunction(functions map[string]interface{}, parameters *enforceP return nil, errors.New("argument of eval(subrule string) must be a string") } expression = util.EscapeAssertion(expression) - // Create environment with functions and parameter tokens for compilation + // Create environment with functions for compilation env := make(map[string]interface{}) for k, v := range functions { env[k] = v } - // Add all r and p parameter names with empty string for type checking - for token := range parameters.rTokens { - env[token] = "" - } - for token := range parameters.pTokens { - env[token] = "" - } - program, err := expr.Compile(expression, expr.Env(env)) + // Compile with AllowUndefinedVariables to support dynamic parameter access + program, err := expr.Compile(expression, expr.Env(env), expr.AllowUndefinedVariables()) if err != nil { return nil, fmt.Errorf("error while parsing eval parameter: %s, %s", expression, err.Error()) } diff --git a/management_api.go b/management_api.go index 42d6c1556..35b868bfa 100644 --- a/management_api.go +++ b/management_api.go @@ -160,6 +160,8 @@ func (e *Enforcer) GetFilteredNamedPolicyWithMatcher(ptype string, matcher strin } else { expString = util.RemoveComments(util.EscapeAssertion(matcher)) } + // Convert govaluate IN operator syntax to expr syntax + expString = util.ConvertInOperatorSyntax(expString) var expression *vm.Program @@ -168,7 +170,8 @@ func (e *Enforcer) GetFilteredNamedPolicyWithMatcher(ptype string, matcher strin for k, v := range functions { env[k] = v } - expression, err = expr.Compile(expString, expr.Env(env)) + // Compile with AllowUndefinedVariables to support dynamic parameter access + expression, err = expr.Compile(expString, expr.Env(env), expr.AllowUndefinedVariables()) if err != nil { return res, err } diff --git a/util/util.go b/util/util.go index b72823a4c..34a733ec0 100644 --- a/util/util.go +++ b/util/util.go @@ -311,6 +311,21 @@ func EscapeStringLiterals(expr string) string { return result.String() } +// ConvertInOperatorSyntax converts govaluate's IN operator syntax to expr's syntax. +// Changes: `x in ('a', 'b')` to `x in ['a', 'b']` +// Also handles: `x IN ('a', 'b')` (case insensitive) +// And: `x IN array` to `x in array` +func ConvertInOperatorSyntax(expression string) string { + // First, replace all IN/In/iN with lowercase 'in' (case insensitive) + // Use word boundaries to avoid replacing IN in the middle of identifiers + reCase := regexp.MustCompile(`\bIN\b`) + expression = reCase.ReplaceAllString(expression, "in") + + // Then, replace `in (...)` with `in [...]` + re := regexp.MustCompile(`\bin\s*\(([^)]+)\)`) + return re.ReplaceAllString(expression, "in [$1]") +} + func RemoveDuplicateElement(s []string) []string { result := make([]string, 0, len(s)) temp := map[string]struct{}{} From 25e24a4153cce2bffdf5fd1f29fa8b48da930f4d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 13 Jan 2026 18:50:41 +0000 Subject: [PATCH 04/11] Address code review comments - fix regex case sensitivity and add IN operator conversion to eval function Co-authored-by: nomeguy <85475922+nomeguy@users.noreply.github.com> --- enforcer.go | 2 ++ util/util.go | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/enforcer.go b/enforcer.go index 9fdd6d0a5..ef7005e73 100644 --- a/enforcer.go +++ b/enforcer.go @@ -1114,6 +1114,8 @@ func generateEvalFunction(functions map[string]interface{}, parameters *enforceP return nil, errors.New("argument of eval(subrule string) must be a string") } expression = util.EscapeAssertion(expression) + // Convert IN operator syntax for compatibility + expression = util.ConvertInOperatorSyntax(expression) // Create environment with functions for compilation env := make(map[string]interface{}) for k, v := range functions { diff --git a/util/util.go b/util/util.go index 34a733ec0..91e1a5b36 100644 --- a/util/util.go +++ b/util/util.go @@ -318,10 +318,11 @@ func EscapeStringLiterals(expr string) string { func ConvertInOperatorSyntax(expression string) string { // First, replace all IN/In/iN with lowercase 'in' (case insensitive) // Use word boundaries to avoid replacing IN in the middle of identifiers - reCase := regexp.MustCompile(`\bIN\b`) + reCase := regexp.MustCompile(`(?i)\bIN\b`) expression = reCase.ReplaceAllString(expression, "in") // Then, replace `in (...)` with `in [...]` + // This handles simple cases but may not work with deeply nested parentheses re := regexp.MustCompile(`\bin\s*\(([^)]+)\)`) return re.ReplaceAllString(expression, "in [$1]") } From b1b2782151f0bfb4f78990b770da786ea3838fef Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 02:33:20 +0000 Subject: [PATCH 05/11] Fix linting issues - correct import order and add missing periods in comments Co-authored-by: nomeguy <85475922+nomeguy@users.noreply.github.com> --- enforcer.go | 6 +++--- management_api.go | 5 +++-- util/util.go | 10 +++++----- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/enforcer.go b/enforcer.go index ef7005e73..04ab32aeb 100644 --- a/enforcer.go +++ b/enforcer.go @@ -21,6 +21,9 @@ import ( "strings" "sync" + "github.com/expr-lang/expr" + "github.com/expr-lang/expr/vm" + "github.com/casbin/casbin/v3/detector" "github.com/casbin/casbin/v3/effector" "github.com/casbin/casbin/v3/log" @@ -30,9 +33,6 @@ import ( "github.com/casbin/casbin/v3/rbac" defaultrolemanager "github.com/casbin/casbin/v3/rbac/default-role-manager" "github.com/casbin/casbin/v3/util" - - "github.com/expr-lang/expr" - "github.com/expr-lang/expr/vm" ) // Enforcer is the main interface for authorization enforcement and policy management. diff --git a/management_api.go b/management_api.go index 35b868bfa..5629f726f 100644 --- a/management_api.go +++ b/management_api.go @@ -19,10 +19,11 @@ import ( "fmt" "strings" - "github.com/casbin/casbin/v3/constant" - "github.com/casbin/casbin/v3/util" "github.com/expr-lang/expr" "github.com/expr-lang/expr/vm" + + "github.com/casbin/casbin/v3/constant" + "github.com/casbin/casbin/v3/util" ) // GetAllSubjects gets the list of subjects that show up in the current policy. diff --git a/util/util.go b/util/util.go index 91e1a5b36..0387d36ea 100644 --- a/util/util.go +++ b/util/util.go @@ -313,16 +313,16 @@ func EscapeStringLiterals(expr string) string { // ConvertInOperatorSyntax converts govaluate's IN operator syntax to expr's syntax. // Changes: `x in ('a', 'b')` to `x in ['a', 'b']` -// Also handles: `x IN ('a', 'b')` (case insensitive) -// And: `x IN array` to `x in array` +// Also handles: `x IN ('a', 'b')` (case insensitive). +// And: `x IN array` to `x in array`. func ConvertInOperatorSyntax(expression string) string { // First, replace all IN/In/iN with lowercase 'in' (case insensitive) - // Use word boundaries to avoid replacing IN in the middle of identifiers + // Use word boundaries to avoid replacing IN in the middle of identifiers. reCase := regexp.MustCompile(`(?i)\bIN\b`) expression = reCase.ReplaceAllString(expression, "in") - + // Then, replace `in (...)` with `in [...]` - // This handles simple cases but may not work with deeply nested parentheses + // This handles simple cases but may not work with deeply nested parentheses. re := regexp.MustCompile(`\bin\s*\(([^)]+)\)`) return re.ReplaceAllString(expression, "in [$1]") } From 322d864b1bf2e38b4e9cc05c6ed6c357ae3c23d0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 02:40:08 +0000 Subject: [PATCH 06/11] Fix goimports - remove blank line between third-party imports Co-authored-by: nomeguy <85475922+nomeguy@users.noreply.github.com> --- enforcer.go | 5 ++--- management_api.go | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/enforcer.go b/enforcer.go index 04ab32aeb..d2993c689 100644 --- a/enforcer.go +++ b/enforcer.go @@ -21,9 +21,6 @@ import ( "strings" "sync" - "github.com/expr-lang/expr" - "github.com/expr-lang/expr/vm" - "github.com/casbin/casbin/v3/detector" "github.com/casbin/casbin/v3/effector" "github.com/casbin/casbin/v3/log" @@ -33,6 +30,8 @@ import ( "github.com/casbin/casbin/v3/rbac" defaultrolemanager "github.com/casbin/casbin/v3/rbac/default-role-manager" "github.com/casbin/casbin/v3/util" + "github.com/expr-lang/expr" + "github.com/expr-lang/expr/vm" ) // Enforcer is the main interface for authorization enforcement and policy management. diff --git a/management_api.go b/management_api.go index 5629f726f..35b868bfa 100644 --- a/management_api.go +++ b/management_api.go @@ -19,11 +19,10 @@ import ( "fmt" "strings" - "github.com/expr-lang/expr" - "github.com/expr-lang/expr/vm" - "github.com/casbin/casbin/v3/constant" "github.com/casbin/casbin/v3/util" + "github.com/expr-lang/expr" + "github.com/expr-lang/expr/vm" ) // GetAllSubjects gets the list of subjects that show up in the current policy. From 0ed14806e2de494234150850da0abc5217f12d34 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 03:34:30 +0000 Subject: [PATCH 07/11] Fix goimports - separate external packages from internal casbin packages Co-authored-by: nomeguy <85475922+nomeguy@users.noreply.github.com> --- enforcer.go | 1 + management_api.go | 1 + 2 files changed, 2 insertions(+) diff --git a/enforcer.go b/enforcer.go index d2993c689..ef7005e73 100644 --- a/enforcer.go +++ b/enforcer.go @@ -30,6 +30,7 @@ import ( "github.com/casbin/casbin/v3/rbac" defaultrolemanager "github.com/casbin/casbin/v3/rbac/default-role-manager" "github.com/casbin/casbin/v3/util" + "github.com/expr-lang/expr" "github.com/expr-lang/expr/vm" ) diff --git a/management_api.go b/management_api.go index 35b868bfa..5a4138962 100644 --- a/management_api.go +++ b/management_api.go @@ -21,6 +21,7 @@ import ( "github.com/casbin/casbin/v3/constant" "github.com/casbin/casbin/v3/util" + "github.com/expr-lang/expr" "github.com/expr-lang/expr/vm" ) From 39453e6aa18fdca59daca7ba6d5a38994f8df680 Mon Sep 17 00:00:00 2001 From: Gucheng <85475922+nomeguy@users.noreply.github.com> Date: Wed, 14 Jan 2026 12:04:14 +0800 Subject: [PATCH 08/11] Update management_api.go --- management_api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/management_api.go b/management_api.go index 5a4138962..fc47c44f6 100644 --- a/management_api.go +++ b/management_api.go @@ -203,7 +203,7 @@ func (e *Enforcer) GetFilteredNamedPolicyWithMatcher(ptype string, matcher strin for k, v := range functions { evalEnv[k] = v } - + result, err := expr.Run(expression, evalEnv) if err != nil { From 5db9f67ea85ddbc023d56b14667d6b3b4138322e Mon Sep 17 00:00:00 2001 From: Gucheng <85475922+nomeguy@users.noreply.github.com> Date: Wed, 14 Jan 2026 12:04:41 +0800 Subject: [PATCH 09/11] Update enforcer.go --- enforcer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enforcer.go b/enforcer.go index ef7005e73..4864d812a 100644 --- a/enforcer.go +++ b/enforcer.go @@ -821,7 +821,7 @@ func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interfac for k, v := range functions { env[k] = v } - + result, err := expr.Run(expression, env) // log.LogPrint("Result: ", result) From 78a0526ed5935a986e08017b18bc72caa7bfcce4 Mon Sep 17 00:00:00 2001 From: Gucheng <85475922+nomeguy@users.noreply.github.com> Date: Wed, 14 Jan 2026 13:24:02 +0800 Subject: [PATCH 10/11] Update enforcer.go --- enforcer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enforcer.go b/enforcer.go index 4864d812a..fe7d94149 100644 --- a/enforcer.go +++ b/enforcer.go @@ -885,7 +885,7 @@ func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interfac for k, v := range functions { env[k] = v } - + result, err := expr.Run(expression, env) if err != nil { From 099beb409e1767b62a60ae17e681f9983ab608e3 Mon Sep 17 00:00:00 2001 From: Gucheng <85475922+nomeguy@users.noreply.github.com> Date: Wed, 14 Jan 2026 13:48:29 +0800 Subject: [PATCH 11/11] Update enforcer.go --- enforcer.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/enforcer.go b/enforcer.go index fe7d94149..f82a2c5d7 100644 --- a/enforcer.go +++ b/enforcer.go @@ -1065,17 +1065,17 @@ type enforceParameters struct { // ToMap converts enforceParameters to a map suitable for expr evaluation. func (p enforceParameters) ToMap() map[string]interface{} { env := make(map[string]interface{}) - + // Add r parameters for token, index := range p.rTokens { env[token] = p.rVals[index] } - + // Add p parameters for token, index := range p.pTokens { env[token] = p.pVals[index] } - + return env }