From 42cab8c5aa84c1702948978b6d95c4c37fb6907f Mon Sep 17 00:00:00 2001 From: Anders Eknert Date: Tue, 13 Feb 2024 23:25:38 +0100 Subject: [PATCH] Rule: `with-outside-test-context` This also introduces a new `performance` category. Fixes #548 Signed-off-by: Anders Eknert --- README.md | 131 +++++++++--------- bundle/regal/config/provided/data.yaml | 3 + bundle/regal/main.rego | 2 + .../with_outside_test_context.rego | 18 +++ .../with_outside_test_context_test.rego | 51 +++++++ .../performance/with-outside-test-context.md | 98 +++++++++++++ e2e/testdata/violations/most_violations.rego | 6 + 7 files changed, 244 insertions(+), 65 deletions(-) create mode 100644 bundle/regal/rules/performance/with_outside_test_context.rego create mode 100644 bundle/regal/rules/performance/with_outside_test_context_test.rego create mode 100644 docs/rules/performance/with-outside-test-context.md diff --git a/README.md b/README.md index ea800603..7ef96583 100644 --- a/README.md +++ b/README.md @@ -188,71 +188,72 @@ The following rules are currently available: -| Category | Title | Description | -|-----------|-----------------------------------------------------------------------------------------------------|-----------------------------------------------------------| -| bugs | [constant-condition](https://docs.styra.com/regal/rules/bugs/constant-condition) | Constant condition | -| bugs | [deprecated-builtin](https://docs.styra.com/regal/rules/bugs/deprecated-builtin) | Avoid using deprecated built-in functions | -| bugs | [duplicate-rule](https://docs.styra.com/regal/rules/bugs/duplicate-rule) | Duplicate rule | -| bugs | [if-empty-object](https://docs.styra.com/regal/rules/bugs/if-empty-object) | Empty object following `if` | -| bugs | [inconsistent-args](https://docs.styra.com/regal/rules/bugs/inconsistent-args) | Inconsistently named function arguments | -| bugs | [invalid-metadata-attribute](https://docs.styra.com/regal/rules/bugs/invalid-metadata-attribute) | Invalid attribute in metadata annotation | -| bugs | [not-equals-in-loop](https://docs.styra.com/regal/rules/bugs/not-equals-in-loop) | Use of != in loop | -| bugs | [redundant-existence-check](https://docs.styra.com/regal/rules/bugs/redundant-existence-check) | Redundant existence check | -| bugs | [rule-named-if](https://docs.styra.com/regal/rules/bugs/rule-named-if) | Rule named "if" | -| bugs | [rule-shadows-builtin](https://docs.styra.com/regal/rules/bugs/rule-shadows-builtin) | Rule name shadows built-in | -| bugs | [top-level-iteration](https://docs.styra.com/regal/rules/bugs/top-level-iteration) | Iteration in top-level assignment | -| bugs | [unused-return-value](https://docs.styra.com/regal/rules/bugs/unused-return-value) | Non-boolean return value unused | -| bugs | [zero-arity-function](https://docs.styra.com/regal/rules/bugs/zero-arity-function) | Avoid functions without args | -| custom | [forbidden-function-call](https://docs.styra.com/regal/rules/custom/forbidden-function-call) | Forbidden function call | -| custom | [naming-convention](https://docs.styra.com/regal/rules/custom/naming-convention) | Naming convention violation | -| custom | [one-liner-rule](https://docs.styra.com/regal/rules/custom/one-liner-rule) | Rule body could be made a one-liner | -| custom | [prefer-value-in-head](https://docs.styra.com/regal/rules/custom/prefer-value-in-head) | Prefer value in rule head | -| idiomatic | [boolean-assignment](https://docs.styra.com/regal/rules/idiomatic/boolean-assignment) | Prefer `if` over boolean assignment | -| idiomatic | [custom-has-key-construct](https://docs.styra.com/regal/rules/idiomatic/custom-has-key-construct) | Custom function may be replaced by `in` and `object.keys` | -| idiomatic | [custom-in-construct](https://docs.styra.com/regal/rules/idiomatic/custom-in-construct) | Custom function may be replaced by `in` keyword | -| idiomatic | [equals-pattern-matching](https://docs.styra.com/regal/rules/idiomatic/equals-pattern-matching) | Prefer pattern matching in function arguments | -| idiomatic | [no-defined-entrypoint](https://docs.styra.com/regal/rules/idiomatic/no-defined-entrypoint) | Missing entrypoint annotation | -| idiomatic | [non-raw-regex-pattern](https://docs.styra.com/regal/rules/idiomatic/non-raw-regex-pattern) | Use raw strings for regex patterns | -| idiomatic | [prefer-set-or-object-rule](https://docs.styra.com/regal/rules/idiomatic/prefer-set-or-object-rule) | Prefer set or object rule over comprehension | -| idiomatic | [use-contains](https://docs.styra.com/regal/rules/idiomatic/use-contains) | Use the `contains` keyword | -| idiomatic | [use-if](https://docs.styra.com/regal/rules/idiomatic/use-if) | Use the `if` keyword | -| idiomatic | [use-in-operator](https://docs.styra.com/regal/rules/idiomatic/use-in-operator) | Use in to check for membership | -| idiomatic | [use-some-for-output-vars](https://docs.styra.com/regal/rules/idiomatic/use-some-for-output-vars) | Use `some` to declare output variables | -| imports | [avoid-importing-input](https://docs.styra.com/regal/rules/imports/avoid-importing-input) | Avoid importing input | -| imports | [implicit-future-keywords](https://docs.styra.com/regal/rules/imports/implicit-future-keywords) | Use explicit future keyword imports | -| imports | [import-after-rule](https://docs.styra.com/regal/rules/imports/import-after-rule) | Import declared after rule | -| imports | [import-shadows-builtin](https://docs.styra.com/regal/rules/imports/import-shadows-builtin) | Import shadows built-in namespace | -| imports | [import-shadows-import](https://docs.styra.com/regal/rules/imports/import-shadows-import) | Import shadows another import | -| imports | [prefer-package-imports](https://docs.styra.com/regal/rules/imports/prefer-package-imports) | Prefer importing packages over rules | -| imports | [redundant-alias](https://docs.styra.com/regal/rules/imports/redundant-alias) | Redundant alias | -| imports | [redundant-data-import](https://docs.styra.com/regal/rules/imports/redundant-data-import) | Redundant import of data | -| imports | [use-rego-v1](https://docs.styra.com/regal/rules/imports/use-rego-v1) | Use `import rego.v1` | -| style | [avoid-get-and-list-prefix](https://docs.styra.com/regal/rules/style/avoid-get-and-list-prefix) | Avoid `get_` and `list_` prefix for rules and functions | -| style | [chained-rule-body](https://docs.styra.com/regal/rules/style/chained-rule-body) | Avoid chaining rule bodies | -| style | [default-over-else](https://docs.styra.com/regal/rules/style/default-over-else) | Prefer default assignment over fallback else | -| style | [default-over-not](https://docs.styra.com/regal/rules/style/default-over-not) | Prefer default assignment over negated condition | -| style | [detached-metadata](https://docs.styra.com/regal/rules/style/detached-metadata) | Detached metadata annotation | -| style | [external-reference](https://docs.styra.com/regal/rules/style/external-reference) | Reference to input, data or rule ref in function body | -| style | [file-length](https://docs.styra.com/regal/rules/style/file-length) | Max file length exceeded | -| style | [function-arg-return](https://docs.styra.com/regal/rules/style/function-arg-return) | Function argument used for return value | -| style | [line-length](https://docs.styra.com/regal/rules/style/line-length) | Line too long | -| style | [no-whitespace-comment](https://docs.styra.com/regal/rules/style/no-whitespace-comment) | Comment should start with whitespace | -| style | [opa-fmt](https://docs.styra.com/regal/rules/style/opa-fmt) | File should be formatted with `opa fmt` | -| style | [prefer-snake-case](https://docs.styra.com/regal/rules/style/prefer-snake-case) | Prefer snake_case for names | -| style | [prefer-some-in-iteration](https://docs.styra.com/regal/rules/style/prefer-some-in-iteration) | Prefer `some .. in` for iteration | -| style | [rule-length](https://docs.styra.com/regal/rules/style/rule-length) | Max rule length exceeded | -| style | [todo-comment](https://docs.styra.com/regal/rules/style/todo-comment) | Avoid TODO comments | -| style | [unconditional-assignment](https://docs.styra.com/regal/rules/style/unconditional-assignment) | Unconditional assignment in rule body | -| style | [unnecessary-some](https://docs.styra.com/regal/rules/style/unnecessary-some) | Unnecessary use of `some` | -| style | [use-assignment-operator](https://docs.styra.com/regal/rules/style/use-assignment-operator) | Prefer := over = for assignment | -| style | [yoda-condition](https://docs.styra.com/regal/rules/style/yoda-condition) | Yoda condition | -| testing | [dubious-print-sprintf](https://docs.styra.com/regal/rules/testing/dubious-print-sprintf) | Dubious use of print and sprintf | -| testing | [file-missing-test-suffix](https://docs.styra.com/regal/rules/testing/file-missing-test-suffix) | Files containing tests should have a _test.rego suffix | -| testing | [identically-named-tests](https://docs.styra.com/regal/rules/testing/identically-named-tests) | Multiple tests with same name | -| testing | [metasyntactic-variable](https://docs.styra.com/regal/rules/testing/metasyntactic-variable) | Metasyntactic variable name | -| testing | [print-or-trace-call](https://docs.styra.com/regal/rules/testing/print-or-trace-call) | Call to print or trace function | -| testing | [test-outside-test-package](https://docs.styra.com/regal/rules/testing/test-outside-test-package) | Test outside of test package | -| testing | [todo-test](https://docs.styra.com/regal/rules/testing/todo-test) | TODO test encountered | +| Category | Title | Description | +|-------------|-------------------------------------------------------------------------------------------------------|-----------------------------------------------------------| +| bugs | [constant-condition](https://docs.styra.com/regal/rules/bugs/constant-condition) | Constant condition | +| bugs | [deprecated-builtin](https://docs.styra.com/regal/rules/bugs/deprecated-builtin) | Avoid using deprecated built-in functions | +| bugs | [duplicate-rule](https://docs.styra.com/regal/rules/bugs/duplicate-rule) | Duplicate rule | +| bugs | [if-empty-object](https://docs.styra.com/regal/rules/bugs/if-empty-object) | Empty object following `if` | +| bugs | [inconsistent-args](https://docs.styra.com/regal/rules/bugs/inconsistent-args) | Inconsistently named function arguments | +| bugs | [invalid-metadata-attribute](https://docs.styra.com/regal/rules/bugs/invalid-metadata-attribute) | Invalid attribute in metadata annotation | +| bugs | [not-equals-in-loop](https://docs.styra.com/regal/rules/bugs/not-equals-in-loop) | Use of != in loop | +| bugs | [redundant-existence-check](https://docs.styra.com/regal/rules/bugs/redundant-existence-check) | Redundant existence check | +| bugs | [rule-named-if](https://docs.styra.com/regal/rules/bugs/rule-named-if) | Rule named "if" | +| bugs | [rule-shadows-builtin](https://docs.styra.com/regal/rules/bugs/rule-shadows-builtin) | Rule name shadows built-in | +| bugs | [top-level-iteration](https://docs.styra.com/regal/rules/bugs/top-level-iteration) | Iteration in top-level assignment | +| bugs | [unused-return-value](https://docs.styra.com/regal/rules/bugs/unused-return-value) | Non-boolean return value unused | +| bugs | [zero-arity-function](https://docs.styra.com/regal/rules/bugs/zero-arity-function) | Avoid functions without args | +| custom | [forbidden-function-call](https://docs.styra.com/regal/rules/custom/forbidden-function-call) | Forbidden function call | +| custom | [naming-convention](https://docs.styra.com/regal/rules/custom/naming-convention) | Naming convention violation | +| custom | [one-liner-rule](https://docs.styra.com/regal/rules/custom/one-liner-rule) | Rule body could be made a one-liner | +| custom | [prefer-value-in-head](https://docs.styra.com/regal/rules/custom/prefer-value-in-head) | Prefer value in rule head | +| idiomatic | [boolean-assignment](https://docs.styra.com/regal/rules/idiomatic/boolean-assignment) | Prefer `if` over boolean assignment | +| idiomatic | [custom-has-key-construct](https://docs.styra.com/regal/rules/idiomatic/custom-has-key-construct) | Custom function may be replaced by `in` and `object.keys` | +| idiomatic | [custom-in-construct](https://docs.styra.com/regal/rules/idiomatic/custom-in-construct) | Custom function may be replaced by `in` keyword | +| idiomatic | [equals-pattern-matching](https://docs.styra.com/regal/rules/idiomatic/equals-pattern-matching) | Prefer pattern matching in function arguments | +| idiomatic | [no-defined-entrypoint](https://docs.styra.com/regal/rules/idiomatic/no-defined-entrypoint) | Missing entrypoint annotation | +| idiomatic | [non-raw-regex-pattern](https://docs.styra.com/regal/rules/idiomatic/non-raw-regex-pattern) | Use raw strings for regex patterns | +| idiomatic | [prefer-set-or-object-rule](https://docs.styra.com/regal/rules/idiomatic/prefer-set-or-object-rule) | Prefer set or object rule over comprehension | +| idiomatic | [use-contains](https://docs.styra.com/regal/rules/idiomatic/use-contains) | Use the `contains` keyword | +| idiomatic | [use-if](https://docs.styra.com/regal/rules/idiomatic/use-if) | Use the `if` keyword | +| idiomatic | [use-in-operator](https://docs.styra.com/regal/rules/idiomatic/use-in-operator) | Use in to check for membership | +| idiomatic | [use-some-for-output-vars](https://docs.styra.com/regal/rules/idiomatic/use-some-for-output-vars) | Use `some` to declare output variables | +| imports | [avoid-importing-input](https://docs.styra.com/regal/rules/imports/avoid-importing-input) | Avoid importing input | +| imports | [implicit-future-keywords](https://docs.styra.com/regal/rules/imports/implicit-future-keywords) | Use explicit future keyword imports | +| imports | [import-after-rule](https://docs.styra.com/regal/rules/imports/import-after-rule) | Import declared after rule | +| imports | [import-shadows-builtin](https://docs.styra.com/regal/rules/imports/import-shadows-builtin) | Import shadows built-in namespace | +| imports | [import-shadows-import](https://docs.styra.com/regal/rules/imports/import-shadows-import) | Import shadows another import | +| imports | [prefer-package-imports](https://docs.styra.com/regal/rules/imports/prefer-package-imports) | Prefer importing packages over rules | +| imports | [redundant-alias](https://docs.styra.com/regal/rules/imports/redundant-alias) | Redundant alias | +| imports | [redundant-data-import](https://docs.styra.com/regal/rules/imports/redundant-data-import) | Redundant import of data | +| imports | [use-rego-v1](https://docs.styra.com/regal/rules/imports/use-rego-v1) | Use `import rego.v1` | +| performance | [with-outside-test-context](https://docs.styra.com/regal/rules/performance/with-outside-test-context) | `with` used outside test context | +| style | [avoid-get-and-list-prefix](https://docs.styra.com/regal/rules/style/avoid-get-and-list-prefix) | Avoid `get_` and `list_` prefix for rules and functions | +| style | [chained-rule-body](https://docs.styra.com/regal/rules/style/chained-rule-body) | Avoid chaining rule bodies | +| style | [default-over-else](https://docs.styra.com/regal/rules/style/default-over-else) | Prefer default assignment over fallback else | +| style | [default-over-not](https://docs.styra.com/regal/rules/style/default-over-not) | Prefer default assignment over negated condition | +| style | [detached-metadata](https://docs.styra.com/regal/rules/style/detached-metadata) | Detached metadata annotation | +| style | [external-reference](https://docs.styra.com/regal/rules/style/external-reference) | Reference to input, data or rule ref in function body | +| style | [file-length](https://docs.styra.com/regal/rules/style/file-length) | Max file length exceeded | +| style | [function-arg-return](https://docs.styra.com/regal/rules/style/function-arg-return) | Function argument used for return value | +| style | [line-length](https://docs.styra.com/regal/rules/style/line-length) | Line too long | +| style | [no-whitespace-comment](https://docs.styra.com/regal/rules/style/no-whitespace-comment) | Comment should start with whitespace | +| style | [opa-fmt](https://docs.styra.com/regal/rules/style/opa-fmt) | File should be formatted with `opa fmt` | +| style | [prefer-snake-case](https://docs.styra.com/regal/rules/style/prefer-snake-case) | Prefer snake_case for names | +| style | [prefer-some-in-iteration](https://docs.styra.com/regal/rules/style/prefer-some-in-iteration) | Prefer `some .. in` for iteration | +| style | [rule-length](https://docs.styra.com/regal/rules/style/rule-length) | Max rule length exceeded | +| style | [todo-comment](https://docs.styra.com/regal/rules/style/todo-comment) | Avoid TODO comments | +| style | [unconditional-assignment](https://docs.styra.com/regal/rules/style/unconditional-assignment) | Unconditional assignment in rule body | +| style | [unnecessary-some](https://docs.styra.com/regal/rules/style/unnecessary-some) | Unnecessary use of `some` | +| style | [use-assignment-operator](https://docs.styra.com/regal/rules/style/use-assignment-operator) | Prefer := over = for assignment | +| style | [yoda-condition](https://docs.styra.com/regal/rules/style/yoda-condition) | Yoda condition | +| testing | [dubious-print-sprintf](https://docs.styra.com/regal/rules/testing/dubious-print-sprintf) | Dubious use of print and sprintf | +| testing | [file-missing-test-suffix](https://docs.styra.com/regal/rules/testing/file-missing-test-suffix) | Files containing tests should have a _test.rego suffix | +| testing | [identically-named-tests](https://docs.styra.com/regal/rules/testing/identically-named-tests) | Multiple tests with same name | +| testing | [metasyntactic-variable](https://docs.styra.com/regal/rules/testing/metasyntactic-variable) | Metasyntactic variable name | +| testing | [print-or-trace-call](https://docs.styra.com/regal/rules/testing/print-or-trace-call) | Call to print or trace function | +| testing | [test-outside-test-package](https://docs.styra.com/regal/rules/testing/test-outside-test-package) | Test outside of test package | +| testing | [todo-test](https://docs.styra.com/regal/rules/testing/todo-test) | TODO test encountered | diff --git a/bundle/regal/config/provided/data.yaml b/bundle/regal/config/provided/data.yaml index a1dcd457..db8abb58 100644 --- a/bundle/regal/config/provided/data.yaml +++ b/bundle/regal/config/provided/data.yaml @@ -79,6 +79,9 @@ rules: level: error use-rego-v1: level: error + performance: + with-outside-test-context: + level: error style: avoid-get-and-list-prefix: level: error diff --git a/bundle/regal/main.rego b/bundle/regal/main.rego index 3d56e078..2c1484b2 100644 --- a/bundle/regal/main.rego +++ b/bundle/regal/main.rego @@ -116,6 +116,7 @@ aggregate_report contains violation if { ["aggregates_internal"], ) + # regal ignore:with-outside-test-context some violation in data.regal.rules[category][title].aggregate_report with input as input_for_rule not ignored(violation, ignore_directives) @@ -137,6 +138,7 @@ aggregate_report contains violation if { ["aggregates_internal"], ) + # regal ignore:with-outside-test-context some violation in data.custom.regal.rules[category][title].aggregate_report with input as input_for_rule not ignored(violation, ignore_directives) diff --git a/bundle/regal/rules/performance/with_outside_test_context.rego b/bundle/regal/rules/performance/with_outside_test_context.rego new file mode 100644 index 00000000..470eb732 --- /dev/null +++ b/bundle/regal/rules/performance/with_outside_test_context.rego @@ -0,0 +1,18 @@ +# METADATA +# description: '`with` used outside test context' +package regal.rules.performance["with-outside-test-context"] + +import rego.v1 + +import data.regal.ast +import data.regal.result + +report contains violation if { + some rule in input.rules + some expr in rule.body + + expr["with"] + not strings.any_prefix_match(ast.name(rule), {"test_", "todo_test"}) + + violation := result.fail(rego.metadata.chain(), result.location(expr["with"][0])) +} diff --git a/bundle/regal/rules/performance/with_outside_test_context_test.rego b/bundle/regal/rules/performance/with_outside_test_context_test.rego new file mode 100644 index 00000000..d247533c --- /dev/null +++ b/bundle/regal/rules/performance/with_outside_test_context_test.rego @@ -0,0 +1,51 @@ +package regal.rules.performance["with-outside-test-context_test"] + +import rego.v1 + +import data.regal.ast +import data.regal.config + +import data.regal.rules.performance["with-outside-test-context"] as rule + +test_fail_with_used_outside_test if { + module := ast.with_rego_v1(` + allow if { + not foo.deny with input as {} + } + `) + + r := rule.report with input as module + r == {{ + "category": "performance", + "description": "`with` used outside test context", + "level": "error", + "location": {"col": 16, "file": "policy.rego", "row": 7, "text": "\t\tnot foo.deny with input as {}"}, + "related_resources": [{ + "description": "documentation", + "ref": config.docs.resolve_url("$baseUrl/$category/with-outside-test-context", "performance"), + }], + "title": "with-outside-test-context", + }} +} + +test_success_with_used_in_test if { + module := ast.with_rego_v1(` + test_foo_deny if { + not foo.deny with input as {} + } + `) + + r := rule.report with input as module + r == set() +} + +test_success_with_used_in_todo_test if { + module := ast.with_rego_v1(` + todo_test_foo_deny if { + not foo.deny with input as {} + } + `) + + r := rule.report with input as module + r == set() +} diff --git a/docs/rules/performance/with-outside-test-context.md b/docs/rules/performance/with-outside-test-context.md new file mode 100644 index 00000000..373321f5 --- /dev/null +++ b/docs/rules/performance/with-outside-test-context.md @@ -0,0 +1,98 @@ +# with-outside-test-context + +**Summary**: `with` used outside of test context + +**Category**: Performance + +**Avoid** +```rego +package policy + +import rego.v1 + +allow if { + some user in data.users + + # mock input to pass data to `allowed_user` rule + allowed_user with input as {"user": user} +} + +verified := io.jwt.verify_rs256(input.token, data.keys.verification_key) + +allowed_user := input.user if { + # this expensive rule will be evaluated for each user! + verified + "admin" in input.user.roles +} +``` + +**Prefer** +```rego +package policy + +import rego.v1 + +allow if { + some user in data.users + + allowed_user({"user": user}) +} + +verified := io.jwt.verify_rs256(input.token, data.keys.verification_key) + +allowed_user(user) := user if { + # this expensive rule will be evaluated only once + verified + "admin" in input.user.roles +} +``` + +## Rationale + +The `with` keyword exists primarily as a way to easily mock `input` or `data` in unit tests. While it's not forbidden to +use `with` in other contexts, and it's occasionally useful to do so, `with` is not optimized for performance and can +easily result in increased evaluation time if not used with care. + +One optimization that OPA does all the time is to cache the result of rule evaluation. If OPA needs to evaluate the same +rule more than once as part of evaluating a query, the result of the first evaluation is memorized and the cost of +subsequent evaluations is essentially zero. Caching however assumes that the conditions that produced the result of the +first evaluation won't _change_ — and changing the conditions (i.e. `input` or `data`) for evaluation is the very +purpose of `with`! This means that rules evaluated in the context of `with` won't be cached, and an expensive operation, +like the `io.jwt.verify_rs256` built-in function called in the examples above would be evaluated for each `user` in +`data.users`, even if the `with` clause in this case doesn't change any value that the JWT verification function depends +on. + +## Exceptions + +The obvious exception is stated already in the title of this rule: unit tests! Use `with` as much as want here, as that +is what `with` is for. + +Using `with` outside the context of unit tests is most commonly seen in policies using +[dynamic policy composition](https://www.styra.com/blog/dynamic-policy-composition-for-opa/), which typically involves +a "main" policy dispatching to a number of other policies and aggregating the result of evaluating each one. In this +scenario it's quite common to need to alter either `input` or `data` before evaluating a policy or rule, and `with` is +commonly used for this purpose. If you need to use `with` outside of tests, make sure that rules evaluated frequently +are done so outside of the scope of `with` to avoid performance issues. + +## Configuration Options + +This linter rule provides the following configuration options: + +```yaml +rules: + performance: + with-outside-test-context: + # one of "error", "warning", "ignore" + level: error +``` + +## Related Resources + +- OPA Docs: [With Keyword](https://www.openpolicyagent.org/docs/latest/policy-language/#with-keyword) +- Styra Blog: [Dynamic Policy Composition for OPA](https://www.styra.com/blog/dynamic-policy-composition-for-opa/) + +## Community + +If you think you've found a problem with this rule or its documentation, would like to suggest improvements, new rules, +or just talk about Regal in general, please join us in the `#regal` channel in the Styra Community +[Slack](https://communityinviter.com/apps/styracommunity/signup)! diff --git a/e2e/testdata/violations/most_violations.rego b/e2e/testdata/violations/most_violations.rego index 0c10e78a..c257e6b2 100644 --- a/e2e/testdata/violations/most_violations.rego +++ b/e2e/testdata/violations/most_violations.rego @@ -220,3 +220,9 @@ foo := "bar" y if { print(sprintf("name is: %s domain is: %s", [input.name, input.domain])) } + +### Performance + +with_outside_test if { + foo with input as {} +}