circular-import
Summary: Avoid circular imports
Category: Imports
Avoid
# authz.rego
package authz
import rego.v1
import data.shared
admins := {
"anna",
"bob",
}
allow if {
input.role in shared.roles
}
allow if {
input.user in admins
}
# shared.rego
package shared
import data.authz # circular import!
roles := { "admin", "editor", "viewer" }
users := authz.admins | {
"chloe",
"dave",
}
Prefer
Break out shared rules into a tree-like structure of packages. For example, one way we could refactor the above example
is to move the admins
set into a new package.
# authz.rego
package authz
import rego.v1
import data.shared
allow if {
input.role in shared.roles
}
allow if {
input.user in shared.users
}
# admins.rego
package admins
admins := {
"anna",
"bob",
}
# shared.rego
package shared
import data.admins
roles := {"admin", "editor", "viewer"}
users := admins.admins | {
"chloe",
"david",
}
Rationale
A circular import is when a package imports itself, either by directly importing itself, or indirectly by importing a which in turn imports a series of packages that eventually import the original package.
As long as recursive rules definitions are avoided, circular imports are permitted in Rego. However, such import graphs are not advisable and a signal of poorly structured policy code.
If you have a circular import, it's recommended that you refactor your code into different packages that do not import each other. This will make your code easier to navigate and maintain.
Configuration Options
This linter rule provides the following configuration options:
rules:
imports:
circular-import:
# one of "error", "warning", "ignore"
level: error
Related Resources
- GitHub: Source Code
Community
If you think you've found a problem with this rule or its documentation, would like to suggest improvements, new rules,
or just talk about Regal in general, please join us in the #regal
channel in the Styra Community
Slack!