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 e9df34e  ci: migrate golangci-lint to v2 and fix lint issues
e9df34e is described below

commit e9df34e092f925e0031f7db4e062f2fbddf3dc86
Author: Yang Luo <[email protected]>
AuthorDate: Tue Aug 4 17:03:20 2026 +0800

    ci: migrate golangci-lint to v2 and fix lint issues
---
 .github/workflows/golangci-lint.yml |   4 +-
 .golangci.yml                       | 536 +++++++++++++-----------------------
 ai_api.go                           |  16 +-
 enforcer.go                         |  36 +--
 enforcer_context.go                 |   4 +-
 frontend_test.go                    |   6 +-
 model/constraint.go                 |   4 +-
 model/model.go                      |  19 +-
 model/model_test.go                 |   4 +-
 persist/persist_test.go             |   4 +-
 util/builtin_operators.go           |  12 +-
 util/util.go                        |   5 +-
 12 files changed, 249 insertions(+), 401 deletions(-)

diff --git a/.github/workflows/golangci-lint.yml 
b/.github/workflows/golangci-lint.yml
index f16c34e..9b9a94f 100644
--- a/.github/workflows/golangci-lint.yml
+++ b/.github/workflows/golangci-lint.yml
@@ -23,6 +23,4 @@ jobs:
           go-version: '1.21'
 
       - name: golangci-lint
-        uses: golangci/golangci-lint-action@v4
-        with:
-          version: v1.56.2
\ No newline at end of file
+        uses: golangci/golangci-lint-action@v8
\ No newline at end of file
diff --git a/.golangci.yml b/.golangci.yml
index b8d3620..a332bdb 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -2,353 +2,197 @@
 # This code is licensed under the terms of the MIT license 
https://opensource.org/license/mit
 # Copyright (c) 2021 Marat Reymers
 
