1"use strict";(self.webpackChunkopa_website=self.webpackChunkopa_website||[]).push([[37973],{2943:(e,n,o)=>{o.d(n,{A:()=>u});var t=o(28774),i=o(96540),r=o(87331);const a={table:"table_dkRm",th:"th_GnNN",td:"td_aFro",categoryCell:"categoryCell_H_CG",idCell:"idCell_POs2",summaryCell:"summaryCell_WWY4",controls:"controls_pmgB",input:"input_DH9l",select:"select_ug3B",contentMatchIndicator:"contentMatchIndicator_vH1S"};var s=o(44848),l=o(74848);function u(e){var n=e.category,o=void 0===n?"":n,u=(0,i.useState)(""),c=u[0],d=u[1],p=(0,i.useState)(""),g=p[0],m=p[1],h=o||null,f=h||g,y=(0,i.useMemo)((function(){return Object.values(s).map((function(e){var n,o,t=e.filePath.match(/\/regal\/rules\/([^/]+)\//),i=t?t[1]:"unknown",r=e.content||"",a=r.match(/\*\*Summary\*\*:\s*(.*?)\n/),s=r.match(/\*\*Type\*\*:\s*(.*?)\n/),l=r.match(/\*\*Automatically fixable\*\*:\s*\[(.*?)\]\((.*?)\)/),u=[],c=null==a||null==(n=a[1])?void 0:n.trim();c&&u.push(c);var d=null==s||null==(o=s[1])?void 0:o.trim();if(d&&u.push("**Type**: "+d),l){var p=l[1],g=l[2];u.push("**Automatically fixable**: ["+p+"]("+g+")")}if(0===u.length)return null;var m=r.match(/\*\*Category\*\*:\s*(.*?)\n/);return{pathCategory:i,displayCategory:(null==m?void 0:m[1])||i,id:e.id,content:r,summary:u.join("\n\n")}})).filter(Boolean)}),[]),b=(0,i.useMemo)((function(){var e=new Set(y.map((function(e){return e.pathCategory})));return Array.from(e).sort()}),[y]),w=(0,i.useMemo)((function(){var e=c.toLowerCase();return y.map((function(n){if(!e)return Object.assign({},n,{contentOnlyMatch:!1});var o=n.id.toLowerCase().includes(e),t=n.displayCategory.toLowerCase().includes(e),i=n.content.toLowerCase().includes(e),r=i&&!o&&!t;return o||t||i?Object.assign({},n,{contentOnlyMatch:r}):null})).filter(Boolean).filter((function(e){return!f||e.pathCategory===f})).sort((function(e,n){return e.displayCategory.localeCompare(n.displayCategory)}))}),[y,c,f]);return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsxs)("div",{className:a.controls,children:[!h&&(0,l.jsxs)("select",{className:a.select,value:g,onChange:function(e){return m(e.target.value)},children:[(0,l.jsx)("option",{value:"",children:"All Categories"}),b.map((function(e){return(0,l.jsx)("option",{value:e,children:e.charAt(0).toUpperCase()+e.slice(1)},e)}))]}),(0,l.jsx)("input",{className:a.input,type:"text",placeholder:"Search rules...",value:c,onChange:function(e){return d(e.target.value)}})]}),0===w.length&&(0,l.jsx)("div",{children:(0,l.jsx)("p",{children:"No rules found."})}),w.length>0&&(0,l.jsxs)("table",{className:a.table,children:[(0,l.jsx)("thead",{children:(0,l.jsxs)("tr",{children:[!h&&(0,l.jsx)("th",{className:a.th,children:"Category"}),(0,l.jsx)("th",{className:a.th,children:"ID"}),(0,l.jsx)("th",{className:a.th,children:"Summary"})]})}),(0,l.jsx)("tbody",{children:w.map((function(e){return(0,l.jsxs)("tr",{children:[!h&&(0,l.jsx)("td",{className:a.categoryCell,children:e.displayCategory}),(0,l.jsxs)("td",{className:a.idCell,children:[(0,l.jsx)(t.A,{to:"/projects/regal/rules/"+e.id,children:e.id}),e.contentOnlyMatch&&(0,l.jsx)("span",{className:a.contentMatchIndicator,children:"Content Matches Search"})]}),(0,l.jsx)("td",{className:a.summaryCell,children:(0,l.jsx)(r.oz,{children:e.summary})})]},e.id)}))})]})]})}},28453:(e,n,o)=>{o.d(n,{R:()=>a,x:()=>s});var t=o(96540);const i={},r=t.createContext(i);function a(e){const n=t.useContext(r);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function s(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),t.createElement(r.Provider,{value:n},e.children)}},44848:e=>{e.exports=JSON.parse('[{"filePath":"projects/regal/rules/testing/todo-test.md","content":"# todo-test\\n\\n**Summary**: TODO test encountered\\n\\n**Category**: Testing\\n\\n**Avoid**\\n```rego\\npackage policy_test\\n\\nimport data.policy\\n\\n# Make sure this passes\\ntodo_test_allow_if_admin {\\n policy.allow with input as {\\"user\\": {\\"roles\\": [\\"admin\\"]}}\\n}\\n```\\n\\n## Rationale\\n\\nWriting TODO tests by prefixing `todo_` to any test is a good way to keep track of tests that need to be written while\\ndeveloping policy. They are however not to be committed, and should be removed before submitting the change for review.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n testing:\\n todo-test:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\
1n- OPA Docs: [Policy Testing](https://www.openpolicyagent.org/docs/policy-testing/)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/testing/todo-test/todo_test.rego)\\n","id":"testing/todo-test"},{"filePath":"projects/regal/rules/testing/test-outside-test-package.md","content":"# test-outside-test-package\\n\\n**Summary**: Test outside of test package\\n\\n**Category**: Testing\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nallow if {\\n \\"admin\\" in input.user.roles\\n}\\n\\n# Tests in same package as policy\\ntest_allow_if_admin {\\n allow with input as {\\"user\\": {\\"roles\\": [\\"admin\\"]}}\\n}\\n```\\n\\n**Prefer**\\n```rego\\n# Tests in separate package with _test suffix\\npackage policy_test\\n\\nimport data.policy\\n\\ntest_allow_if_admin {\\n policy.allow with input as {\\"user\\": {\\"roles\\": [\\"admin\\"]}}\\n}\\n```\\n\\n## Rationale\\n\\nWhile OPA\'s test runner will evaluate any rules with a `test_` prefix, it is a good practice to clearly separate tests\\nfrom production policy. This is easily done by placing tests in a separate package with a `_test` suffix, and correctly\\n[naming](https://www.openpolicyagent.org/projects/regal/rules/testing/file-missing-test-suffix) the test files.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n testing:\\n test-outside-test-package:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Policy Testing](https://www.openpolicyagent.org/docs/policy-testing/)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/testing/test-outside-test-package/test_outside_test_package.rego)\\n","id":"testing/test-outside-test-package"},{"filePath":"projects/regal/rules/testing/print-or-trace-call.md","content":"# print-or-trace-call\\n\\n**Summary**: Call to `print` or `trace` function\\n\\n**Category**: Testing\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nreasons contains sprintf(\\"%q is a dog!\\", [user.name]) if {\\n some user in input.users\\n user.species == \\"canine\\"\\n\\n # Useful for debugging, but leave out before committing\\n print(\\"user:\\", user)\\n}\\n```\\n\\n## Rationale\\n\\nThe `print` function is really useful for development and debugging, but should normally not be included in production\\npolicy. In order to be as useful for debugging purposes as possible, some performance optimizations are disabled when\\n`print` calls are encountered. Prefer decision logging in production.\\n\\nThe `trace` function serves no real purpose since the introduction of `print`, and should be considered deprecated.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n testing:\\n print-or-trace-call:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Blog: [Introducing the OPA print function](https://blog.openpolicyagent.org/introducing-the-opa-print-function-809da6a13aee)\\n- OPA Docs: [Policy Reference: Debugging](https://www.openpolicyagent.org/docs/policy-reference/#debugging)\\n- OPA Docs: [Decision Logs](https://www.openpolicyagent.org/docs/management-decision-logs)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/testing/print-or-trace-call/print_or_trace_call.rego)\\n","id":"testing/print-or-trace-call"},{"filePath":"projects/regal/rules/testing/metasyntactic-variable.md","content":"# metasyntactic-variable\\n\\n**Summary**: Metasyntactic variable name\\n\\n**Category**: Testing\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\n# Using metasyntactic name\\nfoo := [\\"developer\\", \\"admin\\"]\\n\\n# ...\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\n# Using name relevant to the context\\nroles := [\\"developer\\", \\"admin\\"]\\n\\n# ...\\n```\\n\\n## Rationale\\n\\nUsing \\"foo\\", \\"bar\\", \\"baz\\" and other [metasyntactic variables](https://en.wikipedia.org/wiki/Metasyntactic_variable) is\\noccasionally useful in examples, but should be avoided in production policy.\\n\\nThis linter rules forbids any metasyntactic variable names, as listed by Wikipedia:\\n\\n\x3c!-- cspell:disable --\x3e\\n- foobar\\n- foo\\n- bar\\n- baz\\n- qux\\n- quux\\n- corge\\n- grault\\n- garply\\n- waldo\\n- fred\\n- plugh\\n- xyzzy\\n- thud\\n\x3c!-- cspell:enable --\x3e\\n\\n## Exceptions\\n\\nWhile there are no recommended exceptions to this rule, you could choose to allow metasyntactic variables in tests, or\\nperhaps code meant to be used in examples. When using a\\n[proper suffix](https://www.openpolicyagent.org/projects/regal/rules/testing/file-missing-test-suffix) for tests, like `_test.rego`,\\nsimply configure an ignore pattern with the configuration of this rule:\\n\\n```yaml\\nrules:\\n testing:\\n metasyntactic-variable:\\n level: error\\n ignore:\\n files:\\n - \\"*_test.rego\\"\\n```\\n\\nIf you\'d rather use your own list of forbidden variable names or patterns, see the\\n[naming convention](https://www.openpolicyagent.org/projects/regal/rules/custom/naming-convention) rule.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n testing:\\n metasyntactic-variable:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\
1n- Regal Docs: [Naming convention rule](https://www.openpolicyagent.org/projects/regal/rules/custom/naming-convention)\\n- Wikipedia: [Metasyntactic variable](https://en.wikipedia.org/wiki/Metasyntactic_variable)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/testing/metasyntactic-variable/metasyntactic_variable.rego)\\n","id":"testing/metasyntactic-variable"},{"filePath":"projects/regal/rules/testing/identically-named-tests.md","content":"# identically-named-tests\\n\\n**Summary**: Multiple tests with same name\\n\\n**Category**: Testing\\n\\n**Avoid**\\n```rego\\npackage policy_test\\n\\nimport data.policy\\n\\ntest_allow_if_admin {\\n policy.allow with input as {\\"user\\": {\\"roles\\": [\\"admin\\"]}}\\n}\\n\\ntest_allow_if_admin {\\n policy.allow with input as {\\"user\\": {\\"roles\\": [\\"superadmin\\"]}}\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy_test\\n\\nimport data.policy\\n\\ntest_allow_if_admin {\\n policy.allow with input as {\\"user\\": {\\"roles\\": [\\"admin\\"]}}\\n}\\n\\ntest_allow_if_superadmin {\\n policy.allow with input as {\\"user\\": {\\"roles\\": [\\"superadmin\\"]}}\\n}\\n```\\n\\n## Rationale\\n\\nWhile OPA allows multiple tests with the same name, using unique names for tests makes for easier to read test code, as\\nwell as more informative test output. Since a single test may include any number of assertions, there\'s no need to reuse\\ntest names within the same test package.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n testing:\\n identically-named-tests:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Policy Testing](https://www.openpolicyagent.org/docs/policy-testing/)\\n- OPA GitHub: [Support running of individual test rules sharing same name](https://github.com/open-policy-agent/opa/issues/5766)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/testing/identically-named-tests/identically_named_tests.rego)\\n","id":"testing/identically-named-tests"},{"filePath":"projects/regal/rules/testing/file-missing-test-suffix.md","content":"# file-missing-test-suffix\\n\\n**Summary**: Files containing tests should have a `_test.rego` suffix\\n\\n**Category**: Testing\\n\\n## Rationale\\n\\nIn order to clearly communicate intent, and to avoid bundling tests with production policy, tests should be kept in a\\nseparate file with a `_test.rego` suffix, and ideally prefixed with the same name as the policy the tests are targeting,\\ne.g. `policy.rego` and `policy_test.rego`.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n testing:\\n file-missing-test-suffix:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Policy Testing](https://www.openpolicyagent.org/docs/policy-testing/)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/testing/file-missing-test-suffix/file_missing_test_suffix.rego)\\n","id":"testing/file-missing-test-suffix"},{"filePath":"projects/regal/rules/testing/dubious-print-sprintf.md","content":"# dubious-print-sprintf\\n\\n**Summary**: Dubious use of `print` and `sprintf`\\n\\n**Category**: Testing\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nallow if {\\n # if any of input.name or input.domain are undefined, this will just print <undefined>\\n print(sprintf(\\"name is: %s domain is: %s\\", [input.name, input.domain]))\\n\\n input.name == \\"admin\\"\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nallow if {\\n # if any of input.name or input.domain are undefined, this will still print the whole\\n # sentence, with the value undefined printed as such, e.g.\\n # name is: admin domain is: <undefined>\\n print(\\"name is:\\", input.name, \\"domain is:\\", input.domain)\\n\\n input.name == \\"admin\\"\\n}\\n```\\n\\n## Rationale\\n\\nSince `print` allows any number of arguments, there\'s rarely any benefit to using `sprintf` for formatting the output of\\n
1a `print` call. But more importantly, the `print` function is unique in that it will allow any arguments passed to be\\n*undefined* without terminating, but will print such values as `<undefined>`. Using `sprintf` will however nullify this\\nbenefit, and just print `<undefined>` without the context.\\n\\nNote that using `print` is generally discouraged outside of development, and other rules exists to check for its use.\\nHowever, in the context of development and testing, one may choose to allow `print`, in e.g. `_test.rego` files, while\\nstill wanting to avoid the use of `sprintf` in such cases.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n testing:\\n dubious-print-sprintf:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Regal Docs: [Call to `print` or `trace` function](https://www.openpolicyagent.org/projects/regal/rules/testing/print-or-trace-call)\\n- OPA Docs: [Policy Testing](https://www.openpolicyagent.org/docs/policy-testing)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/testing/dubious-print-sprintf/dubious_print_sprintf.rego)\\n","id":"testing/dubious-print-sprintf"},{"filePath":"projects/regal/rules/style/yoda-condition.md","content":"# yoda-condition\\n\\n**Summary**: Yoda condition, it is\\n\\n**Category**: Style\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nallow if {\\n \\"GET\\" == input.request.method\\n \\"users\\" == input.request.path[0]\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nallow if {\\n input.request.method == \\"GET\\"\\n input.request.path[0] == \\"users\\"\\n}\\n```\\n\\n## Rationale\\n\\nYoda conditions \u2014 expressions where the constant portion of a comparison is placed on the left-hand side of the\\ncomparison \u2014 provide no benefits in Rego. They do however add a certain amount of cognitive overhead for most policy\\nauthors in the galaxy.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n yoda-condition:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Wikipedia: [Yoda conditions](https://en.wikipedia.org/wiki/Yoda_conditions)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/yoda-condition/yoda_condition.rego)\\n","id":"style/yoda-condition"},{"filePath":"projects/regal/rules/style/use-assignment-operator.md","content":"# use-assignment-operator\\n\\n**Summary**: Prefer `:=` over `=` for assignment\\n\\n**Category**: Style\\n\\n**Automatically fixable**: [Yes](https://www.openpolicyagent.org/projects/regal/fixing)\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\ndefault allow = false\\n\\nfirst_name(name) = split(name, \\" \\")[0]\\n\\nallow if {\\n username = input.user.name\\n # .. more conditions ..\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\ndefault allow := false\\n\\nfirst_name(full_name) := split(full_name, \\" \\")[0]\\n\\nallow if {\\n username := input.user.name\\n # .. more conditions ..\\n}\\n```\\n\\n## Rationale\\n\\nRego has three operators related to assignment and equality:\\n\\n- `:=` is the assignment operator, and is only used to assign values to variables\\n- `==` is the equality operator, and is only used to compare values\\n- `=` is the unification operator, and is used both to assign values to variables **and** compare values\\n\\nWhile it often is \\"harmless\\" to use the unification operator (`=`) for assignment, the assignment operator (`:=`)\\nremoves any ambiguities around intent, and prevents some hard to debug issues. Consider:\\n\\n```rego\\nallow if {\\n username = input.user.name\\n # .. more conditions ..\\n}\\n```\\n\\nUsing the unification operator, `username` is either assigned (if `username` isn\'t defined elsewhere in the\\npolicy) or being checked for equality (if `username` is defined elsewhere in the policy). Using `:=` for assignment,\\nand `==` for equality comparison removes this ambiguity and make the intent obvious.\\n\\nIn some cases, `=` and `:=` may be used interchangeably, as the result is the same either way:\\n\\n```rego\\nfirst_name(full_name) = split(full_name, \\" \\")[0]\\n# same as\\nfirst_name(full_name) := split(full_name, \\" \\")[0]\\n```\\n\\nEven when that is the case, using `:=` consistently should be considered a best practice.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n use-assignment-operator:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\
1n- OPA Docs: [Equality: Assignment, Comparison, and Unification](https://www.openpolicyagent.org/docs/policy-language/#equality-assignment-comparison-and-unification)\\n- Rego Style Guide: [Don\'t use unification operator for assignment or comparison](https://www.openpolicyagent.org/docs/style-guide#dont-use-unification-operator-for-assignment-or-comparison)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/use-assignment-operator/use_assignment_operator.rego)\\n","id":"style/use-assignment-operator"},{"filePath":"projects/regal/rules/style/unnecessary-some.md","content":"# unnecessary-some\\n\\n**Summary**: Unnecessary use of `some`\\n\\n**Category**: Style\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nis_developer if some \\"developer\\" in input.user.roles\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\nis_developer if \\"developer\\" in input.user.roles\\n```\\n\\n## Rationale\\n\\nUse the `some .. in` construct when you want to loop over a collection and assign variables in the iteration. If you\\nknow the value you\'re looking for, just use the `in` keyword directly without using `some`.\\n\\n## Exceptions\\n\\nNote that `some .. in` iteration can be used with a limited form of pattern matching where either the key or the value\\nshould match for the loop assignment to succeed. This is not commonly needed, but considered OK.\\n\\n```rego\\npackage policy\\n\\ndevelopers contains name if {\\n # name will only be bound when the value is \\"developer\\"\\n some name, \\"developer\\" in {\\"alice\\": \\"developer\\", \\"bob\\": \\"developer\\", \\"charlie\\": \\"manager\\"}\\n}\\n```\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n unnecessary-some:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Membership and iteration: `in`](https://www.openpolicyagent.org/docs/policy-language/#membership-and-iteration-in)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/unnecessary-some/unnecessary_some.rego)\\n","id":"style/unnecessary-some"},{"filePath":"projects/regal/rules/style/unconditional-assignment.md","content":"# unconditional-assignment\\n\\n**Summary**: Unconditional assignment in rule body\\n\\n**Category**: Style\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nfull_name := name if {\\n name := concat(\\", \\", [input.first_name, input.last_name])\\n}\\n\\ndivide_by_ten(x) := y if {\\n y := x / 10\\n}\\n\\nnames contains name if {\\n name := \\"Regal\\"\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nfull_name := concat(\\", \\", [input.first_name, input.last_name])\\n\\ndivide_by_ten(x) := x / 10\\n\\nnames contains \\"Regal\\"\\n```\\n\\n## Rationale\\n\\nRules that return values unconditionally should place the assignment directly in the rule head, as doing so in the rule\\nbody adds unnecessary noise.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n unconditional-assignment:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Rego Style Guide: [Prefer unconditional assignment in rule head over rule body](https://www.openpolicyagent.org/docs/style-guide#prefer-unconditional-assignment-in-rule-head-over-rule-body)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/unconditional-assignment/unconditional_assignment.rego)\\n","id":"style/unconditional-assignment"},{"filePath":"projects/regal/rules/style/trailing-default-rule.md","content":"# trailing-default-rule\\n\\n**Summary**: Default rule should be declared first\\n\\n**Category**: Style\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nallow if {\\n # some conditions\\n}\\n\\ndefault allow := false\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\ndefault allow := false\\n\\nallow if {\\n # some conditions\\n}\\n```\\n\\n## Rationale\\n\\nPresenting the default value of a rule (if one is used) before the conditional rule assignments is a common practice,\\nand it\'s often easier to to reason about conditional assignments knowing there is a default fallback value in place.\\nFor that reason, it\'s recommended to follow the convention and place the default rule declaration before rules\\nconditionally assigning values.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n trailing-default-rule:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\
1n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/trailing-default-rule/trailing_default_rule.rego)\\n","id":"style/trailing-default-rule"},{"filePath":"projects/regal/rules/style/todo-comment.md","content":"# todo-comment\\n\\n**Summary**: Avoid TODO and FIXME comments\\n\\n**Category**: Style\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\n# TODO: implementation\\nallow := true\\n\\ni := input.i + 1\\n\\n# Fixme: surely there\'s a better way to do recursion\\nresponse := http.send({\\n \\"url\\": \\"http://localhost:8080/v1/data/policy\\",\\n \\"method\\": \\"POST\\",\\n \\"body\\": {\\n \\"input\\": {\\n \\"i\\": i\\n }\\n }\\n})\\n```\\n\\n**Prefer**\\n\\nTo fix the problem, or use an issue tracker to track it.\\n\\n## Rationale\\n\\nWhile TODO and FIXME comments are occasionally useful, they essentially provide a way to do issue tracking inside of\\nthe code rather than where issues belong \u2014 in your issue tracker.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n todo-comment:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- DEV Community: [//TODO: Write a better comment](https://dev.to/adammc331/todo-write-a-better-comment-4c8c)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/todo-comment/todo_comment.rego)\\n","id":"style/todo-comment"},{"filePath":"projects/regal/rules/style/rule-name-repeats-package.md","content":"# rule-name-repeats-package\\n\\n**Summary**: Avoid repeating package path in rule names\\n\\n**Category**: Style\\n\\n**Avoid**\\n```rego\\npackage policy.authz\\n\\nauthz_allow if {\\n user.is_admin\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy.authz\\n\\nallow if {\\n user.is_admin\\n}\\n```\\n\\n## Rationale\\n\\nWhen rules are referenced outside the package in which they are defined, they will be referenced using the package path.\\nFor example, the `allow` rule in the `example` package, is available at `data.example.allow`. When rule names include\\nall or part of their package paths, this creates repetition in such references. For example, `authz_allow` in a package\\n`authz` is referenced with: `data.authz.authz_allow`. This repetition is undesirable as the reference is longer than\\nneeded, and harder to read.\\n\\nThis rule was inspired by [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments#package-names).\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n rule-name-repeats-package:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/rule-name-repeats-package/rule_name_repeats_package.rego)\\n","id":"style/rule-name-repeats-package"},{"filePath":"projects/regal/rules/style/rule-length.md","content":"# rule-length\\n\\n**Summary**: Max rule length exceeded\\n\\n**Category**: Style\\n\\n**Avoid**\\n\\nHaving too much logic placed in a single rule body.\\n\\n**Prefer**\\n\\nTo use helper rules and functions to compose your rules.\\n\\n## Rationale\\n\\nSplitting up large rules into smaller ones, and liberally using helper rules and functions, makes your policy easier for\\nothers to read and understand, and for yourself and your team to maintain.\\n\\nNote that this rule only counts the number of lines of a rule, and currently does not take into account the actual\\ncontent inside of it. Neither does it try to analyze the complexity of the code in the rule.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n rule-length:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n # default limit is 30 lines\\n max-rule-length: 30\\n # default limit is 60 lines for test rules (i.e. prefixed with \'test_\')\\n max-test-rule-length: 60\\n # whether to count comments as lines\\n # by default, this is set to false\\n count-comments: false\\n # except rules with empty bodies from this rule, as they\'re\\n # likely an assignment of long values rather than a \\"rule\\"\\n # with conditions:\\n #\\n # users := [\\n # {\\"username\\": \\"ted\\"},\\n # {\\"username\\": \\"alice\\"},\\n # {\\"username\\": \\"bob\\"},\\n # # ... many more lines\\n # ]\\n #\\n # the default value is true\\n except-empty-body: true\\n```\\n\\n## Related Resources\\n\\
1n- Regal Docs: [file-length](https://www.openpolicyagent.org/projects/regal/rules/style/file-length)\\n- Regal Docs: [line-length](https://www.openpolicyagent.org/projects/regal/rules/style/line-length)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/rule-length/rule_length.rego)\\n","id":"style/rule-length"},{"filePath":"projects/regal/rules/style/prefer-some-in-iteration.md","content":"# prefer-some-in-iteration\\n\\n**Summary**: Prefer `some .. in` for iteration\\n\\n**Category**: Style\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nengineering_roles := {\\"engineer\\", \\"dba\\", \\"developer\\"}\\n\\nengineers contains employee if {\\n employee := data.employees[_]\\n employee.role in engineering_roles\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nengineering_roles := {\\"engineer\\", \\"dba\\", \\"developer\\"}\\n\\nengineers contains employee if {\\n some employee in data.employees\\n employee.role in engineering_roles\\n}\\n```\\n\\n## Rationale\\n\\nUsing the `some .. in` construct for iteration removes ambiguity around iteration vs. membership checks, and is\\ngenerally more pleasant to read. Consider the following example:\\n\\n```rego\\nsome_condition if {\\n other_rule[user]\\n # ...\\n}\\n```\\n\\nAre we iterating users over a partial \\"other_rule\\" here, or checking if the set contains a user defined elsewhere?\\nOr is `other_rule` a map-generating rule, and we\'re checking for the existence of a key? We won\'t know without looking\\nelsewhere in the code. Using `some .. in` removes this ambiguity, and makes the intent clear without having to jump\\naround in the policy.\\n\\nImproved readability is not the only benefit of using `some .. in`. The `some` keyword ensures that the bindings\\nfollowing the keyword are bound to the local scope, and modifications outside of e.g. a rule body won\'t affect how the\\nvariables are evaluated. Consider the following simplified example to iterate over the keys of a map:\\n\\n```rego\\npackage policy\\n\\nkey_traversal if {\\n map[key]\\n # do something with key\\n}\\n\\n\\nkey_traversal if {\\n some key in object.keys(map)\\n # do something with key\\n}\\n```\\n\\nThe two rules above are equivalent in that they both bind the variable `key` to the keys of `map`. The first\\nexample would however change behavior entirely if a rule named `key` was introduced in the package, as the expression\\nwould then mean \\"does map have key `key`?\\". While this isn\'t common, using `some .. in` means one less thing to worry\\nabout.\\n\\n## Exceptions\\n\\nDeeply nested iteration is often easier to read using the more compact form.\\n\\n```rego\\npackage policy\\n\\n# These rules are equivalent, but the more compact form is arguably easier to read\\n\\nany_user_is_admin if {\\n some user in input.users\\n some attribute in user.attributes\\n some role in attribute.roles\\n role == \\"admin\\"\\n}\\n\\nany_user_is_admin if {\\n input.users[_].attributes[_].roles[_] == \\"admin\\"\\n}\\n\\n# Using \\"if\\", we may even omit the brackets for single line rules\\nany_user_is_admin if input.users[_].attributes[_].roles[_] == \\"admin\\"\\n```\\n\\nThe `ignore-nesting-level` configuration option allows setting the threshold for nesting. Any level of nesting\\n**equal or greater than** the threshold won\'t be considered a violation. The default setting of `2` allows all _nested_\\niteration, but not e.g. `my_array[x]`.\\n\\n**Note:** not all nesting is _iteration_! The following example is considered to have a nesting level of `1`, as only\\none of the variables (including wildcards: `_`) is an output variable bound in iteration:\\n\\n```rego\\npackage policy\\n\\nexample_users contains user if {\\n domain := \\"example.com\\"\\n user := input.sites[domain].users[_]\\n}\\n```\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n prefer-some-in-iteration:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n # except iteration if nested at or above the level i.e. setting of\\n # \'2\' will allow `input[_].users[_]` but not `input[_]`\\n ignore-nesting-level: 2\\n # except iteration over items with sub-attributes, like\\n # `name := input.users[_].name`\\n # default is true\\n ignore-if-sub-attribute: true\\n```\\n\\n## Related Resources\\n\\
1n- Rego Style Guide: [Prefer some .. in for iteration](https://www.openpolicyagent.org/docs/style-guide#prefer-some--in-for-iteration)\\n- Regal Docs: [Use `some` to declare output variables](https://www.openpolicyagent.org/projects/regal/rules/idiomatic/use-some-for-output-vars)\\n- OPA Docs: [Membership and Iteration: `in`](https://www.openpolicyagent.org/docs/policy-language/#membership-and-iteration-in)\\n- OPA Docs: [Some Keyword](https://www.openpolicyagent.org/docs/policy-language/#some-keyword)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/prefer-some-in-iteration/prefer_some_in_iteration.rego)\\n","id":"style/prefer-some-in-iteration"},{"filePath":"projects/regal/rules/style/prefer-snake-case.md","content":"# prefer-snake-case\\n\\n**Summary**: Prefer snake_case for names\\n\\n**Category**: Style\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\n# camelCase rule name\\nuserIsAdmin if \\"admin\\" in input.user.roles\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\n# snake_case rule name\\nuser_is_admin if \\"admin\\" in input.user.roles\\n```\\n\\n## Rationale\\n\\nThe built-in functions use `snake_case` for naming \u2014 follow that convention for your own packages, rules, functions,\\nand variables, unless you have a really good reason not to.\\n\\n## Exceptions\\n\\nIn many cases, you might not control the format of the `input` data \u2014 if the domain of a policy (e.g. Envoy)\\nmandates a different style, making an exception might seem reasonable. Adapting policy format after `input` is however\\nprone to inconsistencies, as you\'ll likely end up mixing different styles in the same policy (due to imports of common\\ncode, etc).\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n prefer-snake-case:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Rego Style Guide: [Prefer snake_case for rule names and variables](https://www.openpolicyagent.org/docs/style-guide#prefer-snake_case-for-rule-names-and-variables)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/prefer-snake-case/prefer_snake_case.rego)\\n","id":"style/prefer-snake-case"},{"filePath":"projects/regal/rules/style/pointless-reassignment.md","content":"# pointless-reassignment\\n\\n**Summary**: Pointless reassignment of variable\\n\\n**Category**: Style\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nallow if {\\n users := all_users\\n any_admin(users)\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nallow if {\\n any_admin(all_users)\\n}\\n```\\n\\n## Rationale\\n\\nValues and variables are immutable in Rego, so reassigning the value of one variable to another only adds noise.\\n\\n## Exceptions\\n\\nReassigning the value of a long reference often helps readability, and especially so when it needs to be referenced\\nmultiple times:\\n\\n```rego\\npackage policy\\n\\nallow if {\\n users := input.context.permissions.users\\n any_admin(users)\\n}\\n```\\n\\nThis rule does not consider such assignments violations.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n pointless-reassignment:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/pointless-reassignment/pointless_reassignment.rego)\\n","id":"style/pointless-reassignment"},{"filePath":"projects/regal/rules/style/opa-fmt.md","content":"# opa-fmt\\n\\n**Summary**: File should be formatted with `opa fmt`\\n\\n**Category**: Style\\n\\n**Automatically fixable**: [Yes](https://www.openpolicyagent.org/projects/regal/fixing)\\n\\n**Avoid**\\n\\nInconsistent style across policy files and repositories.\\n\\n## Rationale\\n\\nThe `opa fmt` tool ensures consistent formatting across teams and projects. Unified formatting is a big win, and saves a\\nlot of time in code reviews arguing over details around style.\\n\\nA good idea could be to run `opa fmt --write` on save, which can be configured in most editors.\\n\\n**Tip**: `opa fmt` uses tabs for indentation. By default, GitHub uses 8 spaces to display tabs, which is arguably a bit\\nmuch. You can change this preference for your account in `github.com/settings/appearance`, or provide an `.editor
1config`\\nfile in your policy repository, which will be used by GitHub (and other tools) to properly display your Rego files:\\n\\n```ini\\n[*.rego]\\nend_of_line = lf\\ninsert_final_newline = true\\ncharset = utf-8\\nindent_style = tab\\nindent_size = 4\\n```\\n\\n## OPA Format with Rego v1 and v0\\n\\nOPA 1.0 makes Rego v1 the default. This change mandated some changes to the\\nfunctionality of the `opa fmt` command and a number of new options for working\\nwith mixed version code bases. See the\\n[OPA documentation](https://www.openpolicyagent.org/docs/cli/#opa-fmt)\\nfor the command\'s options.\\n\\nIn Regal, a v0 file will have the `opa-fmt` violation unless it\'s been formatted\\nwith `opa fmt --v0-v1`. A v1 file will have the `opa-fmt` violation unless it\'s\\nbeen formatted with `opa fmt` (the rego.v1 keyword is permitted but not added).\\n\\nWhen formatting, a file expected to be v1 based on the configuration, but with\\nv0 syntax is still formatted as `opa fmt \u2013-v0-v1`. Please see\\n[Configuring Rego Version](https://www.openpolicyagent.org/projects/regal#configuring-rego-version)\\nfor more configuration help for multi version projects.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n opa-fmt:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [CLI Reference `opa fmt`](https://www.openpolicyagent.org/docs/cli/#opa-fmt)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/opa-fmt/opa_fmt.rego)\\n","id":"style/opa-fmt"},{"filePath":"projects/regal/rules/style/no-whitespace-comment.md","content":"# no-whitespace-comment\\n\\n**Summary**: Comment should start with whitespace\\n\\n**Category**: Style\\n\\n**Automatically fixable**: [Yes](https://www.openpolicyagent.org/projects/regal/fixing)\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\n#Deny by default\\ndefault allow := false\\n\\n#Allow only admins\\nallow if \\"admin\\" in input.user.roles\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\n# Deny by default\\ndefault allow := false\\n\\n# Allow only admins\\nallow if \\"admin\\" in input.user.roles\\n```\\n\\n## Rationale\\n\\nComments should be preceded by a single space, as this makes them easier to read.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n no-whitespace-comment:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n # optional pattern to except from this rule\\n # this example would allow comments like \\"#--\\"\\n # use or (`|`) to separate multiple patterns\\n except-pattern: \\"^--\\"\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/no-whitespace-comment/no_whitespace_comment.rego)\\n","id":"style/no-whitespace-comment"},{"filePath":"projects/regal/rules/style/mixed-iteration.md","content":"# mixed-iteration\\n\\n**Summary**: Mixed iteration style\\n\\n**Category**: Style\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\nallow if {\\n # mixing \'some .. in\' and reference iteration\\n some resource in input.assets[_]\\n\\n # do something with resource\\n}\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\nallow if {\\n # using \'some .. in\' iteration consistently\\n some asset in input.assets\\n some resource in asset\\n\\n # do something with resource\\n}\\n\\n# alternatively\\n\\nallow if {\\n # using reference iteration consistently\\n resource := input.assets[_][_]\\n\\n # do something with resource\\n}\\n```\\n\\n## Rationale\\n\\nUsing `some .. in` is often the [best choice](https://www.openpolicyagent.org/projects/regal/rules/style/prefer-some-in-iteration) for\\niteration in modern Rego, as it clearly communicates what\'s going on and which variables will be bound in each\\niteration. An alternative approach is to place variables (including the special \\"wildcard\\" variable `_`)
1in parts of a\\nreferences, which unless assigned elsewhere automatically will be bound to every possible value in the collection being\\ntraversed (often called \\"output variables\\").\\n\\n\\"Reference style\\" iteration is often preferred when deeply nested structures are traversed, as they allow\\nexpressing that in a very concise (and sometimes, more performant) manner.\\n\\nWhile both forms of iteration are valid and have their place, mixing both forms in a single iteration is arguably\\nconfusing. Feel free to choose either `some .. in` or reference style depending on your preference (and when in doubt,\\nuse `some .. in`), but don\'t mix the two different styles in a single iteration expression.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n mixed-iteration:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Regal Docs: [prefer-some-in-iteration](https://www.openpolicyagent.org/projects/regal/rules/style/prefer-some-in-iteration)\\n- OPA Docs: [Membership and iteration](https://www.openpolicyagent.org/docs/policy-language/#membership-and-iteration-in)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/mixed-iteration/mixed_iteration.rego)\\n","id":"style/mixed-iteration"},{"filePath":"projects/regal/rules/style/messy-rule.md","content":"# messy-rule\\n\\n**Summary**: Messy incremental rule\\n\\n**Category**: Style\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\nallow if something\\n\\nunrelated_rule if { # <--- this rule is breaking up allow\\n # ...\\n}\\n\\nallow if something_else # <--- should be with the first allow\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\nallow if something\\n\\nallow if something_else\\n\\nunrelated_rule if {\\n # ...\\n}\\n```\\n\\n## Rationale\\n\\nIn Rego, rules can can be formed of many \'rule heads\', partial definitions\\ncovering specific cases which together make up the behaviour of the whole rule.\\nRules that are defined incrementally should have their definitions grouped together, as this makes the code easier to\\nfollow. While this is mostly a style preference, having incremental rules grouped also allows editors like VS Code to\\n\\"know\\" that the rules belong together, allowing them to be smarter when displaying the symbols of a workspace.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n messy-rule:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/messy-rule/messy_rule.rego)\\n","id":"style/messy-rule"},{"filePath":"projects/regal/rules/style/line-length.md","content":"# line-length\\n\\n**Summary**: Line too long\\n\\n**Category**: Style\\n\\n**Avoid**\\n\\nExcessive line length.\\n\\n## Rationale\\n\\nRego does not have many nested constructs, and long lines of code are thus almost never needed. If you find yourself\\nclose to the maximum line length, consider refactoring your policy.\\n\\nThe default maximum line length is 120 characters.\\n\\n## Exceptions\\n\\nOn a few rare occasions, a single word \u2014 like a really long URL in a metadata annotation \u2014 can\'t possibly be made any\\nshorter. Using an ignore directive isn\'t an option in that context, and ignoring the whole file is rarely what you\'ll\\nwant. The `non-breakable-word-threshold` configuration option allows defining a threshold length for when a single word\\nshould be considered so long that the line length rule should ignore the line entirely.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n line-length:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n # maximum line length\\n max-line-length: 120\\n # if any single word on a line exceeds this length, ignore it\\n non-breakable-word-threshold: 100\\n```\\n\\n## Related Resources\\n\\
1n- Regal Docs: [file-length](https://www.openpolicyagent.org/projects/regal/rules/style/file-length)\\n- Regal Docs: [rule-length](https://www.openpolicyagent.org/projects/regal/rules/style/rule-length)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/line-length/line_length.rego)\\n","id":"style/line-length"},{"filePath":"projects/regal/rules/style/function-arg-return.md","content":"# function-arg-return\\n\\n**Summary**: Return value assigned in function argument\\n\\n**Category**: Style\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nhas_email(user) if {\\n indexof(user.email, \\"@\\", i)\\n i != -1\\n}\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\nhas_email(user) if {\\n i := indexof(user.email, \\"@\\")\\n i != -1\\n}\\n```\\n\\n## Rationale\\n\\nOlder Rego policies sometimes contain an unusual way to declare where the return value of a function call should be\\nstored \u2014 the last argument of the function. True to its Datalog roots, return values may be stored either using\\nassignment (i.e. `:=`) or by appending a variable name to the argument list of a function. While both forms are valid,\\nusing assignment `:=` consistently is preferred.\\n\\n## Exceptions\\n\\nThe `walk` built-in function is a special one, as it\'s the only one producing a *relation*. Therefore, it is okay to\\ntreat it as one even in style, and:\\n\\n```rego\\nwalk(object, [path, value])\\n```\\n\\nis arguably more idiomatic than:\\n\\n```rego\\n[path, value] := walk(object)\\n```\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n function-arg-return:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n # list of function names to ignore\\n # * by default, walk is excepted from this rule\\n # * note that `print` is always ignored as it does not return a value\\n except-functions:\\n - walk\\n```\\n\\n## Related Resources\\n\\n- Rego Style Guide: [Avoid using the last argument for the return value](https://www.openpolicyagent.org/docs/style-guide#avoid-using-the-last-argument-for-the-return-value)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/function-arg-return/function_arg_return.rego)\\n","id":"style/function-arg-return"},{"filePath":"projects/regal/rules/style/file-length.md","content":"# file-length\\n\\n**Summary**: Max file length exceeded\\n\\n**Category**: Style\\n\\n**Avoid**\\n\\nExcessively large policy files.\\n\\n**Prefer**\\n\\nSplitting large policy files into smaller ones.\\n\\n## Rationale\\n\\nPutting too much logic into a single file makes your policy harder to browse, read and maintain. Splitting logic into\\nseveral smaller files, and composing policy by proper use of packages and imports, highlights dependencies and\\nmakes it easier to reason about.\\n\\nNote that even a single **package** may be split up across several files! This is sometimes useful when different\\nfeatures or functions belong in the same \\"group\\", but are not directly related to each other. An example of this could\\nbe having a single package for configuration split across different files for different parts or functions of that\\nconfiguration.\\n\\nAs an added bonus, some tools \u2014 like Regal! \u2014 may even benefit from avoiding huge files as they process files in\\nparallel and thus will be able to handle many smaller files faster than a few large ones.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n file-length:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n # default limit is 500 lines\\n max-file-length: 500\\n```\\n\\n## Related Resources\\n\\n- Styra Blog: [Dynamic Policy Composition](https://web.archive.org/web/https://www.styra.com/blog/dynamic-policy-composition-for-opa/)\\n- Regal Docs: [line-length](https://www.openpolicyagent.org/projects/regal/rules/style/line-length)\\n- Regal Docs: [rule-length](https://www.openpolicyagent.org/projects/regal/rules/style/rule-length)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/file-length/file_length.rego)\\n","id":"style/file-length"},{"filePath":"projects/regal/rules/style/external-reference.md","content":"# external-reference\\n\\n**Summary**: External reference in function\\n\\n**Category**: Style\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\n# Depends on both `input` and `data`\\nis_preferred_login_method(method
1) if {\\n preferred_login_methods := {login_method |\\n some login_method in data.authentication.all_login_methods\\n login_method in input.user.login_methods\\n }\\n method in preferred_login_methods\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\n# Depends only on function arguments\\nis_preferred_login_method(method, user, all_login_methods) if {\\n preferred_login_methods := {login_method |\\n some login_method in all_login_methods\\n login_method in user.login_methods\\n }\\n method in preferred_login_methods\\n}\\n```\\n\\n## Rationale\\n\\nWhat separates functions from rules is that they accept arguments. While a function also may reference anything from\\n`input`, `data` or other rules declared in a policy, these references create dependencies that aren\'t obvious simply by\\nchecking the function signature, and it makes it harder to reuse that function in other contexts. Additionally,\\nfunctions that only depend on their arguments are easier to test standalone.\\n\\n## Exceptions\\n\\nRego does not provide first-class functions \u2014 functions can\'t be passed as arguments to other functions. Therefore, this\\nrule allows functions to freely reference (i.e. call) _other functions_, whether built-in functions, or custom functions\\ndefined in the same package or elsewhere, and these do not count as \\"external references\\" simply because there is not\\nother way to import them into the function body.\\n\\n```rego\\npackage policy\\n\\nfirst_name(full_name) := capitalized {\\n first_name := split(full_name, \\" \\")[0]\\n\\n # while data.utils.capitalize is an external reference, it\'s not flagged\\n # as such, since there is no way to import it via function arguments\\n capitalized := data.utils.capitalize(first_name)\\n}\\n```\\n\\n### Changed default behavior since Regal v0.33.0\\n\\nWhile we still consider it a best practice to pass any dependencies of a function in its arguments, the previous\\n(non-configurable) default of not allowing **any** external references was often considered too distracting. This led\\nto many disabling this rule entirely, or used inline ignore directives where this would be reported. Even in Regal\'s own\\npolicies, there were quite a few locations where the latter option was used.\\n\\nFrom v0.33.0 and onwards, this rule\'s default has been relaxed to allow 2 external references in any given function\\ndefinition, and the new `max-allowed` configuration option allows changing this value to whatever feels like a\\nreasonable default. If you previously disabled this rule in your projects, consider enabling it again configured to\\nmatch your preference.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n external-reference:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n # the number of external references to allow for any given function\\n #\\n # introduced in v0.33.0 and defaults to 2. set to 0 to revert to\\n # original behavior to not allow any external references\\n max-allowed: 2\\n```\\n\\n## Related Resources\\n\\n- Rego Style Guide: [Prefer using arguments over input, data or rule references](https://www.openpolicyagent.org/docs/style-guide#prefer-using-arguments-over-input-data-or-rule-references)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/external-reference/external_reference.rego)\\n","id":"style/external-reference"},{"filePath":"projects/regal/rules/style/double-negative.md","content":"# double-negative\\n\\n**Summary**: Avoid double negatives\\n\\n**Category**: Style\\n\\n**Avoid**\\n```rego\\npackage negative\\n\\nfine if not not_fine\\n\\nwith_friends if not without_friends\\n\\nnot_fine := input.fine != true\\n\\nwithout_friends if count(input.friends) == 0\\n```\\n\\n**Prefer**\\n```rego\\npackage negative\\n\\nfine if input.fine == true\\n\\nwith_friends if count(input.friends) > 0\\n```\\n\\n## Rationale\\n\\nWhile rules using double negatives \u2014 like `not no_funds` \u2014 occasionally make sense, it is often worth considering\\nwhether the rule could be rewritten without the negative. For example, `not no_funds` could be rewritten as `funds` or\\n`has_funds`, or `funds_available`.\\n\\nAccess control policy often includes rules using some form of double negatives, like `allow if not deny`. That\'s\\nconsidered OK, and the `double-negative` rule is limited to check for a limited list of words:\\n\\n- `not cannot_`\\n- `not no_`\\n- `not non_`\\n- `not not_`,\\n- `not without_`\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n double-negative:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\
1n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/double-negative/double_negative.rego)\\n","id":"style/double-negative"},{"filePath":"projects/regal/rules/style/detached-metadata.md","content":"# detached-metadata\\n\\n**Summary**: Detached metadata annotation\\n\\n**Category**: Style\\n\\n**Avoid**\\n```rego\\npackage authz\\n\\n # METADATA\\n # description: allow any requests by admin users\\n\\nallow if {\\n \\"admin\\" in input.user.roles\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage authz\\n\\n# METADATA\\n# description: allow any requests by admin users\\nallow if {\\n \\"admin\\" in input.user.roles\\n}\\n```\\n\\n## Rationale\\n\\nMetadata annotations should be placed directly above the package, rule or function they are annotating. While OPA\\naccepts any number of newlines between an annotation and the package/rule it applies to, this makes it difficult to\\nconnect the two when reading the policy. Always optimize for readability!\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n detached-metadata:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Annotations](https://www.openpolicyagent.org/docs/policy-language/#annotations)\\n- OPA Docs: [Accessing Annotations](https://www.openpolicyagent.org/docs/policy-language/#accessing-annotations)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/detached-metadata/detached_metadata.rego)\\n","id":"style/detached-metadata"},{"filePath":"projects/regal/rules/style/default-over-not.md","content":"# default-over-not\\n\\n**Summary**: Prefer default assignment over negated condition\\n\\n**Category**: Style\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nusername := input.user.name\\n\\nusername := \\"anonymous\\" if not input.user.name\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\ndefault username := \\"anonymous\\"\\n\\nusername := input.user.name\\n```\\n\\n## Rationale\\n\\nWhile both forms are valid, using the `default` keyword to assign a constant value in the fallback case better\\ncommunicates intent, avoids negation where it isn\'t needed, and requires less instructions to evaluate. Note that this\\nrule only covers simple cases where one rule assigns the \\"happy\\" path, and another rule assigns on the same condition\\nnegated. This is by design, as using `not` and negation may very well be the right choice for more complex cases!\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n default-over-not:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Default Keyword](https://www.openpolicyagent.org/docs/policy-language/#default-keyword)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/default-over-not/default_over_not.rego)\\n","id":"style/default-over-not"},{"filePath":"projects/regal/rules/style/default-over-else.md","content":"# default-over-else\\n\\n**Summary**: Prefer default assignment over fallback `else`\\n\\n**Category**: Style\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\npermissions := [\\"read\\", \\"write\\"] if {\\n input.user == \\"admin\\"\\n} else := [\\"read\\"]\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\ndefault permissions := [\\"read\\"]\\n\\npermissions := [\\"read\\", \\"write\\"] if {\\n input.user == \\"admin\\"\\n}\\n```\\n\\n## Rationale\\n\\nThe `else` keyword has a single purpose in Rego \u2014 to allow a policy author to control the order of evaluation. Whether\\nseveral `else`-clauses are chained or not, it\'s common to use a last \\"fallback\\" `else` to cover all cases not covered by\\nthe conditions in the preceding `else`-bodies. A kind of \\"catch all\\", or \\"default\\" condition. This is useful, but Rego\\narguably provides a more idiomatic construct for default assignment: the\\n[default keyword](https://www.openpolicyagent.org/docs/policy-language/#default-keyword).\\n\\nWhile the end result is the same, default assignment has the benefit of more clearly \u2014 and **before** the conditional\\nassignments \u2014 communicating what the *safe* option is. This is particularly important for\\n[entrypoint](https://www.openpolicyagent.org/projects/regal/rules/idiomatic/no-defined-entrypoint) rules, where the\\ndefault value of a rule is a part of the rule\'s contract.\\n\\n## Exceptions\\n\\nOPA [v0.55.0](https://github.com/open-policy-agent/opa/releases/tag/v0.55.0) introduced supp
1ort for the default keyword\\nfor custom functions. This means that `else` fallbacks in functions may now be rewritten to use default assignment too:\\n\\n```rego\\npackage policy\\n\\nfirst_name(full_name) := split(full_name, \\" \\")[0] if {\\n full_name != \\"\\"\\n} else := \\"Unknown\\"\\n```\\n\\nCould now be written as:\\n\\n```rego\\npackage policy\\n\\ndefault first_name(_) := \\"Unknown\\"\\n\\nfirst_name(full_name) := split(full_name, \\" \\")[0] if {\\n full_name != \\"\\"\\n}\\n```\\n\\nDefault value assignment for functions however come with a big caveat \u2014 the default case will only be triggered if all\\narguments passed to the function evaluate to a *defined value*. Thus, calling the `first_name` function from our above\\nexample is **not** guaranteed to return a value of `\\"Unknown\\"`:\\n\\n```rego\\n# undefined if `input.name` is undefined\\nfname := first_name(input.name)\\n```\\n\\nWhether deemed acceptable or not, this differs enough from default assignment of rules to make this preference opt-in\\nrather than opt-out. Use the `prefer-default-functions` configuration option to control whether `default` assignment\\nshould be preferred over `else` fallbacks also for custom functions. The default value (no pun intended!) of this config\\noption is `false`.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n default-over-else:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n # whether to prefer default assignment over\\n # `else` fallbacks for custom functions\\n prefer-default-functions: false\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Default Keyword](https://www.openpolicyagent.org/docs/policy-language/#default-keyword)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/default-over-else/default_over_else.rego)\\n","id":"style/default-over-else"},{"filePath":"projects/regal/rules/style/comprehension-term-assignment.md","content":"# comprehension-term-assignment\\n\\n**Summary**: Assignment can be moved to comprehension term\\n\\n**Category**: Style\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nnames := [name |\\n some user in input.users\\n name := user.name # redundant assignment\\n]\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nnames := [user.name |\\n some user in input.users\\n]\\n\\n# which in this case can be made a one-liner\\nnames := [user.name | some user in input.users]\\n```\\n\\n## Rationale\\n\\nAdding an intermediate assignment in a comprehension body to a variable used as the comprehension term (i.e. the value\\nto the left side of `|` in a comprehension) is redundant, as the value can be used directly as the comprehension term.\\nMaking code as compact as possible should never be a goal in itself, but the same is true for making code needlessly\\nverbose. And in cases like `names := [user.name | some user in input.users]`, adding an intermediate assignment does\\nnothing to improve readability.\\n\\n## Exceptions\\n\\nThis rule will only flag simple assignments where the value could be moved directly into the comprehension term. More\\ncomplex assignments involving dynamic references or function calls, will not be considered as violations.\\n\\nExample:\\n\\n```rego\\nfirst_names := [first_name |\\n some user in input.users\\n first_name := capitalize(user.name.split(\\" \\")[0])\\n]\\n```\\n\\nWhile it\'s possible to move the value of the `first_name` assignment directly to the comprehension term, it\'s arguably\\nless readable, as it makes it harder to see that the form is a comprehension to begin with.\\n\\n```rego\\n# Not recommended\\nfirst_names := [capitalize(user.name.split(\\" \\")[0]) |\\n some user in input.users\\n]\\n```\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n comprehension-term-assignment:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\
1n- OPA Docs: [Comprehensions](https://www.openpolicyagent.org/docs/policy-language/#comprehensions)\\n- Regal Docs: [pointless-reassignment](https://www.openpolicyagent.org/projects/regal/rules/style/pointless-reassignment)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/comprehension-term-assignment/comprehension_term_assignment.rego)\\n","id":"style/comprehension-term-assignment"},{"filePath":"projects/regal/rules/style/avoid-get-and-list-prefix.md","content":"# avoid-get-and-list-prefix\\n\\n**Summary**: Avoid `get_` and `list_` prefix for rules and functions\\n\\n**Category**: Style\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nget_first_name(user) := split(user.name, \\" \\")[0]\\n\\n# Partial rule, so a set of users is to be expected\\nlist_developers contains user if {\\n some user in data.application.users\\n user.type == \\"developer\\"\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\n# \\"get\\" is implied\\nfirst_name(user) := split(user.name, \\" \\")[0]\\n\\n# Parti
1al rule, so a set of users is to be expected\\ndevelopers contains user if {\\n some user in data.application.users\\n user.type == \\"developer\\"\\n}\\n```\\n\\n## Rationale\\n\\nSince Rego evaluation is generally free of side effects, any rule or function is essentially a \\"getter\\". Adding a\\n`get_` prefix to a rule or function (like `get_resources`) thus adds little of value compared to just naming it\\n`resources`. Additionally, the type and return value of the rule should serve to tell whether a rule might return a\\nsingle value (i.e. a complete rule) or a collection (a partial rule).\\n\\n## Exceptions\\n\\nUsing `is_`, or `has_` for boolean helper functions, like `is_admin(user)` may be easier to comprehend than\\n`admin(user)`.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n style:\\n avoid-get-and-list-prefix:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Rego Style Guide: [Avoid prefixing rules and functions with `get_` or `list_`](https://www.openpolicyagent.org/docs/style-guide#avoid-prefixing-rules-and-functions-with-get_-or-list_)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/style/avoid-get-and-list-prefix/avoid_get_and_list_prefix.rego)\\n","id":"style/avoid-get-and-list-prefix"},{"filePath":"projects/regal/rules/performance/with-outside-test-context.md","content":"# with-outside-test-context\\n\\n**Summary**: `with` used outside of test context\\n\\n**Category**: Performance\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nallow if {\\n some user in data.users\\n\\n # mock input to pass data to `allowed_user` rule\\n allowed_user with input as {\\"user\\": user}\\n}\\n\\nverified := io.jwt.verify_rs256(input.token, data.keys.verification_key)\\n\\nallowed_user := input.user if {\\n # this expensive rule will be evaluated for each user!\\n verified\\n \\"admin\\" in input.user.roles\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nallow if {\\n some user in data.users\\n\\n allowed_user({\\"user\\": user})\\n}\\n\\nverified := io.jwt.verify_rs256(input.token, data.keys.verification_key)\\n\\nallowed_user(user) := user if {\\n # this expensive rule will be evaluated only once\\n verified\\n \\"admin\\" in user.roles\\n}\\n```\\n\\n## Rationale\\n\\nThe `with` keyword exists primarily as a way to easily mock `input` or `data` in unit tests. While it\'s not forbidden to\\nuse `with` in other contexts, and it\'s occasionally useful to do so, `with` is not optimized for performance and can\\neasily result in increased evaluation time if not used with care.\\n\\nOne optimization that OPA does all the time is to cache the result of rule evaluation. If OPA needs to evaluate the same\\nrule more than once as part of evaluating a query, the result of the first evaluation is memorized and the cost of\\nsubsequent evaluations is essentially zero. Caching however assumes that the conditions that produced the result of the\\nfirst evaluation won\'t _change_ \u2014 and changing the conditions (i.e. `input` or `data`) for evaluation is the very\\npurpose of `with`! This means that rules evaluated in the context of `with` won\'t be cached, and an expensive operation,\\nlike the `io.jwt.verify_rs256` built-in function called in the examples above would be evaluated for each `user` in\\n`data.users`, even if the `with` clause in this case doesn\'t change any value that the JWT verification function depends\\non.\\n\\n## Exceptions\\n\\nThe obvious exception is stated already in the title of this rule: unit tests! Use `with` as much as want here, as that\\nis what `with` is for.\\n\\nUsing `with` outside the context of unit tests is most commonly seen in policies using\\n[dynamic policy composition](https://web.archive.org/web/https://www.styra.com/blog/dynamic-policy-composition-for-opa/), which typically involves\\na \\"main\\" policy dispatching to a number of other policies and aggregating the result of evaluating each one. In this\\nscenario it\'s quite common to need to alter either `input` or `data` before evaluating a policy or rule, and `with` is\\ncommonly used for this purpose. If you need to use `with` outside of tests, make sure that rules evaluated frequently\\nare done so outside of the scope of `with` to avoid performance issues.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n performance:\\n with-outside-test-context:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\
1n- OPA Docs: [With Keyword](https://www.openpolicyagent.org/docs/policy-language/#with-keyword)\\n- Styra Blog: [Dynamic Policy Composition for OPA](https://web.archive.org/web/https://www.styra.com/blog/dynamic-policy-composition-for-opa/)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/performance/with-outside-test-context/with_outside_test_context.rego)\\n","id":"performance/with-outside-test-context"},{"filePath":"projects/regal/rules/performance/walk-no-path.md","content":"# walk-no-path\\n\\n**Summary**: Call to `walk` can be optimized\\n\\n**Category**: Performance\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nallow if {\\n # traverse potentially nested permissions structure looking\\n # for an admin role, but notice how the path is never referenced\\n # later\\n walk(user.permissions, [path, value])\\n\\n value.type == \\"role\\"\\n value.name == \\"admin\\"\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nallow if {\\n # replacing `path` with a wildcard variable tells the evaluator that it won\'t\\n # have to build the path array for each node `walk` traverses, thereby avoiding\\n # unnecessary allocations\\n walk(user.permissions, [_, value])\\n\\n value.type == \\"role\\"\\n value.name == \\"admin\\"\\n}\\n```\\n\\n## Rationale\\n\\nThe primary purpose of the `walk` function is to traverse nested data structures, and often at an arbitrary depth.\\nEach node traversed \\"produces\\" a path/value pair, where the path is an array of keys that lead to the current node,\\nand the value is the current node itself. Most often, rules only need to account for the value of the node and not the\\npath, and when that is the case, using a wildcard variable (`_`) in place of path tells the evaluation engine that\\nthere\'s no need to build the path array for each node traversed, thereby avoiding unnecessary allocations. This can\\nhave a big impact on performance when huge data structures are traversed!\\n\\nMore concretely, `walk`ing without generating the path array cuts down evaluation time by about 33%, and reduces the\\nnumber of allocations by about 40%.\\n\\n**Trivia**: this optimization was originally made in OPA to improve the performance of Regal, where `walk` is used\\nextensively to traverse the AST of the policy being linted.\\n\\n## Exceptions\\n\\nThis rule can only optimize `walk` calls where the path/value array is provided as a second argument to `walk`, and\\n**not** when assigned using `:=`:\\n\\n```rego\\npackage policy\\n\\nallow if {\\n # this can\'t be optimized, as the `walk` function can\'t\\n # \\"see\\" the array assignment on the left hand side\\n [path, value] := walk(user.permissions)\\n\\n value.type == \\"role\\"\\n value.name == \\"admin\\"\\n}\\n```\\n\\nFor this reason, and a few historic ones, using the second argument for the return value is the preferred way to use\\n`walk`, which is [unique](https://www.openpolicyagent.org/projects/regal/rules/style/function-arg-return#exceptions) for the walk built-in\\nfunction.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n performance:\\n walk-no-path:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Regal Docs: [function-arg-return](https://www.openpolicyagent.org/projects/regal/rules/style/function-arg-return)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/performance/walk-no-path/walk_no_path.rego)\\n","id":"performance/walk-no-path"},{"filePath":"projects/regal/rules/performance/non-loop-expression.md","content":"# non-loop-expression\\n\\n**Summary**: Non-loop expression in loop\\n\\n**Category**: Performance\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\nallow if {\\n some email in input.emails\\n \\"admin\\" in input.roles # <- this is not required in the loop\\n endswith(email, \\"@example.com\\")\\n}\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\nallow if {\\n \\"admin\\" in input.roles # <- moved out of the loop\\n some email in input.emails\\n endswith(email, \\"@example.com\\")\\n}\\n```\\n\\n## Rationale\\n\\nExpressions in loops are evaluated in each iteration of the loop. Expressions\\nthat do not depend on the loop variable should be moved out of the loop to\\nsave computation time.\\n\\n\'Loops\' in Rego refers to anywhere a rule branches, for example:\\n\\n- `some foo, bar in data.baz`\\n- `foo := data.baz[_]` (prefer using `some`)\\n- `walk(data.baz, [path, value])`\\n- ...\\n\\n## Exceptions\\n\\nThis rule c
1annot yet detect the following cases.\\n\\nExpressions overly nested in more than one loop:\\n\\n```rego\\npackage policy\\n\\nallow if {\\n some role in data.roles\\n # <--- Should be Here\\n some permission in data.permissions[role]\\n startswith(role, \\"admin-\\") # <- this is not required in the permission loop\\n operation.permission == permission\\n}\\n```\\n\\nExpressions nested within comprehensions:\\n\\n```rego\\npackage policy\\n\\nallow if {\\n roles := {role |\\n prefix := data.prefix\\n # <--- Should be Here\\n some role in data.roles\\n prefix != \\"\\" # <- this is not required in the role loop\\n startswith(role, prefix)\\n }\\n}\\n```\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n performance:\\n non-loop-expression:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Regal Docs: [defer-assignment](https://www.openpolicyagent.org/projects/regal/rules/performance/defer-assignment)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/performance/non-loop-expression/non_loop_expression.rego)\\n","id":"performance/non-loop-expression"},{"filePath":"projects/regal/rules/performance/equals-over-count.md","content":"# equals-over-count\\n\\n**Summary**: Prefer direct use of `==`/`!=` over `count` to check for empty collections\\n\\n**Category**: Performance\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\ndenied if count(deny) > 0\\n\\nusers_with_no_emails_provided contains user if {\\n some user in data.store.users\\n\\n count(user.emails) == 0\\n}\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\ndenied if deny != set()\\n\\nusers_with_no_emails_provided contains user if {\\n some user in data.store.users\\n\\n user.emails == []\\n}\\n```\\n\\n## Rationale\\n\\n**Note!** This is an **optional** rule (disabled by default) for optimizing performance in hot paths, and is not\\nrecommended for general use in most projects. As our general guideline on policy authoring states: policy authors should\\noptimize for readability and to communicate intent. Policy evaluation with OPA is generally **very** fast. Additionally,\\nthis rule comes with a few caveats of its own, as described further down. Read on to learn how you may benefit from this\\nrule even if you leave it disabled by default.\\n\\nAll function calls come with some cost, and while `count` is generally very cheap to use, it goes without saying that\\navoiding a function call always is faster than making one. A common \u2014 and by all means idiomatic \u2014 pattern in Rego is\\nto evaluate something conditionally based on whether a collection (or string) is empty or not. The most straightforward\\nway to do this is probably to use `count` and compare the result to `0`, using either `==`, `!=` or `>`. This entails\\nmaking two function calls: one to `count` and one to the function behind the comparison operator.\\n\\n**Cheap**\\n\\n```rego\\na := count(deny) > 0 # calls `count` and `gt` (`>`)\\nb := count(input.roles) != 0 # calls `count` and `neq` (`!=`)\\nc := count(data.users) == 0 # calls `count` and `equal` (`==`)\\n```\\n\\nWhile this is perfectly idiomatic Rego, expressing the same logic using direct comparison to an empty collection or\\nstring is more efficient, as it needs only the comparison function call. The cheaper form is also perfectly idiomatic,\\nbut may not communicate intent as clearly as the `count` form.\\n\\n**Cheaper**\\n\\n```rego\\na := deny != set() # calls only `neq` (`!=`)\\nb := input.roles != [] # calls only `neq` (`!=`)\\nc := data.users == [] # calls only `equal` (`==`)\\n```\\n\\nA small benefit of using the direct comparison form besides performance is that it communicates type\\ninformation at the call site, which the `count` form does not. While this rarely is necessary, it makes a pretty good\\ncase for why some may prefer this form over the `count` alternative even for non-performance-critical code.\\n\\n### Caveats\\n\\n- This rule assumes a collection (or string) is always of the same type. While this is generally the case \u2014 and a good\\n practice to follow \u2014 this rule will emit **false positives** on collections that may either be e.g. an array or a set,\\n as the `count` form then isn\'t directly replaceable with the direct comparison form.\\n- This rule only applies to comparisons to \\"empty\\" or \\"not empty\\", and n
1ot e.g. `count(x) > 1` or `count(x) == 2`\\n- Just as when using `count`, evaluation still halts in the case of a non-existent (i.e. undefined) collection or\\n string.\\n- Future versions of OPA could potentially perform this optimization as part of compilation, which would make both forms\\n equally efficient. This wouldn\'t mean you\'d have to change your code back \u2014 only that there no longer would be a\\n performance benefit to using the direct comparison form. Some may still prefer it for other reasons though, like the\\n extra type information it provides at call sites. Should this happen, we\'ll update this documentation accordingly.\\n\\n### Recommended Use\\n\\nUnless you\'re working in a project where every microsecond counts, you probably shouldn\'t enable this rule. What you\\ncan do is to **occasionally** run the linter with `equals-over-count` enabled, and see if any of the reported\\nlocations possibly may be in a hot path, and decide on a case-by-case basis whether to change the code or not. Don\'t\\nforget to benchmark to verify your assumptions!\\n\\nIt could also be that you prefer the direct comparison form over the `count` form for aesthetic reasons! In which case\\nyou may choose to enable it by default. Just keep the caveats described above in mind.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n performance:\\n equals-over-count:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/performance/equals-over-count/equals_over_count.rego)\\n","id":"performance/equals-over-count"},{"filePath":"projects/regal/rules/performance/defer-assignment.md","content":"# defer-assignment\\n\\n**Summary**: Assignment can be deferred\\n\\n**Category**: Performance\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nallow if {\\n resp := http.send({\\"method\\": \\"GET\\", \\"url\\": \\"http://example.com\\"})\\n\\n # this check does not depend on the response above\\n # and thus the resp := ... assignment can be deferred to\\n # after the check\\n input.user.name in allowed_users\\n\\n resp.status_code == 200\\n\\n # more done with response here\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nallow if {\\n input.user.name in allowed_users\\n\\n # the next expression *does* depend on `resp`\\n resp := http.send({\\"method\\": \\"GET\\", \\"url\\": \\"http://example.com\\"})\\n\\n resp.status_code == 200\\n\\n # more done with response here\\n}\\n```\\n\\n## Rationale\\n\\nAssignments are normally cheap, but certainly not always. If the right-hand side of an assignment is expensive,\\ndeferring the assignment to where it\'s needed can save a considerable amount of time. Even for less expensive\\nassignments, code tends to be more readable when assignments are placed close to where they\'re used.\\n\\nThis rule uses a fairly simplistic heuristic to determine if an assignment can be deferred:\\n\\n- The next expression is not an assignment\\n- The next expression does not depend on the assignment\\n- The next expression does not initialize iteration\\n\\nIt is possible that the rule will be improved to cover more cases in the future.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n performance:\\n defer-assignment:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/performance/defer-assignment/defer_assignment.rego)\\n","id":"performance/defer-assignment"},{"filePath":"projects/regal/rules/imports/use-rego-v1.md","content":"# use-rego-v1\\n\\n**Summary**: Use `import rego.v1`\\n\\n**Category**: Imports\\n\\n**Automatically fixable**: [Yes](https://www.openpolicyagent.org/projects/regal/fixing)\\n\\n## Notice: Rule disabled by default since OPA 1.0\\n\\
1nThis rule is only enabled for projects that have either been explicitly configured to target versions of OPA before 1.0,\\nor if no configuration is provided \u2014 where Regal is able to determine that an older version of OPA/Rego is being\\ntargeted. Consult the documentation on Regal\'s [configuration](https://www.openpolicyagent.org/projects/regal#configuration)\\nfor information on how to best work with older versions of OPA and Rego.\\n\\nSince OPA v1.0, the `rego.v1` import is effectively a no-op. Developers working on a **policy library**, or other\\nRego polices that are expected to be used with many different OPA versions, may however benefit from enabling this rule,\\nas having an `import rego.v1` in the policy ensures that v1 keywords will work correctly with OPA versions both\\nbefore and after OPA v1.0.\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\n# before OPA v0.59.0, this was best practice\\nimport future.keywords.contains\\nimport future.keywords.if\\n\\nreport contains item if {\\n # ...\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\n# with OPA v0.59.0 and later, use import rego.v1 instead\\n# with OPA v1.0 and later, this import is unnecessary\\nimport rego.v1\\n\\nreport contains item if {\\n # ...\\n}\\n```\\n\\n## Rationale\\n\\nOPA [v0.59.0](https://github.com/open-policy-agent/opa/releases/tag/v0.59.0) introduced a new `rego.v1` import, which\\nallows policy authors to prepare for language changes coming in the future OPA 1.0 release. Some notable changes include:\\n\\n- All \\"future\\" keywords that currently must be imported through `import future.keywords` will be part of Rego by\\n default, without the need to first import them\\n- The `if` keyword will be required before the body of a rule\\n- The `contains` keyword will be required when declaring a multi-value rule (partial set rule)\\n- Deprecated built-in functions will be removed\\n\\nUsing `import rego.v1` ensures that these requirements are met in any package including the import, and tools like\\n`opa check` and `opa fmt` have been updated to help users in this transition.\\n\\nSee the [OPA v0.59.0 release notes](https://github.com/open-policy-agent/opa/releases/tag/v0.59.0) for more details.\\n\\n### Capabilities\\n\\nIf you aren\'t yet using OPA v0.59.0 or later, it is recommended that you use the\\n[capabilities](https://www.openpolicyagent.org/projects/regal#capabilities) setting in your Regal configuration file to tell Regal what\\nversion of OPA to target. This way you won\'t need to disable rules that require capabilities that aren\'t in the version\\nof OPA you\'re targeting, and allows for a smoother transition to newer versions of OPA when you\'re ready for that.\\nAnother benefit of using capabilities is that Regal will include notices in the report when there are rules that have\\nbeen disabled due to missing capabilities, kindly reminding you of them, but without having the command fail.\\n\\nIn the example below we\'re using the capabilities setting to target OPA v0.55.0 (where `import rego.v1` is not\\navailable):\\n\\n`.regal/config.yaml` or `.regal.yaml`\\n```yaml\\ncapabilities:\\n from:\\n engine: opa\\n version: v0.55.0\\n```\\n\\nLinting with the above configuration will exclude the `use-rego-v1` rule, but add a notice to the report reminding you\\nthat it was disabled due to missing capabilities:\\n\\n```shell\\n$ regal lint bundle\\n131 files linted. No violations found. 1 rule skipped:\\n- use-rego-v1: Missing capability for `import rego.v1`\\n```\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n imports:\\n use-rego-v1:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n\\n# rather than disabling this rule, use the capabilities setting\\n# to tell Regal which version of OPA to target:\\ncapabilities:\\n from:\\n engine: opa\\n version: v0.58.0\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/imports/use-rego-v1/use_rego_v1.rego)\\n","id":"imports/use-rego-v1"},{"filePath":"projects/regal/rules/imports/unresolved-reference.md","content":"# unresolved-reference\\n\\n**Summary**: Unresolved Reference\\n\\n**Category**: Imports\\n\\
1n**Avoid**\\nReferences to unresolved packages and rules.\\n\\n## Rationale\\n\\nThis rule is similar to `unresolved-import` rule and has the same rationale:\\nto avoid accidentally referencing rules and data that does not exist.\\nAs the name suggests, this rule is stricter than the `unresolved-import` rule,\\nand will check for references to packages and rules that may not exist throughout the entire policy,\\nrather than just the imports.\\n\\nThis rule will have Regal try to resolve all references to external packages and rules by scanning all the policies it is\\nprovided for **packages**, **rules** and **functions** that may resolve the reference. Note that Regal does not scan any\\n_data_ files. If no reference is found, the rule will flag it as unresolved.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n imports:\\n unresolved-reference:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n # list of paths that should be ignored\\n # these may be paths to data, or rules that may\\n # not be present at the time of linting\\n # using glob syntax\\n except-paths:\\n - data.identity.users\\n - data.permissions.*\\n```\\n\\n## Related Resources\\n\\n- Unresolved Import Rule: [unresolved-import](./unresolved-import)\\n- OPA Docs: [Imports](https://www.openpolicyagent.org/docs/policy-language/#imports)\\n- OPA Docs: [Collaboration Using Import](https://www.openpolicyagent.org/docs/faq/#collaboration-using-import)\\n- OPA Issues: [Missing import should create error](https://github.com/open-policy-agent/opa/issues/491)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/imports/unresolved-reference/unresolved_reference.rego)\\n","id":"imports/unresolved-reference"},{"filePath":"projects/regal/rules/imports/unresolved-import.md","content":"# unresolved-import\\n\\n**Summary**: Unresolved import\\n\\n**Category**: Imports\\n\\n**Type**: Aggregate - only runs when more than one file is provided for linting\\n\\n**Avoid**\\n\\nImports that can\'t be resolved.\\n\\n## Rationale\\n\\nOPA does no compile time checks to ensure that references in imports _resolve_ to anything, and unresolved references at\\nruntime are simply **undefined**. This is not a bug in OPA, but a necessary feature to allow for dynamic loading of data\\nand policy at runtime. The fact that it\'s not a bug does however not mean that it can\'t be\\n[a problem](https://github.com/open-policy-agent/opa/issues/491)! A simple typo, a refactoring, or a mistake, could\\neasily lead to an an import being unresolved, and as such undefined at runtime.\\n\\nThis rule takes a stricter approach to imports, and will have Regal try to resolve them by scanning all the policies it\\nis provided for **packages**, **rules** and **functions** that may resolve the import. Note that Regal does not scan any\\n_data_ files. If no reference is found, the rule will flag it as unresolved.\\n\\nSince unresolved imports may be perfectly valid \u2014 for example when an import points to data \u2014 this rule provides an\\noption in its configuration to except certain paths from being checked. These paths may even contain a wildcard suffix\\nto indicate that any path past the wildcard (e.g. `data.users.*`) should be ignored. It is also possible to use a\\nregular [ignore directive](https://www.openpolicyagent.org/projects/regal#inline-ignore-directives):\\n\\n```rego\\npackage example\\n\\n# this is provided as data!\\n# regal ignore:unresolved-import\\nimport data.users\\n```\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n imports:\\n unresolved-import:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n # list of paths that should be ignored\\n # these may be paths to data, or rules that may\\n # not be present at the time of linting\\n except-imports:\\n - data.identity.users\\n - data.permissions.*\\n```\\n\\n## Related Resources\\n\\
1n- OPA Docs: [Imports](https://www.openpolicyagent.org/docs/policy-language/#imports)\\n- OPA Docs: [Collaboration Using Import](https://www.openpolicyagent.org/docs/faq/#collaboration-using-import)\\n- OPA Issues: [Missing import should create error](https://github.com/open-policy-agent/opa/issues/491)\\n - GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/imports/unresolved-import/unresolved_import.rego)\\n","id":"imports/unresolved-import"},{"filePath":"projects/regal/rules/imports/redundant-data-import.md","content":"# redundant-data-import\\n\\n**Summary**: Redundant import of data\\n\\n**Category**: Imports\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nimport data\\n```\\n\\n## Rationale\\n\\nJust like `input`, `data` is always globally available and does not need to be imported.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n imports:\\n redundant-data-import:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/imports/redundant-data-import/redundant_data_import.rego)\\n","id":"imports/redundant-data-import"},{"filePath":"projects/regal/rules/imports/redundant-alias.md","content":"# redundant-alias\\n\\n**Summary**: Redundant alias\\n\\n**Category**: Imports\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nimport data.users.permissions as permissions\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nimport data.users.permissions\\n```\\n\\n## Rationale\\n\\nThe last component of an import path can always be referenced by the last\\ncomponent of the import path itself inside the package in which it\'s imported.\\nUsing an alias with the same name is thus redundant, and should be omitted.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n imports:\\n redundant-alias:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/imports/redundant-alias/redundant_alias.rego)\\n","id":"imports/redundant-alias"},{"filePath":"projects/regal/rules/imports/prefer-package-imports.md","content":"# prefer-package-imports\\n\\n**Summary**: Prefer importing packages over rules\\n\\n**Category**: Imports\\n\\n**Type**: Aggregate - only runs when more than one file is provided for linting\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\n# Rule imported directly\\nimport data.users.first_names\\n\\nhas_waldo if {\\n # Not obvious where \\"first_names\\" comes from\\n \\"Waldo\\" in first_names\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\n# Package imported rather than rule\\nimport data.users\\n\\nhas_waldo if {\\n # Obvious where \\"first_names\\" comes from\\n \\"Waldo\\" in users.first_names\\n}\\n```\\n\\n## Rationale\\n\\nImporting packages and using the package name as a \\"namespace\\" for imported rules and functions tends to make your code\\neasier to follow. This is especially true for large policies, where the distance from the import to actual use may be\\nseveral hundreds of lines.\\n\\n## Exceptions\\n\\nRegal has no way of knowing whether an import points to a rule, function or some external data \u2014 only that it doesn\'t\\npoint to a package. Use the `ignore-import-paths` configuration option if you want to make exceptions for e.g. imports\\nof external data, or use the various ignore options to ignore entire files.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n imports:\\n prefer-package-imports:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n ignore-import-paths:\\n # Make an exception for some specific import paths\\n - data.permissions.admin.users\\n```\\n\\n## Related Resources\\n\\
1n- Rego Style Guide: [Prefer importing packages over rules and functions](https://www.openpolicyagent.org/docs/style-guide#prefer-importing-packages-over-rules-and-functions)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/imports/prefer-package-imports/prefer_package_imports.rego)\\n","id":"imports/prefer-package-imports"},{"filePath":"projects/regal/rules/imports/pointless-import.md","content":"# pointless-import\\n\\n**Summary**: Importing own package is pointless\\n\\n**Category**: Imports\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\n# pointless, as policy is the own package\\nimport data.policy\\n\\n# pointless, as rules in own package can be referenced without the import\\nimport data.policy.rule\\n\\nrule if {\\n # ..conditions..\\n}\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n```\\n\\n## Rationale\\n\\nThere\'s no point importing the own package, or rules from the same module, as both can be referenced just as well\\nwithout the import.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n imports:\\n pointless-import:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/imports/pointless-import/pointless_import.rego)\\n","id":"imports/pointless-import"},{"filePath":"projects/regal/rules/imports/import-shadows-import.md","content":"# import-shadows-import\\n\\n**Summary**: Import shadows another import\\n\\n**Category**: Imports\\n\\n## Notice: Rule disabled by default since OPA 1.0\\n\\nThis rule is only enabled for projects that have either been explicitly configured to target versions of OPA before 1.0,\\nor if no configuration is provided \u2014 where Regal is able to determine that an older version of OPA/Rego is being\\ntargeted. Consult the documentation on Regal\'s [configuration](https://www.openpolicyagent.org/projects/regal#configuration)\\nfor information on how to best work with older versions of OPA and Rego.\\n\\nSince OPA v1.0, this rule is automatically disabled as OPA itself now forbids this, and shadowed imports will result in\\na parse error.\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nimport data.permissions\\nimport data.users\\n\\n# Already imported\\nimport data.permissions\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nimport data.permissions\\nimport data.users\\n```\\n\\n## Rationale\\n\\nDuplicate imports are redundant, and while harmless, should just be removed.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n imports:\\n import-shadows-import:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Strict Mode](https://www.openpolicyagent.org/docs/policy-language/#strict-mode)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/imports/import-shadows-import/import_shadows_import.rego)\\n","id":"imports/import-shadows-import"},{"filePath":"projects/regal/rules/imports/import-shadows-builtin.md","content":"# import-shadows-builtin\\n\\n**Summary**: Import shadows built-in namespace\\n\\n**Category**: Imports\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\n# Shadows the built-in `print` function\\nimport data.print\\n\\n# Shadows the built-in `http.send` function\\nimport input.attributes.http\\n```\\n\\n**Prefer**\\nTo either use different names for your packages, or use import aliases to avoid shadowing built-ins.\\n```rego\\npackage policy\\n\\n# Using a different package name\\nimport data.printer\\n\\n# Using an alias\\nimport input.attributes.http as http_attributes\\n```\\n\\n## Rationale\\n\\nOPA will not complain about an import shadowing the name or the \\"namespace\\" (i.e. `array` in `array.slice`) until a\\nconflicting built-in function is used in the same policy. Preventing this to happen in the first place is a better\\noption!\\n\\nWhy does this happen? The OPA compiler rewrites any import used in a policy, so that the shorthand form expands to its\\nlonger form. Provided a simple policy like this:\\n\\n```rego\\npackage policy\\n\\nimport data.http\\n\\nallow if {\\n http.send({\\"method\\": \\"GET\\", \\"url\\": \\"https://example.com\\"})\\n}\\n```\\n\\nThe compiler will go ahead and rewrite the `http.send` call using the import:\\n\\
1n```rego\\nallow if {\\n data.http.send({\\"method\\": \\"GET\\", \\"url\\": \\"https://example.com\\"})\\n}\\n```\\n\\nThis is obviously not what the policy author intended.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n imports:\\n import-shadows-builtin:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Built-in Functions](https://www.openpolicyagent.org/docs/policy-reference/#built-in-functions)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/imports/import-shadows-builtin/import_shadows_builtin.rego)\\n","id":"imports/import-shadows-builtin"},{"filePath":"projects/regal/rules/imports/import-after-rule.md","content":"# import-after-rule\\n\\n**Summary**: Import declared after rule\\n\\n**Category**: Imports\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nrequired_role := \\"developer\\"\\n\\nimport data.identity.users\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nimport data.identity.users\\n\\nrequired_role := \\"developer\\"\\n```\\n\\n## Rationale\\n\\nImports should be declared at the top of a policy, and before any rules. This makes it easy to quickly see the\\ndependencies imported in the policy simply by looking at the top of the file.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n imports:\\n import-after-rule:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/imports/import-after-rule/import_after_rule.rego)\\n","id":"imports/import-after-rule"},{"filePath":"projects/regal/rules/imports/implicit-future-keywords.md","content":"# implicit-future-keywords\\n\\n**Summary**: Avoid implicit future keyword imports\\n\\n**Category**: Imports\\n\\n## Notice: Rule disabled by default since OPA 1.0\\n\\nThis rule is only enabled for projects that have either been explicitly configured to target versions of OPA before 1.0,\\nor if no configuration is provided \u2014 where Regal is able to determine that an older version of OPA/Rego is being\\ntargeted. Consult the documentation on Regal\'s [configuration](https://www.openpolicyagent.org/projects/regal#configuration)\\nfor information on how to best work with older versions of OPA and Rego.\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nimport future.keywords\\n\\nreport contains violation if {\\n not \\"developer\\" in input.user.roles\\n\\n violation := \\"Required role \'developer\' missing\\"\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nimport future.keywords.contains\\nimport future.keywords.if\\nimport future.keywords.in\\n\\nreport contains violation if {\\n not \\"developer\\" in input.user.roles\\n\\n violation := \\"Required role \'developer\' missing\\"\\n}\\n```\\n\\n## Rationale\\n\\nUsing the \\"catch all\\" import of `future.keywords` is convenient, but it can lead to unexpected behavior. If future\\nversions of OPA introduces new keywords, there\'s always a risk that these keywords will conflict with existing rule and\\nvariable names in your policy.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n imports:\\n implicit-future-keywords:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Rego Style Guide: [Use explicit imports for future keywords](https://www.openpolicyagent.org/docs/style-guide#use-explicit-imports-for-future-keywords)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/imports/implicit-future-keywords/implicit_future_keywords.rego)\\n","id":"imports/implicit-future-keywords"},{"filePath":"projects/regal/rules/imports/ignored-import.md","content":"# ignored-import\\n\\n**Summary**: Reference ignores import\\n\\n**Category**: Imports\\n\\
1n**Avoid**\\n```rego\\npackage policy\\n\\nimport data.authz.roles\\n\\nallow if {\\n some role in input.user.roles\\n # data.authz.roles has been imported, but the import is ignored here\\n role in data.authz.roles.admin_roles\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nimport data.authz.roles\\n\\nallow if {\\n some role in input.user.roles\\n # imported data.authz.roles used\\n role in roles.admin_roles\\n}\\n```\\n\\n## Rationale\\n\\nImports tend to make long, nested references more readable, and encourages reuse of common logic. Using a full reference\\n(like `data.users.permissions`) despite having previously imported the reference, or parts of it (like `data.users`)\\ndefeats the purpose of the import, and you\'re better off referring to the import directly.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n imports:\\n ignored-import:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/imports/ignored-import/ignored_import.rego)\\n","id":"imports/ignored-import"},{"filePath":"projects/regal/rules/imports/confusing-alias.md","content":"# confusing-alias\\n\\n**Summary**: Confusing alias of existing import\\n\\n**Category**: Imports\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\n# both \'users\' and \'employees\' point to the same imported resource\\nimport data.resources.users\\nimport data.resources.users as employees\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\n# a single import for any given resource\\nimport data.resources.users\\n```\\n\\n**or**\\n\\n```rego\\npackage policy\\n\\n# a single aliased import for any given resource\\nimport data.resources.users as employees\\n```\\n\\n## Rationale\\n\\nUsing an alias for an import occasionally helps improve intent and readability by using a name that\'s relevant to the\\ncontext in which the import is used. But an aliased import should never be used for a reference also imported\\n**without** an alias, as that\'s just confusing. Either use and alias or don\'t, but stick to one convention for any\\ngiven import.\\n\\nUsing two different aliases for the same import is also likely a mistake, and is similarly flagged by this rule.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n imports:\\n confusing-alias:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/imports/confusing-alias/confusing_alias.rego)\\n","id":"imports/confusing-alias"},{"filePath":"projects/regal/rules/imports/circular-import.md","content":"# circular-import\\n\\n**Summary**: Avoid circular imports\\n\\n**Category**: Imports\\n\\n**Avoid**\\n\\n```mermaid\\ngraph LR\\n authz --\x3e shared\\n shared --\x3e authz\\n```\\n\\n```rego\\n# authz.rego\\npackage authz\\n\\nimport data.shared\\n\\nadmins := {\\n \\"anna\\",\\n \\"bob\\",\\n}\\n\\nallow if {\\n input.role in shared.roles\\n}\\n\\nallow if {\\n input.user in admins\\n}\\n```\\n\\n```rego\\n# shared.rego\\npackage shared\\n\\nimport data.authz # circular import!\\n\\nroles := { \\"admin\\", \\"editor\\", \\"viewer\\" }\\n\\nusers := authz.admins | {\\n \\"chloe\\",\\n \\"dave\\",\\n}\\n```\\n\\n**Prefer**\\n\\nBreak out shared rules into a tree-like structure of packages. For example, one way we could refactor the above example\\nis to move the `admins` set into a new package.\\n\\n```mermaid\\ngraph LR\\n authz --\x3e shared\\n shared --\x3e admins\\n```\\n\\n```rego\\n# authz.rego\\npackage authz\\n\\nimport data.shared\\n\\nallow if {\\n input.role in shared.roles\\n}\\n\\nallow if {\\n input.user in shared.users\\n}\\n```\\n\\n```rego\\n# admins.rego\\npackage admins\\n\\nadmins := {\\n \\"anna\\",\\n \\"bob\\",\\n}\\n```\\n\\n```rego\\n# shared.rego\\npackage shared\\n\\nimport data.admins\\n\\nroles := {\\"admin\\", \\"editor\\", \\"viewer\\"}\\n\\nusers := admins.admins | {\\n \\"chloe\\",\\n \\"david\\",\\n}\\n```\\n\\n## Rationale\\n\\nA circular import is when a package imports itself, either by directly importing itself,\\nor indirectly by importing a which in turn imports a series of packages that eventually import the original package.\\n\\nAs long as re
1cursive rules definitions are avoided, circular imports are permitted in Rego.\\nHowever, such import graphs are not advisable and a signal of poorly structured policy code.\\n\\nIf you have a circular import,\\nit\'s recommended that you refactor your code into different packages that do not import each other.\\nThis will make your code easier to navigate and maintain.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n imports:\\n circular-import:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/imports/circular-import/circular_import.rego)\\n","id":"imports/circular-import"},{"filePath":"projects/regal/rules/imports/avoid-importing-input.md","content":"# avoid-importing-input\\n\\n**Summary**: Avoid importing `input`\\n\\n**Category**: Imports\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\n# This is always redundant\\nimport input\\n\\n# This might be useful, but better to move to a local assignment\\nimport input.user.email\\n\\nallow if \\"admin\\" in input.user.roles\\n\\nallow if {\\n endswith(email, \\"@acmecorp.com\\")\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nallow if \\"admin\\" in input.user.roles\\n\\nallow if {\\n email := input.user.email\\n endswith(email, \\"@acmecorp.com\\")\\n}\\n```\\n\\n## Rationale\\n\\nUsing an import for `input` is not necessary, as both `input` and `data` are globally available.\\n\\n## Exceptions\\n\\nUsing an alias for `input` can sometimes be useful, e.g. when using `input` is known to represent something specific,\\nlike a Terraform plan. Aliasing of specific input attributes should however be avoided in favor of local assignments.\\n\\n```rego\\npackage policy\\n\\n# This is acceptable\\nimport input as tfplan\\n\\n# But this should be avoided - use assignment instead:\\n# username := input.user.name\\nimport input.user.name as username\\n\\nallow if {\\n some resource_change in tfplan.resource_changes\\n # ...\\n}\\n```\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n imports:\\n avoid-importing-input:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Rego Style Guide: [Avoid importing `input`](https://www.openpolicyagent.org/docs/style-guide#avoid-importing-input)\\n- OPA Docs: [Terraform Tutorial](https://www.openpolicyagent.org/docs/terraform)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/imports/avoid-importing-input/avoid_importing_input.rego)\\n","id":"imports/avoid-importing-input"},{"filePath":"projects/regal/rules/custom/prefer-value-in-head.md","content":"# prefer-value-in-head\\n\\n**Summary**: Prefer value in rule head\\n\\n**Category**: Custom\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\npin_as_number := val if {\\n is_number(input.pin_code)\\n val := to_number(input.pin_code)\\n}\\n\\ndeny contains message if {\\n not input.user\\n message := \\"user attribute missing from input\\"\\n}\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\npin_as_number := to_number(input.pin_code) if is_number(input.pin_code)\\n\\ndeny contains \\"user attribute missing from input\\" if not input.user\\n```\\n\\n## Rationale\\n\\nRules that return the value assigned in the last expression of the rule body may have the value, or the function\\nreturning the value, moved directly to the rule head. This creates more succinct rules, and often allows for rules to be\\nexpressed as \\"one-liners\\". This is not a general recommendation, but a style preference that a team or organization\\nmight want to standardize on. As such, it is placed in the custom category, and must be explicitly enabled in\\nconfiguration.\\n\\nThe `only-scalars` configuration option may be used to only suggest moving scalar values (strings, numbers, booleans,\\nnull) to the head, and not expressions or functions returning a value. With this option set to `true`, the following\\nexample would be flagged:\\n\\n```rego\\ndeny contains message if {\\n not input.user\\n # value is a scalar\\n message := \\"user attribute missing from input\\"\\n}\\n```\\n\\nBut not:\\n\\n```rego\\ndeny contains message if {\\n not input.user\\n # value returned from a function call, not suggested if `only-scalars` is set to `true`\\n message := sprintf(\\"user attribute missing from input: %v\\", [input])\\n}\\n```\\n\\nThe `include-interpolated` configuration option may be used to count interpolated strings as a scalar (string) values,\\nwhich will have Regal recommend moving them to the head even when `only-scalars` is set to `true`.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n custom:\\
1n prefer-value-in-head:\\n # note that all rules in the \\"custom\\" category are disabled by default\\n # (i.e. level \\"ignore\\")\\n #\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n # whether to only suggest moving scalar values (strings, numbers, booleans, null)\\n # to the head, and not expressions or functions\\n only-scalars: false\\n # when set to true, counts interpolated strings as a scalar value, and will suggest\\n # moving them to the head even when `only-scalars` is true\\n include-interpolated: false\\n # variable names to exempt from the rule (by default, none)\\n except-var-names:\\n - report\\n - violation\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/custom/prefer-value-in-head/prefer_value_in_head.rego)\\n","id":"custom/prefer-value-in-head"},{"filePath":"projects/regal/rules/custom/one-liner-rule.md","content":"# one-liner-rule\\n\\n**Summary**: Rule body could be made a one-liner\\n\\n**Category**: Custom\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nallow if {\\n is_admin\\n}\\n\\nis_admin if {\\n \\"admin\\" in input.user.roles\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nallow if is_admin\\n\\nis_admin if \\"admin\\" in input.user.roles\\n```\\n\\n## Rationale\\n\\nRules with only a single expression in the body may omit the curly braces around the body, and be written as a\\none-liner. This makes simple rules read more like English, and will have more rules fit on the screen.\\n\\nAs with other rules in the `custom` category, this is not necessarily a general recommendation, but a style preference\\nteams or organizations might want to standardize on. As such, it must be enabled via configuration.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n custom:\\n one-liner-rule:\\n # note that all rules in the \\"custom\\" category are disabled by default\\n # (i.e. level \\"ignore\\")\\n #\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n # maximum line length for a rule to be suggested as a one-liner\\n # default: 120\\n max-line-length: 120\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/custom/one-liner-rule/one_liner_rule.rego)\\n","id":"custom/one-liner-rule"},{"filePath":"projects/regal/rules/custom/narrow-argument.md","content":"# narrow-argument\\n\\n**Summary**: Function argument can be narrowed\\n\\n**Category**: Custom\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\nvalid_user(user) if endswith(user.email, \\"acmecorp.com\\")\\nvalid_user(user) if endswith(user.email, \\"acmecorp.org\\")\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\nvalid_email(email) if endswith(email, \\"acmecorp.com\\")\\nvalid_email(email) if endswith(email, \\"acmecorp.org\\")\\n```\\n\\n## Rationale\\n\\n**Note!** This is a highly opinionated rule with some caveats that you should be aware of before you use it.\\n\\nAccepting the most minimal types/values as functions arguments avoids unnecessary \\"dependencies\\", makes them more\\nlikely to be reusable, and tends to make code more readable as it\'s often easier to predict from a call site what\\na specifically named function does compared to a more generic version. It\'s fairly common to realize a function with\\nnarrowed arguments would benefit from being renamed. That is however left as an exercise to you!\\n\\nThis rule scans all use of arguments inside function heads and bodies, and will suggest narrowing down any argument\\npassed to the minimal value which the function depends on. Incrementally defined functions are scanned in their entirety\\nto make sure the narrowing is valid for all definitions. Example:\\n\\n```rego\\npackage policy\\n\\ncountry_code(user) := 61 if user.country == \\"Australia\\"\\ncountry_code(user) := 81 if user.country == \\"Japan\\"\\n```\\n\\nIn the above example, the functions only depen
1ds on `user.country`, and this rule (when enabled) will thus recommend\\nnarrowing the argument passed:\\n\\n```rego\\npackage policy\\n\\ncountry_code(country) := 61 if country == \\"Australia\\"\\ncountry_code(country) := 81 if country == \\"Japan\\"\\n```\\n\\nInstead of passing around potentially large `user` objects, our function now only needs to consider a `country` string,\\nwhich perhaps may prove useful for more than just users. Another benefit of this approach is that it\'s often possible\\nto simplify functions even further by moving the equality comparison directly into the function\'s arguments \u2014 a simple\\nform of [pattern matching](https://www.openpolicyagent.org/projects/regal/rules/idiomatic/equals-pattern-matching):\\n\\n```rego\\npackage policy\\n\\ncountry_code(\\"Australia\\") := 61\\ncountry_code(\\"Japan\\") := 81\\n```\\n\\n### Reference prefix narrowing\\n\\nSo far we have looked only at functions using an identical reference to one of its arguments. That\'s not always the\\ncase, but it doesn\'t mean the value passed can\'t be narrowed! Consider the following example:\\n\\n```rego\\npackage policy\\n\\ninternal_user(context) if endswith(context.user.email, \\"@acmecorp.com\\")\\ninternal_user(context) if \\"staff\\" in context.user.roles\\n```\\n\\nIn the example above, the `narrow-argument` rule would point out that while two different references to the `context`\\nargument are used, they both have the `context.user` prefix in common, and the value passed could thus be narrowed to\\nthat:\\n\\n```rego\\npackage policy\\n\\ninternal_user(user) if endswith(user.email, \\"@acmecorp.com\\")\\ninternal_user(user) if \\"staff\\" in user.roles\\n```\\n\\n## Caveats\\n\\nNarrowing the types passed as function arguments may come with unintended and/or undesired side-effects. More\\nspecifically, the way OPA evaluates functions means that arguments are evaluated before the function is called. \\"Big\\"\\nobjects, like a `user` tend to be less likely to be undefined than e.g. a `user.fax` attribute. Aborting evaluation only\\nbecause a user is without a fax machine is probably not what we want! But could be an unfortunate consequence of our\\nc
1hange unless we are careful (or better, have extensive test coverage). Consider the following example:\\n\\n```rego\\npackage policy\\n\\nis_unreachable(user) if {\\n not has_phone(user)\\n not has_fax(user)\\n}\\n\\nhas_phone(user) if\\n is_string(user.phone)\\n user.phone != \\"\\"\\n}\\n\\nhas_fax(user) if {\\n is_string(user.fax)\\n user.fax != \\"\\"\\n}\\n```\\n\\nWhile it\'s tempting to try and narrow the arguments passed to `has_phone` and `has_fax` only to what they need:\\n\\n```rego\\npackage policy\\n\\nis_unreachable(user) if {\\n not has_phone(user.phone)\\n not has_fax(user.fax)\\n}\\n\\nhas_phone(phone) if\\n is_string(phone)\\n phone != \\"\\"\\n}\\n\\nhas_fax(fax) if {\\n is_string(fax)\\n fax != \\"\\"\\n}\\n```\\n\\nWe have now changed the behavior of `is_unreachable`, and a user without phone or fax will no longer be considered\\nunreachable. Why? Again, because OPA evaluates the function arguments before they are passed to the function, **and**\\nbefore the result is negated by `not`, an expression like:\\
1n\\n```rego\\nnot has_phone(user.phone)\\n```\\n\\nWill be rewritten by OPA to something like this:\\n\\n```rego\\narg1 := user.phone\\nnot has_phone(arg1)\\n```\\n\\nIf the `user.phone` attribute doesn\'t exist, evaluation will never reach the next line where the function is called!\\n\\nBefore narrowing arguments, always consider the impact of undefined values, negation and how functions are evaluated.\\nAnd make sure to not rewrite any function that isn\'t extensively covered by unit tests! With that said, there are often\\nways to deal with undefined attributes even when passing narrower argument types. In the example above, we could for\\nexample rewrite `is_unreachable` to `is_reachable`, and then use `not` to negate _that_ to answer if the user is\\nimpossible to reach.\\n\\nFind what works best for you, and use the `exclude-args` configuration option (see below) to exclude arg names that you\\ncommonly don\'t want to narrow, or [ignore directives](https://www.openpolicyagent.org/projects/regal#inline-ignore-directives) for single\\nlocations.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n custom:\\n narrow-argument:\\n # note that all rules in the \\"custom\\" category are disabled by default\\n # (i.e. level \\"ignore\\")\\n #\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n # exclude args by name\\n # example below excludes any argument named \'config\' or \'user\'\\n exclude-args:\\n - config\\n - user\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/custom/narrow-argument/narrow_argument.rego)\\n","id":"custom/narrow-argument"},{"filePath":"projects/regal/rules/custom/naming-convention.md","content":"# naming-convention\\n\\n**Summary**: Naming convention violation\\n\\n**Category**: Custom\\n\\n## Description\\n\\nThis custom rule allows teams and organizations to define their own naming conventions for their Rego projects, without\\nhaving to write custom linter policies. Naming conventions are simply defined in the Regal configuration file using\\nregex patterns.\\n\\nRegal can enforce naming conventions for:\\n\\n- Package names\\n- Rule names\\n- Function names\\n- Variable names\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n custom:\\n naming-convention:\\n # note that all rules in the \\"custom\\" category are disabled by default\\n # (i.e. level \\"ignore\\") as some configuration needs to be provided by\\n # the user (i.e. you!) in order for them to be useful.\\n #\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n conventions:\\n # allow only \\"private\\" rules and functions, i.e. those starting with\\n # underscore, or rules named \\"deny\\" or \\"allow\\"\\n - pattern: \\"^_[a-z]+$|^deny$|^allow$\\"\\n # one of \\"package\\", \\"rule\\", \\"function\\", \\"variable\\"\\n targets:\\n - rule\\n - function\\n # any number of naming rules may be added\\n # package names must start with \\"acmecorp\\" or \\"system\\"\\n - pattern: \\"^acmecorp|^system\\"\\n targets:\\n - package\\n # a list of names may be provided in addition to a pattern\\n # if both a pattern and a list of names are provided, identifiers\\n # must match either the pattern or one of the names in the list\\n - names:\\n - i\\n - j\\n - k\\n targets:\\n - var\\n```\\n\\n**Note:** In order to avoid characters accidentally getting escaped, always use single quotes to encode your regex\\npatterns. Additionally, you\'ll most often want to include anchors for the start and end of the string (`^` and `$`) in\\nyour patterns, or else your pattern might accidentally match only parts of the name rather than the whole name.\\n\\n## Related Resources\\n\\
1n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/custom/naming-convention/naming_convention.rego)\\n","id":"custom/naming-convention"},{"filePath":"projects/regal/rules/custom/missing-metadata.md","content":"# missing-metadata\\n\\n**Summary**: Package or rule missing metadata\\n\\n**Category**: Custom\\n\\n**Avoid**\\n```rego\\npackage acmecorp.authz\\n\\nauthorized_users contains user if {\\n # logic to determine authorized users\\n}\\n```\\n\\n**Prefer**\\n```rego\\n# METADATA\\n# description: The `acmecorp.authz` module provides authorization logic for the AcmeCorp application.\\npackage acmecorp.authz\\n\\n# METADATA\\n# description: Provides a set of all authorized users given the conditions in `input`.\\n# scope: document\\nauthorized_users contains user if {\\n # logic to determine authorized users\\n}\\n```\\n\\n## Rationale\\n\\nUsing metadata annotations is a great way to document your policies, for both yourself and others. While using metadata\\nannotations _everywhere_ might be overkill for many projects, it should absolutely be considered for libraries, or\\npolicies that target a larger audience.\\n\\n## Exceptions\\n\\nRules and functions with an underscore prefix in their name are commonly used to denote that they are intended\\nto be used internally (i.e. within the same file) only, and while metadata occasionally help document these,\\nthey are not part of the \\"public API\\". The `missing-metadata` thus excludes these from the metadata requirement.\\n\\nIt is also possible to configure your own exceptions for both package and rule paths. See the configuration options\\nbelow.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n custom:\\n missing-metadata:\\n # note that all rules in the \\"custom\\" category are disabled by default\\n # (i.e. level \\"ignore\\"), so make sure to set the level to \\"error\\" if you\\n # want this enabled!\\n #\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n # package path pattern(s) to exclude from the requirement\\n # defaults to no exclusions\\n except-package-path-pattern: ^internal\\\\.*\\n # rule path pattern(s) to exclude from the requirement\\n # defaults to no exclusions\\n except-rule-path-pattern: \\\\.report$\\n # you might also want to exclude files based on their name,\\n # like e.g. tests:\\n ignore:\\n files:\\n - \\"*_test.rego\\"\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Metadata](https://www.openpolicyagent.org/docs/policy-language/#metadata)\\n- OPA Docs: [Annotations](https://www.openpolicyagent.org/docs/policy-language/#annotations)\\n- Rego Style Guide: [Use Metadata Annotations](https://www.openpolicyagent.org/docs/style-guide)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/custom/missing-metadata/missing_metadata.rego)\\n","id":"custom/missing-metadata"},{"filePath":"projects/regal/rules/custom/forbidden-function-call.md","content":"# forbidden-function-call\\n\\n**Summary**: Forbidden function call\\n\\n**Category**: Custom\\n\\n## Description\\n\\nThis custom rule allows providing Regal a list of\\n[built-in functions](https://www.openpolicyagent.org/docs/policy-reference/#built-in-functions) that should be\\nconsidered forbidden. Any call to a function in the list will be reported as a violation.\\n\\nAnother, more advanced, option to achieve the same result is the\\n[capabilities](https://www.openpolicyagent.org/docs/deployments/#capabilities) feature in OPA. While a more\\ncapable option, allowing things like:\\n\\n- Adding new custom built-in functions that OPA should be aware of\\n- Disabling certain features not necessarily being built-in functions, like \\"future\\" keywords\\n- List allowed hosts in network calls\\n\\n...it is also more demanding to configure and maintain. If you\'re already using the capabilities feature\\nto forbid certain functions as part of your policy development process, there\'s no need to enable this rule.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n custom:\\
1n forbidden-function-call:\\n # note that all rules in the \\"custom\\" category are disabled by default\\n # (i.e. level \\"ignore\\") as some configuration needs to be provided by\\n # the user (i.e. you!) in order for them to be useful.\\n #\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n # Just an example \u2014 no functions forbidden by default\\n forbidden-functions:\\n # Prefer to use asymmetric algorithms\\n - io.jwt.verify_hs256\\n - io.jwt.verify_hs384\\n - io.jwt.verify_hs512\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Capabilities](https://www.openpolicyagent.org/docs/deployments/#capabilities)\\n- OPA Docs: [Built-in Functions](https://www.openpolicyagent.org/docs/policy-reference/#built-in-functions)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/custom/forbidden-function-call/forbidden_function_call.rego)\\n","id":"custom/forbidden-function-call"},{"filePath":"projects/regal/rules/custom/disallow-rego-v1.md","content":"# disallow-rego-v1\\n\\n**Summary**: Use of disallowed `import rego.v1`\\n\\n**Category**: Custom\\n\\n## Rationale\\n\\nSince OPA v1.0, the `rego.v1` import is effectively a no-op. As such, this rule serves as a way for teams to\\nkeep this import from popping up in code when it is no longer needed. Also, because this import is still\\nneeded to evaluate policy for older OPA versions, this rule serves as a way to ensure older versions of\\nOPA (any prior to v1.0) are not being used.\\n\\n## Note\\n\\nThis rule is intended to be enabled for projects that have been configured to target versions of OPA from 1.0\\nonwards, but Regal does not explicitly check which version of OPA is being targeted for this rule. If working\\nwith older versions of OPA and Rego, you probably don\'t want to enable this rule.\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/custom/disallow-rego-v1/disallow_rego_v1.rego)\\n- OPA Docs: [Imports](https://www.openpolicyagent.org/docs/policy-language/#imports)\\n","id":"custom/disallow-rego-v1"},{"filePath":"projects/regal/rules/custom/chained-rule-body.md","content":"# chained-rule-body\\n\\n**Summary**: Avoid chaining rule bodies\\n\\n**Category**: Custom\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nhas_x_or_y {\\n input.x\\n} {\\n input.y\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nhas_x_or_y {\\n input.x\\n}\\n\\nhas_x_or_y {\\n input.y\\n}\\n```\\n\\n## Rationale\\n\\nIf the head of the rule is same, it\'s possible to chain multiple rule bodies together to obtain the same result. This\\nform was more common in the past, but is no longer recommended as it is arguably less readable, and less likely to be\\nunderstood by people new to Rego.\\n\\n## Exceptions\\n\\nThe `opa fmt` command will automatically \\"unchain\\" chained rule bodies, so if you have enabled the [opa-fmt](https://www.openpolicyagent.org/projects/regal/rules/style/opa-fmt)\\nrule (as it is by default), there\'s no point in enabling this rule.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n custom:\\n chained-rule-body:\\n # note that all rules in the \\"custom\\" category are disabled by default\\n # (i.e. level \\"ignore\\") as some configuration needs to be provided by\\n # the user (i.e. you!) in order for them to be useful.\\n #\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Incremental Definitions](https://www.openpolicyagent.org/docs/policy-language/#incremental-definitions)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/custom/chained-rule-body/chained_rule_body.rego)\\n","id":"custom/chained-rule-body"},{"filePath":"projects/regal/rules/idiomatic/use-strings-count.md","content":"# use-strings-count\\n\\n**Summary**: Use `strings.count` where possible\\n\\n**Category**: Idiomatic\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nnum_as := count(indexof_n(\\"foobarbaz\\", \\"a\\"))\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nnum_as := strings.count(\\"foobarbaz\\", \\"a\\")\\n```\\n\\n## Rationale\\n\\nThe `strings.count` function added in [OPA v0.67.0](https://github.com/open-policy-agent/opa/releases/tag/v0.67.0)\\nis both more readable and efficie
1nt compared to using `count(indexof_n(...))` and should therefore be preferred.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n use-strings-count:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [strings.count](https://www.openpolicyagent.org/docs/policy-reference/#builtin-strings-stringscount)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/use-strings-count/use_strings_count.rego)\\n","id":"idiomatic/use-strings-count"},{"filePath":"projects/regal/rules/idiomatic/use-some-for-output-vars.md","content":"# use-some-for-output-vars\\n\\n**Summary**: Use `some` to declare output variables\\n\\n**Category**: Idiomatic\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nallow if {\\n userinfo := data.users[id]\\n # ...\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nallow if {\\n some id\\n userinfo := data.users[id]\\n # ...\\n}\\n\\n# alternatively, and arguably more idiomatic:\\nallow if {\\n some id, userinfo in data.users\\n # ...\\n}\\n```\\n\\n## Rationale\\n\\nAn interesting, and likely unfamiliar aspect of Rego for developers coming from other languages, is the concept of\\n[unification](https://en.wikipedia.org/wiki/Unification_(computer_science)). Unification happens not just explicitly via\\nthe unification operator (`=`), but is an integral part of Rego. In the context of this rule, unification means that a\\nvariable can either be an _input_ or an _output_. What does that mean?\\n\\nFrom the example above, consider that `data.users` is a map of user IDs to user objects:\\n\\n```json\\n{\\n \\"jane\\": {\\"email\\": \\"[email protected]\\", \\"firstname\\": \\"Jane\\", \\"lastname\\": \\"Doe\\"},\\n \\"joe\\": {\\"email\\": \\"[email protected]\\", \\"firstname\\": \\"Joe\\", \\"lastname\\": \\"Bloggs\\"},\\n \\"john\\": {\\"email\\": \\"[email protected]\\", \\"firstname\\": \\"John\\", \\"lastname\\": \\"Smith\\"}\\n}\\n```\\n\\n```rego\\nusernames contains name if {\\n data.users[name]\\n}\\n```\\n\\nWhat is the meaning of `name` in the body of the `usernames` rule? In most programming languages, evaluation would\\nfail unless `name` was defined elsewhere in the code. That is because `name` would be expected to be an **input** in the\\nexpression \u2014 the result of using, say \\"joe\\", as the input in `users[\\"joe\\"]` would predictably be the value associated\\nwith that key. In Rego, however, `name` may also be an **output** \u2014 meaning that if the variable is not defined\\nelsewhere, OPA will attempt to _unify_ it with any value that satisfies the expression. In this case, that means that\\n`name` will be bound to each of the keys in the `users` object in turn, and the rule will succeed for each of them.\\n\\nThis is a powerful feature of Rego, but it can also be a source of confusion. If we were to define `name` somewhere\\nelse in the policy, perhaps by mistake:\\n\\n```rego\\nname := \\"joe\\"\\n\\n# hundreds of lines of Rego later..\\n\\nusernames contains name if {\\n data.users[name]\\n}\\n```\\n\\nOur `usernames` rule would no longer iterate over all the users, as the condition would be satisfied by simply mapping\\nthe key \\"joe\\" to its value. By using `some` to locally declare `name`, we can avoid this problem:\\n\\n```rego\\nname := \\"joe\\"\\n\\n# hundreds of lines of Rego later..\\n\\nusernames contains name if {\\n some name\\n data.users[name]\\n}\\n```\\n\\nEven though `name` is defined in the global scope, the `some` keyword will ensure it\'s now considered as an output\\nvariable in the local scope of the `usernames` rule.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n use-some-for-output-vars:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Rego Style Guide: [Don\'t use undeclared variables](https://www.openpolicyagent.org/docs/style-guide#dont-use-undeclared-variables)\\n- OPA Docs: [The `some` keyword](https://www.openpolicyagent.org/docs/policy-language/#some-keyword)\\n- Wikipedia: [Unification](https://en.wikipedia.org/wiki/Unification_(computer_science))\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/use-some-for-output-vars/use_some_for_output_vars.rego)\\n","id":"idiomatic/use-some-for-output-vars"},{"filePath":"projects/regal/rules/idiomatic/use-object-union-n.md","content":"# use-object-union-n\\n\\n**Summary**: Prefer using `object.union_n` over nested `object.union` calls\\n\\n**Category**: Idiomatic\\n\\n**Avoid**\\n\\
1n```rego\\npackage policy\\n\\nobj := object.union(obj1, object.union(obj2, obj3))\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\nobj := object.union_n([obj1, obj2, obj3])\\n```\\n\\n## Rationale\\n\\nPrefer to use `object.union_n` over nested `object.union` calls, as that is both easier to read and more efficient.\\n\\n## (Optional) Always prefer `object.union_n` over `object.union`\\n\\nSince there is nothing that `object.union` can do that `object.union_n` cannot, some users and teams may prefer the\\nconsistency of using a single function for all their union needs. Set the `flag-all-union` configuration option\\nto `true` to always recommend replacing `object.union` with `object.union_n`.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n use-object-union-n:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n # recommend replacing all calls to `object.union` with `object.union_n`\\n #\\n # default: false\\n flag-all-union: false\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/use-object-union-n/use_object_union_n.rego)\\n","id":"idiomatic/use-object-union-n"},{"filePath":"projects/regal/rules/idiomatic/use-object-keys.md","content":"# use-object-keys\\n\\n**Summary**: Prefer to use `object.keys`\\n\\n**Category**: Idiomatic\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\nkeys := {k | some k, _ in input.object}\\n\\n# or\\n\\nkeys := {k | some k; input.object[k]}\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\nkeys := object.keys(input.object)\\n```\\n\\n## Rationale\\n\\nInstead of using a set comprehension to collect keys from an object, prefer to use the built-in function\\n[object.keys](https://www.openpolicyagent.org/docs/policy-reference/#builtin-object-objectkeys).\\nThis option is both more declarative and better conveys the intent of the code.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n use-object-keys:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [object.keys](https://www.openpolicyagent.org/docs/policy-reference/#builtin-object-objectkeys)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/use-object-keys/use_object_keys.rego)\\n","id":"idiomatic/use-object-keys"},{"filePath":"projects/regal/rules/idiomatic/use-in-operator.md","content":"# use-in-operator\\n\\n**Summary**: Use `in` to check for membership\\n\\n**Category**: Idiomatic\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\n# \\"Old\\" way of checking for membership - iteration + comparison\\nallow if {\\n \\"admin\\" == input.user.roles[_]\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nallow if {\\n \\"admin\\" in input.user.roles\\n}\\n```\\n\\n## Rationale\\n\\nUsing `in` for membership checks clearly communicates intent, and is less prone to errors. This is especially true when\\nchecking if something is **not** part of a collection.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n use-in-operator:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Rego Style Guide: [Use `in` to check for membership](https://www.openpolicyagent.org/docs/style-guide#use-in-to-check-for-membership)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/use-in-operator/use_in_operator.rego)\\n","id":"idiomatic/use-in-operator"},{"filePath":"projects/regal/rules/idiomatic/use-if.md","content":"# use-if\\n\\n**Summary**: Use the `if` keyword\\n\\n**Category**: Idiomatic\\n\\n## Notice: Rule disabled by default since OPA 1.0\\n\\nThis rule is only enabled for projects that have either been explicitly configured to target versions of OPA before 1.0,\\nor if no configuration is provided \u2014 where Regal is able to determine that an older version of OPA/Rego is being\\ntargeted. Consult the documentation on Regal\'s [configuration](https://www.openpolicyagent.org/projects/regal#configuration)\\nfor information on how to best work with older versions of OPA and Rego.\\n\\nSince OPA v1.0, this rule is no longer needed
1simply because the Rego v1 syntax is made mandatory, and the use of `if`\\nis now enforced before all rule bodies.\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nimport future.keywords.in\\n\\nis_admin {\\n \\"admin\\" in input.user.roles\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nimport future.keywords.if\\nimport future.keywords.in\\n\\nis_admin if {\\n \\"admin\\" in input.user.roles\\n}\\n\\n# alternatively\\n\\nis_admin if \\"admin\\" in input.user.roles\\n```\\n\\n## Rationale\\n\\nThe `if` keyword helps communicate what Rego rules really are \u2014 conditional assignments. Using `if` in other words makes\\nthe rule read the same way in English as it will be interpreted by OPA, i.e:\\n\\n```rego\\nrule := \\"some value\\" if some_condition\\n```\\n\\nOPA version 1.0, which is planned for 2024, will make the `if` keyword mandatory. This rule helps you get ahead of the\\ncurve and start using it today.\\n\\n**Note**: don\'t forget to `import future.keywords.if`! Or from OPA v0.59.0 and onwards, `import rego.v1`.\\n\\n**Tip**: When either of the imports mentioned above are found in a Rego file, the `if` keyword will be inserted\\nautomatically at any applicable location by the `opa fmt` tool.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n use-if:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Regal Docs: [use-contains](https://www.openpolicyagent.org/projects/regal/rules/idiomatic/use-contains)\\n- OPA Docs: [Future Keywords](https://www.openpolicyagent.org/docs/policy-language/#future-keywords)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/use-if/use_if.rego)\\n","id":"idiomatic/use-if"},{"filePath":"projects/regal/rules/idiomatic/use-contains.md","content":"# use-contains\\n\\n**Summary**: Use the `contains` keyword\\n\\n**Category**: Idiomatic\\n\\n## Notice: Rule disabled by default since OPA 1.0\\n\\nThis rule is only enabled for projects that have either been explicitly configured to target versions of OPA before 1.0,\\nor if no configuration is provided \u2014 where Regal is able to determine that an older version of OPA/Rego is being\\ntargeted. Consult the documentation on Regal\'s [configuration](https://www.openpolicyagent.org/projects/regal#configuration)\\nfor information on how to best work with older versions of OPA and Rego.\\n\\nSince OPA v1.0, this rule is no longer needed as the Rego v1 syntax is now mandatory, and using `contains` is now the\\nde-facto way to define multi-value rules.\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nimport future.keywords.in\\n\\nreport[item] if {\\n some item in input.items\\n startswith(item, \\"report\\")\\n}\\n\\n# unconditionally add an item to report\\nreport[\\"report1\\"]\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nimport future.keywords.contains\\nimport future.keywords.if\\nimport future.keywords.in\\n\\nreport contains item if {\\n some item in input.items\\n startswith(item, \\"report\\")\\n}\\n\\n# unconditionally add an item to report\\nreport contains \\"report1\\"\\n```\\n\\n## Rationale\\n\\nThe `contains` keyword helps to clearly distinguish *multi-value rules* (or \\"partial rules\\") from\\nsingle-value rules (\\"complete rules\\"). Just like the `if` keyword, `contains` additionally makes the rule read the same\\nway in English as OPA interprets its meaning \u2014 a set that contains one or more values given some (optional) conditions.\\n\\nOPA version 1.0, which is planned for 2024, will make the `contains` keyword mandatory. This rule helps you get ahead of\\nthe curve and start using it today.\\n\\n**Note**: don\'t forget to `import future.keywords.contains`! Or from OPA v0.59.0 and onwards, `import rego.v1`.\\n\\n**Tip**: When either of the imports mentioned above are found in a Rego file, the `contains` keyword will be inserted\\nautomatically at any applicable location by the `opa fmt` tool.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n use-contains:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\
1n- Regal Docs: [use-if](https://www.openpolicyagent.org/projects/regal/rules/idiomatic/use-if)\\n- OPA Docs: [Future Keywords](https://www.openpolicyagent.org/docs/policy-language/#future-keywords)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/use-contains/use_contains.rego)\\n","id":"idiomatic/use-contains"},{"filePath":"projects/regal/rules/idiomatic/use-array-flatten.md","content":"# use-array-flatten\\n\\n**Summary**: Prefer using `array.flatten` over nested `array.concat` calls\\n\\n**Category**: Idiomatic\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\nflat1 := array.concat(arr1, array.concat(arr2, arr3))\\n\\nflat2 := array.concat(arr1, array.concat(arr2, array.concat(arr3, arr4)))\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\nflat1 := array.flatten([arr1, arr2, arr3])\\n\\nflat2 := array.flatten([arr1, arr2, arr3, arr4])\\n```\\n\\n## Rationale\\n\\nSince the introduction of\\n[array.flatten](https://www.openpolicyagent.org/docs/policy-reference/builtins/array#builtin-array-arrayflatten)\\n(OPA v1.13.0), nested `array.concat` calls can be replaced by a single call to `array.flatten`, which is both easier to\\nread and more efficient. Double win!\\n\\n## (Optional) Recommend replacing `array.concat` calls wrapping arguments\\n\\nThe `array.concat` function is sometimes used to prepend or append a non-array value to an array, by wrapping the\\nnon-array value in an array literal. Since the `array.flatten` function accepts values of any type, it can be used in\\nplace of `array.concat` in these cases too, which arguably looks cleaner. Set the `flag-wrapped-concat` configuration\\noption to `true` to enable this check.\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\nflat := array.concat([not_arr], arr) # => [not_arr, arr...]\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\nflat := array.flatten([not_arr, arr]) # => [not_arr, arr...]\\n```\\n\\n## (Optional) Always prefer `array.flatten` over `array.concat`\\n\\nSince there is nothing that `array.concat` can do that `array.flatten` cannot, some users and teams may prefer the\\nconsistency of using a single function for all their concatenation needs. Set the `flag-all-concat` configuration option\\nto `true` to always recommend replacing `array.concat` with `array.flatten`.\\n\\n## Exceptions\\n\\nIf you are targeting an OPA version prior to v1.13.0, you\'ll need to provide Regal with the capabilities of your OPA,\\nso that only rules applicable to your OPA version are enforced. See the\\n[capabilities](https://www.openpolicyagent.org/projects/regal/configuration/capabilities) page of the documentation for\\nmore details.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n use-array-flatten:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n # recommend also replacing calls to `array.concat` where at least one argument is an array literal,\\n # e.g. `array.concat([a], b)` -> `array.flatten([a, b])`\\n #\\n # default: false\\n flag-wrapped-concat: false\\n # recommend replacing all calls to `array.concat` with `array.flatten`\\n #\\n # default: false\\n flag-all-concat: false\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/use-array-flatten/use_array_flatten.rego)\\n","id":"idiomatic/use-array-flatten"},{"filePath":"projects/regal/rules/idiomatic/superfluous-object-get.md","content":"# superfluous-object-get\\n\\n**Summary**: Superfluous `object.get` call\\n\\n**Category**: Idiomatic\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\nallow if {\\n object.get(input, [\\"path\\", \\"to\\", \\"value\\"], \\"default\\") == \\"expected\\"\\n}\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\nallow if {\\n input.path.to.value == \\"expected\\"\\n}\\n```\\n\\n## Rationale\\n\\nThe `object.get` function is sometimes used to guard against undefined references halting evaluation. Immediately\\ncomparing the result of the call to a constant value that isn\'t the same as the default is however superfluous, as\\nthe expression will evaluate the same without using `object.get`. In such cases the call can simply be removed.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n superfluous-object-get:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\
1n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/superfluous-object-get/superfluous_object_get.rego)\\n","id":"idiomatic/superfluous-object-get"},{"filePath":"projects/regal/rules/idiomatic/single-item-in.md","content":"# single-item-in\\n\\n**Summary**: Avoid `in` for single item collection\\n\\n**Category**: Idiomatic\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nallow if input.role in {\\"admin\\"}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nallow if input.role == \\"admin\\"\\n```\\n\\n## Rationale\\n\\nUsing `in` on a single-item collection (array, set or object) is a convoluted way of checking for equality. Better\\nthen to check for equality directly! Besides being more obvious, equality checks are also subject to rule indexing,\\nwhereas `in` checks currently aren\'t.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n single-item-in:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Use indexed statements](https://www.openpolicyagent.org/docs/policy-performance/#use-indexed-statements)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/single-item-in/single_item_in.rego)\\n","id":"idiomatic/single-item-in"},{"filePath":"projects/regal/rules/idiomatic/prefer-set-or-object-rule.md","content":"# prefer-set-or-object-rule\\n\\n**Summary**: Prefer set or object rule over comprehension\\n\\n**Category**: Idiomatic\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\n# top level set comprehension\\ndevelopers := {developer |\\n some user in input.users\\n \\"developer\\" in user.roles\\n developer := user.name\\n}\\n\\n# top level object comprehension\\nuser_roles_mapping := {user: roles |\\n some user in input.users\\n roles := user.roles\\n}\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\n# set generating rule\\ndevelopers contains developer if {\\n some user in input.users\\n \\"developer\\" in user.roles\\n developer := user.name\\n}\\n\\n# object generating rule\\nuser_roles_mapping[user] := roles if {\\n some user in input.users\\n roles := user.roles\\n}
1\\n```\\n\\n## Rationale\\n\\nComprehensions are [awesome](https://web.archive.org/web/https://www.styra.com/blog/five-things-you-didnt-know-about-opa/),\\nand should be part of\\nany policy author\'s toolbox. Using comprehensions inside of rule bodies allow for a wide variety of elegant solutions to\\notherwise hard problems. However, when used as the value directly (and unconditionally) assigned to a rule, it is almost\\nalways better to use a rule that generates a set or object in the rule body rather than having a comprehension do so in\\nthe rule head. Why is that?\\n\\n### Readability\\n\\nRules that generate objects, and sets even more so, read more natural than comprehensions, and are generally more\\ndescriptive. While both constructs are easy to spot for a seasoned Rego author, anything that helps improve readability\\nis a win.\\n\\n### Extensibility\\n\\nWhile readability is important, the real benefit of using a rule to generate a set or object is that it allows the rule\\nto be _extended_. This is particularly true for set generating rules, and it\'s not by accident they often are referred\\nto as **multi-value rules**. A rule assigned the value of a set comprehension can\'t have its value changed later, or\\nmore items added to the set. A set generating rule however, can easily be extended to contain more items, conditionally\\nor unconditionally.\\n\\n```rego\\npackage policy\\n\\n# Getting developers from input\\ndevelopers contains developer if {\\n some user in input.users\\n \\"developer\\" in user.roles\\n developer := user.name\\n}\\n\\n# *Also* getting developers from data\\ndevelopers contains developer if {\\n some user in data.users\\n \\"developer\\" in user.roles\\n developer := user.name\\n}\\n\\n# Unconditionally adding a developer to the set\\ndevelopers contains \\"Hackerman\\"\\n```\\n\\nIn the example above, all three rules contribute to the `developers` set. If we wanted to, we could even create another\\npolicy file using the same package, and have more rules added there that would contribute to the set. This creates some\\ngreat opportunities for extensibility, and collaboration across developers and teams working on policy together.\\n\\nObjects differ somewhat from sets in that while several rules can be used to generate an object, there cannot be more\\nthan one rule contributing to a single key-value pair.\\n\\n```rego\\npackage policy\\n\\nnovels[title] := content if {\\n some document in input.documents\\n document.type == \\"novel\\"\\n title := document.title\\n content := document.content\\n}\\n\\n# This works as long as \\"The Hobbit\\" is not already in the novels object\\nnovels[\\"The Hobbit\\"] := \\"In a hole in the ground there lived a hobbit.\\"\\n\\n# Map and set generating objects can also be c
1ombined, in which case the\\n# value is extensible even for the same key! In the example above, more\\n# rules could help contribute titles to an author, perhaps using different\\n# data sources.\\ntitles_by_author[document.author] contains document.title if {\\n some document in input.documents\\n}\\n```\\n\\n## Exceptions\\n\\nNote that this rule does **not** apply to array comprehensions, as there is no equivalent tp use a rule to generate an\\narray.\\n\\nThis rule will also ignore simple comprehensions used solely for the purpose of converting an array to a set, i.e:\\n\\n```rego\\npackage policy\\n\\n# Convert set to array. This is fine.\\nmy_set := {item | some item in arr}\\n```\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n prefer-set-or-object-rule:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Generating Sets](https://www.openpolicyagent.org/docs/policy-language/#generating-sets)\\n- OPA Docs: [Generating Objects](https://www.openpolicyagent.org/docs/policy-language/#generating-objects)\\n- OPA Docs: [Comprehensions](https://www.openpolicyagent.org/docs/policy-language/#comprehensions)\\n- Styra Blog: [Five Things You Didn\'t Know About OPA](https://web.archive.org/web/https://www.styra.com/blog/five-things-you-didnt-know-about-opa/)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/prefer-set-or-object-rule/prefer_set_or_object_rule.rego)\\n","id":"idiomatic/prefer-set-or-object-rule"},{"filePath":"projects/regal/rules/idiomatic/prefer-equals-comparison.md","content":"# prefer-equals-comparison\\n\\n**Summary**: Prefer `==` for equality comparison\\n\\n**Category**: Idiomatic\\n\\n**Automatically fixable**: [Yes](https://www.openpolicyagent.org/projects/regal/fixing)\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nallow if {\\n input.request.method = \\"GET\\"\\n # .. more conditions ..\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nallow if {\\n input.request.method == \\"GET\\"\\n # .. more conditions ..\\n}\\n```\\n\\n## Rationale\\n\\nThe unification operator (`=`) can be used for both assignment and equality comparison in Rego. This can be a really\\npowerful feature where appropriate, but when the intent is to perform either assignment (`:=`) **or** an equality\\ncomparison (`==`), using the operators designed for those specific purposes helps communicate that intent much more\\nclearly, and avoid some behaviors of the unification operator that may potentially be surprising (like in which order\\nexpresions are evaluated). This is not a general recommendation against using the unification operator, mind you! But to\\nuse the operators specifically for what they are designed for: `:=` for assignment, `==` for equality comparison, and\\n`=` for unification.\\n\\nThe OPA docs provide [more information](https://www.openpolicyagent.org/docs/policy-language#equality-assignment-comparison-and-unification)\\non the topic, but to demonstrate a valid use case for the unification operator, this would be a good example:\\n\\n```rego\\nuser_id := id if [\\"users\\", id] = input.path\\n```\\n\\nWhich without unification would need both comparison and assignment:\\n\\n```rego\\nuser_id := id if {\\n count(input.path) == 2\\n input.path[0] == \\"users\\"\\n id := input.path[1]\\n}\\n```\\n\\n## How comparison is determined\\n\\nSince the unification operator can be used for both assignment and comparison, this rule needs to determine that `=` is\\nused for comparison only. The rule reports a violation only when both sides of the `=` operator are determined to be\\n\\"unassignable\\", which is defined as:\\n\\n1. Literal values (strings, numbers, booleans, nulls) or composite values containing no variables\\n2. References (e.g. `input.foo.bar`)\\n3. An input variable \u2014 meaning a variable which has previously been assigned a value outside of the expression\\n\\nTo provide a simple example of the the third point:\\n\\n```rego\\nrule if {\\n x = input.x # assignment, provided that `x` is not assigned elsewhere\\n}\\n\\nrule if {\\n x := 5\\n x = input.x # comparison, as `x` is assigned above and unassignable here\\n}\\n```\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n prefer-equals-comparison:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\
1n- Regal Docs: [use-assignment-operator](https://www.openpolicyagent.org/projects/regal/rules/style/use-assignment-operator)\\n- OPA Docs: [Equality: Assignment, Comparison, and Unification](https://www.openpolicyagent.org/docs/policy-language#equality-assignment-comparison-and-unification)\\n- OPA Docs: [Comparisons](https://www.openpolicyagent.org/docs/policy-reference/builtins/comparison)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/prefer-equals-comparison/prefer_equals_comparison.rego)\\n","id":"idiomatic/prefer-equals-comparison"},{"filePath":"projects/regal/rules/idiomatic/non-raw-regex-pattern.md","content":"# non-raw-regex-pattern\\n\\n**Summary**: Use raw strings for regex patterns\\n\\n**Category**: Idiomatic\\n\\n**Automatically fixable**: [Yes](https://www.openpolicyagent.org/projects/regal/fixing)\\n\\n**Avoid**\\n```rego\\nall_digits if {\\n regex.match(\\"[\\\\\\\\d]+\\", \\"12345\\")\\n}\\n```\\n\\n**Prefer**\\n```rego\\nall_digits if {\\n regex.match(`[\\\\d]+`, \\"12345\\")\\n}\\n```\\n\\n## Rationale\\n\\n[Raw strings](https://www.openpolicyagent.org/docs/policy-language/#strings) are interpreted literally, allowing\\nyou to avoid having to escape special characters like `\\\\` in your regex patterns. Using raw strings for regex patterns\\nadditionally makes them easier to identify as such.\\n\\n## Limitations\\n\\nThis rule currently only scans regex string literals in the place of the `pattern` argument of the various\\n[regex built-in functions](https://www.openpolicyagent.org/docs/policy-reference/#regex). It will not **not**\\ntry to \\"resolve\\" patterns assigned to variables. The following example would as such not render a warning:\\n\\n```rego\\npackage policy\\n\\n# Pattern assigned to variable\\npattern := \\"[\\\\\\\\d]+\\"\\n\\n# This won\'t trigger a violation\\nallow if regex.match(pattern, \\"12345\\")\\n```\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n non-raw-regex-pattern:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Rego Style Guide: [Use raw strings for regex patterns](https://www.openpolicyagent.org/docs/style-guide#use-raw-strings-for-regex-patterns)\\n- OPA Docs: [Regex Functions Reference](https://www.openpolicyagent.org/docs/policy-reference/#regex)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/non-raw-regex-pattern/non_raw_regex_pattern.rego)\\n","id":"idiomatic/non-raw-regex-pattern"},{"filePath":"projects/regal/rules/idiomatic/no-defined-entrypoint.md","content":"# no-defined-entrypoint\\n\\n**Summary**: Missing entrypoint annotation\\n\\n**Category**: Idiomatic\\n\\n**Type**: Aggregate - only runs when more than one file is provided for linting\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\ndefault allow := false\\n\\n# Nothing wrong with this rule, but an\\n# entrypoint should be documented as such\\nallow if user_is_admin\\nallow if public_resource_read\\n\\nuser_is_admin if {\\n some role in input.user.roles\\n role in data.permissions.admin_roles\\n}\\n\\npublic_resource_read if {\\n input.request.method == \\"GET\\"\\n input.request.path[0] == \\"public\\"\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\ndefault allow := false\\n\\n# METADATA\\n# description: Allow only admins, or reading public resources\\n# entrypoint: true\\nallow if user_is_admin\\nallow if public_resource_read\\n\\nuser_is_admin if {\\n some role in input.user.roles\\n role in data.permissions.admin_roles\\n}\\n\\npublic_resource_read if {\\n input.request.method == \\"GET\\"\\n input.request.path[0] == \\"public\\"\\n}\\n```\\n\\n## Rationale\\n\\nDefining one or more entrypoints for your policies is a good practice to follow. An entrypoint is simply a package or\\nrule that is meant to be queried for decisions from the outside. While it might seem obvious to the policy author which\\nrules are meant to be queried, adding an extra line of two of metadata will help make it obvious to others.\\n\\nMarking a package or rule via an\\n[entrypoint annotation attribute](https://www.openpolicyagent.org/docs/policy-language/#entrypoint) not only\\nprovides good documentation for others, but also unlocks programmatic possibilities, like:\\n\\n1. Your policy library may be compiled to WebAssembly without extra entrypoint arguments\\n1. Your policy library may be compiled to an\\n [intermediate representation](https://blog.openpolicyagent.org/i-have-a-plan-exploring-the-opa-intermediate-representation-ir-format-7319cd94b37d)\\n (IR) format without extra entrypoint arguments\\n1. Exter
1nal applications may present your entrypoints as part of rendered documentation\\n1. External applications may use your entrypoints to know what to evaluate\\n1. External applications \u2014 like Regal \u2014 may use this information to determine what other rules are used or not\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n no-defined-entrypoint:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Metadata](https://www.openpolicyagent.org/docs/policy-language/#metadata)\\n- OPA Docs: [Entrypoint](https://www.openpolicyagent.org/docs/policy-language/#entrypoint)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/no-defined-entrypoint/no_defined_entrypoint.rego)\\n","id":"idiomatic/no-defined-entrypoint"},{"filePath":"projects/regal/rules/idiomatic/in-wildcard-key.md","content":"# in-wildcard-key\\n\\
1n**Summary**: Unnecessary wildcard key\\n\\n**Category**: Idiomatic\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\nallow if {\\n # since only the value is used, we don\'t need to iterate the keys\\n some _, user in input.users\\n\\n # do something with each user\\n}\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\nallow if {\\n some user in input.users\\n\\n # do something with each user\\n}\\n```\\n\\n## Rationale\\n\\nThe `some .. in` iteration form can either iterate only values:\\n\\n```rego\\nsome value in object\\n```\\n\\nOr keys and values:\\n\\n```rego\\nsome key, value in object\\n```\\n\\nUsing a wildcard variable for the key in the key-value form is thus unnecessary, and:\\n\\n```rego\\nsome _, value in object\\n```\\n\\nCan simply be replaced by:\\n\\n```rego\\nsome value in object\\n```\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n in-wildcard-key:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/in-wildcard-key/in_wildcard_key.rego)\\n","id":"idiomatic/in-wildcard-key"},{"filePath":"projects/regal/rules/idiomatic/equals-pattern-matching.md","content":"# equals-pattern-matching\\n\\n**Summary**: Prefer pattern matching in function arguments\\n\\n**Category**: Idiomatic\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nreadable_number(x) := \\"one\\" if x == 1\\nreadable_number(x) := \\"two\\" if x == 2\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nreadable_number(1) := \\"one\\"\\nreadable_number(2) := \\"two\\"\\n```\\n\\n## Rationale\\n\\nPattern matching on equality in function arguments is one of Rego\'s most well-kept secrets. As secret as it might be,\\nit\'s a great way to simplify custom functions performing equality checks on their arguments in the rule body, by\\nmoving the equality check to match on the function call itself. This means that a function like the one below:\\n\\n```rego\\npackage policy\\n\\nnormalize_role(role) := \\"admin\\" if {\\n role == \\"administrator\\"\\n}\\n\\nnormalize_role(role) := \\"admin\\" if {\\n role == \\"root\\"\\n}\\n```\\n\\nMay have the equality check moved to the function argument, and the function only evaluated in case the argument matches\\nthe equality \\"pattern\\":\\n\\n```rego\\npackage policy\\n\\nnormalize_role(\\"administrator\\") := \\"admin\\"\\n\\nnormalize_role(\\"root\\") := \\"admin\\"\\n```\\n\\nRules that evaluate to `true` may even have the assignment removed altogether, i.e.:\\n\\n```rego\\npackage policy\\n\\nis_admin(role) if role == \\"admin\\"\\n\\nis_admin(role) if role == \\"administrator\\"\\n\\nis_admin(role) if role == \\"root\\"\\n```\\n\\nCan be simplified to just:\\n\\n```rego\\npackage policy\\n\\nis_admin(\\"admin\\")\\n\\nis_admin(\\"administrator\\")\\n\\nis_admin(\\"root\\")\\n```\\n\\n## Limitations\\n\\nThis rule is currently limited to simple rules where the equality check is the **only** condition in the rule body. This\\nwill be improved in future releases.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n equals-pattern-matching:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Styra Blog: [How to express OR in Rego](https://web.archive.org/web/https://www.styra.com/blog/how-to-express-or-in-rego/)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/equals-pattern-matching/equals_pattern_matching.rego)\\n","id":"idiomatic/equals-pattern-matching"},{"filePath":"projects/regal/rules/idiomatic/directory-package-mismatch.md","content":"# directory-package-mismatch\\n\\n**Summary**: Directory structure should mirror package\\n\\n**Category**: Idiomatic\\n\\n**Automatically fixable**: Yes\\n\\n## Rationale\\n\\nQuickly finding the package you\'re looking for in a policy repository is made much easier when package paths are\\nmirrored in the directory structure of your project. Meaning that if the name of your package is\\n`permissions.users.claims`, it should reside in a file under the `permissions/users/claims` directory. Note however\\nthat any number of files can contribute to the same package! The `permissions/users/claims` directory may thus\\ncontain several policy files that all declare `package permissions.users.claims`.\\n\\n### Example\\n\\nAn example of directory structure for a project following this convention might look like this:\\n\\n```shell\\n# Directory structure # Package path\\n.\\n\u251c\u2500\u2500 README.md\\n\u2514\u2500\u2500 bundle\\n \u2514\u2500\u2500 authorization\\n \u251c\u2500\u2500 main.rego # authorization\\n \u2514\u2500\u2500 rbac\\n \u251c\u2500\u2500 data.json # authorization.rbac\\n \u251c\u2500\u2500 roles\\n \u2502\xa0\xa0 \u2514\u2500\u2500 roles.rego # authorization.rbac.roles\\n \u2502\xa0\xa0 \u2514\u2500\u2500 roles_test.rego # authorization.rbac.roles_test\\n \u2514\u2500\u2500 users\\n \u251c\u2500\u2500 customers.rego # authorization.rbac.users\\n \u251c\u2500\u2500 customers_test.rego # authorization.rbac.users_test\\n \u251c\u2500\u2500 internal.rego # authorization.rbac.users\\n \u2514\u2500\u2500 internal_test.rego # authorization.rbac.users_test\\n```\\n\\n### Tests\\n\\nAstute observers may notice that the test files in the example above are placed in the same directory as the\\npolicies they test. This may seem to contradict the\\n[test-outside-test-package](https://www.openpolicyagent.org/projects/regal/rules/testing/test-outside-test-package) rule, which\\nsays that any test package should have a `_test` suffix in its package path. However, putting tests next to\\nthe file they target arguably makes it _easier_ to find, and is a common practice in the OPA community. This\\nrule therefore by default ignores the `_test` suffix when determining whether the package path matches the\\ndirectory structure.\\n\\nThis behavior can be changed by setting the `exclude-test-suffix` configuration option to `false`, in which\\ncase package paths with a `_test` suffix also will be required to reside in a directory with a `_test` suffix.\\n\\nSetting the `exclude-test-suffix` option to `false` means the example from above would now look like this:\\n\\n```shell\\n# Directory structure # Package path\\n.\\n\u251c\u2500\u2500 README.md\\n\u2514\u2500\u2500 bundle\\n \u2514\u2500\u2500 authorization\\n \u251c\u2500\u2500 main.rego # authorization\\n \u2514\u2500\u2500 rbac\\n \u251c\u2500\u2500 data.json # authorization.rbac\\n \u251c\u2500\u2500 roles\\n \u2502\xa0\xa0 \u2514\u2500\u2500 roles.rego # authorization.rbac.roles\\n \u251c\u2500\u2500 roles_test\\n \u2502\xa0\xa0 \u2514\u2500\u2500 roles_test.rego # authorization.rbac.roles_test\\n \u251c\u2500\u2500 users\\n \u2502\xa0\xa0 \u251c\u2500\u2500 customers.rego # authorization.rbac.users\\n \u2502\xa0\xa0 \u2514\u2500\u2500 internal.rego # authorization.rbac.users\\n \u2514\u2500\u2500 users_test\\n \u251c\u2500\u2500 customers_test.rego # authorization.rbac.users_test\\n \u2514\u2500\u2500 internal_test.rego # authorization.rbac.users_test\\n```\\n\\nWhichever way you choose is up to you. Consistency is key!\\n\\n### Bundles\\n\\nWhile directory structure doesn\'t matter to OPA when parsing _policies_, directories parsed as\\n[bundles](https://www.openpolicyagent.org/docs/management-bundles/) will read _data_ (`data.json` or\\n`data.yaml`) files and insert the data in the `data` document tree based on the directory structure relative\\nto the bundle root. Having policies structured in the same manner provides a uniform experience, and makes it\\neasier to understand where both policies and data come from.\\n\\n### `regal fix` & Editor Support\\n\\nRegal\'s [`fix` command](https://www.openpolicyagent.org/projects/regal/fixing) can automatically\\nrename files in a project to ensure compliance with this rule. This is\\nparticularly useful when refactoring a project with many files.\\n\\n:::info\\nNote that files will be renamed relative to their nearest root, see the\\n[documentation on roots](https://www.openpolicyagent.org/projects/regal#project-roots) when using\\nthis rule with policy roots different from the project root.\\n:::\\n\\nEditors integrating Regal\'s [language server](https://www.openpolicyagent.org/projects/regal/language-server) will automatically display\\nsuggestions for idiomatic package paths based on the directory structure in which a policy resides. The image below\\ndemonstrates a new policy being created inside an `authorization/rbac/roles` directory, and the editor\\n([via Regal](https://www.openpolicyagent.org/projects/regal/language-server#code-completions)) suggesting the package path\\n`authorization.rbac.roles`.\\n\\n<img\\nsrc={require(\'../../assets/rules/pkg_name_completion.png\').default}\\nalt=\\"Package path auto-completion in VS Code\\"/>\\n\\nIn addition, empty files will be be \'formatted\' to have the correct package\\nbased on the directory structure. Newly created Rego files are treated in much\\nthe same way. When a new file is created, the server will send a series of edits\\nback to set the content. If `exclude-test-suffix` is set to `false`, the file\\nwill also be moved if required to the `_test` directory for that package.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n directory-p
1ackage-mismatch:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n # exclude _test suffixes from package paths before comparing\\n # them to directory structure paths. when set to false, a\\n # package like authz.policy_test would need to be placed in\\n # an authz/policy_test directory, and if set to true (default)\\n # would be expected to be in authz/policy\\n exclude-test-suffix: true\\n```\\n\\n## Related Resources\\n\\n- Rego Style Guide: [Package name should match file location](https://www.openpolicyagent.org/docs/style-guide#package-name-should-match-file-location)\\n- Regal Docs: [test-outside-test-package](https://www.openpolicyagent.org/projects/regal/rules/testing/test-outside-test-package)\\n- OPA Docs: [Bundles](https://www.openpolicyagent.org/docs/management-bundles/)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/directory-package-mismatch/directory_package_mismatch.rego)\\n","id":"idiomatic/directory-package-mismatch"},{"filePath":"projects/regal/rules/idiomatic/custom-in-construct.md","content":"# custom-in-construct\\n\\n**Summary**: Custom function may be replaced by `in` keyword\\n\\n**Category**: Idiomatic\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nallow if has_value(input.user.roles, \\"admin\\")\\n\\n# This custom function was commonly seen before the introduction\\n# of the `in` keyword. Avoid it now.\\nhas_value(arr, item) if {\\n item == arr[_]\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nallow if \\"admin\\" in input.user.roles\\n```\\n\\n## Rationale\\n\\nThe `in` keyword was introduced in OPA [v0.34.0](https://github.com/open-policy-agent/opa/releases/tag/v0.34.0).\\nPrior to that, it was a common practice to create a custom helper function that would iterate over values of an array in\\norder to check if it contained a provided value. Since the introduction of the `in` keyword, this is no longer\\nnecessary. The `in` keyword additionally supports sets and maps as the collection type, so using it consistently is\\nrecommended.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n custom-in-construct:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/custom-in-construct/custom_in_construct.rego)\\n","id":"idiomatic/custom-in-construct"},{"filePath":"projects/regal/rules/idiomatic/custom-has-key-construct.md","content":"# custom-has-key-construct\\n\\n**Summary**: Custom function may be replaced by `in` and `object.keys`\\n\\n**Category**: Idiomatic\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nmfa if has_key(input.claims, \\"mfa\\")\\n\\nhas_key(map, key) if {\\n _ = map[key]\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nmfa if \\"mfa\\" in object.keys(input.claims)\\n```\\n\\n## Rationale\\n\\nChecking if a key exists in an object (regardless of the attribute\'s value) used to be done using custom functions. With\\nthe introduction of the [object.keys](https://www.openpolicyagent.org/docs/policy-reference/#builtin-object-objectkeys)\\n(OPA [v0.47.0](https://github.com/open-policy-agent/opa/releases/tag/v0.47.0)) function, this is no longer necessary,\\nand using the built-in function together with `in` should be preferred.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n custom-has-key-construct:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/custom-has-key-construct/custom_has_key_construct.rego)\\n","id":"idiomatic/custom-has-key-construct"},{"filePath":"projects/regal/rules/idiomatic/boolean-assignment.md","content":"# boolean-assignment\\n\\n**Summary**: Prefer `if` over boolean assignment\\n\\n**Category**: Idiomatic\\n\\n**Avoid**\\n\\
1n```rego\\npackage policy\\n\\nmore_than_one_member := count(input.members) > 1\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nmore_than_one_member if count(input.members) > 1\\n```\\n\\n## Rationale\\n\\nAssigning the result of a boolean function is almost always redundant, as the boolean value returned by the expression\\nrarely is used for anything but to determine whether to continue evaluation. Moving the condition to the body following\\nan `if` will have the rule either evaluate to `true` or be undefined. For the few cases where `false` should be\\nreturned, using a `default` rule assignment is preferable, as it is guaranteed to be assigned a value even on undefined\\ninput:\\n\\n```rego\\npackage policy\\n\\ndefault more_than_one_member := false\\n\\n# will be assigned `false` even if input.members is undefined\\nmore_than_one_member if count(input.members) > 1\\n```\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n boolean-assignment:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Styra Blog: [How to express OR in Rego](https://web.archive.org/web/https://www.styra.com/blog/how-to-express-or-in-rego/)\\n- Regal Docs: [default-over-else](https://www.openpolicyagent.org/projects/regal/rules/style/default-over-else)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/boolean-assignment/boolean_assignment.rego)\\n","id":"idiomatic/boolean-assignment"},{"filePath":"projects/regal/rules/idiomatic/ambiguous-scope.md","content":"# ambiguous-scope\\n\\n**Summary**: Ambiguous metadata scope\\n\\n**Category**: Idiomatic\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\n# METADATA\\n# description: allow is true if the user is admin, or the requested resource is public\\nallow if user_is_admin\\n\\nallow if public_resource\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\n# METADATA\\n# description: allow is true if the user is admin, or the requested resource is public\\n# scope: document\\nallow if user_is_admin\\n\\nallow if public_resource\\n```\\n\\n**Or (scope `rule` implied, but _all_ incremental definitions are annotated)**\\n```rego\\npackage policy\\n\\n# METADATA\\n# description: allow is true if the user is admin\\nallow if user_is_admin\\n\\n# METADATA\\n# description: allow is true if the requested resource is public\\nallow if public_resource\\n```\\n\\n**Or (scope `rule` explicit)**\\n```rego\\npackage policy\\n\\n# METADATA\\n# description: allow is true if the user is admin\\n# scope: rule\\nallow if user_is_admin\\n\\nallow if public_resource\\n```\\n\\n## Rationale\\n\\nThe default scope for metadata annotating a rule is the `rule` scope, which\\n\\"[applies to the individual rule statement](https://www.openpolicyagent.org/docs/policy-language/#scope)\\" only.\\nThis default is sensible for a rule defined only once, but is somewhat ambiguous for a rule defined incrementally, like\\nthe `allow` rule in the examples above. Was the intention really to annotate that single definition, or the rule as\\nwhole? Most likely the latter, and that\'s what the `document` scope is for.\\n\\nIf only a single rule in a group of incremental rule definitions is annotated, it should have its `scope` set explicitly\\nto either `document` or `rule`. If all incremental definitions are annotated, explicit `scope: rule` is not required.\\n\\n## Exceptions\\n\\nIf a single incremental rule definition is annotated as `entrypoint: true`, this rule will allow that.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n idiomatic:\\n ambiguous-scope:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Annotations](https://www.openpolicyagent.org/docs/policy-language/#annotations)\\n- Regal Docs: [no-defined-entrypoint](https://www.openpolicyagent.org/projects/regal/rules/idiomatic/no-defined-entrypoint)\\n- G
1itHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/idiomatic/ambiguous-scope/ambiguous_scope.rego)\\n","id":"idiomatic/ambiguous-scope"},{"filePath":"projects/regal/rules/bugs/zero-arity-function.md","content":"# zero-arity-function\\n\\n**Summary**: Avoid functions without args\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\nfirst_user() := input.users[0]\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\nfirst_user := input.users[0]\\n```\\n\\n## Rationale\\n\\n**Note:** From Regal v0.39.0, this rule is no longer enabled by default. The reason for this is that OPA\'s formatter\\n(`opa fmt`) already removes parentheses from zero-arity function definitions, and as such, this is already covered by\\nthe [opa-fmt](https://www.openpolicyagent.org/projects/regal/rules/style/opa-fmt) rule. The only time you might still\\nwant to enable this rule is if you don\'t use `opa fmt` in your workflow (you should!) and still want to enforce this.\\n\\nZero-arity functions, or functions without arguments, aren\'t treated as functions by Rego, but as regular rules. For\\nthat reason, they should also be expressed as such. One potential benefit of using functions over rules is that\\nfunctions don\'t contribute to the\\n[document](https://www.openpolicyagent.org/docs/philosophy/#the-opa-document-model) when a package is evaluated,\\nand as such sometimes used to \\"hide\\" information from the result of evaluation. Whether this is a good practice or not,\\nit importantly _doesn\'t work_ with zero-arity functions, as they are treated as rules and _do_ contribute to the\\ndocument.\\n\\nThere is an [open issue](https://github.com/open-policy-agent/opa/issues/6315) in the OPA project to try and address\\nthis in the future, and allow zero-arity functions to be treated as other functions. Until then, the recommendation\\nis to avoid them and just use rules in their place.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n zero-arity-function:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [The OPA Document Model](https://www.openpolicyagent.org/docs/philosophy/#the-opa-document-model)\\n- OPA Issues: [Allow user-defined zero-argument functions in Rego](https://github.com/open-policy-agent/opa/issues/6315)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/zero-arity-function/zero_arity_function.rego)\\n","id":"bugs/zero-arity-function"},{"filePath":"projects/regal/rules/bugs/var-shadows-builtin.md","content":"# var-shadows-builtin\\n\\n**Summary**: Variable shadows built-in\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\n# variable `http` shadows `http.send` built-in function\\nallow if {\\n http := startswith(input.url, \\"http://\\")\\n # do something with http\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\n# variable `is_http` doesn\'t shadow any built-in function\\nallow if {\\n is_http := startswith(input.url, \\"http://\\")\\n # do something with is_http\\n}\\n```\\n\\n## Rationale\\n\\nUsing the name of built-in functions or operators as variable names can lead to confusion and unexpected behavior.\\nA variable that shadows a built-in function (or the namespace of a function, like `http` in `http.send`) prevents any\\nfunction in that namespace to be used later in the rule. Avoid this!\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n var-shadows-builtin:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Built-in Functions](https://www.openpolicyagent.org/docs/policy-reference/#built-in-functions)\\n- OPA Repo: [builtin_metadata.json](https://github.com/open-policy-agent/opa/blob/main/builtin_metadata.json)\\n- Regal Docs: [rule-shadows-builtin](https://www.openpolicyagent.org/projects/regal/rules/bugs/rule-shadows-builtin)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/var-shadows-builtin/var_shadows_builtin.rego)\\n","id":"bugs/var-shadows-builtin"},{"filePath":"projects/regal/rules/bugs/unused-output-variable.md","content":"# unused-output-variable\\n\\n**Summary**: Unused output variable\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nallow if {\\n some x\\n role := input.user.roles[x]\\n\\
1n # do something with \\"role\\", but not \\"x\\"\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nallow if {\\n # don\'t declare `x` output var as it is redundant\\n role := input.user.roles[_]\\n\\n # do something with \\"role\\"\\n}\\n\\n# or better (see prefer-some-in-iteration rule)\\n\\nallow if {\\n some role in input.user.roles\\n\\n # do something with \\"role\\"\\n}\\n\\n# or actually _use_ value bound to `x` somewhere, like in another\\n# reference, function call, etc\\n\\nallow if {\\n some x\\n input.user.roles[x] == data.required_roles[x]\\n}\\n```\\n\\n## Rationale\\n\\nOutput variables are variables \\"automatically\\" bound to values during evaluation, most commonly in iteration. This is\\na powerful feature of Rego that when used correctly can create concise but readable policies. However, output variables\\nthat are declared but not later referenced are _effectively_ unused and should be replaced by wildcard variables (`_`),\\nor the use of `some .. in` iteration.\\n\\nOPA itself has two methods for detecting and reporting unused variables as errors \u2014 one when using `some`:\\n\\n```rego\\nallow if {\\n # `x` is never used in the body \u2014 this is a compiler error\\n some x\\n input.user.roles[role]\\n\\n role == \\"admin\\"\\n}\\n```\\n\\nAnd a [strict mode](https://www.openpolicyagent.org/docs/policy-language/#strict-mode) check for unused\\nvariables defined in assignment (`:=`), or as a function arguments:\\n\\n```rego\\nallow(role, required) {\\n required_roles := data.required_roles\\n\\n role == \\"admin\\"\\n\\n # `required` never used in body, and neither is `required_roles`\\n # both would be errors when strict mode is enabled\\n}\\n```\\n\\nNeither of these methods however considers an unused output variable as \\"unused\\".\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n unused-output-variable:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Regal Docs: [prefer-some-in-iteration](https://www.openpolicyagent.org/projects/regal/rules/style/prefer-some-in-iteration)\\n- OPA Docs: [Strict Mode](https://www.openpolicyagent.org/docs/policy-language/#strict-mode)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/unused-output-variable/unused_output_variable.rego)\\n","id":"bugs/unused-output-variable"},{"filePath":"projects/regal/rules/bugs/unassigned-return-value.md","content":"# unassigned-return-value\\n\\n**Summary**: Non-boolean return value unassigned\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nallow if {\\n # return value not assigned\\n lower(input.user.name)\\n # ...\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nallow if {\\n # return value assigned\\n name_lower := lower(input.user.name)\\n # ...\\n}\\n```\\n\\n## Rationale\\n\\nCalling a built-in function that returns a non-boolean value without actually assigning the returned value is almost\\nalways a mistake. Only return of `false` or undefined will cause evaluation to halt, so a function that e.g. always\\nreturns a string will always be evaluated as \\"truthy\\". But more importantly \u2014 not handling the return value in that case\\nis almost certainly a mistake.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n unassigned-return-value:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/unassigned-return-value/unassigned_return_value.rego)\\n","id":"bugs/unassigned-return-value"},{"filePath":"projects/regal/rules/bugs/top-level-iteration.md","content":"# top-level-iteration\\n\\n**Summary**: Iteration in top-level assignment\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nuser := input.users[_]\\n```\\n\\n## Rationale\\n\\nWhile OPA allows this construct \u2014 it probably shouldn\'t. Performing iteration outside of a rule or function body\\ndoesn\'t make any sense, and traversing **any** collection containing more than one item in this context will result\\nin an error:\\n\\n```shell\\neval_conflict_error: complete rules must not produce multiple outputs\\n```\\n\\nIf the collection only contains a single item, the assignment will succeed, and the result will be the single element\\nassigned to the variable. As such, it is possible that a policy passing all tests still will fail when provided real\\ndata.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n top-level-iteration:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\
1n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/top-level-iteration/top_level_iteration.rego)\\n","id":"bugs/top-level-iteration"},{"filePath":"projects/regal/rules/bugs/time-now-ns-twice.md","content":"# time-now-ns-twice\\n\\n**Summary**: Repeated calls to `time.now_ns`\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\ntimed if {\\n now := time.now_ns()\\n\\n # do some work here\\n\\n # this doesn\'t work! result is always 0\\n print(\\"work done in:\\", time.now_ns() - now, \\"ns)\\n}\\n```\\n\\n**Prefer**\\n\\nTo use the tools OPA provides for measuring performance.\\n\\n## Rationale\\n\\nAn important property of Rego is that it makes policy evaluation _predictable_. Using the same input to query OPA for a\\ndecision multiple times should result in the same decision being made each time! A few built-in functions, like\\n`http.send`, or [time.now_ns](https://www.openpolicyagent.org/docs/policy-reference/#builtin-time-timenow_ns) are\\nhowever not **deterministic**. This means that repeated queries to policies where such functions are used may result in\\ndifferent decisions being made. For example, a policy that validates JSON Web Tokens would normally check if the current\\ntime is past the expiry value of the token, and deny any request where a token is found to be expired.\\n\\nBut while the use of non-deterministic built-in functions may result in different outcomes across different\\nqueries, all built-in functions are deterministic **within the scope of a single evaluation**. This means that calling\\ne.g. `http.send` twice in a policy using the exact same arguments never results in different values being returned.\\nThis is equally true for `time.now_ns`. In order to ensure predictable evaluation, the time returned by `time.now_ns` is\\nset once at the start of the evaluation, and never changes for the course of the request. Calling `time.now_ns` several\\ntimes within a rule is thus pointless, as the same value will be returned each time.\\n\\nThis mistake is most commonly observed when developers try to measure elapsed time in some parts of their policy, the\\nsame way they\'d normally do it using a traditional programming language (that is not deterministic). While this won\'t\\nwork, OPA provides several tools to help measure performance, and learning how to use them well is the best way to\\nunderstand the performance characteristics of policy evaluation.\\n\\nSee the [performance](https://www.openpolicyagent.org/docs/policy-performance) section of the OPA docs for an\\nintroduction to these tools, as well as advice on how to write performant policies.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n time-now-ns-twice:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [time.now_ns](https://www.openpolicyagent.org/docs/policy-reference/#builtin-time-timenow_ns)\\n- OPA Docs: [Policy Performance](https://www.openpolicyagent.org/docs/policy-performance)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/time-now-ns-twice/time_now_ns_twice.rego)\\n","id":"bugs/time-now-ns-twice"},{"filePath":"projects/regal/rules/bugs/sprintf-arguments-mismatch.md","content":"# sprintf-arguments-mismatch\\n\\n**Summary**: Mismatch in `sprintf` arguments count\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nmax_issues := 1\\n\\nreport contains warning if {\\n count(issues) > max_issues\\n\\n # two placeholders found in the string, but only one value in the array\\n warning := sprintf(\\"number of issues (%d) must not be higher than %d\\", [count(issues)])\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nmax_issues := 1\\n\\nreport contains warning if {\\n count(issues) > max_issues\\n\\n # two placeholders found in the string, and two values in the array\\n warning := sprintf(\\"number of issues (%d) must not be higher than %d\\", [count(issues), max_issues])\\n}\\n```\\n\\n## Rationale\\n\\nWhile the built-in `sprintf` function itself reports argument mismatches, it\'ll do so by returning a string containing\\nthe error message rather than actually failing.\\n\\n```shell\\n> opa eval -f pretty \'sprintf(\\"%v %d\\", [1])\'\\n\\"1 %!d(MISSING)\\"\\n```\\n\\nWhile this is normally caught in development and testing, having this issue reported at \\"compile time\\", which ideally\\nis [directly in your editor](https://www.openpolicyagent.org/projects/regal/language-server) as you work on your policy. This means less\\ntime spent chasing down issues later, and a happier development experience.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n sprintf-arguments-mismatch:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\
1n- OPA Docs: [Built-in Functions: `sprintf`](https://www.openpolicyagent.org/docs/policy-reference/#builtin-strings-sprintf)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/sprintf-arguments-mismatch/sprintf_arguments_mismatch.rego)\\n","id":"bugs/sprintf-arguments-mismatch"},{"filePath":"projects/regal/rules/bugs/rule-shadows-builtin.md","content":"# rule-shadows-builtin\\n\\n**Summary**: Rule name shadows built-in\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\n# `or` is an operator\\nor := 1 + 1\\n\\n# `startswith` is a built-in function\\nstartswith := indexof(\\"rego\\", \\"r\\")\\n```\\n\\n## Rationale\\n\\nUsing the name of built-in functions or operators as rule and variable names can lead to confusion and unexpected\\nbehavior.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n rule-shadows-builtin:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Built-in Functions](https://www.openpolicyagent.org/docs/policy-reference/#built-in-functions)\\n- OPA Repo: [builtin_metadata.json](https://github.com/open-policy-agent/opa/blob/main/builtin_metadata.json)\\n- Regal Docs: [var-shadows-builtin](https://www.openpolicyagent.org/projects/regal/rules/bugs/var-shadows-builtin)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/rule-shadows-builtin/rule_shadows_builtin.rego)\\n","id":"bugs/rule-shadows-builtin"},{"filePath":"projects/regal/rules/bugs/rule-named-if.md","content":"# rule-named-if\\n\\n**Summary**: Rule named `if`\\n\\n**Category**: Bugs\\n\\n## Notice: Rule disabled by default since OPA 1.0\\n\\nThis rule is only enabled for projects that have either been explicitly configured to target versions of OPA before 1.0,\\nor if no configuration is provided \u2014 where Regal is able to determine that an older version of OPA/Rego is being\\ntargeted. Consult the documentation on Regal\'s [configuration](https://www.openpolicyagent.org/projects/regal#configuration)\\nfor information on how to best work with older versions of OPA and Rego.\\n\\nSince OPA v1.0, this rule is automatically disabled, as the parser itself will throw an error if a rule is named `if`,\\nas that is made a keyword in Rego v1.0.\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nallow := true if {\\n authorized\\n}\\n```\\n\\nWhich actually means:\\n\\n```rego\\npackage policy\\n\\nallow := true\\n\\nif {\\n authorized\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nimport rego.v1\\n\\nallow := true if {\\n authorized\\n}\\n```\\n\\n## Rationale\\n\\nForgetting to import the `if` keyword (using `import future.keywords.if`, or from OPA v0.59.0+ `import rego.v1`) is a\\ncommon mistake. While this often results in a parse error, there are some situations where the parser can\'t tell if the\\n`if` is intended to be used as the imported keyword, or a new rule named `if`. This is almost always a mistake, and if\\nit isn\'t \u2014 consider using a better name for your rule!\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n rule-named-if:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/rule-named-if/rule_named_if.rego)\\n","id":"bugs/rule-named-if"},{"filePath":"projects/regal/rules/bugs/rule-assigns-default.md","content":"# rule-assigns-default\\n\\n**Summary**: Rule assigned its default value\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\ndefault allow := false\\n\\n# this rule assigns the same value as the default\\n# and the policy would work the same without it\\nallow := false if {\\n not \\"admin\\" in input.user.roles\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\ndefault allow := false\\n\\n# or just `allow if {` as `true` is implicit\\nallow := true if {\\n \\"admin\\" in input.user.roles\\n}\\n```\\n\\n## Rationale\\n\\nWhen a default value is used for a rule, assigning the same value anywhere else to that rule is pointless, as the rule\\nwould evaluate to the same value with or without the assignment.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n rule-assigns-default:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\
1n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/rule-assigns-default/rule_assigns_default.rego)\\n","id":"bugs/rule-assigns-default"},{"filePath":"projects/regal/rules/bugs/redundant-loop-count.md","content":"# redundant-loop-count\\n\\n**Summary**: Redundant count before loop\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\nallow if {\\n # redundant count and > comparison\\n count(input.user.roles) > 0\\n some role in input.user.roles\\n # .. do more with role ..\\n}\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\nallow if {\\n some role in input.user.roles\\n # .. do more with role ..\\n}\\n```\\n\\n## Rationale\\n\\nA loop that iterates over an empty collection evaluates to nothing, and counting the collection before the loop to\\nensure it\'s not empty is therefore redundant.\\n\\n## Exceptions\\n\\nNote that this check is currently only performed on `some` loops, and not \\"ref-style\\" loops:\\n\\n```rego\\npackage policy\\n\\nallow if {\\n # this won\'t be flagged\\n count(input.user.roles) > 0\\n role := input.user.roles[_]\\n # .. do more with role ..\\n}\\n```\\n\\nAnother good reason to\\n[prefer some .. in for iteration](https://www.openpolicyagent.org/projects/regal/rules/style/prefer-some-in-iteration)!\\n\\n### `every` iteration\\n\\nCounting to ensure a non-empty collection is used before `every` loops may **not** be redundant, as `every` evaluates\\nto `true` when an empty collection is passed.\\n\\n```rego\\npackage policy\\n\\nallow if {\\n # every would otherwise be `true` on empty input.user.roles\\n # so this may be valid, depending on the outcome you expect\\n count(input.user.roles) > 0\\n every role in input.user.roles {\\n # .. do more with each role ..\\n }\\n}\\n```\\n\\nIf you want to have empty collections fail on `every` conditions, do make sure to use `count`!\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n redundant-loop-count:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/redundant-loop-count/redundant_loop_count.rego)\\n","id":"bugs/redundant-loop-count"},{"filePath":"projects/regal/rules/bugs/redundant-existence-check.md","content":"# redundant-existence-check\\n\\n**Summary**: Redundant existence check\\n\\n**Category**: Bugs\\n\\n**Automatically fixable**: [Yes](https://www.openpolicyagent.org/projects/regal/fixing)\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nemployee if {\\n input.user.email\\n endswith(input.user.email, \\"@acmecorp.com\\")\\n}\\n\\nis_admin(user) if {\\n user\\n \\"admin\\" in user.roles\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nemployee if {\\n endswith(input.user.email, \\"@acmecorp.com\\")\\n}\\n\\n# alternatively\\n\\nemployee if endswith(input.user.email, \\"@acmecorp.com\\")\\n\\nis_admin(user) if {\\n \\"admin\\" in user.roles\\n}\\n```\\n\\n## Rationale\\n\\nChecking that a reference (like `input.user.email`) is defined before immediately using it is redundant. If the\\nreference is undefined, the next expression will fail anyway, as the value will be checked before the rest of the\\nexpression is evaluated. While an extra check doesn\'t \\"hurt\\", it also serves no purpose, similarly to an unused\\nvariable.\\n\\n**Note**: This rule only applies to references that are immediately used in the next expression. If the reference is\\nused later in the rule, it won\'t be flagged. While the existence check _could_ be redundant even in that case, it could\\nalso be used to avoid making some expensive computation, an `http.send` call, or whatnot.\\n\\n## Exceptions\\n\\nFunction arguments where a boolean value is expected will be flagged as redundant existence checks, even though the\\nintent was to check the boolean condition.\\n\\n```rego\\nreport(user, is_admin) if {\\n is_admin\\n\\n # more conditions\\n}\\n```\\n\\nFor these cases, prefer to be explicit about what the assertion is checking:\\n\\n```rego\\nreport(user, is_admin) if {\\n is_admin == false # or true, != false, etc.\\n\\n # more conditions\\n}\\n```\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n redundant-existence-check:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\
1n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/redundant-existence-check/redundant_existence_check.rego)\\n","id":"bugs/redundant-existence-check"},{"filePath":"projects/regal/rules/bugs/not-equals-in-loop.md","content":"# not-equals-in-loop\\n\\n**Summary**: Use of != in loop\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\ndeny if {\\n \\"admin\\" != input.user.roles[_]\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\ndeny if {\\n not \\"admin\\" in input.user.roles\\n}\\n\\n# Or as a one-liner\\ndeny if not \\"admin\\" in input.user.roles\\n```\\n\\n## Rationale\\n\\nLikely one of the most common mistakes in Rego is to use `!=` in a loop thinking it means \\"not in\\". It took some years\\nfor the `in` keyword to be added to Rego, so perhaps it\'s not surprising that this mistake is a common one even to this\\nday. If it doesn\'t mean \\"not in\\", what does it mean?\\n\\n```rego\\npackage policy\\n\\ndeny if {\\n \\"admin\\" != input.user.roles[_]\\n}\\n```\\n\\nThe body of the `deny` rule above roughly translates to \\"for any item in `input.user.roles`, return true if the item is\\nnot `admin`\\". This is almost never what the policy author intended. What the policy author likely intended was\\n\\"deny if `admin` is not in `input.user.roles`\\". The above policy would thus **not** deny a user with the roles\\n`[\\"user\\", \\"admin\\"]` since the first item in the array is not \\"admin\\". This is almost never what the policy author\\nintended.\\n\\n**Note**: This linter rule currently only checks for `!=` in a non-nested comparison where iteration happens on either\\nside of the comparison in the same expression. This will be improved in time. Another limitation is that this rule\\ncurrently only checks for wildcard iteration (`[_]`).\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n not-equals-in-loop:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/not-equals-in-loop/not_equals_in_loop.rego)\\n","id":"bugs/not-equals-in-loop"},{"filePath":"projects/regal/rules/bugs/leaked-internal-reference.md","content":"# leaked-internal-reference\\n\\n**Summary**: Outside reference to internal rule or function\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\n# Import of rule or functions marked as internal\\nimport data.users._all_users\\n\\nallow if {\\n # reference to rule or function marked as internal\\n some role in data.permissions._roles\\n # ...some conditions\\n}\\n```\\n\\n## Rationale\\n\\nOPA doesn\'t have a concept of \\"internal\\", or private rules and functions \u2014 and all rules can be queried or referenced\\nfrom the outside. Despite this fact, it has become a common convention to use an underscore prefix in the name of\\nrules and functions to indicate that they should be considered internal to the package that they\'re in:\\n\\n```rego\\n# `allow` may be referenced from outside the package\\nallow if _user_is_developer\\n\\n# `_user_is_developer` should not be referenced from outside the package\\n_user_is_developer if \\"developer\\" in input.users.roles\\n```\\n\\nWhile this might seem like a pointless convention if it isn\'t enforced by OPA, it comes with a number of benefits:\\n\\n- While OPA doesn\'t enforce it, other tools like linters can help with that. Like this rule does!\\n- It clearly communicates intent to other policy authors, and as a simple form of documentation\\n- Completion suggestions in editors can be filtered to exclude internal rules and functions\\n- Tools that render documentation from Rego policies and metadata annotations can exclude internal rules and functions\\n- Checking for unused rules and functions can be done much faster if they\'re known not to be referenced from outside\\n\\nDo note that if you disagree with this rule, you don\'t need to disable it unless you use underscore prefixes to mean\\nsomething else. If you don\'t use underscore prefixes, nothing will be reported by this rule anyway. It does however\\nmean that the benefits listed above won\'t apply to your project.\\n\\n## Exceptions\\n\\nThis rule is not enabled by default for test files. In tests, it can be useful\\nto reference internal rules and functions to achieve good test coverage, which\\nwould be a violation of this rule. If you want to run this rule for tests\\ntoo, you can set `include-test-files: true` in the configuration for this rule\\nin your Regal config file.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n leaked-internal-reference:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n include-test-files: false # default is false\\n```\\n\\n## Related Resources\\n\\
1n- Rego Style Guide: [Optionally, use leading underscore for rules intended for internal use](https://www.openpolicyagent.org/docs/style-guide#optionally-use-leading-underscore-for-rules-intended-for-internal-use)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/leaked-internal-reference/leaked_internal_reference.rego)\\n","id":"bugs/leaked-internal-reference"},{"filePath":"projects/regal/rules/bugs/invalid-regexp.md","content":"# invalid-regexp\\n\\n**Summary**: Invalid regular expression\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\ninvalid if regex.match(`[abc`, input.text)\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\nvalid if regex.match(`[abc]`, input.text)\\n```\\n\\n## Rationale\\n\\nAn invalid regular expression typically fails silently (i.e. the result is undefined) at runtime when OPA evaluates the\\nfunction call, or with a runtime error if the `show-builtin-errors` option is enabled. While hopefully caught by unit\\ntests, tracking down a typo in a regular expression is still time consuming. This rule instead analyzes any regular\\nexpressions found in a policy as you author it (using OPA\'s own `regex.is_valid` function) and reports invalid patterns\\ndirectly.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n invalid-regexp:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Regex Functions](https://www.openpolicyagent.org/docs/latest/policy-reference/#regex-functions)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/invalid-regexp/invalid_regexp.rego)\\n","id":"bugs/invalid-regexp"},{"filePath":"projects/regal/rules/bugs/invalid-metadata-attribute.md","content":"# invalid-metadata-attribute\\n\\n**Summary**: Invalid attribute in metadata annotation\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n```rego\\n# METADATA\\n# title: Main policy routing requests to other policies based on input\\n# category: Routing\\npackage router\\n```\\n\\n**Prefer**\\n```rego\\n# METADATA\\n# title: Main policy routing requests to other policies based on input\\n# custom:\\
1n# category: Routing\\npackage router\\n```\\n\\n## Rationale\\n\\nMetadata comments should follow the schema expected by\\n[annotations](https://www.openpolicyagent.org/docs/policy-language/#annotations). Custom attributes, like\\n`category` above, should be placed under the `custom` key, which is a map of arbitrary key-value pairs.\\n\\nWhile arbitrary attributes are accepted, they will not be treated as metadata annotations but regular comments, and as\\nsuch won\'t be available to other tools that\\n[process annotations](https://www.openpolicyagent.org/docs/policy-language/#accessing-annotations).\\nThese tools include built-in functions like\\n[rego.metadata.rule](https://www.openpolicyagent.org/docs/policy-reference/#builtin-rego-regometadatarule) and\\n[rego.metadata.chain](https://www.openpolicyagent.org/docs/policy-reference/#builtin-rego-regometadatachain).\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n invalid-metadata-attribute:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Annotations](https://www.openpolicyagent.org/docs/policy-language/#annotations)\\n- OPA Docs: [Accessing Annotations](https://www.openpolicyagent.org/docs/policy-language/#accessing-annotations)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/invalid-metadata-attribute/invalid_metadata_attribute.rego)\\n","id":"bugs/invalid-metadata-attribute"},{"filePath":"projects/regal/rules/bugs/internal-entrypoint.md","content":"# internal-entrypoint\\n\\n**Summary**: Entrypoint can\'t be marked internal\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\n# METADATA\\n# entrypoint: true\\n_authorized if {\\n # some conditions\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\n# METADATA\\n# entrypoint: true\\nallow if _authorized\\n\\n_authorized if {\\n # some conditions\\n}\\n```\\n\\n## Rationale\\n\\nRules marked as internal using the [underscore prefix convention](https://www.openpolicyagent.org/docs/style-guide#optionally-use-leading-underscore-for-rules-intended-for-internal-use)\\ncannot be used as entrypoints, as entrypoints by definition are public. Either rename the rule to mark it as public,\\nor use another public rule as an entrypoint, which may reference the internal rule.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n internal-entrypoint:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Rego Style Guide: [Optionally, use leading underscore for rules intended for internal use](https://www.openpolicyagent.org/docs/style-guide#optionally-use-leading-underscore-for-rules-intended-for-internal-use)\\n- Regal Docs: [no-defined-entrypoint](https://www.openpolicyagent.org/projects/regal/rules/idiomatic/no-defined-entrypoint)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/internal-entrypoint/internal_entrypoint.rego)\\n","id":"bugs/internal-entrypoint"},{"filePath":"projects/regal/rules/bugs/inconsistent-args.md","content":"# inconsistent-args\\n\\
1n**Summary**: Inconsistently named function arguments\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nfind_vars(rule, node) if node in rule\\n\\n# Order of arguments changed, or at least it looks like it\\nfind_vars(node, rule) if {\\n walk(rule, [path, value])\\n # ...\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nfind_vars(rule, node) if node in rule\\n\\nfind_vars(rule, node) if {\\n walk(rule, [path, value])\\n # ...\\n}\\n```\\n\\n## Rationale\\n\\nWhenever a custom function declaration is repeated, the argument names should remain consistent in each declaration.\\n\\nInconsistently named function arguments is a likely source of bugs, and should be avoided.\\n\\n## Exceptions\\n\\nUsing wildcards (`_`) in place of unused arguments is always allowed, and in fact enforced by the compiler:\\n\\n```rego\\npackage policy\\n\\nfind_vars(rule, node) if node in rule\\n\\n# We don\'t use `node` here\\nfind_vars(rule, _) if {\\n walk(rule, [path, value])\\n # ...\\n}\\n```\\n\\nUsing [pattern matching for equality](https://www.openpolicyagent.org/projects/regal/rules/idiomatic/equals-pattern-matching) checks is\\nalso allowed.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n inconsistent-args:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Regal Docs: [equals-pattern-matching](https://www.openpolicyagent.org/projects/regal/rules/idiomatic/equals-pattern-matching)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/inconsistent-args/inconsistent_args.rego)\\n","id":"bugs/inconsistent-args"},{"filePath":"projects/regal/rules/bugs/impossible-not.md","content":"# impossible-not\\n\\n**Summary**: Impossible `not` condition\\n\\n**Category**: Bugs\\n\\n**Type**: Aggregate - runs both on single files as well as when more than one file is provided for linting\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nreport contains violation if {\\n # ... some conditions\\n}\\n```\\n\\n```rego\\npackage policy_test\\n\\nimport data.policy\\n\\ntest_report_is_empty {\\n # evaluation will stop here, as even an empty set is \\"true\\"\\n not policy.report\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nreport contains violation if {\\n # ... some conditions\\n}\\n```\\n\\n```rego\\npackage policy_test\\n\\nimport data.policy\\n\\ntest_report_is_empty {\\n count(policy.report) == 0\\n}\\n```\\n\\n## Rationale\\n\\nThe `not` keyword negates the expression that follows it. A common mistake, especially in tests, is to use `not`\\nto test the result of evaluating a partial (i.e. multi-value) rule. However, as even an empty set is considered\\n\\"truthy\\", the `not` will in that case always evaluate to `false`. There are more cases where `not` is impossible,\\nor a [constant condition](https://www.openpolicyagent.org/projects/regal/rules/bugs/constant-condition), but references to partial\\nrules are by far the most common. For tests where you want to assert the set is empty or has a specific number of\\nitems, use the built-in `count` function instead.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n impossible-not:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Regal Docs: [constant-condition](https://www.openpolicyagent.org/projects/regal/rules/bugs/constant-condition)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/impossible-not/impossible_not.rego)\\n","id":"bugs/impossible-not"},{"filePath":"projects/regal/rules/bugs/import-shadows-rule.md","content":"# import-shadows-rule\\n\\n**Summary**: Import shadows rule\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n\\n```rego\\npackage policy\\n\\nimport data.resources\\n\\n# \'resources\' shadowed by import\\nresources contains resource if {\\n # ...\\n}\\n```\\n\\n**Prefer**\\n\\n```rego\\npackage policy\\n\\nimport data.resources\\n\\
1n# using a different name for the rule\\nreport contains resource if {\\n # ...\\n}\\n```\\n\\n```rego\\npackage policy\\n\\n# using an alias to avoid shadowing \'resources\' rule\\nimport data.resources as inventory\\n\\nresources contains resource if {\\n # ...\\n}\\n```\\n\\n## Rationale\\n\\nImported identifers like `bar` in `import data.foo.bar` has higher precedence than a rule named `bar` in the same\\npackage. This means that any rule that is shadowed by an import is effectively unreachable inside of the module.\\nAvoid shadowing either by renaming your rule or by using an alias for the imported identifier.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n import-shadows-rule:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/import-shadows-rule/import_shadows_rule.rego)\\n","id":"bugs/import-shadows-rule"},{"filePath":"projects/regal/rules/bugs/if-object-literal.md","content":"# if-object-literal\\n\\n**Summary**: Object literal following `if`\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\n# {} interpreted as object, not a rule body\\nallow if {}\\n\\nallow if {\\n # perhaps meant to be comparison?\\n # but this too is an object\\n input.x: 10\\n}\\n```\\n\\n## Rationale\\n\\nAn object literal immediately following an `if` is almost certainly a mistake, and the intention was likely to express\\na rule body in its place. This isn\'t too common, but can happen when either an empty object `{}` is all that follows the\\n`if`, or an expression in the \\"body\\" mistakenly is written as a `key: value` pair.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n if-object-literal:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/if-object-literal/if_object_literal.rego)\\n","id":"bugs/if-object-literal"},{"filePath":"projects/regal/rules/bugs/if-empty-object.md","content":"# if-empty-object\\n\\n**This rule has been deprecated and replaced by the\\n[if-object-literal](https://www.openpolicyagent.org/projects/regal/rules/bugs/if-object-literal) rule. Documentation kept here only for\\nthe sake of posterity.**\\n\\n**Summary**: Empty object following `if`\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nallow if {}\\n```\\n\\n## Rationale\\n\\nAn empty rule body would previously be considered an error by OPA. With the introduction, and use of the `if` keyword,\\nthat is no longer the case. In fact, empty `{}` is not considered a rule body _at all_, but rather an empty object,\\nmeaning that `if {}` will always evaluate. This is likely a mistake, and while hopefully caught by tests, should be\\navoided.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n if-empty-object:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- Regal Docs: [constant-condition](https://www.openpolicyagent.org/projects/regal/rules/bugs/constant-condition)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/if-empty-object/if_empty_object.rego)\\n","id":"bugs/if-empty-object"},{"filePath":"projects/regal/rules/bugs/duplicate-rule.md","content":"# duplicate-rule\\n\\n**Summary**: Duplicate rule\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nallow if user.is_admin\\n\\nallow if user.is_developer\\n\\n# we already covered this!\\nallow if user.is_admin\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nallow if user.is_admin\\n\\nallow if user.is_developer\\n```\\n\\n## Rationale\\n\\nDuplicated rules are likely a mistake, perhaps from pasting contents from another file.\\n\\nThis rule identifies rules that are _identical_ in terms of their name, assigned value, and body \u2014 excluding\\nwhitespace. In technical terms, if two or more rules share the same abstract syntax tree, they are considered\\nto be duplicates.\\n\\n## Exceptions\\n\\nNote that this rule currently works at the scope of a single file. If you\'re using the same package across multiple\\nfiles, there could still be duplicates across those files. This will be addressed in a future version of this rule.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n duplicate-rule:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\
1n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/duplicate-rule/duplicate_rule.rego)\\n","id":"bugs/duplicate-rule"},{"filePath":"projects/regal/rules/bugs/deprecated-builtin.md","content":"# deprecated-builtin\\n\\n**Summary**: Avoid using deprecated built-in functions\\n\\n**Category**: Bugs\\n\\n## Notice: Rule disabled with OPA 1.0\\n\\nSince Regal v0.30.0, this rule is only enabled for projects that have either been explicitly configured to target\\nversions of OPA before 1.0, or if no configuration is provided \u2014 where Regal is able to determine that an older version\\nof OPA/Rego is being targeted. Consult the documentation on Regal\'s\\n[configuration](https://www.openpolicyagent.org/projects/regal#configuration) for information on how to best work with older versions of\\nOPA and Rego.\\n\\nSince OPA v1.0, this rule is automatically disabled, as there currently are no deprecated built-in functions\\nin that version, and trying to use a previously deprecated function will result in a parser error. Note however that\\nthis may change if later OPA versions deprecate current built-in functions. If/when that happens, this rule will be\\nre-enabled.\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nimport future.keywords.if\\n\\n# call to deprecated `any` built-in function\\nallow if any([input.user.is_admin, input.user.is_root])\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nimport future.keywords.if\\n\\nallow if input.user.is_admin\\nallow if input.user.is_root\\n```\\n\\n## Rationale\\n\\nCalling deprecated built-in functions should always be avoided, and replacing them is usually trivial.\\n\\n## Replacing Deprecated Built-in Functions\\n\\n### `any`\\n\\nUse the `in` keyword (OPA v0.34.0+) to replace the `any` function:\\n\\n**Instead of**\\n```rego\\na := any([input.foo, input.bar])\\n```\\n\\n**Do this**\\n```rego\\nimport future.keywords.in # or `import rego.v1` (OPA v0.59.0+)\\n\\na := true in [input.foo, input.bar]\\n```\\n\\nUsing `in` additionally has the benefit that it can be used to check for any type of value, and not just boolean\\n`true`!\\n\\n### `all`\\n\\nUse the `every` keyword (OPA v0.34.0+) to replace the `all` function:\\n\\n**Instead of**\\n```rego\\na {\\n all([input.foo, input.bar])\\n}\\n```\\n\\n**Do this**\\n```rego\\nimport future.keywords.every # or `import rego.v1` (OPA v0.59.0+)\\n\\na {\\n every x in [input.foo, input.bar] {\\n x == true\\n }\\n}\\n```\\n\\nJust like `in` may be used for much more than `any`, `every` can be used to evaluate complex expressions!\\n\\n### `set_diff`\\n\\nUse the minus (`-`) operator instead, of `set_diff`:\\n\\n**Instead of**\\n```rego\\na := set_diff(s1, s2)\\n```\\n\\n**Do this**\\n```rego\\na := s1 - s2\\n```\\n\\n### `re_match` and `net.cidr_overlap`\\n\\nThese built-in function were renamed `regex.match` and `net.cidr_intersects` respectively, so simply use the new names\\ninstead.\\n\\n### `cast_array`, `cast_set`, `cast_string`, `cast_boolean`, `cast_null`, `cast_object`\\n\\nUse the `is_X` equivalent built-in function in their place:\\n\\n**Instead of**\\n```rego\\na {\\n cast_string(input.name)\\n}\\n```\\n\\n**Do this**\\n```rego\\na {\\n is_string(input.name)\\n}\\n```\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n deprecated-builtin:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Strict Mode](https://www.openpolicyagent.org/docs/policy-language/#strict-mode)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/deprecated-builtin/deprecated_builtin.rego)\\n","id":"bugs/deprecated-builtin"},{"filePath":"projects/regal/rules/bugs/constant-condition.md","content":"# constant-condition\\n\\n**Summary**: Constant condition\\n\\n**Category**: Bugs\\n\\n**Automatically fixable**: [Yes](https://www.openpolicyagent.org/projects/regal/fixing)\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\nallow if {\\n 1 == 1\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nallow := true\\n```\\n\\n## Rationale\\n\\nWhile most often a mistake, constant conditions are sometimes used as placeholders, or \\"TODO logic\\". While this is\\nharmless, it has no place in production policy, and should be replaced or removed before deployment.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n constant-condition:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\
1n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/constant-condition/constant_condition.rego)\\n","id":"bugs/constant-condition"},{"filePath":"projects/regal/rules/bugs/argument-always-wildcard.md","content":"# argument-always-wildcard\\n\\n**Summary**: Argument is always a wildcard\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\n# there\'s only one definition of the last_name function in\\n# this package, and the second argument is never used\\nlast_name(name, _) := lname if {\\n parts := split(name, \\" \\")\\n lname := parts[count(parts) - 1]\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\nlast_name(name) := lname if {\\n parts := split(name, \\" \\")\\n lname := parts[count(parts) - 1]\\n}\\n```\\n\\n## Rationale\\n\\nFunction definitions may use wildcard variables as arguments to indicate that the value is not used in the body of\\nthe function. This helps make the function definition more readable, as it\'s immediately clear which of the arguments\\nare used in that definition of the function. This is particularly useful for incrementally defined functions:\\n\\n```rego\\npackage policy\\n\\ndefault authorized(_, _) := false\\n\\nauthorized(user, _) if {\\n # some logic to determine if authorized\\n}\\n\\n# or\\n\\nauthorized(user, _) if {\\n # some further logic to determine if authorized\\n}\\n```\\n\\nIn the example above, the second argument is a wildcard in all definitions, and could just as well be removed for a\\ncleaner definition. More likely, the argument was meant to be _used_, if only in one of the definitions:\\n\\n```rego\\npackage policy\\n\\ndefault authorized(_, _) := false\\n\\nauthorized(user, _) if {\\n # some logic to determine if authorized\\n}\\n\\n# or\\n\\nauthorized(_, request) if {\\n # some further logic to determine if authorized\\n}\\n```\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n argument-always-wildcard:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n # function name patterns for which this rule should make an exception\\n # default is to ignore any function name starting with \\"mock_\\" as these\\n # commonly don\'t need named arguments\\n except-function-name-pattern: \\"^mock_\\"\\n```\\n\\n## Related Resources\\n\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/argument-always-wildcard/argument_always_wildcard.rego)\\n","id":"bugs/argument-always-wildcard"},{"filePath":"projects/regal/rules/bugs/annotation-without-metadata.md","content":"# annotation-without-metadata\\n\\n**Summary**: Annotation without metadata\\n\\n**Category**: Bugs\\n\\n**Avoid**\\n```rego\\npackage policy\\n\\n# description: allow allows\\nallow if {\\n # ... some conditions\\n}\\n```\\n\\n**Prefer**\\n```rego\\npackage policy\\n\\n# METADATA\\n# description: allow allows\\nallow if {\\n # ... some conditions\\n}\\n```\\n\\n## Rationale\\n\\nA comment that starts with `<annotation-attribute>:` but is not part of a metadata block is likely a mistake. Add\\n`# METADATA` above the line to turn it into a\\n[metadata](https://www.openpolicyagent.org/docs/policy-language/#annotations) block.\\n\\n## Configuration Options\\n\\nThis linter rule provides the following configuration options:\\n\\n```yaml\\nrules:\\n bugs:\\n annotation-without-metadata:\\n # one of \\"error\\", \\"warning\\", \\"ignore\\"\\n level: error\\n```\\n\\n## Related Resources\\n\\n- OPA Docs: [Annotations](https://www.openpolicyagent.org/docs/policy-language/#annotations)\\n- GitHub: [Source Code](https://github.com/open-policy-agent/regal/blob/main/bundle/regal/rules/bugs/annotation-without-metadata/annotation_without_metadata.rego)\\n","id":"bugs/annotation-without-metadata"}]')},90676:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>u,contentTitle:()=>l,default:()=>p,frontMatter:()=>s,metadata:()=>t,toc:()=>c});const t=JSON.parse('{"id":"rules/idiomatic/index","title":"Idiomatic","description":"Idiomatic | Regal","source":"@site/projects/regal/rules/idiomatic/index.md","sourceDirName":"rules/idiomatic","slug":"/rules/idiomatic/","permalink":"/projects/regal/rules/idiomatic/","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":2,"frontMatter":{"title":"Idiomatic","sidebar_label":"Idiomatic","sidebar_position":2},"sidebar":"autoSidebar","previous":{"title":"zero-arity-function","permalink":"/projects/regal/rules/bugs/zero-arity-function"},"next":{"title":"ambiguous-scope","permalink":"/projects/regal/rules/idiomatic/ambiguou
1s-scope"}}');var i=o(74848),r=o(28453),a=o(2943);const s={title:"Idiomatic",sidebar_label:"Idiomatic",sidebar_position:2},l="Idiomatic",u={},c=[];function d(e){const n={h1:"h1",header:"header",p:"p",...(0,r.R)(),...e.components},{Head:o}=n;return o||function(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Head",!0),(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(o,{children:(0,i.jsx)("title",{children:"Idiomatic | Regal"})}),"\n",(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"idiomatic",children:"Idiomatic"})}),"\n",(0,i.jsx)(n.p,{children:"Rules that enforce idiomatic code."}),"\n","\n",(0,i.jsx)(a.A,{category:"idiomatic"})]})}function p(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.