Regal is a linter for Rego, with the goal of making your Rego magnificent!
regal
adj : of notable excellence or magnificence : splendid
- Identify common mistakes, bugs and inefficiencies in Rego policies, and suggest better approaches
- Provide advice on best practices, coding style, and tooling
- Allow users, teams and organizations to enforce custom rules on their policy code
Regal rules are to as large extent as possible written in Rego themselves, using the JSON representation of the Rego abstract syntax tree (AST) as input, a few additional custom built-in functions and some indexed data structures to help with linting.
MacOS and Linux
brew install styrainc/packages/regal
Manual download options
MacOS (Apple Silicon)
curl -L -o regal "https://github.com/StyraInc/regal/releases/latest/download/regal_Darwin_arm64"
MacOS (x86_64)
curl -L -o regal "https://github.com/StyraInc/regal/releases/latest/download/regal_Darwin_x86_64"
Linux (x86_64)
curl -L -o regal "https://github.com/StyraInc/regal/releases/latest/download/regal_Linux_x86_64"
chmod +x regal
Windows
curl.exe -L -o regal.exe "https://github.com/StyraInc/regal/releases/latest/download/regal_Windows_x86_64.exe"
Docker
docker pull ghcr.io/styrainc/regal:latest
See all versions, and checksum files, at the Regal releases page, and published Docker images at the packages page.
First, author some Rego!
policy/authz.rego
package authz
import future.keywords
default allow = false
deny if {
"admin" != input.user.roles[_]
}
allow if not deny
Next, run regal lint
pointed at one or more files or directories to have them linted.
regal lint policy/
Rule: not-equals-in-loop
Description: Use of != in loop
Category: bugs
Location: policy/authz.rego:8:10
Text: "admin" != input.user.roles[_]
Documentation: https://github.com/StyraInc/regal/blob/main/docs/rules/bugs/not-equals-in-loop.md
Rule: implicit-future-keywords
Description: Use explicit future keyword imports
Category: imports
Location: policy/authz.rego:3:8
Text: import future.keywords
Documentation: https://github.com/StyraInc/regal/blob/main/docs/rules/imports/implicit-future-keywords.md
Rule: use-assignment-operator
Description: Prefer := over = for assignment
Category: style
Location: policy/authz.rego:5:1
Text: default allow = false
Documentation: https://github.com/StyraInc/regal/blob/main/docs/rules/style/use-assignment-operator.md
1 file linted. 3 violations found.
Note If you're running Regal on an existing policy library, you may want to disable the
style
category initially, as it will likely generate a lot of violations. You can do this by passing the--disable-category style
flag toregal lint
.
Regal comes with a set of built-in rules, grouped by category.
- bugs: Common mistakes, potential bugs and inefficiencies in Rego policies.
- idiomatic: Suggestions for more idiomatic constructs.
- imports: Best practices for imports.
- style: Rego Style Guide rules.
- testing: Rules for testing and development.
The following rules are currently available:
Category | Title | Description |
---|---|---|
bugs | constant-condition | Constant condition |
bugs | invalid-metadata-attribute | Invalid attribute in metadata annotation |
bugs | not-equals-in-loop | Use of != in loop |
bugs | rule-named-if | Rule named "if" |
bugs | rule-shadows-builtin | Rule name shadows built-in |
bugs | top-level-iteration | Iteration in top-level assignment |
bugs | unused-return-value | Non-boolean return value unused |
idiomatic | custom-has-key-construct | Custom function may be replaced by in and object.keys |
idiomatic | custom-in-construct | Custom function may be replaced by in keyword |
idiomatic | use-in-operator | Use in to check for membership |
imports | redundant-data-import | Redundant import of data |
imports | implicit-future-keywords | Use explicit future keyword imports |
imports | import-shadows-import | Import shadows another import |
imports | redundant-alias | Redundant alias |
imports | avoid-importing-input | Avoid importing input |
style | prefer-snake-case | Prefer snake_case for names |
style | todo-comment | Avoid TODO comments |
style | external-reference | Reference to input, data or rule ref in function body |
style | function-arg-return | Function argument used for return value |
style | line-length | Line too long |
style | no-whitespace-comment | Comment should start with whitespace |
style | avoid-get-and-list-prefix | Avoid get_ and list_ prefix for rules and functions |
style | detached-metadata | Detached metadata annotation |
style | unconditional-assignment | Unconditional assignment in rule body |
style | use-assignment-operator | Prefer := over = for assignment |
style | opa-fmt | File should be formatted with opa fmt |
testing | identically-named-tests | Multiple tests with same name |
testing | print-or-trace-call | Call to print or trace function |
testing | test-outside-test-package | Test outside of test package |
testing | todo-test | TODO test encountered |
testing | file-missing-test-suffix | Files containing tests should have a _test.rego suffix |
By default, all rules are currently enabled.
If you'd like to see more rules, please open an issue for your feature request, or better yet, submit a PR! See the custom rules page for more information on how to develop your own rules, for yourself or for inclusion in Regal.
A custom configuration file may be used to override the default configuration options provided by Regal. The most common use case for this is to change the severity level of a rule. These three levels are available:
ignore
— disable the rule entirelywarning
— report the violation without changing the exit code of the lint commanderror
— report the violation and have the lint command exit with a non-zero exit code (default)
Additionally, some rules may have configuration options of their own. See the documentation page for a rule to learn more about it.
.regal/config.yaml
# Files can be excluded from all lint
# rules according to glob-patterns
ignore:
files:
- file1.rego
- "*_tmp.rego"
rules:
style:
todo-comment:
# don't report on todo comments
level: ignore
line-length:
# custom rule configuration
max-line-length: 100
# warn on too long lines, but don't fail
level: warning
opa-fmt:
# not needed as error is the default, but
# being explicit won't hurt
level: error
# Files can be ignored.
# In this example, test files are ignored
ignore:
files:
- "*_test.rego"
Regal will automatically search for a configuration file (.regal/config.yaml
) in the current directory, and if not
found, traverse the parent directories either until either one is found, or the top of the directory hierarchy is
reached. If no configuration file is found, Regal will use the default configuration.
A custom configuration may be also be provided using the --config-file
/-c
option for regal lint
, which when
provided will be used to override the default configuration.
For development, rules may also quickly be enabled or disabled using the relevant CLI flags for the regal lint
command.
--disable-all
disables all rules--disable-category
disables all rules in a category, overriding--enable-all
(may be repeated)--disable
disables a specific rule, overriding--enable-all
and--enable-category
(may be repeated)--enable-all
enables all rules--enable-category
enables all rules in a category, overriding--disable-all
(may be repeated)--enable
enables a specific rule, overriding--disable-all
and--disable-category
(may be repeated)--ignore-files
ignores files using glob patterns, overridingignore
in the config file (may be repeated)
All CLI flags override configuration provided in file.
Exit codes are used to indicate the result of the lint
command. The --fail-level
provided for regal lint
may be
used to change the exit code behavior, and allows a value of either warning
or error
(default).
If --fail-level error
is supplied, exit code will be zero even if warnings are present:
0
: no errors were found0
: one or more warnings were found3
: one or more errors were found
This is the default behavior.
If --fail-level warning
is supplied, warnings will result in a non-zero exit code:
0
: no errors or warnings were found2
: one or more warnings were found3
: one or more errors were found
If you'd like to ignore a specific violation, you can add an ignore directive above the line in question:
package policy
# regal ignore:prefer-snake-case
camelCase := "yes"
The format of an ignore directive is regal ignore:<rule-name>,<rule-name>...
, where <rule-name>
is the name of the
rule to ignore. Multiple rules may be added to the same ignore directive, separated by commas.
Note that at this point in time, Regal only considers the line following the ignore directive, i.e. it does not ignore entire blocks of code (like rules, functions or even packages). See configuration if you want to ignore certain rules altogether.
- Custom Rules describes how to develop your own rules
- Development for info about how to hack on Regal itself
- Rego Style Guide contains notes on implementing the Rego Style Guide rules
Regal the Rego Linter, CNCF London meetup, June 2023
Regal is currently in beta. End-users should not expect any drastic changes, but any API may change without notice. If you want to embed Regal in another project or product, please reach out!
- More rules!
- Add
custom
(ororganizational
,opinionated
, or..) category for built-in "custom", or organizational rules, to enforce things like naming conventions. The most common customizations should not require writing custom rules, but be made available in configuration. - Simplify custom rules authoring by providing command for scaffolding
- Make more rules consider nested AST nodes
- GitHub Action
- VS Code extension
For questions, discussions and announcements related to Styra products, services and open source projects, please join the Styra community on Slack!