-## Golden config for golangci-lint v1.56.2
-#
-# This is the best config for golangci-lint based on my experience and opinion.
-# It is very strict, but not extremely strict.
-# Feel free to adapt and change it for your needs.
-
-run:
-  # Timeout for analysis, e.g. 30s, 5m.
-  # Default: 1m
-  timeout: 3m
-
-
-# This file contains only configs which differ from defaults.
-# All possible options can be found here 
https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml
-linters-settings:
-  cyclop:
-    # The maximal code complexity to report.
-    # Default: 10
-    max-complexity: 30
-    # The maximal average package complexity.
-    # If it's higher than 0.0 (float) the check is enabled
-    # Default: 0.0
-    package-average: 10.0
-
-  errcheck:
-    # Report about not checking of errors in type assertions: `a := 
b.(MyStruct)`.
-    # Such cases aren't reported by default.
-    # Default: false
-    check-type-assertions: true
-
-  exhaustive:
-    # Program elements to check for exhaustiveness.
-    # Default: [ switch ]
-    check:
-      - switch
-      - map
-
-  exhaustruct:
-    # List of regular expressions to exclude struct packages and their names 
from checks.
-    # Regular expressions must match complete canonical struct 
package/name/structname.
-    # Default: []
-    exclude:
-      # std libs
-      - "^net/http.Client$"
-      - "^net/http.Cookie$"
-      - "^net/http.Request$"
-      - "^net/http.Response$"
-      - "^net/http.Server$"
-      - "^net/http.Transport$"
-      - "^net/url.URL$"
-      - "^os/exec.Cmd$"
-      - "^reflect.StructField$"
-      # public libs
-      - "^github.com/Shopify/sarama.Config$"
-      - "^github.com/Shopify/sarama.ProducerMessage$"
-      - "^github.com/mitchellh/mapstructure.DecoderConfig$"
-      - "^github.com/prometheus/client_golang/.+Opts$"
-      - "^github.com/spf13/cobra.Command$"
-      - "^github.com/spf13/cobra.CompletionOptions$"
-      - "^github.com/stretchr/testify/mock.Mock$"
-      - "^github.com/testcontainers/testcontainers-go.+Request$"
-      - "^github.com/testcontainers/testcontainers-go.FromDockerfile$"
-      - "^golang.org/x/tools/go/analysis.Analyzer$"
-      - "^google.golang.org/protobuf/.+Options$"
-      - "^gopkg.in/yaml.v3.Node$"
-
-  funlen:
-    # Checks the number of lines in a function.
-    # If lower than 0, disable the check.
-    # Default: 60
-    lines: 100
-    # Checks the number of statements in a function.
-    # If lower than 0, disable the check.
-    # Default: 40
-    statements: 50
-    # Ignore comments when counting lines.
-    # Default false
-    ignore-comments: true
-
-  gocognit:
-    # Minimal code complexity to report.
-    # Default: 30 (but we recommend 10-20)
-    min-complexity: 20
-
-  gocritic:
-    # Settings passed to gocritic.
-    # The settings key is the name of a supported gocritic checker.
-    # The list of supported checkers can be find in 
https://go-critic.github.io/overview.
-    settings:
-      captLocal:
-        # Whether to restrict checker to params only.
-        # Default: true
-        paramsOnly: false
-      underef:
-        # Whether to skip (*x).method() calls where x is a pointer receiver.
-        # Default: true
-        skipRecvDeref: false
-
-  gomnd:
-    # List of function patterns to exclude from analysis.
-    # Values always ignored: `time.Date`,
-    # `strconv.FormatInt`, `strconv.FormatUint`, `strconv.FormatFloat`,
-    # `strconv.ParseInt`, `strconv.ParseUint`, `strconv.ParseFloat`.
-    # Default: []
-    ignored-functions:
-      - flag.Arg
-      - flag.Duration.*
-      - flag.Float.*
-      - flag.Int.*
-      - flag.Uint.*
-      - os.Chmod
-      - os.Mkdir.*
-      - os.OpenFile
-      - os.WriteFile
-      - prometheus.ExponentialBuckets.*
-      - prometheus.LinearBuckets
-
-  gomodguard:
-    blocked:
-      # List of blocked modules.
-      # Default: []
-      modules:
-        - github.com/golang/protobuf:
-            recommendations:
-              - google.golang.org/protobuf
-            reason: "see 
https://developers.google.com/protocol-buffers/docs/reference/go/faq#modules";
-        - github.com/satori/go.uuid:
-            recommendations:
-              - github.com/google/uuid
-            reason: "satori's package is not maintained"
-        - github.com/gofrs/uuid:
-            recommendations:
-              - github.com/gofrs/uuid/v5
-            reason: "gofrs' package was not go module before v5"
-
-  govet:
-    # Enable all analyzers.
-    # Default: false
-    enable-all: true
-    # Disable analyzers by name.
-    # Run `go tool vet help` to see all analyzers.
-    # Default: []
-    disable:
-      - fieldalignment # too strict
-    # Settings per analyzer.
-    settings:
-      shadow:
-        # Whether to be strict about shadowing; can be noisy.
-        # Default: false
-        #strict: true
-
-  inamedparam:
-    # Skips check for interface methods with only a single parameter.
-    # Default: false
-    skip-single-param: true
-
-  nakedret:
-    # Make an issue if func has more lines of code than this setting, and it 
has naked returns.
-    # Default: 30
-    max-func-lines: 0
-
-  nolintlint:
-    # Exclude following linters from requiring an explanation.
-    # Default: []
-    allow-no-explanation: [ funlen, gocognit, lll ]
-    # Enable to require an explanation of nonzero length after each nolint 
directive.
-    # Default: false
-    require-explanation: true
-    # Enable to require nolint directives to mention the specific linter being 
suppressed.
-    # Default: false
-    require-specific: true
-
-  perfsprint:
-    # Optimizes into strings concatenation.
-    # Default: true
-    strconcat: false
-
-  rowserrcheck:
-    # database/sql is always checked
-    # Default: []
-    packages:
-      - github.com/jmoiron/sqlx
-
-  tenv:
-    # The option `all` will run against whole test files (`_test.go`) 
regardless of method/function signatures.
-    # Otherwise, only methods that take `*testing.T`, `*testing.B`, and 
`testing.TB` as arguments are checked.
-    # Default: false
-    all: true
-
-  stylecheck:
-    # STxxxx checks in 
https://staticcheck.io/docs/configuration/options/#checks
-    # Default: ["*"]
-    checks: ["all", "-ST1003"]
-
-  revive:
-    rules:
-      # 
https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unused-parameter
-      - name: unused-parameter
-        disabled: true
-
+version: "2"
 linters:
-  disable-all: true
+  default: none
   enable:
-    ## enabled by default
-    #- errcheck # checking for unchecked errors, these unchecked errors can be 
critical bugs in some cases
-    - gosimple # specializes in simplifying a code
-    - govet # reports suspicious constructs, such as Printf calls whose 
arguments do not align with the format string
-    - ineffassign # detects when assignments to existing variables are not used
-    - staticcheck # is a go vet on steroids, applying a ton of static analysis 
checks
-    - typecheck # like the front-end of a Go compiler, parses and type-checks 
Go code
-    - unused # checks for unused constants, variables, functions and types
-    ## disabled by default
-    - asasalint # checks for pass []any as any in variadic func(...any)
-    - asciicheck # checks that your code does not contain non-ASCII identifiers
-    - bidichk # checks for dangerous unicode character sequences
-    - bodyclose # checks whether HTTP response body is closed successfully
-    - cyclop # checks function and package cyclomatic complexity
-    - dupl # tool for code clone detection
-    - durationcheck # checks for two durations multiplied together
-    - errname # checks that sentinel errors are prefixed with the Err and 
error types are suffixed with the Error
-    #- errorlint # finds code that will cause problems with the error wrapping 
scheme introduced in Go 1.13
-    - execinquery # checks query string in Query function which reads your Go 
src files and warning it finds
-    - exhaustive # checks exhaustiveness of enum switch statements
-    - exportloopref # checks for pointers to enclosing loop variables
-    #- forbidigo # forbids identifiers
-    - funlen # tool for detection of long functions
-    - gocheckcompilerdirectives # validates go compiler directive comments 
(//go:)
-    #- gochecknoglobals # checks that no global variables exist
-    - gochecknoinits # checks that no init functions are present in Go code
-    - gochecksumtype # checks exhaustiveness on Go "sum types"
-    #- gocognit # computes and checks the cognitive complexity of functions
-    #- goconst # finds repeated strings that could be replaced by a constant
-    #- gocritic # provides diagnostics that check for bugs, performance and 
style issues
-    - gocyclo # computes and checks the cyclomatic complexity of functions
-    - godot # checks if comments end in a period
-    - goimports # in addition to fixing imports, goimports also formats your 
code in the same style as gofmt
-    #- gomnd # detects magic numbers
-    - gomoddirectives # manages the use of 'replace', 'retract', and 
'excludes' directives in go.mod
-    - gomodguard # allow and block lists linter for direct Go module 
dependencies. This is different from depguard where there are different block 
types for example version constraints and module recommendations
-    - goprintffuncname # checks that printf-like functions are named with f at 
the end
-    - gosec # inspects source code for security problems
-    #- lll # reports long lines
-    - loggercheck # checks key value pairs for common logger libraries 
(kitlog,klog,logr,zap)
-    - makezero # finds slice declarations with non-zero initial length
-    - mirror # reports wrong mirror patterns of bytes/strings usage
-    - musttag # enforces field tags in (un)marshaled structs
-    - nakedret # finds naked returns in functions greater than a specified 
function length
-    - nestif # reports deeply nested if statements
-    - nilerr # finds the code that returns nil even if it checks that the 
error is not nil
-    #- nilnil # checks that there is no simultaneous return of nil error and 
an invalid value
-    - noctx # finds sending http request without context.Context
-    - nolintlint # reports ill-formed or insufficient nolint directives
-    #- nonamedreturns # reports all named returns
-    - nosprintfhostport # checks for misuse of Sprintf to construct a host 
with port in a URL
-    #- perfsprint # checks that fmt.Sprintf can be replaced with a faster 
alternative
-    - predeclared # finds code that shadows one of Go's predeclared identifiers
-    - promlinter # checks Prometheus metrics naming via promlint
-    - protogetter # reports direct reads from proto message fields when 
getters should be used
-    - reassign # checks that package variables are not reassigned
-    - revive # fast, configurable, extensible, flexible, and beautiful linter 
for Go, drop-in replacement of golint
-    - rowserrcheck # checks whether Err of rows is checked successfully
-    - sloglint # ensure consistent code style when using log/slog
-    - spancheck # checks for mistakes with OpenTelemetry/Census spans
-    - sqlclosecheck # checks that sql.Rows and sql.Stmt are closed
-    - stylecheck # is a replacement for golint
-    - tenv # detects using os.Setenv instead of t.Setenv since Go1.17
-    - testableexamples # checks if examples are testable (have an expected 
output)
-    - testifylint # checks usage of github.com/stretchr/testify
-    #- testpackage # makes you use a separate _test package
-    - tparallel # detects inappropriate usage of t.Parallel() method in your 
Go test codes
-    - unconvert # removes unnecessary type conversions
-    #- unparam # reports unused function parameters
-    - usestdlibvars # detects the possibility to use variables/constants from 
the Go standard library
-    - wastedassign # finds wasted assignment statements
-    - whitespace # detects leading and trailing whitespace
-
-    ## you may want to enable
-    #- decorder # checks declaration order and count of types, constants, 
variables and functions
-    #- exhaustruct # [highly recommend to enable] checks if all structure 
fields are initialized
-    #- gci # controls golang package import order and makes it always 
deterministic
-    #- ginkgolinter # [if you use ginkgo/gomega] enforces standards of using 
ginkgo and gomega
-    #- godox # detects FIXME, TODO and other comment keywords
-    #- goheader # checks is file header matches to pattern
-    #- inamedparam # [great idea, but too strict, need to ignore a lot of 
cases by default] reports interfaces with unnamed method parameters
-    #- interfacebloat # checks the number of methods inside an interface
-    #- ireturn # accept interfaces, return concrete types
-    #- prealloc # [premature optimization, but can be used in some cases] 
finds slice declarations that could potentially be preallocated
-    #- tagalign # checks that struct tags are well aligned
-    #- varnamelen # [great idea, but too many false positives] checks that the 
length of a variable's name matches its scope
-    #- wrapcheck # checks that errors returned from external packages are 
wrapped
-    #- zerologlint # detects the wrong usage of zerolog that a user forgets to 
dispatch zerolog.Event
-
-    ## disabled
-    #- containedctx # detects struct contained context.Context field
-    #- contextcheck # [too many false positives] checks the function whether 
use a non-inherited context
-    #- depguard # [replaced by gomodguard] checks if package imports are in a 
list of acceptable packages
-    #- dogsled # checks assignments with too many blank identifiers (e.g. x, 
_, _, _, := f())
-    #- dupword # [useless without config] checks for duplicate words in the 
source code
-    #- errchkjson # [don't see profit + I'm against of omitting errors like in 
the first example https://github.com/breml/errchkjson] checks types passed to 
the json encoding functions. Reports unsupported types and optionally reports 
occasions, where the check for the returned error can be omitted
-    #- forcetypeassert # [replaced by errcheck] finds forced type assertions
-    #- goerr113 # [too strict] checks the errors handling expressions
-    #- gofmt # [replaced by goimports] checks whether code was gofmt-ed
-    #- gofumpt # [replaced by goimports, gofumports is not available yet] 
checks whether code was gofumpt-ed
-    #- gosmopolitan # reports certain i18n/l10n anti-patterns in your Go 
codebase
-    #- grouper # analyzes expression groups
-    #- importas # enforces consistent import aliases
-    #- maintidx # measures the maintainability index of each function
-    #- misspell # [useless] finds commonly misspelled English words in comments
-    #- nlreturn # [too strict and mostly code is not more readable] checks for 
a new line before return and branch statements to increase code clarity
-    #- paralleltest # [too many false positives] detects missing usage of 
t.Parallel() method in your Go test
-    #- tagliatelle # checks the struct tags
-    #- thelper # detects golang test helpers without t.Helper() call and 
checks the consistency of test helpers
-    #- wsl # [too strict and mostly code is not more readable] whitespace 
linter forces you to use empty lines
-
-    ## deprecated
-    #- deadcode # [deprecated, replaced by unused] finds unused code
-    #- exhaustivestruct # [deprecated, replaced by exhaustruct] checks if all 
struct's fields are initialized
-    #- golint # [deprecated, replaced by revive] golint differs from gofmt. 
Gofmt reformats Go source code, whereas golint prints out style mistakes
-    #- ifshort # [deprecated] checks that your code uses short syntax for 
if-statements whenever possible
-    #- interfacer # [deprecated] suggests narrower interface types
-    #- maligned # [deprecated, replaced by govet fieldalignment] detects Go 
structs that would take less memory if their fields were sorted
-    #- nosnakecase # [deprecated, replaced by revive var-naming] detects snake 
case of variable naming and function name
-    #- scopelint # [deprecated, replaced by exportloopref] checks for unpinned 
variables in go programs
-    #- structcheck # [deprecated, replaced by unused] finds unused struct 
fields
-    #- varcheck # [deprecated, replaced by unused] finds unused global 
variables and constants
-
-
+    - asasalint
+    - asciicheck
+    - bidichk
+    - bodyclose
+    - cyclop
+    - dupl
+    - durationcheck
+    - errname
+    - exhaustive
+    - funlen
+    - gocheckcompilerdirectives
+    - gochecknoinits
+    - gochecksumtype
+    - gocyclo
+    - godot
+    - gomoddirectives
+    - gomodguard_v2
+    - goprintffuncname
+    - gosec
+    - govet
+    - ineffassign
+    - loggercheck
+    - makezero
+    - mirror
+    - musttag
+    - nakedret
+    - nestif
+    - nilerr
+    - noctx
+    - nolintlint
+    - nosprintfhostport
+    - predeclared
+    - promlinter
+    - protogetter
+    - reassign
+    - revive
+    - rowserrcheck
+    - sloglint
+    - spancheck
+    - sqlclosecheck
+    - staticcheck
+    - testableexamples
+    - testifylint
+    - tparallel
+    - unconvert
+    - unused
+    - usestdlibvars
+    - wastedassign
+    - whitespace
+  settings:
+    cyclop:
+      max-complexity: 30
+      package-average: 10
+    errcheck:
+      check-type-assertions: true
+    exhaustive:
+      check:
+        - switch
+        - map
+    exhaustruct:
+      exclude:
+        - ^net/http.Client$
+        - ^net/http.Cookie$
+        - ^net/http.Request$
+        - ^net/http.Response$
+        - ^net/http.Server$
+        - ^net/http.Transport$
+        - ^net/url.URL$
+        - ^os/exec.Cmd$
+        - ^reflect.StructField$
+        - ^github.com/Shopify/sarama.Config$
+        - ^github.com/Shopify/sarama.ProducerMessage$
+        - ^github.com/mitchellh/mapstructure.DecoderConfig$
+        - ^github.com/prometheus/client_golang/.+Opts$
+        - ^github.com/spf13/cobra.Command$
+        - ^github.com/spf13/cobra.CompletionOptions$
+        - ^github.com/stretchr/testify/mock.Mock$
+        - ^github.com/testcontainers/testcontainers-go.+Request$
+        - ^github.com/testcontainers/testcontainers-go.FromDockerfile$
+        - ^golang.org/x/tools/go/analysis.Analyzer$
+        - ^google.golang.org/protobuf/.+Options$
+        - ^gopkg.in/yaml.v3.Node$
+    funlen:
+      lines: 100
+      statements: 50
+      ignore-comments: true
+    gocognit:
+      min-complexity: 20
+    gocritic:
+      settings:
+        captLocal:
+          paramsOnly: false
+        underef:
+          skipRecvDeref: false
+    gomodguard_v2:
+      blocked:
+        - module: github.com/golang/protobuf
+          recommendations:
+            - google.golang.org/protobuf
+          reason: see 
https://developers.google.com/protocol-buffers/docs/reference/go/faq#modules
+        - module: github.com/satori/go.uuid
+          recommendations:
+            - github.com/google/uuid
+          reason: satori's package is not maintained
+        - module: github.com/gofrs/uuid
+          recommendations:
+            - github.com/gofrs/uuid/v5
+          reason: gofrs' package was not go module before v5
+    govet:
+      disable:
+        - fieldalignment
+      enable-all: true
+    inamedparam:
+      skip-single-param: true
+    mnd:
+      ignored-functions:
+        - flag.Arg
+        - flag.Duration.*
+        - flag.Float.*
+        - flag.Int.*
+        - flag.Uint.*
+        - os.Chmod
+        - os.Mkdir.*
+        - os.OpenFile
+        - os.WriteFile
+        - prometheus.ExponentialBuckets.*
+        - prometheus.LinearBuckets
+    nakedret:
+      max-func-lines: 0
+    nolintlint:
+      require-explanation: true
+      require-specific: true
+      allow-no-explanation:
+        - funlen
+        - gocognit
+        - lll
+    perfsprint:
+      strconcat: false
+    revive:
+      rules:
+        - name: unused-parameter
+          disabled: true
+    rowserrcheck:
+      packages:
+        - github.com/jmoiron/sqlx
+    staticcheck:
+      checks:
+        - all
+        - -ST1003
+  exclusions:
+    generated: lax
+    presets:
+      - comments
+      - common-false-positives
+      - legacy
+      - std-error-handling
+    rules:
+      - linters:
+          - godot
+        source: (noinspection|TODO)
+      - linters:
+          - gocritic
+        source: //noinspection
+      - linters:
+          - bodyclose
+          - dupl
+          - funlen
+          - goconst
+          - gosec
+          - noctx
+          - wrapcheck
+        path: _test\.go
+      - linters:
+          - perfsprint
+        text: fmt.Sprintf can be replaced with string addition
+    paths:
+      - third_party$
+      - builtin$
+      - examples$
 issues:
-  # Maximum count of issues with the same text.
-  # Set to 0 to disable.
-  # Default: 3
   max-same-issues: 50
-
-  exclude-rules:
-    - source: "(noinspection|TODO)"
-      linters: [ godot ]
-    - source: "//noinspection"
-      linters: [ gocritic ]
-    - path: "_test\\.go"
-      linters:
-        - bodyclose
-        - dupl
-        - funlen
-        - goconst
-        - gosec
-        - noctx
-        - wrapcheck
-    # TODO: remove after PR is released 
https://github.com/golangci/golangci-lint/pull/4386
-    - text: "fmt.Sprintf can be replaced with string addition"
-      linters: [ perfsprint ]
\ No newline at end of file
+formatters:
+  enable:
+    - goimports
+  exclusions:
+    generated: lax
+    paths:
+      - third_party$
+      - builtin$
+      - examples$
diff --git a/ai_api.go b/ai_api.go
index 9d5978d..c5804a3 100644
--- a/ai_api.go
+++ b/ai_api.go
@@ -102,20 +102,20 @@ func (e *Enforcer) buildExplainContext(rvals 
[]interface{}, result bool, matched
 
        // Add request information
        sb.WriteString("Authorization Request:\n")
-       sb.WriteString(fmt.Sprintf("Subject: %v\n", rvals[0]))
+       fmt.Fprintf(&sb, "Subject: %v\n", rvals[0])
        if len(rvals) > 1 {
-               sb.WriteString(fmt.Sprintf("Object: %v\n", rvals[1]))
+               fmt.Fprintf(&sb, "Object: %v\n", rvals[1])
        }
        if len(rvals) > 2 {
-               sb.WriteString(fmt.Sprintf("Action: %v\n", rvals[2]))
+               fmt.Fprintf(&sb, "Action: %v\n", rvals[2])
        }
-       sb.WriteString(fmt.Sprintf("\nEnforcement Result: %v\n", result))
+       fmt.Fprintf(&sb, "\nEnforcement Result: %v\n", result)
 
        // Add matched rules
        if len(matchedRules) > 0 {
                sb.WriteString("\nMatched Policy Rules:\n")
                for _, rule := range matchedRules {
-                       sb.WriteString(fmt.Sprintf("- %s\n", rule))
+                       fmt.Fprintf(&sb, "- %s\n", rule)
                }
        } else {
                sb.WriteString("\nNo policy rules matched.\n")
@@ -125,12 +125,12 @@ func (e *Enforcer) buildExplainContext(rvals 
[]interface{}, result bool, matched
        sb.WriteString("\nAccess Control Model:\n")
        if m, ok := e.model["m"]; ok {
                for key, ast := range m {
-                       sb.WriteString(fmt.Sprintf("Matcher (%s): %s\n", key, 
ast.Value))
+                       fmt.Fprintf(&sb, "Matcher (%s): %s\n", key, ast.Value)
                }
        }
        if eff, ok := e.model["e"]; ok {
                for key, ast := range eff {
-                       sb.WriteString(fmt.Sprintf("Effect (%s): %s\n", key, 
ast.Value))
+                       fmt.Fprintf(&sb, "Effect (%s): %s\n", key, ast.Value)
                }
        }
 
@@ -139,7 +139,7 @@ func (e *Enforcer) buildExplainContext(rvals []interface{}, 
result bool, matched
        if len(policies) > 0 {
                sb.WriteString("\nAll Policy Rules:\n")
                for _, policy := range policies {
-                       sb.WriteString(fmt.Sprintf("- %s\n", 
strings.Join(policy, ", ")))
+                       fmt.Fprintf(&sb, "- %s\n", strings.Join(policy, ", "))
                }
        }
 
diff --git a/enforcer.go b/enforcer.go
index d2ca570..c575534 100644
--- a/enforcer.go
+++ b/enforcer.go
@@ -89,14 +89,20 @@ func (e EnforceContext) GetCacheKey() string {
 func NewEnforcer(params ...interface{}) (*Enforcer, error) {
        e := &Enforcer{}
 
-       parsedParamLen := 0
-       paramLen := len(params)
+       // Bind the parameters up front so the accesses below are provably in 
range.
+       var param0, param1 interface{}
+       if len(params) > 0 {
+               param0 = params[0]
+       }
+       if len(params) > 1 {
+               param1 = params[1]
+       }
 
-       switch paramLen - parsedParamLen {
+       switch len(params) {
        case 2:
-               switch p0 := params[0].(type) {
+               switch p0 := param0.(type) {
                case string:
-                       switch p1 := params[1].(type) {
+                       switch p1 := param1.(type) {
                        case string:
                                err := e.InitWithFile(p0, p1)
                                if err != nil {
@@ -109,18 +115,18 @@ func NewEnforcer(params ...interface{}) (*Enforcer, 
error) {
                                }
                        }
                default:
-                       switch params[1].(type) {
+                       switch param1.(type) {
                        case string:
                                return nil, errors.New("invalid parameters for 
enforcer")
                        default:
-                               err := 
e.InitWithModelAndAdapter(p0.(model.Model), params[1].(persist.Adapter))
+                               err := 
e.InitWithModelAndAdapter(p0.(model.Model), param1.(persist.Adapter))
                                if err != nil {
                                        return nil, err
                                }
                        }
                }
        case 1:
-               switch p0 := params[0].(type) {
+               switch p0 := param0.(type) {
                case string:
                        err := e.InitWithFile(p0, "")
                        if err != nil {
@@ -316,7 +322,7 @@ func (e *Enforcer) SetDetectors(detectors 
[]detector.Detector) {
 // Returns the first error encountered, or nil if all checks pass.
 // Silently skips role managers that don't support the required iteration 
methods.
 func (e *Enforcer) RunDetections() error {
-       if e.detectors == nil || len(e.detectors) == 0 {
+       if len(e.detectors) == 0 {
                return nil
        }
 
@@ -851,11 +857,12 @@ func (e *Enforcer) enforce(matcher string, explains 
*[]string, rvals ...interfac
 
                        if j, ok := parameters.pTokens[pType+"_eft"]; ok {
                                eft := parameters.pVals[j]
-                               if eft == "allow" {
+                               switch eft {
+                               case "allow":
                                        policyEffects[policyIndex] = 
effector.Allow
-                               } else if eft == "deny" {
+                               case "deny":
                                        policyEffects[policyIndex] = 
effector.Deny
-                               } else {
+                               default:
                                        policyEffects[policyIndex] = 
effector.Indeterminate
                                }
                        } else {
@@ -909,10 +916,7 @@ func (e *Enforcer) enforce(matcher string, explains 
*[]string, rvals ...interfac
        }
 
        // effect -> result
-       result := false
-       if effect == effector.Allow {
-               result = true
-       }
+       result := effect == effector.Allow
 
        return result, nil
 }
diff --git a/enforcer_context.go b/enforcer_context.go
index 5cfb9d6..b7e4f8a 100644
--- a/enforcer_context.go
+++ b/enforcer_context.go
@@ -42,8 +42,8 @@ func NewContextEnforcer(params ...interface{}) 
(IEnforcerContext, error) {
                return nil, err
        }
 
-       if e.Enforcer.adapter != nil {
-               if contextAdapter, ok := 
e.Enforcer.adapter.(persist.ContextAdapter); ok {
+       if e.adapter != nil {
+               if contextAdapter, ok := e.adapter.(persist.ContextAdapter); ok 
{
                        e.adapterCtx = contextAdapter
                } else {
                        return nil, errors.New("adapter does not support 
context operations, ContextAdapter interface not implemented")
diff --git a/frontend_test.go b/frontend_test.go
index 0107807..bdcec01 100644
--- a/frontend_test.go
+++ b/frontend_test.go
@@ -19,7 +19,7 @@ package casbin
 
 import (
        "encoding/json"
-       "io/ioutil"
+       "os"
        "regexp"
        "strings"
        "testing"
@@ -39,7 +39,7 @@ func TestCasbinJsGetPermissionForUser(t *testing.T) {
        if err != nil {
                t.Errorf("Test error: %s", err)
        }
-       expectedModel, err := ioutil.ReadFile("examples/rbac_model.conf")
+       expectedModel, err := os.ReadFile("examples/rbac_model.conf")
        if err != nil {
                t.Errorf("Test error: %s", err)
        }
@@ -52,7 +52,7 @@ func TestCasbinJsGetPermissionForUser(t *testing.T) {
                t.Errorf("%s supposed to be %s", actualModelStr, 
expectedModelStr)
        }
 
-       expectedPolicies, err := 
ioutil.ReadFile("examples/rbac_with_hierarchy_policy.csv")
+       expectedPolicies, err := 
os.ReadFile("examples/rbac_with_hierarchy_policy.csv")
        if err != nil {
                t.Errorf("Test error: %s", err)
        }
diff --git a/model/constraint.go b/model/constraint.go
index 500da02..bebf5b6 100644
--- a/model/constraint.go
+++ b/model/constraint.go
@@ -135,12 +135,12 @@ func parseConstraint(key, value string) (*Constraint, 
error) {
 // ValidateConstraints validates all constraints against the current policy.
 func (model Model) ValidateConstraints() error {
        // Check if constraints exist
-       if model["c"] == nil || len(model["c"]) == 0 {
+       if len(model["c"]) == 0 {
                return nil // No constraints to validate
        }
 
        // Check if RBAC is enabled
-       if model["g"] == nil || len(model["g"]) == 0 {
+       if len(model["g"]) == 0 {
                return errors.ErrConstraintRequiresRBAC
        }
 
diff --git a/model/model.go b/model/model.go
index 2cf4e9d..487d35b 100644
--- a/model/model.go
+++ b/model/model.go
@@ -39,7 +39,7 @@ type AssertionMap map[string]*Assertion
 
 const (
        defaultDomain    string = ""
-       defaultSeparator        = "::"
+       defaultSeparator string = "::"
 )
 
 var sectionNameMap = map[string]string{
@@ -83,16 +83,17 @@ func (model Model) AddDef(sec string, key string, value 
string) bool {
        ast.PolicyMap = make(map[string]int)
        ast.FieldIndexMap = make(map[string]int)
 
-       if sec == "r" || sec == "p" {
+       switch sec {
+       case "r", "p":
                ast.Tokens = strings.Split(ast.Value, ",")
                for i := range ast.Tokens {
                        ast.Tokens[i] = key + "_" + 
strings.TrimSpace(ast.Tokens[i])
                }
-       } else if sec == "g" {
+       case "g":
                ast.ParamsTokens = getParamsToken(ast.Value)
                ast.Tokens = strings.Split(ast.Value, ",")
                ast.Tokens = ast.Tokens[:len(ast.Tokens)-len(ast.ParamsTokens)]
-       } else {
+       default:
                ast.Value = util.RemoveComments(util.EscapeAssertion(ast.Value))
        }
 
@@ -101,7 +102,7 @@ func (model Model) AddDef(sec string, key string, value 
string) bool {
                ast.Value = util.EscapeStringLiterals(ast.Value)
 
                if strings.Contains(ast.Value, "in") {
-                       ast.Value = strings.Replace(strings.Replace(ast.Value, 
"[", "(", -1), "]", ")", -1)
+                       ast.Value = 
strings.ReplaceAll(strings.ReplaceAll(ast.Value, "[", "("), "]", ")")
                }
        }
 
@@ -369,9 +370,9 @@ func (model Model) ToText() string {
                for ptype := range model[sec] {
                        value := model[sec][ptype].Value
                        for tokenPattern, newToken := range tokenPatterns {
-                               value = strings.Replace(value, tokenPattern, 
newToken, -1)
+                               value = strings.ReplaceAll(value, tokenPattern, 
newToken)
                        }
-                       s.WriteString(fmt.Sprintf("%s = %s\n", sec, value))
+                       fmt.Fprintf(&s, "%s = %s\n", sec, value)
                }
        }
        s.WriteString("[request_definition]\n")
@@ -381,13 +382,13 @@ func (model Model) ToText() string {
        if _, ok := model["g"]; ok {
                s.WriteString("[role_definition]\n")
                for ptype := range model["g"] {
-                       s.WriteString(fmt.Sprintf("%s = %s\n", ptype, 
model["g"][ptype].Value))
+                       fmt.Fprintf(&s, "%s = %s\n", ptype, 
model["g"][ptype].Value)
                }
        }
        if _, ok := model["c"]; ok {
                s.WriteString("[constraint_definition]\n")
                for ptype := range model["c"] {
-                       s.WriteString(fmt.Sprintf("%s = %s\n", ptype, 
model["c"][ptype].Value))
+                       fmt.Fprintf(&s, "%s = %s\n", ptype, 
model["c"][ptype].Value)
                }
        }
        s.WriteString("[policy_effect]\n")
diff --git a/model/model_test.go b/model/model_test.go
index 300d4e8..1b3c8c1 100644
--- a/model/model_test.go
+++ b/model/model_test.go
@@ -18,7 +18,7 @@
 package model
 
 import (
-       "io/ioutil"
+       "os"
        "path/filepath"
        "strings"
        "testing"
@@ -66,7 +66,7 @@ func TestNewModelFromFile(t *testing.T) {
 }
 
 func TestNewModelFromString(t *testing.T) {
-       modelBytes, _ := ioutil.ReadFile(basicExample)
+       modelBytes, _ := os.ReadFile(basicExample)
        modelString := string(modelBytes)
        m, err := NewModelFromString(modelString)
        if err != nil {
diff --git a/persist/persist_test.go b/persist/persist_test.go
index 1a2adb8..238e1c7 100644
--- a/persist/persist_test.go
+++ b/persist/persist_test.go
@@ -134,10 +134,10 @@ m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
        }
 
        m := model.NewModel()
-       if err := m.LoadModelFromText(conf); err != nil {
+       if err = m.LoadModelFromText(conf); err != nil {
                t.Fatalf("load model: %v", err)
        }
-       if err := persist.LoadPolicyLine(line, m); err != nil {
+       if err = persist.LoadPolicyLine(line, m); err != nil {
                t.Fatalf("LoadPolicyLine on %q: %v", line, err)
        }
 
diff --git a/util/builtin_operators.go b/util/builtin_operators.go
index c7861f8..404aaa8 100644
--- a/util/builtin_operators.go
+++ b/util/builtin_operators.go
@@ -184,7 +184,7 @@ func KeyMatch2(key1 string, key2 string) bool {
                return matched
        }
 
-       key2 = strings.Replace(key2, "/*", "/.*", -1)
+       key2 = strings.ReplaceAll(key2, "/*", "/.*")
 
        key2 = keyMatch2Re.ReplaceAllString(key2, "$1[^/]+$2")
 
@@ -207,7 +207,7 @@ func KeyMatch2Func(args ...interface{}) (interface{}, 
error) {
 // For example, "/resource1" matches "/:resource"
 // if the pathVar == "resource", then "resource1" will be returned.
 func KeyGet2(key1, key2 string, pathVar string) string {
-       key2 = strings.Replace(key2, "/*", "/.*", -1)
+       key2 = strings.ReplaceAll(key2, "/*", "/.*")
        keys := keyGet2Re1.FindAllString(key2, -1)
        key2 = keyGet2Re1.ReplaceAllString(key2, "$1([^/]+)$2")
        key2 = "^" + key2 + "$"
@@ -245,7 +245,7 @@ func KeyMatch3(key1 string, key2 string) bool {
                return matched
        }
 
-       key2 = strings.Replace(key2, "/*", "/.*", -1)
+       key2 = strings.ReplaceAll(key2, "/*", "/.*")
        key2 = keyMatch3Re.ReplaceAllString(key2, "$1[^/]+$2")
 
        return RegexMatch(key1, "^"+key2+"$")
@@ -267,7 +267,7 @@ func KeyMatch3Func(args ...interface{}) (interface{}, 
error) {
 // For example, "project/proj_project1_admin/" matches 
"project/proj_{project}_admin/"
 // if the pathVar == "project", then "project1" will be returned.
 func KeyGet3(key1, key2 string, pathVar string) string {
-       key2 = strings.Replace(key2, "/*", "/.*", -1)
+       key2 = strings.ReplaceAll(key2, "/*", "/.*")
 
        keys := keyGet3Re1.FindAllString(key2, -1)
        key2 = keyGet3Re1.ReplaceAllString(key2, "$1([^/]+?)$2")
@@ -308,7 +308,7 @@ func KeyMatch4(key1 string, key2 string) bool {
                return matched
        }
 
-       key2 = strings.Replace(key2, "/*", "/.*", -1)
+       key2 = strings.ReplaceAll(key2, "/*", "/.*")
 
        tokens := []string{}
 
@@ -373,7 +373,7 @@ func KeyMatch5(key1 string, key2 string) bool {
                return matched
        }
 
-       key2 = strings.Replace(key2, "/*", "/.*", -1)
+       key2 = strings.ReplaceAll(key2, "/*", "/.*")
        key2 = keyMatch5Re.ReplaceAllString(key2, "$1[^/]+$2")
 
        return RegexMatch(key1, "^"+key2+"$")
diff --git a/util/util.go b/util/util.go
index 88b001f..d4e0f27 100644
--- a/util/util.go
+++ b/util/util.go
@@ -291,10 +291,11 @@ func EscapeStringLiterals(expr string) string {
        for _, ch := range expr {
                if inString {
                        result.WriteRune(ch)
-                       if ch == '\\' {
+                       switch ch {
+                       case '\\':
                                // Found a backslash inside a string - double it
                                result.WriteRune('\\')
-                       } else if ch == quote {
+                       case quote:
                                // End of string literal
                                inString = false
                        }


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

Reply via email to