diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9d57a290..869964c3 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -14,7 +14,7 @@ updates: interval: "monthly" ignore: # update OPA manually to bump version in README too - - dependency-name: "github.com/open-policy-agent/opa" + - dependency-name: "github.com/open-policy-agent/opa/v1" groups: dependencies: patterns: diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 0c587548..3b8579d0 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -63,8 +63,8 @@ jobs: - uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1 if: matrix.os.name == 'linux' with: - version: v1.61.0 - - uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 + version: v1.63.1 + - uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 with: name: regal-${{ matrix.os.name }} path: regal diff --git a/.golangci.yaml b/.golangci.yaml index 7f783c30..2d886b4b 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -11,7 +11,6 @@ linters: - testpackage - goconst - gochecknoinits - - gomnd - mnd - inamedparam - err113 @@ -21,7 +20,6 @@ linters: - ireturn - funlen - gomoddirectives # need replacements for wasip1 - - execinquery # deprecated - exportloopref # deprecated linters-settings: tagliatelle: diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..cbba26f0 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,40 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "regal lint bundle", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}", + "args": [ + "lint", + "--enable-print", + "bundle" + ] + }, + { + "name": "regal fix --dry-run bundle", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}", + "args": [ + "fix", + "--dry-run", + "bundle" + ] + }, + { + "name": "regal test bundle", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}", + "args": [ + "test", + "bundle" + ] + } + ] +} diff --git a/README.md b/README.md index df30e478..361ab3c8 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,14 @@ development, whether you're an experienced Rego developer or just starting out. \- [Merriam Webster](https://www.merriam-webster.com/dictionary/regal) +## **New!** Regal and OPA 1.0 + +OPA 1.0 was [just released](https://blog.openpolicyagent.org/announcing-opa-1-0-a-new-standard-for-policy-as-code-a6d8427ee828), +and starting from version v0.30.0, Regal supports working with both OPA 1.0 policies and Rego from earlier versions +of OPA. While everything should work without additional configuration, we recommend checking out our documentation on +using Regal with [OPA 1.0](https://docs.styra.com/regal/opa-one-dot-zero) for the best possible experience managing +projects of any given Rego version, or even a mix of them. + ## Goals - Deliver an outstanding policy development experience by providing the best possible tools for that purpose @@ -105,8 +113,6 @@ First, author some Rego! ```rego package authz -import rego.v1 - default allow = false allow if { @@ -292,7 +298,9 @@ The following rules are currently available: -By default, all rules except for those in the `custom` category are currently **enabled**. +Rules in all category except for those in `custom` are **enabled** by default. Some rules however — like `use-contains` +and `use-if` — are conditionally enabled only when a version of OPA/Rego before 1.0 is targeted. See the configuration +options below if you want to use Regal to lint "legacy" policies. **Aggregate Rules** @@ -387,6 +395,9 @@ project: # declares the 'main' and 'lib/jwt' directories as project roots - main - lib/jwt + # may also be provided as an object with additional options + - path: lib/legacy + rego-version: 0 ``` Regal will automatically search for a configuration file (`.regal/config.yaml`) in the current directory, and if not @@ -507,8 +518,6 @@ alternatively on the same line to the right of the expression: ```rego package policy -import rego.v1 - # regal ignore:prefer-snake-case camelCase := "yes" @@ -540,6 +549,37 @@ for the `regal lint` command: **Note:** all CLI flags override configuration provided in file. +## Configuring Rego Version + +From OPA 1.0 and onwards, it is no longer necessary to include `import rego.v1` in your policies in order to use +keywords like `if` and `contains`. Since Regal works with with both 1.0+ policies and older versions of Rego, the linter +will first try to parse a policy as 1.0 and if that fails, parse using "v0" rules. This process isn't 100% foolproof, +as some policies are valid in both versions. Additionally, parsing the same file multiple times adds some overhead that +can be skipped if the version is known beforehand. To help Regal determine (and enforce) the version of your policies, +the `rego-version` attribute can be set in the `project` configuration: + +```yaml +project: + # Rego version 1.0, set to 0 for pre-1.0 policies + rego-version: 1 +``` + +It is also possible to set the Rego version for individual project roots (see below for more information): + +```yaml +project: + roots: + - path: lib/legacy + rego-version: 0 + - path: main + rego-version: 1 +``` + +Additionally, Regal will scan the project for any `.manifest` files, and user any `rego_version` found in the manifest +for all policies under that directory. + +Note: the `rego-version` attribute in the configuration file has precedence over `rego_version` found in manifest files. + ## Project Roots While many projects consider the project's root directory (in editors often referred to as **workspace**) their @@ -790,6 +830,7 @@ in the near future: ### Linter +- [x] Full support for both OPA 1.0 policies and older versions of Rego - [ ] Allow remediation of more `style` category rules using the `regal fix` command - [ ] Add [unused-rule](https://github.com/StyraInc/regal/issues/358) linter - [x] Add [unused-output-variable](https://github.com/StyraInc/regal/issues/60) linter diff --git a/build/capabilities.json b/build/capabilities.json index f33379a9..9c4966cd 100644 --- a/build/capabilities.json +++ b/build/capabilities.json @@ -9,6 +9,7 @@ "decl": { "args": [ { + "description": "the number to take the absolute value of", "name": "x", "type": "number" } @@ -58,6 +59,7 @@ "decl": { "args": [ { + "description": "the first set", "name": "x", "of": { "type": "any" @@ -65,6 +67,7 @@ "type": "set" }, { + "description": "the second set", "name": "y", "of": { "type": "any" @@ -118,6 +121,7 @@ "decl": { "args": [ { + "description": "the first array", "dynamic": { "type": "any" }, @@ -125,6 +129,7 @@ "type": "array" }, { + "description": "the second array", "dynamic": { "type": "any" }, @@ -230,6 +235,7 @@ "decl": { "args": [ { + "description": "string to decode", "name": "x", "type": "string" } @@ -251,6 +257,7 @@ "decl": { "args": [ { + "description": "string to encode", "name": "x", "type": "string" } @@ -272,6 +279,7 @@ "decl": { "args": [ { + "description": "string to check", "name": "x", "type": "string" } @@ -293,6 +301,7 @@ "decl": { "args": [ { + "description": "string to decode", "name": "x", "type": "string" } @@ -314,6 +323,7 @@ "decl": { "args": [ { + "description": "string to encode", "name": "x", "type": "string" } @@ -335,6 +345,7 @@ "decl": { "args": [ { + "description": "string to encode", "name": "x", "type": "string" } @@ -353,15 +364,18 @@ "decl": { "args": [ { + "description": "the first integer", "name": "x", "type": "number" }, { + "description": "the second integer", "name": "y", "type": "number" } ], "result": { + "description": "the bitwise AND of `x` and `y`", "name": "z", "type": "number" }, @@ -374,15 +388,18 @@ "decl": { "args": [ { + "description": "the integer to shift", "name": "x", "type": "number" }, { + "description": "the number of bits to shift", "name": "s", "type": "number" } ], "result": { + "description": "the result of shifting `x` `s` bits to the left", "name": "z", "type": "number" }, @@ -395,11 +412,13 @@ "decl": { "args": [ { + "description": "the integer to negate", "name": "x", "type": "number" } ], "result": { + "description": "the bitwise negation of `x`", "name": "z", "type": "number" }, @@ -412,15 +431,18 @@ "decl": { "args": [ { + "description": "the first integer", "name": "x", "type": "number" }, { + "description": "the second integer", "name": "y", "type": "number" } ], "result": { + "description": "the bitwise OR of `x` and `y`", "name": "z", "type": "number" }, @@ -433,15 +455,18 @@ "decl": { "args": [ { + "description": "the integer to shift", "name": "x", "type": "number" }, { + "description": "the number of bits to shift", "name": "s", "type": "number" } ], "result": { + "description": "the result of shifting `x` `s` bits to the right", "name": "z", "type": "number" }, @@ -454,15 +479,18 @@ "decl": { "args": [ { + "description": "the first integer", "name": "x", "type": "number" }, { + "description": "the second integer", "name": "y", "type": "number" } ], "result": { + "description": "the bitwise XOR of `x` and `y`", "name": "z", "type": "number" }, @@ -598,6 +626,7 @@ "decl": { "args": [ { + "description": "string to use as a delimiter", "name": "delimiter", "type": "string" }, @@ -622,6 +651,7 @@ } ], "result": { + "description": "the joined string", "name": "output", "type": "string" }, @@ -831,6 +861,7 @@ "decl": { "args": [ { + "description": "input string", "name": "x", "type": "string" } @@ -879,6 +910,7 @@ "decl": { "args": [ { + "description": "input string", "name": "x", "type": "string" } @@ -897,6 +929,7 @@ "decl": { "args": [ { + "description": "input string", "name": "x", "type": "string" } @@ -1267,6 +1300,7 @@ "decl": { "args": [ { + "description": "glob pattern", "name": "pattern", "type": "string" }, @@ -1287,6 +1321,7 @@ "type": "any" }, { + "description": "string to match against `pattern`", "name": "match", "type": "string" } @@ -1305,6 +1340,7 @@ "decl": { "args": [ { + "description": "glob pattern", "name": "pattern", "type": "string" } @@ -1452,6 +1488,7 @@ "decl": { "args": [ { + "description": "the GraphQL query", "name": "query", "of": [ { @@ -1472,6 +1509,7 @@ "type": "any" }, { + "description": "the GraphQL schema", "name": "schema", "of": [ { @@ -1506,6 +1544,7 @@ "decl": { "args": [ { + "description": "the GraphQL query", "name": "query", "of": [ { @@ -1526,6 +1565,7 @@ "type": "any" }, { + "description": "the GraphQL schema", "name": "schema", "of": [ { @@ -1584,6 +1624,7 @@ "decl": { "args": [ { + "description": "the GraphQL query", "name": "query", "of": [ { @@ -1604,6 +1645,7 @@ "type": "any" }, { + "description": "the GraphQL schema", "name": "schema", "of": [ { @@ -1665,6 +1707,7 @@ "decl": { "args": [ { + "description": "GraphQL query string", "name": "query", "type": "string" } @@ -1691,6 +1734,7 @@ "decl": { "args": [ { + "description": "GraphQL schema string", "name": "schema", "type": "string" } @@ -1717,6 +1761,7 @@ "decl": { "args": [ { + "description": "the schema to verify", "name": "schema", "of": [ { @@ -1826,6 +1871,7 @@ "decl": { "args": [ { + "description": "string to encode", "name": "x", "type": "string" } @@ -1844,6 +1890,7 @@ "decl": { "args": [ { + "description": "the HTTP request object", "dynamic": { "key": { "type": "string" @@ -1857,6 +1904,7 @@ } ], "result": { + "description": "the HTTP response object", "dynamic": { "key": { "type": "any" @@ -2551,6 +2599,7 @@ "decl": { "args": [ { + "description": "input value", "name": "x", "type": "any" } @@ -2572,6 +2621,7 @@ "decl": { "args": [ { + "description": "input value", "name": "x", "type": "any" } @@ -2593,6 +2643,7 @@ "decl": { "args": [ { + "description": "input value", "name": "x", "type": "any" } @@ -2614,6 +2665,7 @@ "decl": { "args": [ { + "description": "input value", "name": "x", "type": "any" } @@ -2635,6 +2687,7 @@ "decl": { "args": [ { + "description": "input value", "name": "x", "type": "any" } @@ -2656,6 +2709,7 @@ "decl": { "args": [ { + "description": "input value", "name": "x", "type": "any" } @@ -2677,6 +2731,7 @@ "decl": { "args": [ { + "description": "input value", "name": "x", "type": "any" } @@ -2698,6 +2753,7 @@ "decl": { "args": [ { + "description": "object to filter", "dynamic": { "key": { "type": "any" @@ -2963,10 +3019,12 @@ "decl": { "args": [ { + "description": "the object to patch", "name": "object", "type": "any" }, { + "description": "the JSON patches to apply", "dynamic": { "dynamic": { "key": { @@ -3013,6 +3071,7 @@ "decl": { "args": [ { + "description": "object to remove paths from", "dynamic": { "key": { "type": "any" @@ -3231,6 +3290,7 @@ "decl": { "args": [ { + "description": "the set or array to be searched", "name": "collection", "of": [ { @@ -3266,6 +3326,7 @@ "decl": { "args": [ { + "description": "the set or array to be searched", "name": "collection", "of": [ { @@ -3409,15 +3470,18 @@ "decl": { "args": [ { + "description": "CIDR to check against", "name": "cidr", "type": "string" }, { + "description": "CIDR or IP to check", "name": "cidr_or_ip", "type": "string" } ], "result": { + "description": "`true` if `cidr_or_ip` is contained within `cidr`", "name": "result", "type": "boolean" }, @@ -3430,6 +3494,7 @@ "decl": { "args": [ { + "description": "CIDRs to check against", "name": "cidrs", "of": [ { @@ -3495,6 +3560,7 @@ "type": "any" }, { + "description": "CIDRs or IPs to check", "name": "cidrs_or_ips", "of": [ { @@ -3585,6 +3651,7 @@ "decl": { "args": [ { + "description": "CIDR to expand", "name": "cidr", "type": "string" } @@ -3606,15 +3673,18 @@ "decl": { "args": [ { + "description": "first CIDR", "name": "cidr1", "type": "string" }, { + "description": "second CIDR", "name": "cidr2", "type": "string" } ], "result": { + "description": "`true` if `cidr1` intersects with `cidr2`", "name": "result", "type": "boolean" }, @@ -3627,11 +3697,13 @@ "decl": { "args": [ { + "description": "CIDR to validate", "name": "cidr", "type": "string" } ], "result": { + "description": "`true` if `cidr` is a valid CIDR", "name": "result", "type": "boolean" }, @@ -3725,10 +3797,12 @@ "decl": { "args": [ { + "description": "the start of the range", "name": "a", "type": "number" }, { + "description": "the end of the range (inclusive)", "name": "b", "type": "number" } @@ -3750,14 +3824,17 @@ "decl": { "args": [ { + "description": "the start of the range", "name": "a", "type": "number" }, { + "description": "the end of the range (inclusive)", "name": "b", "type": "number" }, { + "description": "the step between numbers in the range", "name": "step", "type": "number" } @@ -3792,6 +3869,7 @@ "type": "object" }, { + "description": "keys to keep in `object`", "name": "keys", "of": [ { @@ -4033,6 +4111,7 @@ "decl": { "args": [ { + "description": "left-hand object", "dynamic": { "key": { "type": "any" @@ -4045,6 +4124,7 @@ "type": "object" }, { + "description": "right-hand object", "dynamic": { "key": { "type": "any" @@ -4071,6 +4151,7 @@ "decl": { "args": [ { + "description": "list of objects to merge", "dynamic": { "dynamic": { "key": { @@ -4194,6 +4275,7 @@ "decl": { "args": [ { + "description": "the set or array of numbers to multiply", "name": "collection", "of": [ { @@ -4229,6 +4311,7 @@ "decl": { "args": [ { + "description": "HTTP request object", "dynamic": { "key": { "type": "string" @@ -4241,6 +4324,7 @@ "type": "object" }, { + "description": "AWS configuration object", "dynamic": { "key": { "type": "string" @@ -4253,11 +4337,13 @@ "type": "object" }, { + "description": "nanoseconds since the epoch", "name": "time_ns", "type": "number" } ], "result": { + "description": "HTTP request object with `Authorization` header", "dynamic": { "key": { "type": "any" @@ -4281,10 +4367,12 @@ "decl": { "args": [ { + "description": "seed string for the random number", "name": "str", "type": "string" }, { + "description": "upper bound of the random number (exclusive)", "name": "n", "type": "number" } @@ -4337,6 +4425,7 @@ } ], "result": { + "description": "array of all matches", "dynamic": { "dynamic": { "type": "string" @@ -4387,15 +4476,18 @@ "decl": { "args": [ { + "description": "first glob-style regular expression", "name": "glob1", "type": "string" }, { + "description": "second glob-style regular expression", "name": "glob2", "type": "string" } ], "result": { + "description": "true if the intersection of `glob1` and `glob2` matches a non-empty set of non-empty strings", "name": "result", "type": "boolean" }, @@ -4414,6 +4506,7 @@ } ], "result": { + "description": "true if `pattern` is a valid regular expression", "name": "result", "type": "boolean" }, @@ -4437,6 +4530,7 @@ } ], "result": { + "description": "true if `value` matches `pattern`", "name": "result", "type": "boolean" }, @@ -4465,6 +4559,7 @@ } ], "result": { + "description": "string with replaced substrings", "name": "output", "type": "string" }, @@ -4525,6 +4620,7 @@ } ], "result": { + "description": "true if `value` matches the `template`", "name": "result", "type": "boolean" }, @@ -4575,6 +4671,7 @@ } ], "result": { + "description": "AST object for the Rego module", "dynamic": { "key": { "type": "string" @@ -4675,10 +4772,12 @@ "decl": { "args": [ { + "description": "first version string", "name": "a", "type": "string" }, { + "description": "second version string", "name": "b", "type": "string" } @@ -4697,6 +4796,7 @@ "decl": { "args": [ { + "description": "input to validate", "name": "vsn", "type": "any" } @@ -5070,6 +5170,7 @@ } ], "result": { + "description": "string with replaced substrings", "name": "output", "type": "string" }, @@ -5085,11 +5186,13 @@ "decl": { "args": [ { + "description": "string to reverse", "name": "x", "type": "string" } ], "result": { + "description": "reversed string", "name": "y", "type": "string" }, @@ -5105,6 +5208,7 @@ "decl": { "args": [ { + "description": "string to extract substring from", "name": "value", "type": "string" }, @@ -5136,6 +5240,7 @@ "decl": { "args": [ { + "description": "the set or array of numbers to sum", "name": "collection", "of": [ { @@ -5173,14 +5278,17 @@ "type": "number" }, { + "description": "number of years to add", "name": "years", "type": "number" }, { + "description": "number of months to add", "name": "months", "type": "number" }, { + "description": "number of days to add", "name": "days", "type": "number" } @@ -5291,6 +5399,7 @@ "decl": { "args": [ { + "description": "nanoseconds since the epoch; or a two-element array of the nanoseconds, and a timezone string", "name": "ns1", "of": [ { @@ -5311,6 +5420,7 @@ "type": "any" }, { + "description": "nanoseconds since the epoch; or a two-element array of the nanoseconds, and a timezone string", "name": "ns2", "of": [ { @@ -5470,6 +5580,7 @@ "decl": { "args": [ { + "description": "input string to parse in RFC3339 format", "name": "value", "type": "string" } @@ -5526,6 +5637,7 @@ "decl": { "args": [ { + "description": "value to convert", "name": "x", "of": [ { @@ -5545,6 +5657,7 @@ } ], "result": { + "description": "the numeric representation of `x`", "name": "num", "type": "number" }, @@ -5739,6 +5852,7 @@ "decl": { "args": [ { + "description": "input value", "name": "x", "type": "any" } @@ -5784,7 +5898,7 @@ }, { "name": "units.parse", - "description": "Converts strings like \"10G\", \"5K\", \"4M\", \"1500m\" and the like into a number.\nThis number can be a non-integer, such as 1.5, 0.22, etc. Supports standard metric decimal and\nbinary SI units (e.g., K, Ki, M, Mi, G, Gi etc.) m, K, M, G, T, P, and E are treated as decimal\nunits and Ki, Mi, Gi, Ti, Pi, and Ei are treated as binary units.\n\nNote that 'm' and 'M' are case-sensitive, to allow distinguishing between \"milli\" and \"mega\" units respectively. Other units are case-insensitive.", + "description": "Converts strings like \"10G\", \"5K\", \"4M\", \"1500m\", and the like into a number.\nThis number can be a non-integer, such as 1.5, 0.22, etc. Scientific notation is supported,\nallowing values such as \"1e-3K\" (1) or \"2.5e6M\" (2.5 million M).\n\nSupports standard metric decimal and binary SI units (e.g., K, Ki, M, Mi, G, Gi, etc.) where\nm, K, M, G, T, P, and E are treated as decimal units and Ki, Mi, Gi, Ti, Pi, and Ei are treated as\nbinary units.\n\nNote that 'm' and 'M' are case-sensitive to allow distinguishing between \"milli\" and \"mega\" units\nrespectively. Other units are case-insensitive.", "decl": { "args": [ { @@ -5803,7 +5917,7 @@ }, { "name": "units.parse_bytes", - "description": "Converts strings like \"10GB\", \"5K\", \"4mb\" into an integer number of bytes.\nSupports standard byte units (e.g., KB, KiB, etc.) KB, MB, GB, and TB are treated as decimal\nunits and KiB, MiB, GiB, and TiB are treated as binary units. The bytes symbol (b/B) in the\nunit is optional and omitting it wil give the same result (e.g. Mi and MiB).", + "description": "Converts strings like \"10GB\", \"5K\", \"4mb\", or \"1e6KB\" into an integer number of bytes.\n\nSupports standard byte units (e.g., KB, KiB, etc.) where KB, MB, GB, and TB are treated as decimal\nunits, and KiB, MiB, GiB, and TiB are treated as binary units. Scientific notation is supported,\nenabling values like \"1.5e3MB\" (1500MB) or \"2e6GiB\" (2 million GiB).\n\nThe bytes symbol (b/B) in the unit is optional; omitting it will yield the same result (e.g., \"Mi\"\nand \"MiB\" are equivalent).", "decl": { "args": [ { @@ -5851,6 +5965,7 @@ "decl": { "args": [ { + "description": "the URL-encoded string", "name": "x", "type": "string" } @@ -5905,6 +6020,7 @@ "decl": { "args": [ { + "description": "the string to encode", "name": "x", "type": "string" } @@ -5926,6 +6042,7 @@ "decl": { "args": [ { + "description": "the object to encode", "dynamic": { "key": { "type": "string" @@ -5969,6 +6086,7 @@ "decl": { "args": [ { + "description": "UUID string to parse", "name": "uuid", "type": "string" } @@ -5995,6 +6113,7 @@ "decl": { "args": [ { + "description": "seed string", "name": "k", "type": "string" } @@ -6017,6 +6136,7 @@ "decl": { "args": [ { + "description": "value to walk", "name": "x", "type": "any" } @@ -6158,15 +6278,7 @@ } } ], - "future_keywords": [ - "contains", - "every", - "if", - "in" - ], "features": [ - "rule_head_ref_string_prefixes", - "rule_head_refs", - "rego_v1_import" + "rego_v1" ] } diff --git a/build/simplecov/simplecov.rego b/build/simplecov/simplecov.rego index 91942cf6..e75115c4 100644 --- a/build/simplecov/simplecov.rego +++ b/build/simplecov/simplecov.rego @@ -4,8 +4,6 @@ # simplecov JSON, to be used for Codecov reports, et. al. package build.simplecov -import rego.v1 - # METADATA # entrypoint: true from_opa := {"coverage": _coverage} diff --git a/build/workflows/update_example_index.rego b/build/workflows/update_example_index.rego index 57581bd1..a673c88c 100644 --- a/build/workflows/update_example_index.rego +++ b/build/workflows/update_example_index.rego @@ -7,8 +7,6 @@ # ref: file:///./../../.github/workflows/update-example-index.yaml package build.workflows -import rego.v1 - # METADATA # entrypoint: true symbols := {"keywords": _keywords, "builtins": _builtins} diff --git a/bundle/.manifest b/bundle/.manifest index a54049c6..10b79d00 100644 --- a/bundle/.manifest +++ b/bundle/.manifest @@ -2,5 +2,6 @@ "roots": ["regal"], "metadata": { "name": "regal" - } + }, + "rego_version": 1 } diff --git a/bundle/regal/ast/ast.rego b/bundle/regal/ast/ast.rego index 5c5ac7f2..b5215fe2 100644 --- a/bundle/regal/ast/ast.rego +++ b/bundle/regal/ast/ast.rego @@ -4,8 +4,6 @@ # with OPA's AST, more recently in the form of RoAST package regal.ast -import rego.v1 - import data.regal.config import data.regal.util @@ -171,11 +169,11 @@ is_output_var(rule, var) if { } else if { not var.value in (rule_names | imported_identifiers) # regal ignore:external-reference - num_above := sum([1 | + num_above := count([1 | some above in find_vars_in_local_scope(rule, var.location) above.value == var.value ]) - num_some := sum([1 | + num_some := count([1 | some name in find_some_decl_names_in_scope(rule, var.location) name == var.value ]) diff --git a/bundle/regal/ast/ast_test.rego b/bundle/regal/ast/ast_test.rego index 51ae762a..96b8c913 100644 --- a/bundle/regal/ast/ast_test.rego +++ b/bundle/regal/ast/ast_test.rego @@ -1,7 +1,5 @@ package regal.ast_test -import rego.v1 - import data.regal.ast import data.regal.capabilities @@ -10,8 +8,6 @@ test_find_vars if { policy := ` package p - import rego.v1 - global := "foo" allow if { @@ -59,8 +55,6 @@ test_find_vars_comprehension_lhs if { policy := ` package p - import rego.v1 - allow if { a := [b | input[b]] c := {d | input[d]} @@ -84,8 +78,6 @@ test_find_vars_function_ret_return_args if { policy := ` package p - import rego.v1 - allow if { walk(input, [path, value]) } @@ -104,8 +96,6 @@ test_find_vars_function_ret_return_args if { test_function_decls_multiple_same_name if { policy := `package p - import rego.v1 - f(x) := x if true f(y) := y if false ` @@ -153,8 +143,6 @@ test_find_vars_in_local_scope if { policy := ` package p - import rego.v1 - global := "foo" allow if { @@ -191,8 +179,6 @@ test_find_vars_in_local_scope_complex_comprehension_term if { policy := ` package p - import rego.v1 - allow if { a := [{"b": b} | c := input[b]] }` @@ -213,8 +199,6 @@ test_find_names_in_scope if { policy := ` package p - import rego.v1 - bar := "baz" global := "foo" @@ -244,8 +228,6 @@ test_find_names_in_scope if { test_find_some_decl_names_in_scope if { policy := `package p - import rego.v1 - allow if { foo := 1 some x @@ -256,8 +238,8 @@ test_find_some_decl_names_in_scope if { module := regal.parse_module("p.rego", policy) - {"x"} == ast.find_some_decl_names_in_scope(module.rules[0], {"col": 1, "row": 8}) with input as module - {"x", "y", "z"} == ast.find_some_decl_names_in_scope(module.rules[0], {"col": 1, "row": 10}) with input as module + {"x"} == ast.find_some_decl_names_in_scope(module.rules[0], {"col": 1, "row": 6}) with input as module + {"x", "y", "z"} == ast.find_some_decl_names_in_scope(module.rules[0], {"col": 1, "row": 8}) with input as module } var_names(vars) := {var.value | some var in vars} @@ -334,8 +316,6 @@ test_ref_static_to_string if { test_rule_head_locations if { policy := `package policy -import rego.v1 - default allow := false allow if true @@ -353,10 +333,10 @@ ref_rule[foo] := true if { result := ast.rule_head_locations with input as regal.parse_module("p.rego", policy) result == { - "data.policy.allow": {{"col": 9, "row": 5}, {"col": 1, "row": 7}}, - "data.policy.reasons": {{"col": 1, "row": 9}, {"col": 1, "row": 10}}, - "data.policy.my_func": {{"col": 9, "row": 12}, {"col": 1, "row": 13}}, - "data.policy.ref_rule": {{"col": 1, "row": 15}}, + "data.policy.allow": {{"col": 9, "row": 3}, {"col": 1, "row": 5}}, + "data.policy.reasons": {{"col": 1, "row": 7}, {"col": 1, "row": 8}}, + "data.policy.my_func": {{"col": 9, "row": 10}, {"col": 1, "row": 11}}, + "data.policy.ref_rule": {{"col": 1, "row": 13}}, } } diff --git a/bundle/regal/ast/comments.rego b/bundle/regal/ast/comments.rego index f6e38697..b4529b3f 100644 --- a/bundle/regal/ast/comments.rego +++ b/bundle/regal/ast/comments.rego @@ -1,7 +1,5 @@ package regal.ast -import rego.v1 - import data.regal.util # METADATA diff --git a/bundle/regal/ast/imports.rego b/bundle/regal/ast/imports.rego index 94a7b96a..cd1fd321 100644 --- a/bundle/regal/ast/imports.rego +++ b/bundle/regal/ast/imports.rego @@ -1,7 +1,5 @@ package regal.ast -import rego.v1 - default imports := [] # METADATA diff --git a/bundle/regal/ast/imports_test.rego b/bundle/regal/ast/imports_test.rego index ec9425b9..44cf2301 100644 --- a/bundle/regal/ast/imports_test.rego +++ b/bundle/regal/ast/imports_test.rego @@ -1,7 +1,5 @@ package regal.ast_test -import rego.v1 - import data.regal.ast test_imports_keyword_rego_v1 if { diff --git a/bundle/regal/ast/keywords.rego b/bundle/regal/ast/keywords.rego index 2479c798..78ae2fac 100644 --- a/bundle/regal/ast/keywords.rego +++ b/bundle/regal/ast/keywords.rego @@ -1,7 +1,5 @@ package regal.ast -import rego.v1 - import data.regal.util # METADATA diff --git a/bundle/regal/ast/keywords_test.rego b/bundle/regal/ast/keywords_test.rego index 080b5a24..2feae215 100644 --- a/bundle/regal/ast/keywords_test.rego +++ b/bundle/regal/ast/keywords_test.rego @@ -1,7 +1,5 @@ package regal.ast_test -import rego.v1 - import data.regal.ast test_keywords_package if { @@ -24,7 +22,7 @@ test_keywords_package if { test_keywords_import if { policy := `package policy -import rego.v1` +import data.foo` kwds := ast.keywords with input as regal.parse_module("p.rego", policy) @@ -43,8 +41,6 @@ import rego.v1` test_keywords_if if { policy := `package policy -import rego.v1 - allow if { # if things true @@ -56,14 +52,14 @@ allow if { {"regal": {"file": {"lines": split(policy, "\n")}}}, ) - count(kwds) == 3 # lines with keywords + count(kwds) == 2 # lines with keywords _keyword_on_row( kwds, - 5, + 3, { "name": "if", - "location": {"row": 5, "col": 7}, + "location": {"row": 3, "col": 7}, }, ) } @@ -71,8 +67,6 @@ allow if { test_keywords_if_on_another_line if { policy := `package policy -import rego.v1 - allow contains { "foo": true, } if { @@ -86,14 +80,14 @@ allow contains { {"regal": {"file": {"lines": split(policy, "\n")}}}, ) - count(kwds) == 4 # lines with keywords + count(kwds) == 3 # lines with keywords _keyword_on_row( kwds, - 7, + 5, { "name": "if", - "location": {"row": 7, "col": 3}, + "location": {"row": 5, "col": 3}, }, ) } diff --git a/bundle/regal/ast/search.rego b/bundle/regal/ast/search.rego index 08b68ef9..47b70f34 100644 --- a/bundle/regal/ast/search.rego +++ b/bundle/regal/ast/search.rego @@ -1,7 +1,5 @@ package regal.ast -import rego.v1 - import data.regal.util _find_nested_vars(obj) := [value | diff --git a/bundle/regal/ast/search_test.rego b/bundle/regal/ast/search_test.rego index 67a54d02..f64a65ad 100644 --- a/bundle/regal/ast/search_test.rego +++ b/bundle/regal/ast/search_test.rego @@ -1,7 +1,5 @@ package regal.ast_test -import rego.v1 - import data.regal.ast test_exprs if { diff --git a/bundle/regal/ast/testing.rego b/bundle/regal/ast/testing.rego index 1ef895a4..dcdc6874 100644 --- a/bundle/regal/ast/testing.rego +++ b/bundle/regal/ast/testing.rego @@ -1,7 +1,5 @@ package regal.ast -import rego.v1 - # METADATA # description: parses provided policy with all future keywords imported. Primarily for testing. with_rego_v1(policy) := regal.parse_module("policy.rego", concat("", [ @@ -13,6 +11,15 @@ import rego.v1 policy, ])) +# METADATA +# description: parses provided policy with v0 syntax and no imports. Primarily for testing. +with_rego_v0(policy) := regal.parse_module("policy_v0.rego", concat("", [ + `package policy + +`, + policy, +])) + # METADATA # description: parse provided snippet with a generic package declaration added policy(snippet) := regal.parse_module("policy.rego", concat("", [ diff --git a/bundle/regal/capabilities/capabilities.rego b/bundle/regal/capabilities/capabilities.rego index a8338144..d3be6cb8 100644 --- a/bundle/regal/capabilities/capabilities.rego +++ b/bundle/regal/capabilities/capabilities.rego @@ -7,8 +7,6 @@ package regal.capabilities import data.regal.config -import rego.v1 - default provided := {} # METADATA @@ -35,6 +33,8 @@ has_if if "if" in config.capabilities.future_keywords has_if if has_rego_v1_feature +has_if if is_opa_v1 + # METADATA # description: true if the `contains` keyword is available # scope: document @@ -42,6 +42,12 @@ has_contains if "contains" in config.capabilities.future_keywords has_contains if has_rego_v1_feature +has_contains if is_opa_v1 + # METADATA # description: true if `rego.v1` is available has_rego_v1_feature if "rego_v1_import" in config.capabilities.features + +# METADATA +# description: true if `OPA 1.0+` policy is targeted +is_opa_v1 if "rego_v1" in config.capabilities.features diff --git a/bundle/regal/config/config.rego b/bundle/regal/config/config.rego index 9b5041b2..7550d175 100644 --- a/bundle/regal/config/config.rego +++ b/bundle/regal/config/config.rego @@ -6,8 +6,6 @@ # ignore package regal.config -import rego.v1 - # METADATA # description: the path prefix value set on the current linter instance # scope: document diff --git a/bundle/regal/config/config_test.rego b/bundle/regal/config/config_test.rego index e5280e62..9a76902b 100644 --- a/bundle/regal/config/config_test.rego +++ b/bundle/regal/config/config_test.rego @@ -1,7 +1,5 @@ package regal.config_test -import rego.v1 - import data.regal.config rules_config := {"rules": {"test": {"test-case": { diff --git a/bundle/regal/config/exclusion.rego b/bundle/regal/config/exclusion.rego index 76fa6f2f..1831f442 100644 --- a/bundle/regal/config/exclusion.rego +++ b/bundle/regal/config/exclusion.rego @@ -1,7 +1,5 @@ package regal.config -import rego.v1 - # METADATA # description: | # determines if file should be excluded, either because it's globally diff --git a/bundle/regal/config/exclusion_test.rego b/bundle/regal/config/exclusion_test.rego index 802fbab3..fba33ce4 100644 --- a/bundle/regal/config/exclusion_test.rego +++ b/bundle/regal/config/exclusion_test.rego @@ -1,7 +1,5 @@ package regal.config_test -import rego.v1 - import data.regal.config cases := { diff --git a/bundle/regal/lsp/codelens/codelens.rego b/bundle/regal/lsp/codelens/codelens.rego index 8104b7b6..f854fbd3 100644 --- a/bundle/regal/lsp/codelens/codelens.rego +++ b/bundle/regal/lsp/codelens/codelens.rego @@ -5,8 +5,6 @@ # - input: schema.regal.ast package regal.lsp.codelens -import rego.v1 - import data.regal.ast import data.regal.result import data.regal.util diff --git a/bundle/regal/lsp/codelens/codelens_test.rego b/bundle/regal/lsp/codelens/codelens_test.rego index 12f57623..67d95d86 100644 --- a/bundle/regal/lsp/codelens/codelens_test.rego +++ b/bundle/regal/lsp/codelens/codelens_test.rego @@ -1,7 +1,5 @@ package regal.lsp.codelens_test -import rego.v1 - import data.regal.lsp.codelens # regal ignore:rule-length diff --git a/bundle/regal/lsp/completion/kind/kind.rego b/bundle/regal/lsp/completion/kind/kind.rego index 6ede5b69..63715947 100644 --- a/bundle/regal/lsp/completion/kind/kind.rego +++ b/bundle/regal/lsp/completion/kind/kind.rego @@ -6,8 +6,6 @@ # ref: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionItemKind package regal.lsp.completion.kind -import rego.v1 - # METADATA # description: text text := 1 diff --git a/bundle/regal/lsp/completion/kind/kind_test.rego b/bundle/regal/lsp/completion/kind/kind_test.rego index 0a53dde9..9d0a3aec 100644 --- a/bundle/regal/lsp/completion/kind/kind_test.rego +++ b/bundle/regal/lsp/completion/kind/kind_test.rego @@ -1,7 +1,5 @@ package regal.lsp.completion.kind_test -import rego.v1 - import data.regal.lsp.completion.kind test_kind_for_coverage if { diff --git a/bundle/regal/lsp/completion/location/location.rego b/bundle/regal/lsp/completion/location/location.rego index e4ec995e..e3de5212 100644 --- a/bundle/regal/lsp/completion/location/location.rego +++ b/bundle/regal/lsp/completion/location/location.rego @@ -2,8 +2,6 @@ # description: various rules and functions related to location and position package regal.lsp.completion.location -import rego.v1 - import data.regal.ast import data.regal.util diff --git a/bundle/regal/lsp/completion/location/location_test.rego b/bundle/regal/lsp/completion/location/location_test.rego index 0e95f302..e3ca85ba 100644 --- a/bundle/regal/lsp/completion/location/location_test.rego +++ b/bundle/regal/lsp/completion/location/location_test.rego @@ -1,7 +1,5 @@ package regal.lsp.completion.location_test -import rego.v1 - import data.regal.ast import data.regal.capabilities diff --git a/bundle/regal/lsp/completion/main.rego b/bundle/regal/lsp/completion/main.rego index 745f210d..7732af2c 100644 --- a/bundle/regal/lsp/completion/main.rego +++ b/bundle/regal/lsp/completion/main.rego @@ -5,8 +5,6 @@ # under regal.lsp.completion.providers package regal.lsp.completion -import rego.v1 - # METADATA # description: main entry point for completion suggestions # entrypoint: true diff --git a/bundle/regal/lsp/completion/main_test.rego b/bundle/regal/lsp/completion/main_test.rego index 31503314..2c1ab46d 100644 --- a/bundle/regal/lsp/completion/main_test.rego +++ b/bundle/regal/lsp/completion/main_test.rego @@ -1,7 +1,5 @@ package regal.lsp.completion_test -import rego.v1 - import data.regal.lsp.completion test_completion_entrypoint if { diff --git a/bundle/regal/lsp/completion/providers/booleans/booleans.rego b/bundle/regal/lsp/completion/providers/booleans/booleans.rego index 5a4b5bf4..81f3f92d 100644 --- a/bundle/regal/lsp/completion/providers/booleans/booleans.rego +++ b/bundle/regal/lsp/completion/providers/booleans/booleans.rego @@ -2,8 +2,6 @@ # description: the boolean provider suggests `true`/`false` values where appropriate package regal.lsp.completion.providers.booleans -import rego.v1 - import data.regal.lsp.completion.kind import data.regal.lsp.completion.location diff --git a/bundle/regal/lsp/completion/providers/booleans/booleans_test.rego b/bundle/regal/lsp/completion/providers/booleans/booleans_test.rego index bda269d2..0abd0295 100644 --- a/bundle/regal/lsp/completion/providers/booleans/booleans_test.rego +++ b/bundle/regal/lsp/completion/providers/booleans/booleans_test.rego @@ -1,15 +1,11 @@ package regal.lsp.completion.providers.booleans_test -import rego.v1 - import data.regal.lsp.completion.providers.booleans as provider import data.regal.lsp.completion.providers.test_utils as utils test_suggested_in_head if { workspace := {"file:///p.rego": `package policy -import rego.v1 - allow := f`} regal_module := {"regal": { @@ -18,7 +14,7 @@ allow := f`} "lines": split(workspace["file:///p.rego"], "\n"), }, "context": {"location": { - "row": 5, + "row": 3, "col": 10, }}, }} @@ -35,8 +31,6 @@ allow := f`} test_suggested_in_body if { workspace := {"file:///p.rego": `package policy -import rego.v1 - allow if { foo := t }`} @@ -47,7 +41,7 @@ allow if { "lines": split(workspace["file:///p.rego"], "\n"), }, "context": {"location": { - "row": 6, + "row": 4, "col": 10, }}, }} @@ -64,8 +58,6 @@ allow if { test_suggested_after_equals if { workspace := {"file:///p.rego": `package policy -import rego.v1 - allow if { foo == t }`} @@ -76,7 +68,7 @@ allow if { "lines": split(workspace["file:///p.rego"], "\n"), }, "context": {"location": { - "row": 6, + "row": 4, "col": 10, }}, }} @@ -93,8 +85,6 @@ allow if { test_not_suggested_at_start if { workspace := {"file:///p.rego": `package policy -import rego.v1 - allow if { t }`} @@ -105,7 +95,7 @@ allow if { "lines": split(workspace["file:///p.rego"], "\n"), }, "context": {"location": { - "row": 6, + "row": 4, "col": 3, }}, }} diff --git a/bundle/regal/lsp/completion/providers/commonrule/commonrule.rego b/bundle/regal/lsp/completion/providers/commonrule/commonrule.rego index 99515266..2d868af8 100644 --- a/bundle/regal/lsp/completion/providers/commonrule/commonrule.rego +++ b/bundle/regal/lsp/completion/providers/commonrule/commonrule.rego @@ -3,8 +3,6 @@ # provides completions for common rule names, like 'allow' or 'deny' package regal.lsp.completion.providers.commonrule -import rego.v1 - import data.regal.lsp.completion.kind import data.regal.lsp.completion.location diff --git a/bundle/regal/lsp/completion/providers/commonrule/commonrule_test.rego b/bundle/regal/lsp/completion/providers/commonrule/commonrule_test.rego index f795783c..159278f0 100644 --- a/bundle/regal/lsp/completion/providers/commonrule/commonrule_test.rego +++ b/bundle/regal/lsp/completion/providers/commonrule/commonrule_test.rego @@ -1,7 +1,5 @@ package regal.lsp.completion.providers.commonrule_test -import rego.v1 - import data.regal.lsp.completion.providers.commonrule as provider import data.regal.lsp.completion.providers.test_utils as util diff --git a/bundle/regal/lsp/completion/providers/default/default.rego b/bundle/regal/lsp/completion/providers/default/default.rego index 52900094..b8e93d7e 100644 --- a/bundle/regal/lsp/completion/providers/default/default.rego +++ b/bundle/regal/lsp/completion/providers/default/default.rego @@ -2,8 +2,6 @@ # description: provides completion suggestions for the `default` keyword where applicable package regal.lsp.completion.providers["default"] -import rego.v1 - import data.regal.ast import data.regal.lsp.completion.kind diff --git a/bundle/regal/lsp/completion/providers/default/default_test.rego b/bundle/regal/lsp/completion/providers/default/default_test.rego index 144e8ce5..381c5d93 100644 --- a/bundle/regal/lsp/completion/providers/default/default_test.rego +++ b/bundle/regal/lsp/completion/providers/default/default_test.rego @@ -1,7 +1,5 @@ package regal.lsp.completion.providers.default_test -import rego.v1 - import data.regal.lsp.completion.providers["default"] as provider import data.regal.lsp.completion.providers.test_utils as util diff --git a/bundle/regal/lsp/completion/providers/import/import.rego b/bundle/regal/lsp/completion/providers/import/import.rego index 183482c8..449334b8 100644 --- a/bundle/regal/lsp/completion/providers/import/import.rego +++ b/bundle/regal/lsp/completion/providers/import/import.rego @@ -2,8 +2,6 @@ # description: provides completion suggestions for the `import` keyword where applicable package regal.lsp.completion.providers["import"] -import rego.v1 - import data.regal.lsp.completion.kind import data.regal.lsp.completion.location diff --git a/bundle/regal/lsp/completion/providers/import/import_test.rego b/bundle/regal/lsp/completion/providers/import/import_test.rego index d27d9232..c7cec930 100644 --- a/bundle/regal/lsp/completion/providers/import/import_test.rego +++ b/bundle/regal/lsp/completion/providers/import/import_test.rego @@ -1,7 +1,5 @@ package regal.lsp.completion.providers.import_test -import rego.v1 - import data.regal.lsp.completion.providers["import"] as provider import data.regal.lsp.completion.providers.test_utils as util diff --git a/bundle/regal/lsp/completion/providers/inputdotjson/inputdotjson.rego b/bundle/regal/lsp/completion/providers/inputdotjson/inputdotjson.rego index e59cbcd3..6e3b1dec 100644 --- a/bundle/regal/lsp/completion/providers/inputdotjson/inputdotjson.rego +++ b/bundle/regal/lsp/completion/providers/inputdotjson/inputdotjson.rego @@ -12,8 +12,6 @@ # `input.request.method, and so on package regal.lsp.completion.providers.inputdotjson -import rego.v1 - import data.regal.lsp.completion.kind import data.regal.lsp.completion.location diff --git a/bundle/regal/lsp/completion/providers/inputdotjson/inputdotjson_test.rego b/bundle/regal/lsp/completion/providers/inputdotjson/inputdotjson_test.rego index a9b505e1..63ad5428 100644 --- a/bundle/regal/lsp/completion/providers/inputdotjson/inputdotjson_test.rego +++ b/bundle/regal/lsp/completion/providers/inputdotjson/inputdotjson_test.rego @@ -1,7 +1,5 @@ package regal.lsp.completion.providers.inputdotjson_test -import rego.v1 - import data.regal.lsp.completion.providers.inputdotjson as provider # regal ignore:rule-length diff --git a/bundle/regal/lsp/completion/providers/locals/locals.rego b/bundle/regal/lsp/completion/providers/locals/locals.rego index 31485d58..3c0edac0 100644 --- a/bundle/regal/lsp/completion/providers/locals/locals.rego +++ b/bundle/regal/lsp/completion/providers/locals/locals.rego @@ -2,8 +2,6 @@ # description: provides completion suggestions for local symbols in scope package regal.lsp.completion.providers.locals -import rego.v1 - import data.regal.lsp.completion.kind import data.regal.lsp.completion.location diff --git a/bundle/regal/lsp/completion/providers/locals/locals_test.rego b/bundle/regal/lsp/completion/providers/locals/locals_test.rego index 8eb9b1b1..50328a3a 100644 --- a/bundle/regal/lsp/completion/providers/locals/locals_test.rego +++ b/bundle/regal/lsp/completion/providers/locals/locals_test.rego @@ -1,7 +1,5 @@ package regal.lsp.completion.providers.locals_test -import rego.v1 - import data.regal.util import data.regal.lsp.completion.providers.locals as provider diff --git a/bundle/regal/lsp/completion/providers/package/package.rego b/bundle/regal/lsp/completion/providers/package/package.rego index bd722ee2..df7c62f6 100644 --- a/bundle/regal/lsp/completion/providers/package/package.rego +++ b/bundle/regal/lsp/completion/providers/package/package.rego @@ -2,8 +2,6 @@ # description: provides completion suggestions for the `package` keyword where applicable package regal.lsp.completion.providers["package"] -import rego.v1 - import data.regal.lsp.completion.kind import data.regal.lsp.completion.location diff --git a/bundle/regal/lsp/completion/providers/package/package_test.rego b/bundle/regal/lsp/completion/providers/package/package_test.rego index 1ee6c00f..03243f4f 100644 --- a/bundle/regal/lsp/completion/providers/package/package_test.rego +++ b/bundle/regal/lsp/completion/providers/package/package_test.rego @@ -1,7 +1,5 @@ package regal.lsp.completion.providers.package_test -import rego.v1 - import data.regal.lsp.completion.providers["package"] as provider import data.regal.lsp.completion.providers.test_utils as util diff --git a/bundle/regal/lsp/completion/providers/packagename/packagename.rego b/bundle/regal/lsp/completion/providers/packagename/packagename.rego index 81619191..be9a7b90 100644 --- a/bundle/regal/lsp/completion/providers/packagename/packagename.rego +++ b/bundle/regal/lsp/completion/providers/packagename/packagename.rego @@ -4,8 +4,6 @@ # name based on the directory structure whre the file is located package regal.lsp.completion.providers.packagename -import rego.v1 - import data.regal.lsp.completion.kind import data.regal.lsp.completion.location diff --git a/bundle/regal/lsp/completion/providers/packagename/packagename_test.rego b/bundle/regal/lsp/completion/providers/packagename/packagename_test.rego index fba5d2aa..258bf7e9 100644 --- a/bundle/regal/lsp/completion/providers/packagename/packagename_test.rego +++ b/bundle/regal/lsp/completion/providers/packagename/packagename_test.rego @@ -1,7 +1,5 @@ package regal.lsp.completion.providers.packagename_test -import rego.v1 - import data.regal.lsp.completion.providers.packagename as provider test_package_name_completion_on_typing if { diff --git a/bundle/regal/lsp/completion/providers/regov1/regov1.rego b/bundle/regal/lsp/completion/providers/regov1/regov1.rego index e74d761d..15df96e1 100644 --- a/bundle/regal/lsp/completion/providers/regov1/regov1.rego +++ b/bundle/regal/lsp/completion/providers/regov1/regov1.rego @@ -4,8 +4,6 @@ # `rego.v1` following an `import` declaration package regal.lsp.completion.providers.regov1 -import rego.v1 - import data.regal.lsp.completion.kind import data.regal.lsp.completion.location @@ -13,6 +11,7 @@ import data.regal.lsp.completion.location # description: completion suggestion for rego.v1 items contains item if { not strings.any_prefix_match(input.regal.file.lines, "import rego.v1") + not input.regal.context.rego_version == 3 # the rego.v1 import is not used in v1 rego position := location.to_position(input.regal.context.location) line := input.regal.file.lines[position.line] diff --git a/bundle/regal/lsp/completion/providers/regov1/regov1_test.rego b/bundle/regal/lsp/completion/providers/regov1/regov1_test.rego index d3120705..a9069fba 100644 --- a/bundle/regal/lsp/completion/providers/regov1/regov1_test.rego +++ b/bundle/regal/lsp/completion/providers/regov1/regov1_test.rego @@ -1,7 +1,5 @@ package regal.lsp.completion.providers.regov1_test -import rego.v1 - import data.regal.lsp.completion.providers.test_utils as util import data.regal.lsp.completion.providers.regov1 as provider @@ -10,7 +8,7 @@ test_regov1_completion_on_typing if { policy := `package policy import r` - items := provider.items with input as util.input_with_location(policy, {"row": 3, "col": 9}) + items := provider.items with input as util.input_with_location_and_version(policy, {"row": 3, "col": 9}, 0) items == {{ "label": "rego.v1", "kind": 9, @@ -35,7 +33,7 @@ test_regov1_completion_on_invoked if { policy := `package policy import ` - items := provider.items with input as util.input_with_location(policy, {"row": 3, "col": 8}) + items := provider.items with input as util.input_with_location_and_version(policy, {"row": 3, "col": 8}, 0) items == {{ "label": "rego.v1", "kind": 9, @@ -62,6 +60,18 @@ test_no_regov1_completion_if_already_imported if { import rego.v1 import r` - items := provider.items with input as util.input_with_location(policy, {"row": 5, "col": 9}) + items := provider.items with input as util.input_with_location_and_version(policy, {"row": 5, "col": 9}, 0) + items == set() +} + +test_no_regov1_completion_if_v1_file if { + policy := `package policy + +import r` + items := provider.items with input as util.input_with_location_and_version( + policy, + {"row": 3, "col": 9}, + 3, # RegoV1 + ) items == set() } diff --git a/bundle/regal/lsp/completion/providers/rulerefs/rulerefs.rego b/bundle/regal/lsp/completion/providers/rulerefs/rulerefs.rego index d296d92f..457acce5 100644 --- a/bundle/regal/lsp/completion/providers/rulerefs/rulerefs.rego +++ b/bundle/regal/lsp/completion/providers/rulerefs/rulerefs.rego @@ -2,8 +2,6 @@ # description: provides completion suggestions for rules in the workspace package regal.lsp.completion.providers.rulerefs -import rego.v1 - import data.regal.ast import data.regal.lsp.completion.kind diff --git a/bundle/regal/lsp/completion/providers/rulerefs/rulerefs_test.rego b/bundle/regal/lsp/completion/providers/rulerefs/rulerefs_test.rego index c4b6e61d..6f17f910 100644 --- a/bundle/regal/lsp/completion/providers/rulerefs/rulerefs_test.rego +++ b/bundle/regal/lsp/completion/providers/rulerefs/rulerefs_test.rego @@ -1,7 +1,5 @@ package regal.lsp.completion.providers.rulerefs_test -import rego.v1 - import data.regal.ast import data.regal.lsp.completion.providers.rulerefs as provider diff --git a/bundle/regal/lsp/completion/providers/snippet/snippet.rego b/bundle/regal/lsp/completion/providers/snippet/snippet.rego index ba423fa2..9cd51c7b 100644 --- a/bundle/regal/lsp/completion/providers/snippet/snippet.rego +++ b/bundle/regal/lsp/completion/providers/snippet/snippet.rego @@ -8,8 +8,6 @@ # ref: https://code.visualstudio.com/docs/editor/userdefinedsnippets package regal.lsp.completion.providers.snippet -import rego.v1 - import data.regal.lsp.completion.kind import data.regal.lsp.completion.location diff --git a/bundle/regal/lsp/completion/providers/snippet/snippet_test.rego b/bundle/regal/lsp/completion/providers/snippet/snippet_test.rego index 959982a0..72f7e879 100644 --- a/bundle/regal/lsp/completion/providers/snippet/snippet_test.rego +++ b/bundle/regal/lsp/completion/providers/snippet/snippet_test.rego @@ -1,7 +1,5 @@ package regal.lsp.completion.providers.snippet_test -import rego.v1 - import data.regal.lsp.completion.providers.snippet as provider import data.regal.lsp.completion.providers.test_utils as util diff --git a/bundle/regal/lsp/completion/providers/test_utils/test_utils.rego b/bundle/regal/lsp/completion/providers/test_utils/test_utils.rego index 9e59124e..d0b9c712 100644 --- a/bundle/regal/lsp/completion/providers/test_utils/test_utils.rego +++ b/bundle/regal/lsp/completion/providers/test_utils/test_utils.rego @@ -2,8 +2,6 @@ # description: various helpers to be used for testing completions providers package regal.lsp.completion.providers.test_utils -import rego.v1 - # METADATA # description: returns a map of all parsed modules in the workspace parsed_modules(workspace) := {file_uri: parsed_module | @@ -30,3 +28,16 @@ input_with_location(policy, location) := {"regal": { }, "context": {"location": location}, }} + +# METADATA +# description: same as input_with_location but with option to set rego_version too +input_with_location_and_version(policy, location, rego_version) := {"regal": { + "file": { + "name": "p.rego", + "lines": split(policy, "\n"), + }, + "context": { + "location": location, + "rego_version": rego_version, + }, +}} diff --git a/bundle/regal/lsp/completion/ref_names.rego b/bundle/regal/lsp/completion/ref_names.rego index 5bbf471d..d0754698 100644 --- a/bundle/regal/lsp/completion/ref_names.rego +++ b/bundle/regal/lsp/completion/ref_names.rego @@ -1,7 +1,5 @@ package regal.lsp.completion -import rego.v1 - import data.regal.ast # METADATA diff --git a/bundle/regal/lsp/completion/ref_names_test.rego b/bundle/regal/lsp/completion/ref_names_test.rego index b7dd9fd3..450b4877 100644 --- a/bundle/regal/lsp/completion/ref_names_test.rego +++ b/bundle/regal/lsp/completion/ref_names_test.rego @@ -1,7 +1,5 @@ package regal.lsp.completion_test -import rego.v1 - import data.regal.ast import data.regal.capabilities diff --git a/bundle/regal/lsp/util/location/location.rego b/bundle/regal/lsp/util/location/location.rego index 24d55401..efcb5f36 100644 --- a/bundle/regal/lsp/util/location/location.rego +++ b/bundle/regal/lsp/util/location/location.rego @@ -2,8 +2,6 @@ # description: utility functions for dealing with location data in the LSP package regal.lsp.util.location -import rego.v1 - # METADATA # description: turns an AST location (with `end`` attribute) into an LSP range to_range(location) := { diff --git a/bundle/regal/main/main.rego b/bundle/regal/main/main.rego index 2337e1cc..0a58dca1 100644 --- a/bundle/regal/main/main.rego +++ b/bundle/regal/main/main.rego @@ -8,8 +8,6 @@ # scope of a single file package regal.main -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.util diff --git a/bundle/regal/main/main_test.rego b/bundle/regal/main/main_test.rego index 364c907c..a84fe15c 100644 --- a/bundle/regal/main/main_test.rego +++ b/bundle/regal/main/main_test.rego @@ -1,7 +1,5 @@ package regal.main_test -import rego.v1 - import data.regal.config import data.regal.main import data.regal.util diff --git a/bundle/regal/regal.rego b/bundle/regal/regal.rego index 25ae13b4..ac3d8c47 100644 --- a/bundle/regal/regal.rego +++ b/bundle/regal/regal.rego @@ -7,5 +7,3 @@ # schemas: # - input: schema.regal.ast package regal - -import rego.v1 diff --git a/bundle/regal/result/result.rego b/bundle/regal/result/result.rego index 86a153df..16e02e38 100644 --- a/bundle/regal/result/result.rego +++ b/bundle/regal/result/result.rego @@ -6,8 +6,6 @@ # work across upgrades — i.e. if the result format changes package regal.result -import rego.v1 - import data.regal.config import data.regal.util diff --git a/bundle/regal/result/result_test.rego b/bundle/regal/result/result_test.rego index 72513fe4..c5b30cf7 100644 --- a/bundle/regal/result/result_test.rego +++ b/bundle/regal/result/result_test.rego @@ -1,7 +1,5 @@ package regal.result_test -import rego.v1 - import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/bugs/annotation-without-metadata/annotation_without_metadata.rego b/bundle/regal/rules/bugs/annotation-without-metadata/annotation_without_metadata.rego index 9391ef0f..3bed5279 100644 --- a/bundle/regal/rules/bugs/annotation-without-metadata/annotation_without_metadata.rego +++ b/bundle/regal/rules/bugs/annotation-without-metadata/annotation_without_metadata.rego @@ -2,8 +2,6 @@ # description: Annotation without metadata package regal.rules.bugs["annotation-without-metadata"] -import rego.v1 - import data.regal.ast import data.regal.result import data.regal.util diff --git a/bundle/regal/rules/bugs/annotation-without-metadata/annotation_without_metadata_test.rego b/bundle/regal/rules/bugs/annotation-without-metadata/annotation_without_metadata_test.rego index d3fea77a..421d8c5e 100644 --- a/bundle/regal/rules/bugs/annotation-without-metadata/annotation_without_metadata_test.rego +++ b/bundle/regal/rules/bugs/annotation-without-metadata/annotation_without_metadata_test.rego @@ -1,7 +1,5 @@ package regal.rules.bugs["annotation-without-metadata_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/bugs/argument-always-wildcard/argument_always_wildcard.rego b/bundle/regal/rules/bugs/argument-always-wildcard/argument_always_wildcard.rego index e0d5ffa4..1238daab 100644 --- a/bundle/regal/rules/bugs/argument-always-wildcard/argument_always_wildcard.rego +++ b/bundle/regal/rules/bugs/argument-always-wildcard/argument_always_wildcard.rego @@ -2,8 +2,6 @@ # description: Argument is always a wildcard package regal.rules.bugs["argument-always-wildcard"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/bugs/argument-always-wildcard/argument_always_wildcard_test.rego b/bundle/regal/rules/bugs/argument-always-wildcard/argument_always_wildcard_test.rego index 20c4692a..29f634fe 100644 --- a/bundle/regal/rules/bugs/argument-always-wildcard/argument_always_wildcard_test.rego +++ b/bundle/regal/rules/bugs/argument-always-wildcard/argument_always_wildcard_test.rego @@ -1,7 +1,5 @@ package regal.rules.bugs["argument-always-wildcard_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/bugs/constant-condition/constant_condition.rego b/bundle/regal/rules/bugs/constant-condition/constant_condition.rego index 1a6e01db..5aa275c1 100644 --- a/bundle/regal/rules/bugs/constant-condition/constant_condition.rego +++ b/bundle/regal/rules/bugs/constant-condition/constant_condition.rego @@ -2,8 +2,6 @@ # description: Constant condition package regal.rules.bugs["constant-condition"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/bugs/constant-condition/constant_condition_test.rego b/bundle/regal/rules/bugs/constant-condition/constant_condition_test.rego index fdb3bec5..f09e8a1c 100644 --- a/bundle/regal/rules/bugs/constant-condition/constant_condition_test.rego +++ b/bundle/regal/rules/bugs/constant-condition/constant_condition_test.rego @@ -1,14 +1,12 @@ package regal.rules.bugs["constant-condition_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.bugs["constant-condition"] as rule test_fail_simple_constant_condition if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { 1 }`) r == {{ @@ -30,16 +28,16 @@ test_success_rule_without_body if { } test_fail_rule_with_body_looking_generated if { - r := rule.report with input as ast.policy(`allow { true }`) + r := rule.report with input as ast.policy(`allow if { true }`) r == {{ "category": "bugs", "description": "Constant condition", "location": { "file": "policy.rego", - "col": 9, + "col": 12, "row": 3, - "end": {"row": 3, "col": 13}, - "text": "allow { true }", + "end": {"row": 3, "col": 16}, + "text": "allow if { true }", }, "related_resources": [{ "description": "documentation", @@ -51,7 +49,7 @@ test_fail_rule_with_body_looking_generated if { } test_fail_operator_constant_condition if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { 1 == 1 }`) r == {{ @@ -68,7 +66,7 @@ test_fail_operator_constant_condition if { } test_success_non_constant_condition if { - r := rule.report with input as ast.policy(`allow { 1 == input.one }`) + r := rule.report with input as ast.policy(`allow if { 1 == input.one }`) r == set() } diff --git a/bundle/regal/rules/bugs/deprecated-builtin/deprecated_builtin.rego b/bundle/regal/rules/bugs/deprecated-builtin/deprecated_builtin.rego index 1d9e9210..415b0e42 100644 --- a/bundle/regal/rules/bugs/deprecated-builtin/deprecated_builtin.rego +++ b/bundle/regal/rules/bugs/deprecated-builtin/deprecated_builtin.rego @@ -2,13 +2,24 @@ # description: Avoid using deprecated built-in functions package regal.rules.bugs["deprecated-builtin"] -import rego.v1 - import data.regal.ast +import data.regal.capabilities import data.regal.config import data.regal.result import data.regal.util +# METADATA +# description: | +# Since OPA 1.0, deprecated-builtin enabled only when provided a v0 policy, +# BUT please note that this may change in the future if new built-in functions +# are deprecated. +# custom: +# severity: none +notices contains result.notice(rego.metadata.chain()) if { + capabilities.is_opa_v1 + input.regal.file.rego_version != "v0" +} + report contains violation if { deprecated_builtins := { "any", "all", "re_match", "net.cidr_overlap", "set_diff", "cast_array", diff --git a/bundle/regal/rules/bugs/deprecated-builtin/deprecated_builtin_test.rego b/bundle/regal/rules/bugs/deprecated-builtin/deprecated_builtin_test.rego index f26bf329..02fcc43d 100644 --- a/bundle/regal/rules/bugs/deprecated-builtin/deprecated_builtin_test.rego +++ b/bundle/regal/rules/bugs/deprecated-builtin/deprecated_builtin_test.rego @@ -1,7 +1,5 @@ package regal.rules.bugs["deprecated-builtin_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/bugs/duplicate-rule/duplicate_rule.rego b/bundle/regal/rules/bugs/duplicate-rule/duplicate_rule.rego index 4a00d4d6..7b966dfd 100644 --- a/bundle/regal/rules/bugs/duplicate-rule/duplicate_rule.rego +++ b/bundle/regal/rules/bugs/duplicate-rule/duplicate_rule.rego @@ -2,8 +2,6 @@ # description: Duplicate rule package regal.rules.bugs["duplicate-rule"] -import rego.v1 - import data.regal.result import data.regal.util diff --git a/bundle/regal/rules/bugs/duplicate-rule/duplicate_rule_test.rego b/bundle/regal/rules/bugs/duplicate-rule/duplicate_rule_test.rego index 6eaef8b6..297fcde2 100644 --- a/bundle/regal/rules/bugs/duplicate-rule/duplicate_rule_test.rego +++ b/bundle/regal/rules/bugs/duplicate-rule/duplicate_rule_test.rego @@ -1,7 +1,5 @@ package regal.rules.bugs["duplicate-rule_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/bugs/if-empty-object/if_empty_object.rego b/bundle/regal/rules/bugs/if-empty-object/if_empty_object.rego index 23918f69..d19d6a40 100644 --- a/bundle/regal/rules/bugs/if-empty-object/if_empty_object.rego +++ b/bundle/regal/rules/bugs/if-empty-object/if_empty_object.rego @@ -2,8 +2,6 @@ # description: Empty object following `if` package regal.rules.bugs["if-empty-object"] -import rego.v1 - import data.regal.capabilities import data.regal.result diff --git a/bundle/regal/rules/bugs/if-empty-object/if_empty_object_test.rego b/bundle/regal/rules/bugs/if-empty-object/if_empty_object_test.rego index f35cb097..51511b64 100644 --- a/bundle/regal/rules/bugs/if-empty-object/if_empty_object_test.rego +++ b/bundle/regal/rules/bugs/if-empty-object/if_empty_object_test.rego @@ -1,7 +1,5 @@ package regal.rules.bugs["if-empty-object_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/bugs/if-object-literal/if_object_literal.rego b/bundle/regal/rules/bugs/if-object-literal/if_object_literal.rego index e2845184..229edb5f 100644 --- a/bundle/regal/rules/bugs/if-object-literal/if_object_literal.rego +++ b/bundle/regal/rules/bugs/if-object-literal/if_object_literal.rego @@ -2,8 +2,6 @@ # description: Object literal following `if` package regal.rules.bugs["if-object-literal"] -import rego.v1 - import data.regal.capabilities import data.regal.result diff --git a/bundle/regal/rules/bugs/if-object-literal/if_object_literal_test.rego b/bundle/regal/rules/bugs/if-object-literal/if_object_literal_test.rego index 8a324bc3..99703e66 100644 --- a/bundle/regal/rules/bugs/if-object-literal/if_object_literal_test.rego +++ b/bundle/regal/rules/bugs/if-object-literal/if_object_literal_test.rego @@ -1,7 +1,5 @@ package regal.rules.bugs["if-object-literal_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/bugs/impossible-not/impossible_not.rego b/bundle/regal/rules/bugs/impossible-not/impossible_not.rego index fb0bd076..a5ca6d05 100644 --- a/bundle/regal/rules/bugs/impossible-not/impossible_not.rego +++ b/bundle/regal/rules/bugs/impossible-not/impossible_not.rego @@ -2,8 +2,6 @@ # description: Impossible `not` condition package regal.rules.bugs["impossible-not"] -import rego.v1 - import data.regal.ast import data.regal.result import data.regal.util diff --git a/bundle/regal/rules/bugs/impossible-not/impossible_not_test.rego b/bundle/regal/rules/bugs/impossible-not/impossible_not_test.rego index 55e0d578..53f24aac 100644 --- a/bundle/regal/rules/bugs/impossible-not/impossible_not_test.rego +++ b/bundle/regal/rules/bugs/impossible-not/impossible_not_test.rego @@ -1,7 +1,5 @@ package regal.rules.bugs["impossible-not_test"] -import rego.v1 - import data.regal.config import data.regal.rules.bugs["impossible-not"] as rule diff --git a/bundle/regal/rules/bugs/inconsistent-args/inconsistent_args.rego b/bundle/regal/rules/bugs/inconsistent-args/inconsistent_args.rego index 9c9f1796..f98ccc95 100644 --- a/bundle/regal/rules/bugs/inconsistent-args/inconsistent_args.rego +++ b/bundle/regal/rules/bugs/inconsistent-args/inconsistent_args.rego @@ -2,8 +2,6 @@ # description: Inconsistently named function arguments package regal.rules.bugs["inconsistent-args"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/bugs/inconsistent-args/inconsistent_args_test.rego b/bundle/regal/rules/bugs/inconsistent-args/inconsistent_args_test.rego index 00f05635..6586a917 100644 --- a/bundle/regal/rules/bugs/inconsistent-args/inconsistent_args_test.rego +++ b/bundle/regal/rules/bugs/inconsistent-args/inconsistent_args_test.rego @@ -1,7 +1,5 @@ package regal.rules.bugs["inconsistent-args_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/bugs/internal-entrypoint/internal_entrypoint.rego b/bundle/regal/rules/bugs/internal-entrypoint/internal_entrypoint.rego index 930f3730..5246a2c9 100644 --- a/bundle/regal/rules/bugs/internal-entrypoint/internal_entrypoint.rego +++ b/bundle/regal/rules/bugs/internal-entrypoint/internal_entrypoint.rego @@ -2,8 +2,6 @@ # description: Entrypoint can't be marked internal package regal.rules.bugs["internal-entrypoint"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/bugs/internal-entrypoint/internal_entrypoint_test.rego b/bundle/regal/rules/bugs/internal-entrypoint/internal_entrypoint_test.rego index 51f3226c..6ec0793c 100644 --- a/bundle/regal/rules/bugs/internal-entrypoint/internal_entrypoint_test.rego +++ b/bundle/regal/rules/bugs/internal-entrypoint/internal_entrypoint_test.rego @@ -1,7 +1,5 @@ package regal.rules.bugs["internal-entrypoint_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/bugs/invalid-metadata-attribute/invalid_metadata_attribute.rego b/bundle/regal/rules/bugs/invalid-metadata-attribute/invalid_metadata_attribute.rego index e669add3..01d84a18 100644 --- a/bundle/regal/rules/bugs/invalid-metadata-attribute/invalid_metadata_attribute.rego +++ b/bundle/regal/rules/bugs/invalid-metadata-attribute/invalid_metadata_attribute.rego @@ -2,8 +2,6 @@ # description: Invalid attribute in metadata annotation package regal.rules.bugs["invalid-metadata-attribute"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/bugs/invalid-metadata-attribute/invalid_metadata_attribute_test.rego b/bundle/regal/rules/bugs/invalid-metadata-attribute/invalid_metadata_attribute_test.rego index e6ac016f..873518c2 100644 --- a/bundle/regal/rules/bugs/invalid-metadata-attribute/invalid_metadata_attribute_test.rego +++ b/bundle/regal/rules/bugs/invalid-metadata-attribute/invalid_metadata_attribute_test.rego @@ -1,7 +1,5 @@ package regal.rules.bugs["invalid-metadata-attribute_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.bugs["invalid-metadata-attribute"] as rule diff --git a/bundle/regal/rules/bugs/leaked-internal-reference/leaked_internal_reference.rego b/bundle/regal/rules/bugs/leaked-internal-reference/leaked_internal_reference.rego index c5d19df3..c8015e56 100644 --- a/bundle/regal/rules/bugs/leaked-internal-reference/leaked_internal_reference.rego +++ b/bundle/regal/rules/bugs/leaked-internal-reference/leaked_internal_reference.rego @@ -2,8 +2,6 @@ # description: Outside reference to internal rule or function package regal.rules.bugs["leaked-internal-reference"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/bugs/leaked-internal-reference/leaked_internal_reference_test.rego b/bundle/regal/rules/bugs/leaked-internal-reference/leaked_internal_reference_test.rego index 8dce576e..82d56934 100644 --- a/bundle/regal/rules/bugs/leaked-internal-reference/leaked_internal_reference_test.rego +++ b/bundle/regal/rules/bugs/leaked-internal-reference/leaked_internal_reference_test.rego @@ -1,7 +1,5 @@ package regal.rules.bugs["leaked-internal-reference_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/bugs/not-equals-in-loop/not_equals_in_loop.rego b/bundle/regal/rules/bugs/not-equals-in-loop/not_equals_in_loop.rego index 2eccac57..e0453969 100644 --- a/bundle/regal/rules/bugs/not-equals-in-loop/not_equals_in_loop.rego +++ b/bundle/regal/rules/bugs/not-equals-in-loop/not_equals_in_loop.rego @@ -2,8 +2,6 @@ # description: Use of != in loop package regal.rules.bugs["not-equals-in-loop"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/bugs/not-equals-in-loop/not_equals_in_loop_test.rego b/bundle/regal/rules/bugs/not-equals-in-loop/not_equals_in_loop_test.rego index c3628ed5..e231b4e1 100644 --- a/bundle/regal/rules/bugs/not-equals-in-loop/not_equals_in_loop_test.rego +++ b/bundle/regal/rules/bugs/not-equals-in-loop/not_equals_in_loop_test.rego @@ -1,14 +1,12 @@ package regal.rules.bugs["not-equals-in-loop_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.bugs["not-equals-in-loop"] as rule # regal ignore:rule-length test_fail_neq_in_loop if { - r := rule.report with input as ast.policy(`deny { + r := rule.report with input as ast.policy(`deny if { "admin" != input.user.groups[_] input.user.groups[_] != "admin" }`) diff --git a/bundle/regal/rules/bugs/redundant-existence-check/redundant_existence_check.rego b/bundle/regal/rules/bugs/redundant-existence-check/redundant_existence_check.rego index eeb79dde..7eae8fdc 100644 --- a/bundle/regal/rules/bugs/redundant-existence-check/redundant_existence_check.rego +++ b/bundle/regal/rules/bugs/redundant-existence-check/redundant_existence_check.rego @@ -2,8 +2,6 @@ # description: Redundant existence check package regal.rules.bugs["redundant-existence-check"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/bugs/redundant-existence-check/redundant_existence_check_test.rego b/bundle/regal/rules/bugs/redundant-existence-check/redundant_existence_check_test.rego index a13fe08c..b20d7315 100644 --- a/bundle/regal/rules/bugs/redundant-existence-check/redundant_existence_check_test.rego +++ b/bundle/regal/rules/bugs/redundant-existence-check/redundant_existence_check_test.rego @@ -1,7 +1,5 @@ package regal.rules.bugs["redundant-existence-check_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/bugs/rule-assigns-default/rule_assigns_default.rego b/bundle/regal/rules/bugs/rule-assigns-default/rule_assigns_default.rego index ef7eaaeb..ba0aa3fe 100644 --- a/bundle/regal/rules/bugs/rule-assigns-default/rule_assigns_default.rego +++ b/bundle/regal/rules/bugs/rule-assigns-default/rule_assigns_default.rego @@ -3,8 +3,6 @@ # description: Rule assigned its default value package regal.rules.bugs["rule-assigns-default"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/bugs/rule-assigns-default/rule_assigns_default_test.rego b/bundle/regal/rules/bugs/rule-assigns-default/rule_assigns_default_test.rego index 0fc070bc..06ee132f 100644 --- a/bundle/regal/rules/bugs/rule-assigns-default/rule_assigns_default_test.rego +++ b/bundle/regal/rules/bugs/rule-assigns-default/rule_assigns_default_test.rego @@ -1,7 +1,5 @@ package regal.rules.bugs["rule-assigns-default_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/bugs/rule-named-if/rule_named_if.rego b/bundle/regal/rules/bugs/rule-named-if/rule_named_if.rego index 956987b6..ebf17d5c 100644 --- a/bundle/regal/rules/bugs/rule-named-if/rule_named_if.rego +++ b/bundle/regal/rules/bugs/rule-named-if/rule_named_if.rego @@ -2,11 +2,19 @@ # description: Rule named "if" package regal.rules.bugs["rule-named-if"] -import rego.v1 - import data.regal.ast +import data.regal.capabilities import data.regal.result +# METADATA +# description: Since OPA 1.0, rule-named-if enabled only when provided a v0 policy +# custom: +# severity: none +notices contains result.notice(rego.metadata.chain()) if { + capabilities.is_opa_v1 + input.regal.file.rego_version != "v0" +} + report contains violation if { # this is only an optimization — as we already have collected all the rule # names, we'll do a fast lookup to know if we need to iterate over the rules diff --git a/bundle/regal/rules/bugs/rule-named-if/rule_named_if_test.rego b/bundle/regal/rules/bugs/rule-named-if/rule_named_if_test.rego index ec42a6b9..9e91ff7b 100644 --- a/bundle/regal/rules/bugs/rule-named-if/rule_named_if_test.rego +++ b/bundle/regal/rules/bugs/rule-named-if/rule_named_if_test.rego @@ -1,13 +1,12 @@ package regal.rules.bugs["rule-named-if_test"] -import rego.v1 - import data.regal.ast +import data.regal.capabilities import data.regal.config import data.regal.rules.bugs["rule-named-if"] as rule test_fail_rule_named_if if { - r := rule.report with input as ast.policy(` + r := rule.report with input as ast.with_rego_v0(` allow := true if { input.foo }`) @@ -18,7 +17,7 @@ test_fail_rule_named_if if { "level": "error", "location": { "col": 16, - "file": "policy.rego", + "file": "policy_v0.rego", "row": 4, "end": { "col": 18, @@ -31,5 +30,6 @@ test_fail_rule_named_if if { "ref": config.docs.resolve_url("$baseUrl/$category/rule-named-if", "bugs"), }], "title": "rule-named-if", - }} + }} with input.regal.file.rego_version as "v0" + with capabilities.is_opa_v1 as false } diff --git a/bundle/regal/rules/bugs/rule-shadows-builtin/rule_shadows_builtin.rego b/bundle/regal/rules/bugs/rule-shadows-builtin/rule_shadows_builtin.rego index 32b92a28..8b1018e1 100644 --- a/bundle/regal/rules/bugs/rule-shadows-builtin/rule_shadows_builtin.rego +++ b/bundle/regal/rules/bugs/rule-shadows-builtin/rule_shadows_builtin.rego @@ -2,8 +2,6 @@ # description: Rule name shadows built-in package regal.rules.bugs["rule-shadows-builtin"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/bugs/rule-shadows-builtin/rule_shadows_builtin_test.rego b/bundle/regal/rules/bugs/rule-shadows-builtin/rule_shadows_builtin_test.rego index 59344679..06cc7030 100644 --- a/bundle/regal/rules/bugs/rule-shadows-builtin/rule_shadows_builtin_test.rego +++ b/bundle/regal/rules/bugs/rule-shadows-builtin/rule_shadows_builtin_test.rego @@ -1,7 +1,5 @@ package regal.rules.bugs["rule-shadows-builtin_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.bugs["rule-shadows-builtin"] as rule diff --git a/bundle/regal/rules/bugs/sprintf-arguments-mismatch/sprintf_arguments_mismatch.rego b/bundle/regal/rules/bugs/sprintf-arguments-mismatch/sprintf_arguments_mismatch.rego index e180cb97..0f50baec 100644 --- a/bundle/regal/rules/bugs/sprintf-arguments-mismatch/sprintf_arguments_mismatch.rego +++ b/bundle/regal/rules/bugs/sprintf-arguments-mismatch/sprintf_arguments_mismatch.rego @@ -2,8 +2,6 @@ # description: Mismatch in `sprintf` arguments count package regal.rules.bugs["sprintf-arguments-mismatch"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/bugs/sprintf-arguments-mismatch/sprintf_arguments_mismatch_test.rego b/bundle/regal/rules/bugs/sprintf-arguments-mismatch/sprintf_arguments_mismatch_test.rego index a79fa8d1..b064693d 100644 --- a/bundle/regal/rules/bugs/sprintf-arguments-mismatch/sprintf_arguments_mismatch_test.rego +++ b/bundle/regal/rules/bugs/sprintf-arguments-mismatch/sprintf_arguments_mismatch_test.rego @@ -1,7 +1,5 @@ package regal.rules.bugs["sprintf-arguments-mismatch_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/bugs/top-level-iteration/top_level_iteration.rego b/bundle/regal/rules/bugs/top-level-iteration/top_level_iteration.rego index ebf0facf..81edca3f 100644 --- a/bundle/regal/rules/bugs/top-level-iteration/top_level_iteration.rego +++ b/bundle/regal/rules/bugs/top-level-iteration/top_level_iteration.rego @@ -2,8 +2,6 @@ # description: Iteration in top-level assignment package regal.rules.bugs["top-level-iteration"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/bugs/top-level-iteration/top_level_iteration_test.rego b/bundle/regal/rules/bugs/top-level-iteration/top_level_iteration_test.rego index 1bf65964..3249c282 100644 --- a/bundle/regal/rules/bugs/top-level-iteration/top_level_iteration_test.rego +++ b/bundle/regal/rules/bugs/top-level-iteration/top_level_iteration_test.rego @@ -1,7 +1,5 @@ package regal.rules.bugs["top-level-iteration_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/bugs/unassigned-return-value/unassigned_return_value.rego b/bundle/regal/rules/bugs/unassigned-return-value/unassigned_return_value.rego index 68c0716e..0bac3291 100644 --- a/bundle/regal/rules/bugs/unassigned-return-value/unassigned_return_value.rego +++ b/bundle/regal/rules/bugs/unassigned-return-value/unassigned_return_value.rego @@ -2,8 +2,6 @@ # description: Non-boolean return value unassigned package regal.rules.bugs["unassigned-return-value"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/bugs/unassigned-return-value/unassigned_return_value_test.rego b/bundle/regal/rules/bugs/unassigned-return-value/unassigned_return_value_test.rego index be441419..bf5a397e 100644 --- a/bundle/regal/rules/bugs/unassigned-return-value/unassigned_return_value_test.rego +++ b/bundle/regal/rules/bugs/unassigned-return-value/unassigned_return_value_test.rego @@ -1,7 +1,5 @@ package regal.rules.bugs["unassigned-return-value_test"] -import rego.v1 - import data.regal.ast import data.regal.capabilities import data.regal.config diff --git a/bundle/regal/rules/bugs/unused-output-variable/unused_output_variable.rego b/bundle/regal/rules/bugs/unused-output-variable/unused_output_variable.rego index a96345e0..d50b3f14 100644 --- a/bundle/regal/rules/bugs/unused-output-variable/unused_output_variable.rego +++ b/bundle/regal/rules/bugs/unused-output-variable/unused_output_variable.rego @@ -2,8 +2,6 @@ # description: Unused output variable package regal.rules.bugs["unused-output-variable"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/bugs/unused-output-variable/unused_output_variable_test.rego b/bundle/regal/rules/bugs/unused-output-variable/unused_output_variable_test.rego index 1b8a238f..6997f5ff 100644 --- a/bundle/regal/rules/bugs/unused-output-variable/unused_output_variable_test.rego +++ b/bundle/regal/rules/bugs/unused-output-variable/unused_output_variable_test.rego @@ -1,7 +1,5 @@ package regal.rules.bugs["unused-output-variable_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/bugs/var-shadows-builtin/var_shadows_builtin.rego b/bundle/regal/rules/bugs/var-shadows-builtin/var_shadows_builtin.rego index bb547665..418e44bd 100644 --- a/bundle/regal/rules/bugs/var-shadows-builtin/var_shadows_builtin.rego +++ b/bundle/regal/rules/bugs/var-shadows-builtin/var_shadows_builtin.rego @@ -2,8 +2,6 @@ # description: Variable name shadows built-in package regal.rules.bugs["var-shadows-builtin"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/bugs/var-shadows-builtin/var_shadows_builtin_test.rego b/bundle/regal/rules/bugs/var-shadows-builtin/var_shadows_builtin_test.rego index a79a2249..6fa0f63e 100644 --- a/bundle/regal/rules/bugs/var-shadows-builtin/var_shadows_builtin_test.rego +++ b/bundle/regal/rules/bugs/var-shadows-builtin/var_shadows_builtin_test.rego @@ -1,7 +1,5 @@ package regal.rules.bugs["var-shadows-builtin_test"] -import rego.v1 - import data.regal.ast import data.regal.capabilities import data.regal.config diff --git a/bundle/regal/rules/bugs/zero-arity-function/zero_arity_function.rego b/bundle/regal/rules/bugs/zero-arity-function/zero_arity_function.rego index 6d0f0845..f50e6162 100644 --- a/bundle/regal/rules/bugs/zero-arity-function/zero_arity_function.rego +++ b/bundle/regal/rules/bugs/zero-arity-function/zero_arity_function.rego @@ -2,8 +2,6 @@ # description: Avoid functions without args package regal.rules.bugs["zero-arity-function"] -import rego.v1 - import data.regal.ast import data.regal.result import data.regal.util diff --git a/bundle/regal/rules/bugs/zero-arity-function/zero_arity_function_test.rego b/bundle/regal/rules/bugs/zero-arity-function/zero_arity_function_test.rego index 4a213829..67794c4a 100644 --- a/bundle/regal/rules/bugs/zero-arity-function/zero_arity_function_test.rego +++ b/bundle/regal/rules/bugs/zero-arity-function/zero_arity_function_test.rego @@ -1,7 +1,5 @@ package regal.rules.bugs["zero-arity-function_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/custom/forbidden-function-call/forbidden_function_call.rego b/bundle/regal/rules/custom/forbidden-function-call/forbidden_function_call.rego index 5ca7a5f6..c3665670 100644 --- a/bundle/regal/rules/custom/forbidden-function-call/forbidden_function_call.rego +++ b/bundle/regal/rules/custom/forbidden-function-call/forbidden_function_call.rego @@ -2,8 +2,6 @@ # description: Forbidden function call package regal.rules.custom["forbidden-function-call"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/custom/forbidden-function-call/forbidden_function_call_test.rego b/bundle/regal/rules/custom/forbidden-function-call/forbidden_function_call_test.rego index 32b95077..e8a51b0f 100644 --- a/bundle/regal/rules/custom/forbidden-function-call/forbidden_function_call_test.rego +++ b/bundle/regal/rules/custom/forbidden-function-call/forbidden_function_call_test.rego @@ -1,7 +1,5 @@ package regal.rules.custom["forbidden-function-call_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/custom/missing-metadata/missing_metadata.rego b/bundle/regal/rules/custom/missing-metadata/missing_metadata.rego index 157e55c4..35bf8ede 100644 --- a/bundle/regal/rules/custom/missing-metadata/missing_metadata.rego +++ b/bundle/regal/rules/custom/missing-metadata/missing_metadata.rego @@ -2,8 +2,6 @@ # description: Package or rule missing metadata package regal.rules.custom["missing-metadata"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/custom/missing-metadata/missing_metadata_test.rego b/bundle/regal/rules/custom/missing-metadata/missing_metadata_test.rego index 722713b2..e11c67ff 100644 --- a/bundle/regal/rules/custom/missing-metadata/missing_metadata_test.rego +++ b/bundle/regal/rules/custom/missing-metadata/missing_metadata_test.rego @@ -1,7 +1,5 @@ package regal.rules.custom["missing-metadata_test"] -import rego.v1 - import data.regal.config import data.regal.rules.custom["missing-metadata"] as rule diff --git a/bundle/regal/rules/custom/naming-convention/naming_convention.rego b/bundle/regal/rules/custom/naming-convention/naming_convention.rego index b09e2840..d6707a65 100644 --- a/bundle/regal/rules/custom/naming-convention/naming_convention.rego +++ b/bundle/regal/rules/custom/naming-convention/naming_convention.rego @@ -2,8 +2,6 @@ # description: Naming convention violation package regal.rules.custom["naming-convention"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/custom/naming-convention/naming_convention_test.rego b/bundle/regal/rules/custom/naming-convention/naming_convention_test.rego index aa84635d..a382530b 100644 --- a/bundle/regal/rules/custom/naming-convention/naming_convention_test.rego +++ b/bundle/regal/rules/custom/naming-convention/naming_convention_test.rego @@ -1,7 +1,5 @@ package regal.rules.custom["naming-convention_test"] -import rego.v1 - import data.regal.ast import data.regal.capabilities import data.regal.config @@ -105,7 +103,7 @@ test_success_function_name_matches_pattern if { test_fail_var_name_does_not_match_pattern if { policy := ast.policy(` - allow { + allow if { fooBar := true fooBar == true } @@ -133,7 +131,7 @@ test_fail_var_name_does_not_match_pattern if { test_success_var_name_matches_pattern if { policy := ast.policy(` - allow { + allow if { some foo_bar input[foo_bar] foo_bar == "works" @@ -154,7 +152,7 @@ test_fail_multiple_conventions if { foo := true - bar { + bar if { fooBar := true fooBar == true } diff --git a/bundle/regal/rules/custom/one-liner-rule/one_liner_rule.rego b/bundle/regal/rules/custom/one-liner-rule/one_liner_rule.rego index 2e8dade1..b1c2fca2 100644 --- a/bundle/regal/rules/custom/one-liner-rule/one_liner_rule.rego +++ b/bundle/regal/rules/custom/one-liner-rule/one_liner_rule.rego @@ -2,9 +2,6 @@ # description: Rule body could be made a one-liner package regal.rules.custom["one-liner-rule"] -import rego.v1 - -import data.regal.ast import data.regal.capabilities import data.regal.config import data.regal.result @@ -17,9 +14,6 @@ import data.regal.util notices contains result.notice(rego.metadata.chain()) if not capabilities.has_if report contains violation if { - # No need to traverse rules here if we're not importing `if` - ast.imports_keyword(input.imports, "if") - # Note: this covers both rules and functions, which is what we want here some rule in input.rules diff --git a/bundle/regal/rules/custom/one-liner-rule/one_liner_rule_test.rego b/bundle/regal/rules/custom/one-liner-rule/one_liner_rule_test.rego index 4a38b0a4..6afa10f4 100644 --- a/bundle/regal/rules/custom/one-liner-rule/one_liner_rule_test.rego +++ b/bundle/regal/rules/custom/one-liner-rule/one_liner_rule_test.rego @@ -1,7 +1,5 @@ package regal.rules.custom["one-liner-rule_test"] -import rego.v1 - import data.regal.ast import data.regal.config @@ -10,8 +8,6 @@ import data.regal.rules.custom["one-liner-rule"] as rule test_fail_could_be_one_liner if { module := ast.policy(` - import rego.v1 - allow if { input.yes } @@ -20,10 +16,10 @@ test_fail_could_be_one_liner if { r == expected_with_location({ "col": 2, - "row": 7, + "row": 5, "end": { "col": 7, - "row": 7, + "row": 5, }, "text": "\tallow if {", }) @@ -32,8 +28,6 @@ test_fail_could_be_one_liner if { test_fail_could_be_one_liner_all_keywords if { module := ast.policy(` - import rego.v1 - allow if { input.yes } @@ -43,10 +37,10 @@ test_fail_could_be_one_liner_all_keywords if { r == expected_with_location({ "col": 2, "file": "policy.rego", - "row": 7, + "row": 5, "end": { "col": 7, - "row": 7, + "row": 5, }, "text": "\tallow if {", }) @@ -55,8 +49,6 @@ test_fail_could_be_one_liner_all_keywords if { test_fail_could_be_one_liner_allman_style if { module := ast.policy(` - import rego.v1 - allow if { input.yes @@ -66,26 +58,15 @@ test_fail_could_be_one_liner_allman_style if { r := rule.report with input as module with config.for_rule as {"level": "error"} r == expected_with_location({ "col": 2, - "row": 7, + "row": 5, "end": { "col": 7, - "row": 7, + "row": 5, }, "text": "\tallow if", }) } -test_success_if_not_imported if { - module := ast.policy(` - allow := true if { - 1 == 1 - } - `) - r := rule.report with input as module with config.for_rule as {"level": "error"} - - r == set() -} - test_success_too_long_for_a_one_liner if { module := ast.with_rego_v1(` rule := "quite a long text up here" if { @@ -143,10 +124,8 @@ test_success_no_one_liner_comment_in_rule_body_line_below if { r == set() } -# This will have to be gated with capability version -# later as this will be forced from 1.0 -test_success_does_not_use_if if { - module := ast.policy(` +test_success_does_not_use_if_v0 if { + module := ast.with_rego_v0(` allow { 1 == 1 } diff --git a/bundle/regal/rules/custom/prefer-value-in-head/prefer_value_in_head.rego b/bundle/regal/rules/custom/prefer-value-in-head/prefer_value_in_head.rego index 96ed56d7..ca739157 100644 --- a/bundle/regal/rules/custom/prefer-value-in-head/prefer_value_in_head.rego +++ b/bundle/regal/rules/custom/prefer-value-in-head/prefer_value_in_head.rego @@ -2,8 +2,6 @@ # description: Prefer value in rule head package regal.rules.custom["prefer-value-in-head"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/custom/prefer-value-in-head/prefer_value_in_head_test.rego b/bundle/regal/rules/custom/prefer-value-in-head/prefer_value_in_head_test.rego index 4ca75584..8b56d732 100644 --- a/bundle/regal/rules/custom/prefer-value-in-head/prefer_value_in_head_test.rego +++ b/bundle/regal/rules/custom/prefer-value-in-head/prefer_value_in_head_test.rego @@ -1,14 +1,12 @@ package regal.rules.custom["prefer-value-in-head_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.custom["prefer-value-in-head"] as rule test_fail_value_could_be_in_head_assign if { - module := ast.policy(`value := x { + module := ast.policy(`value := x if { input.x x := 10 }`) @@ -26,7 +24,7 @@ test_fail_value_could_be_in_head_assign if { } test_fail_value_could_be_in_head_assign_composite if { - module := ast.policy(`value := x { + module := ast.policy(`value := x if { input.x x := {"foo": 10} }`) @@ -44,13 +42,13 @@ test_fail_value_could_be_in_head_assign_composite if { } test_fail_value_is_in_head_assign if { - r := rule.report with input as ast.policy(`value := 10 { input.x }`) with config.for_rule as {"level": "error"} + r := rule.report with input as ast.policy(`value := 10 if { input.x }`) with config.for_rule as {"level": "error"} r == set() } test_fail_value_could_be_in_head_eq if { - module := ast.policy(`value := x { + module := ast.policy(`value := x if { input.x x = 10 }`) @@ -69,13 +67,13 @@ test_fail_value_could_be_in_head_eq if { } test_success_value_is_in_head_eq if { - r := rule.report with input as ast.policy(`value = x { input.x }`) with config.for_rule as {"level": "error"} + r := rule.report with input as ast.policy(`value = x if { input.x }`) with config.for_rule as {"level": "error"} r == set() } test_fail_value_could_be_in_head_but_not_a_scalar if { - module := ast.policy(`value := x { + module := ast.policy(`value := x if { input.x x := [i | i := input[_]] }`) @@ -85,7 +83,7 @@ test_fail_value_could_be_in_head_but_not_a_scalar if { } test_fail_value_could_be_in_head_and_is_a_scalar if { - module := ast.policy(`value := x { + module := ast.policy(`value := x if { input.x x := 5 }`) @@ -121,7 +119,7 @@ test_fail_value_could_be_in_head_multivalue_rule if { } test_fail_value_could_be_in_head_object_rule if { - module := ast.policy(`foo["bar"] := x { + module := ast.policy(`foo["bar"] := x if { input.foo x := "bar" }`) diff --git a/bundle/regal/rules/idiomatic/ambiguous-scope/ambiguous_scope.rego b/bundle/regal/rules/idiomatic/ambiguous-scope/ambiguous_scope.rego index 3500ce1c..97b4c245 100644 --- a/bundle/regal/rules/idiomatic/ambiguous-scope/ambiguous_scope.rego +++ b/bundle/regal/rules/idiomatic/ambiguous-scope/ambiguous_scope.rego @@ -2,8 +2,6 @@ # description: Ambiguous metadata scope package regal.rules.idiomatic["ambiguous-scope"] -import rego.v1 - import data.regal.ast import data.regal.result import data.regal.util diff --git a/bundle/regal/rules/idiomatic/ambiguous-scope/ambiguous_scope_test.rego b/bundle/regal/rules/idiomatic/ambiguous-scope/ambiguous_scope_test.rego index 368968d2..15492fae 100644 --- a/bundle/regal/rules/idiomatic/ambiguous-scope/ambiguous_scope_test.rego +++ b/bundle/regal/rules/idiomatic/ambiguous-scope/ambiguous_scope_test.rego @@ -1,7 +1,5 @@ package regal.rules.idiomatic["ambiguous-scope_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/idiomatic/boolean-assignment/boolean_assignment.rego b/bundle/regal/rules/idiomatic/boolean-assignment/boolean_assignment.rego index 95e96107..cf4de99e 100644 --- a/bundle/regal/rules/idiomatic/boolean-assignment/boolean_assignment.rego +++ b/bundle/regal/rules/idiomatic/boolean-assignment/boolean_assignment.rego @@ -2,8 +2,6 @@ # description: Prefer `if` over boolean assignment package regal.rules.idiomatic["boolean-assignment"] -import rego.v1 - import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/idiomatic/boolean-assignment/boolean_assignment_test.rego b/bundle/regal/rules/idiomatic/boolean-assignment/boolean_assignment_test.rego index fba9d1da..0d3e0834 100644 --- a/bundle/regal/rules/idiomatic/boolean-assignment/boolean_assignment_test.rego +++ b/bundle/regal/rules/idiomatic/boolean-assignment/boolean_assignment_test.rego @@ -1,7 +1,5 @@ package regal.rules.idiomatic["boolean-assignment_test"] -import rego.v1 - import data.regal.ast import data.regal.capabilities import data.regal.config diff --git a/bundle/regal/rules/idiomatic/custom-has-key-construct/custom_has_key_construct.rego b/bundle/regal/rules/idiomatic/custom-has-key-construct/custom_has_key_construct.rego index 00915f44..f8667a2d 100644 --- a/bundle/regal/rules/idiomatic/custom-has-key-construct/custom_has_key_construct.rego +++ b/bundle/regal/rules/idiomatic/custom-has-key-construct/custom_has_key_construct.rego @@ -2,8 +2,6 @@ # description: Custom function may be replaced by `in` and `object.keys` package regal.rules.idiomatic["custom-has-key-construct"] -import rego.v1 - import data.regal.ast import data.regal.capabilities import data.regal.result diff --git a/bundle/regal/rules/idiomatic/custom-has-key-construct/custom_has_key_construct_test.rego b/bundle/regal/rules/idiomatic/custom-has-key-construct/custom_has_key_construct_test.rego index 2422ab6e..14654cc8 100644 --- a/bundle/regal/rules/idiomatic/custom-has-key-construct/custom_has_key_construct_test.rego +++ b/bundle/regal/rules/idiomatic/custom-has-key-construct/custom_has_key_construct_test.rego @@ -1,13 +1,11 @@ package regal.rules.idiomatic["custom-has-key-construct_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.idiomatic["custom-has-key-construct"] as rule test_fail_custom_has_key if { - r := rule.report with input as ast.policy(`has_key(name, coll) { + r := rule.report with input as ast.policy(`has_key(name, coll) if { _ = coll[name] }`) @@ -23,7 +21,7 @@ test_fail_custom_has_key if { "col": 20, "row": 3, }, - "text": "has_key(name, coll) {", + "text": "has_key(name, coll) if {", }, "related_resources": [{ "description": "documentation", @@ -34,7 +32,7 @@ test_fail_custom_has_key if { } test_fail_custom_has_key_reversed if { - r := rule.report with input as ast.policy(`has_key(name, coll) { + r := rule.report with input as ast.policy(`has_key(name, coll) if { coll[name] = _ }`) @@ -50,7 +48,7 @@ test_fail_custom_has_key_reversed if { "col": 20, "row": 3, }, - "text": "has_key(name, coll) {", + "text": "has_key(name, coll) if {", }, "related_resources": [{ "description": "documentation", @@ -62,11 +60,11 @@ test_fail_custom_has_key_reversed if { test_fail_custom_has_key_multiple_wildcards if { r := rule.report with input as ast.policy(` - other_rule["foo"] { + other_rule contains "foo" if { wildcard := input[_] } - has_key(name, coll) { + has_key(name, coll) if { coll[name] = _ }`) @@ -82,7 +80,7 @@ test_fail_custom_has_key_multiple_wildcards if { "col": 21, "row": 8, }, - "text": "\thas_key(name, coll) {", + "text": "\thas_key(name, coll) if {", }, "related_resources": [{ "description": "documentation", diff --git a/bundle/regal/rules/idiomatic/custom-in-construct/custom_in_construct.rego b/bundle/regal/rules/idiomatic/custom-in-construct/custom_in_construct.rego index cc11f9da..42e2de1d 100644 --- a/bundle/regal/rules/idiomatic/custom-in-construct/custom_in_construct.rego +++ b/bundle/regal/rules/idiomatic/custom-in-construct/custom_in_construct.rego @@ -2,8 +2,6 @@ # description: Custom function may be replaced by `in` keyword package regal.rules.idiomatic["custom-in-construct"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/idiomatic/custom-in-construct/custom_in_construct_test.rego b/bundle/regal/rules/idiomatic/custom-in-construct/custom_in_construct_test.rego index 8fc5f91a..e7084da8 100644 --- a/bundle/regal/rules/idiomatic/custom-in-construct/custom_in_construct_test.rego +++ b/bundle/regal/rules/idiomatic/custom-in-construct/custom_in_construct_test.rego @@ -1,14 +1,12 @@ package regal.rules.idiomatic["custom-in-construct_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.idiomatic["custom-in-construct"] as rule test_fail_custom_in if { - r := rule.report with input as ast.policy(`has(item, coll) { + r := rule.report with input as ast.policy(`has(item, coll) if { item == coll[_] }`) @@ -24,7 +22,7 @@ test_fail_custom_in if { "col": 16, "row": 3, }, - "text": "has(item, coll) {", + "text": "has(item, coll) if {", }, "related_resources": [{ "description": "documentation", @@ -35,7 +33,7 @@ test_fail_custom_in if { } test_fail_custom_in_reversed if { - r := rule.report with input as ast.policy(`has(item, coll) { coll[_] == item }`) + r := rule.report with input as ast.policy(`has(item, coll) if { coll[_] == item }`) r == {{ "category": "idiomatic", @@ -49,7 +47,7 @@ test_fail_custom_in_reversed if { "col": 16, "row": 3, }, - "text": "has(item, coll) { coll[_] == item }", + "text": "has(item, coll) if { coll[_] == item }", }, "related_resources": [{ "description": "documentation", diff --git a/bundle/regal/rules/idiomatic/directory-package-mismatch/directory_package_mismatch.rego b/bundle/regal/rules/idiomatic/directory-package-mismatch/directory_package_mismatch.rego index 099df590..0213221e 100644 --- a/bundle/regal/rules/idiomatic/directory-package-mismatch/directory_package_mismatch.rego +++ b/bundle/regal/rules/idiomatic/directory-package-mismatch/directory_package_mismatch.rego @@ -2,8 +2,6 @@ # description: Directory structure should mirror package package regal.rules.idiomatic["directory-package-mismatch"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/idiomatic/directory-package-mismatch/directory_package_mismatch_test.rego b/bundle/regal/rules/idiomatic/directory-package-mismatch/directory_package_mismatch_test.rego index 39d7f125..22b9d145 100644 --- a/bundle/regal/rules/idiomatic/directory-package-mismatch/directory_package_mismatch_test.rego +++ b/bundle/regal/rules/idiomatic/directory-package-mismatch/directory_package_mismatch_test.rego @@ -1,7 +1,5 @@ package regal.rules.idiomatic["directory-package-mismatch_test"] -import rego.v1 - import data.regal.config import data.regal.rules.idiomatic["directory-package-mismatch"] as rule diff --git a/bundle/regal/rules/idiomatic/equals-pattern-matching/equals_pattern_matching.rego b/bundle/regal/rules/idiomatic/equals-pattern-matching/equals_pattern_matching.rego index 7617bf7b..5a627f66 100644 --- a/bundle/regal/rules/idiomatic/equals-pattern-matching/equals_pattern_matching.rego +++ b/bundle/regal/rules/idiomatic/equals-pattern-matching/equals_pattern_matching.rego @@ -2,8 +2,6 @@ # description: Prefer pattern matching in function arguments package regal.rules.idiomatic["equals-pattern-matching"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/idiomatic/equals-pattern-matching/equals_pattern_matching_test.rego b/bundle/regal/rules/idiomatic/equals-pattern-matching/equals_pattern_matching_test.rego index 398f1198..5e21ed0e 100644 --- a/bundle/regal/rules/idiomatic/equals-pattern-matching/equals_pattern_matching_test.rego +++ b/bundle/regal/rules/idiomatic/equals-pattern-matching/equals_pattern_matching_test.rego @@ -1,7 +1,5 @@ package regal.rules.idiomatic["equals-pattern-matching_test"] -import rego.v1 - import data.regal.ast import data.regal.config @@ -50,7 +48,7 @@ test_fail_simple_head_comparison_could_be_matched_in_arg_multiple_args if { } test_fail_simple_body_comparison_could_be_matched_in_arg if { - r := rule.report with input as ast.policy(`f(x) := "one" { + r := rule.report with input as ast.policy(`f(x) := "one" if { x == 1 }`) @@ -61,12 +59,12 @@ test_fail_simple_body_comparison_could_be_matched_in_arg if { "col": 3, "row": 5, }, - "text": "f(x) := \"one\" {", + "text": "f(x) := \"one\" if {", }) } test_fail_simple_body_comparison_could_be_matched_in_arg_eq_order if { - r := rule.report with input as ast.policy(`f(x) := "one" { + r := rule.report with input as ast.policy(`f(x) := "one" if { 1 == x }`) @@ -77,7 +75,7 @@ test_fail_simple_body_comparison_could_be_matched_in_arg_eq_order if { "col": 3, "row": 5, }, - "text": "f(x) := \"one\" {", + "text": "f(x) := \"one\" if {", }) } @@ -103,7 +101,7 @@ test_success_actually_pattern_matching if { } test_success_skipped_on_else if { - module := ast.policy(`f(x) { + module := ast.policy(`f(x) if { x == 1 } else := false`) r := rule.report with input as module diff --git a/bundle/regal/rules/idiomatic/no-defined-entrypoint/no_defined_entrypoint.rego b/bundle/regal/rules/idiomatic/no-defined-entrypoint/no_defined_entrypoint.rego index c8043601..2ee32543 100644 --- a/bundle/regal/rules/idiomatic/no-defined-entrypoint/no_defined_entrypoint.rego +++ b/bundle/regal/rules/idiomatic/no-defined-entrypoint/no_defined_entrypoint.rego @@ -2,8 +2,6 @@ # description: Missing entrypoint annotation package regal.rules.idiomatic["no-defined-entrypoint"] -import rego.v1 - import data.regal.ast import data.regal.result import data.regal.util diff --git a/bundle/regal/rules/idiomatic/no-defined-entrypoint/no_defined_entrypoint_test.rego b/bundle/regal/rules/idiomatic/no-defined-entrypoint/no_defined_entrypoint_test.rego index 6fc20711..fabdff03 100644 --- a/bundle/regal/rules/idiomatic/no-defined-entrypoint/no_defined_entrypoint_test.rego +++ b/bundle/regal/rules/idiomatic/no-defined-entrypoint/no_defined_entrypoint_test.rego @@ -1,7 +1,5 @@ package regal.rules.idiomatic["no-defined-entrypoint_test"] -import rego.v1 - import data.regal.config import data.regal.rules.idiomatic["no-defined-entrypoint"] as rule diff --git a/bundle/regal/rules/idiomatic/non-raw-regex-pattern/non_raw_regex_pattern.rego b/bundle/regal/rules/idiomatic/non-raw-regex-pattern/non_raw_regex_pattern.rego index 381c1424..25ab0e59 100644 --- a/bundle/regal/rules/idiomatic/non-raw-regex-pattern/non_raw_regex_pattern.rego +++ b/bundle/regal/rules/idiomatic/non-raw-regex-pattern/non_raw_regex_pattern.rego @@ -2,8 +2,6 @@ # description: Use raw strings for regex patterns package regal.rules.idiomatic["non-raw-regex-pattern"] -import rego.v1 - import data.regal.ast import data.regal.result import data.regal.util diff --git a/bundle/regal/rules/idiomatic/non-raw-regex-pattern/non_raw_regex_pattern_test.rego b/bundle/regal/rules/idiomatic/non-raw-regex-pattern/non_raw_regex_pattern_test.rego index bd076d52..7e939e1e 100644 --- a/bundle/regal/rules/idiomatic/non-raw-regex-pattern/non_raw_regex_pattern_test.rego +++ b/bundle/regal/rules/idiomatic/non-raw-regex-pattern/non_raw_regex_pattern_test.rego @@ -1,7 +1,5 @@ package regal.rules.idiomatic["non-raw-regex-pattern_test"] -import rego.v1 - import data.regal.ast import data.regal.capabilities import data.regal.config @@ -31,7 +29,7 @@ test_fail_non_raw_rule_head if { } test_fail_non_raw_rule_body if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { regex.is_valid("[0-9]+") }`) with data.internal.combined_config as {"capabilities": capabilities.provided} diff --git a/bundle/regal/rules/idiomatic/prefer-set-or-object-rule/prefer_set_or_object_rule.rego b/bundle/regal/rules/idiomatic/prefer-set-or-object-rule/prefer_set_or_object_rule.rego index 23177559..a41ada28 100644 --- a/bundle/regal/rules/idiomatic/prefer-set-or-object-rule/prefer_set_or_object_rule.rego +++ b/bundle/regal/rules/idiomatic/prefer-set-or-object-rule/prefer_set_or_object_rule.rego @@ -2,8 +2,6 @@ # description: Prefer set or object rule over comprehension package regal.rules.idiomatic["prefer-set-or-object-rule"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/idiomatic/prefer-set-or-object-rule/prefer_set_or_object_rule_test.rego b/bundle/regal/rules/idiomatic/prefer-set-or-object-rule/prefer_set_or_object_rule_test.rego index ce27d0ba..72f3efcb 100644 --- a/bundle/regal/rules/idiomatic/prefer-set-or-object-rule/prefer_set_or_object_rule_test.rego +++ b/bundle/regal/rules/idiomatic/prefer-set-or-object-rule/prefer_set_or_object_rule_test.rego @@ -1,7 +1,5 @@ package regal.rules.idiomatic["prefer-set-or-object-rule_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/idiomatic/use-contains/use_contains.rego b/bundle/regal/rules/idiomatic/use-contains/use_contains.rego index 77cf7a84..7768be2e 100644 --- a/bundle/regal/rules/idiomatic/use-contains/use_contains.rego +++ b/bundle/regal/rules/idiomatic/use-contains/use_contains.rego @@ -2,8 +2,6 @@ # description: Use the `contains` keyword package regal.rules.idiomatic["use-contains"] -import rego.v1 - import data.regal.ast import data.regal.capabilities import data.regal.result @@ -15,6 +13,15 @@ import data.regal.util # severity: warning notices contains result.notice(rego.metadata.chain()) if not capabilities.has_contains +# METADATA +# description: Since OPA 1.0, use-contains enabled only when provided a v0 policy +# custom: +# severity: none +notices contains result.notice(rego.metadata.chain()) if { + capabilities.is_opa_v1 + input.regal.file.rego_version != "v0" +} + report contains violation if { # if rego.v1 is imported, OPA will ensure this anyway not ast.imports_has_path(ast.imports, ["rego", "v1"]) diff --git a/bundle/regal/rules/idiomatic/use-contains/use_contains_test.rego b/bundle/regal/rules/idiomatic/use-contains/use_contains_test.rego index e8bcbe5f..f1e9d4ca 100644 --- a/bundle/regal/rules/idiomatic/use-contains/use_contains_test.rego +++ b/bundle/regal/rules/idiomatic/use-contains/use_contains_test.rego @@ -1,14 +1,12 @@ package regal.rules.idiomatic["use-contains_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.idiomatic["use-contains"] as rule test_fail_should_use_contains if { - module := ast.policy(` + module := ast.with_rego_v0(` import future.keywords rule[item] { @@ -22,7 +20,7 @@ test_fail_should_use_contains if { "level": "error", "location": { "col": 2, - "file": "policy.rego", + "file": "policy_v0.rego", "row": 6, "end": { "row": 6, diff --git a/bundle/regal/rules/idiomatic/use-if/use_if.rego b/bundle/regal/rules/idiomatic/use-if/use_if.rego index 828eae32..277506b1 100644 --- a/bundle/regal/rules/idiomatic/use-if/use_if.rego +++ b/bundle/regal/rules/idiomatic/use-if/use_if.rego @@ -2,8 +2,6 @@ # description: Use the `if` keyword package regal.rules.idiomatic["use-if"] -import rego.v1 - import data.regal.ast import data.regal.capabilities import data.regal.result @@ -15,6 +13,15 @@ import data.regal.util # severity: warning notices contains result.notice(rego.metadata.chain()) if not capabilities.has_if +# METADATA +# description: Since OPA 1.0, use-if enabled only when provided a v0 policy +# custom: +# severity: none +notices contains result.notice(rego.metadata.chain()) if { + capabilities.is_opa_v1 + input.regal.file.rego_version != "v0" +} + report contains violation if { # if rego.v1 is imported, OPA will ensure this anyway not ast.imports_has_path(ast.imports, ["rego", "v1"]) diff --git a/bundle/regal/rules/idiomatic/use-if/use_if_test.rego b/bundle/regal/rules/idiomatic/use-if/use_if_test.rego index abea5acb..b5f298ea 100644 --- a/bundle/regal/rules/idiomatic/use-if/use_if_test.rego +++ b/bundle/regal/rules/idiomatic/use-if/use_if_test.rego @@ -1,14 +1,12 @@ package regal.rules.idiomatic["use-if_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.idiomatic["use-if"] as rule test_fail_should_use_if if { - module := ast.policy(`rule := [true | + module := ast.with_rego_v0(`rule := [true | input[_] ] { input.attribute @@ -21,7 +19,7 @@ test_fail_should_use_if if { "level": "error", "location": { "col": 1, - "file": "policy.rego", + "file": "policy_v0.rego", "row": 3, "end": { "col": 3, diff --git a/bundle/regal/rules/idiomatic/use-in-operator/use_in_operator.rego b/bundle/regal/rules/idiomatic/use-in-operator/use_in_operator.rego index 9b440e81..a455fc1b 100644 --- a/bundle/regal/rules/idiomatic/use-in-operator/use_in_operator.rego +++ b/bundle/regal/rules/idiomatic/use-in-operator/use_in_operator.rego @@ -2,8 +2,6 @@ # description: Use in to check for membership package regal.rules.idiomatic["use-in-operator"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/idiomatic/use-in-operator/use_in_operator_test.rego b/bundle/regal/rules/idiomatic/use-in-operator/use_in_operator_test.rego index eb070371..ae5d1892 100644 --- a/bundle/regal/rules/idiomatic/use-in-operator/use_in_operator_test.rego +++ b/bundle/regal/rules/idiomatic/use-in-operator/use_in_operator_test.rego @@ -1,13 +1,11 @@ package regal.rules.idiomatic["use-in-operator_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.idiomatic["use-in-operator"] as rule test_fail_use_in_operator_string_lhs if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { "admin" == input.user.roles[_] }`) @@ -23,7 +21,7 @@ test_fail_use_in_operator_string_lhs if { } test_fail_use_in_operator_number_lhs if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { 1 == input.lucky_numbers[_] }`) @@ -39,7 +37,7 @@ test_fail_use_in_operator_number_lhs if { } test_fail_use_in_operator_array_lhs if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { [1] == input.arrays[_] }`) @@ -55,7 +53,7 @@ test_fail_use_in_operator_array_lhs if { } test_fail_use_in_operator_boolean_lhs if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { true == input.booleans[_] }`) @@ -71,7 +69,7 @@ test_fail_use_in_operator_boolean_lhs if { } test_fail_use_in_operator_object_lhs if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { {"x": "y"} == input.objects[_] }`) @@ -87,7 +85,7 @@ test_fail_use_in_operator_object_lhs if { } test_fail_use_in_operator_null_lhs if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { null == input.objects[_] }`) @@ -103,7 +101,7 @@ test_fail_use_in_operator_null_lhs if { } test_fail_use_in_operator_set_lhs if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { {"foo"} == input.objects[_] }`) @@ -119,7 +117,7 @@ test_fail_use_in_operator_set_lhs if { } test_fail_use_in_operator_var_lhs if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { admin == input.user.roles[_] }`) r == expected_with_location({ @@ -134,7 +132,7 @@ test_fail_use_in_operator_var_lhs if { } test_fail_use_in_operator_string_rhs if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { input.user.roles[_] == "admin" }`) @@ -150,7 +148,7 @@ test_fail_use_in_operator_string_rhs if { } test_fail_use_in_operator_var_rhs if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { input.user.roles[_] == admin }`) @@ -166,7 +164,7 @@ test_fail_use_in_operator_var_rhs if { } test_fail_use_in_operator_ref_lhs if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { data.roles.admin == input.user.roles[_] }`) @@ -182,7 +180,7 @@ test_fail_use_in_operator_ref_lhs if { } test_fail_use_in_operator_ref_rhs if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { input.user.roles[_] == data.roles.admin }`) @@ -198,7 +196,7 @@ test_fail_use_in_operator_ref_rhs if { } test_fail_use_in_operator_scalar_eq_operator if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { input.user.roles[_] == data.roles.admin }`) @@ -214,7 +212,7 @@ test_fail_use_in_operator_scalar_eq_operator if { } test_fail_use_in_operator_ref_eq_operator if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { input.user.roles[_] = "foo" }`) @@ -230,13 +228,13 @@ test_fail_use_in_operator_ref_eq_operator if { } test_success_loop_refs_both_sides if { - r := rule.report with input as ast.policy(`allow { required_roles[_] == input.user.roles[_] }`) + r := rule.report with input as ast.policy(`allow if { required_roles[_] == input.user.roles[_] }`) r == set() } test_success_uses_in_operator if { - r := rule.report with input as ast.with_rego_v1(`allow if { "admin" in input.user.roles }`) + r := rule.report with input as ast.policy(`allow if { "admin" in input.user.roles }`) r == set() } diff --git a/bundle/regal/rules/idiomatic/use-some-for-output-vars/use_some_for_output_vars.rego b/bundle/regal/rules/idiomatic/use-some-for-output-vars/use_some_for_output_vars.rego index cab86a44..e5c86f1a 100644 --- a/bundle/regal/rules/idiomatic/use-some-for-output-vars/use_some_for_output_vars.rego +++ b/bundle/regal/rules/idiomatic/use-some-for-output-vars/use_some_for_output_vars.rego @@ -2,8 +2,6 @@ # description: Use `some` to declare output variables package regal.rules.idiomatic["use-some-for-output-vars"] -import rego.v1 - import data.regal.ast import data.regal.result import data.regal.util diff --git a/bundle/regal/rules/idiomatic/use-some-for-output-vars/use_some_for_output_vars_test.rego b/bundle/regal/rules/idiomatic/use-some-for-output-vars/use_some_for_output_vars_test.rego index d3b1c186..73631321 100644 --- a/bundle/regal/rules/idiomatic/use-some-for-output-vars/use_some_for_output_vars_test.rego +++ b/bundle/regal/rules/idiomatic/use-some-for-output-vars/use_some_for_output_vars_test.rego @@ -1,13 +1,11 @@ package regal.rules.idiomatic["use-some-for-output-vars_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.idiomatic["use-some-for-output-vars"] as rule test_fail_output_var_not_declared if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { "admin" == input.user.roles[i] }`) r == {{ @@ -34,7 +32,7 @@ test_fail_output_var_not_declared if { # regal ignore:rule-length test_fail_multiple_output_vars_not_declared if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { foo := input.foo[i].bar[j] }`) r == { @@ -82,7 +80,7 @@ test_fail_multiple_output_vars_not_declared if { } test_fail_only_one_declared if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { some i foo := input.foo[i].bar[j] }`) @@ -110,7 +108,7 @@ test_fail_only_one_declared if { } test_success_uses_some if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { some i "admin" == input.user.roles[i] }`) @@ -156,7 +154,7 @@ test_success_not_an_output_var if { r := rule.report with input as ast.policy(` i := 0 - allow { + allow if { # i now an *input* var "admin" == input.user.roles[i] }`) diff --git a/bundle/regal/rules/idiomatic/use-strings-count/use_strings_count.rego b/bundle/regal/rules/idiomatic/use-strings-count/use_strings_count.rego index de98b585..1c3195e9 100644 --- a/bundle/regal/rules/idiomatic/use-strings-count/use_strings_count.rego +++ b/bundle/regal/rules/idiomatic/use-strings-count/use_strings_count.rego @@ -2,8 +2,6 @@ # description: Use `strings.count` where possible package regal.rules.idiomatic["use-strings-count"] -import rego.v1 - import data.regal.ast import data.regal.capabilities import data.regal.result diff --git a/bundle/regal/rules/idiomatic/use-strings-count/use_strings_count_test.rego b/bundle/regal/rules/idiomatic/use-strings-count/use_strings_count_test.rego index 170d00ac..6b52d809 100644 --- a/bundle/regal/rules/idiomatic/use-strings-count/use_strings_count_test.rego +++ b/bundle/regal/rules/idiomatic/use-strings-count/use_strings_count_test.rego @@ -1,7 +1,5 @@ package regal.rules.idiomatic["use-strings-count_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/imports/avoid-importing-input/avoid_importing_input.rego b/bundle/regal/rules/imports/avoid-importing-input/avoid_importing_input.rego index 529398fa..1efc4d90 100644 --- a/bundle/regal/rules/imports/avoid-importing-input/avoid_importing_input.rego +++ b/bundle/regal/rules/imports/avoid-importing-input/avoid_importing_input.rego @@ -2,8 +2,6 @@ # description: Avoid importing input package regal.rules.imports["avoid-importing-input"] -import rego.v1 - import data.regal.result report contains violation if { diff --git a/bundle/regal/rules/imports/avoid-importing-input/avoid_importing_input_test.rego b/bundle/regal/rules/imports/avoid-importing-input/avoid_importing_input_test.rego index 75537083..61c70d0e 100644 --- a/bundle/regal/rules/imports/avoid-importing-input/avoid_importing_input_test.rego +++ b/bundle/regal/rules/imports/avoid-importing-input/avoid_importing_input_test.rego @@ -1,7 +1,5 @@ package regal.rules.imports["avoid-importing-input_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.imports["avoid-importing-input"] as rule diff --git a/bundle/regal/rules/imports/circular-import/circular_import.rego b/bundle/regal/rules/imports/circular-import/circular_import.rego index 6aff1f54..678b1c6a 100644 --- a/bundle/regal/rules/imports/circular-import/circular_import.rego +++ b/bundle/regal/rules/imports/circular-import/circular_import.rego @@ -7,8 +7,6 @@ # - input: schema.regal.ast package regal.rules.imports["circular-import"] -import rego.v1 - import data.regal.ast import data.regal.result import data.regal.util diff --git a/bundle/regal/rules/imports/circular-import/circular_import_test.rego b/bundle/regal/rules/imports/circular-import/circular_import_test.rego index 90070aeb..ee10ec4a 100644 --- a/bundle/regal/rules/imports/circular-import/circular_import_test.rego +++ b/bundle/regal/rules/imports/circular-import/circular_import_test.rego @@ -1,7 +1,5 @@ package regal.rules.imports["circular-import_test"] -import rego.v1 - import data.regal.config import data.regal.rules.imports["circular-import"] as rule diff --git a/bundle/regal/rules/imports/ignored-import/ignored_import.rego b/bundle/regal/rules/imports/ignored-import/ignored_import.rego index b3d81387..0ec0703b 100644 --- a/bundle/regal/rules/imports/ignored-import/ignored_import.rego +++ b/bundle/regal/rules/imports/ignored-import/ignored_import.rego @@ -2,8 +2,6 @@ # description: Reference ignores import package regal.rules.imports["ignored-import"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/imports/ignored-import/ignored_import_test.rego b/bundle/regal/rules/imports/ignored-import/ignored_import_test.rego index ff41339e..0617157c 100644 --- a/bundle/regal/rules/imports/ignored-import/ignored_import_test.rego +++ b/bundle/regal/rules/imports/ignored-import/ignored_import_test.rego @@ -1,7 +1,5 @@ package regal.rules.imports["ignored-import_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/imports/implicit-future-keywords/implicit_future_keywords.rego b/bundle/regal/rules/imports/implicit-future-keywords/implicit_future_keywords.rego index 627b7ac5..1050c111 100644 --- a/bundle/regal/rules/imports/implicit-future-keywords/implicit_future_keywords.rego +++ b/bundle/regal/rules/imports/implicit-future-keywords/implicit_future_keywords.rego @@ -2,8 +2,6 @@ # description: Use explicit future keyword imports package regal.rules.imports["implicit-future-keywords"] -import rego.v1 - import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/imports/implicit-future-keywords/implicit_future_keywords_test.rego b/bundle/regal/rules/imports/implicit-future-keywords/implicit_future_keywords_test.rego index e093b526..debcb77e 100644 --- a/bundle/regal/rules/imports/implicit-future-keywords/implicit_future_keywords_test.rego +++ b/bundle/regal/rules/imports/implicit-future-keywords/implicit_future_keywords_test.rego @@ -1,7 +1,5 @@ package regal.rules.imports["implicit-future-keywords_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.imports["implicit-future-keywords"] as rule diff --git a/bundle/regal/rules/imports/import-after-rule/import_after_rule.rego b/bundle/regal/rules/imports/import-after-rule/import_after_rule.rego index e8ed2089..e8af9d4e 100644 --- a/bundle/regal/rules/imports/import-after-rule/import_after_rule.rego +++ b/bundle/regal/rules/imports/import-after-rule/import_after_rule.rego @@ -2,8 +2,6 @@ # description: Import declared after rule package regal.rules.imports["import-after-rule"] -import rego.v1 - import data.regal.result import data.regal.util diff --git a/bundle/regal/rules/imports/import-after-rule/import_after_rule_test.rego b/bundle/regal/rules/imports/import-after-rule/import_after_rule_test.rego index a89a34af..7cd8d04d 100644 --- a/bundle/regal/rules/imports/import-after-rule/import_after_rule_test.rego +++ b/bundle/regal/rules/imports/import-after-rule/import_after_rule_test.rego @@ -1,7 +1,5 @@ package regal.rules.imports["import-after-rule_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/imports/import-shadows-builtin/import_shadows_builtin.rego b/bundle/regal/rules/imports/import-shadows-builtin/import_shadows_builtin.rego index 4df5c56b..39c093c8 100644 --- a/bundle/regal/rules/imports/import-shadows-builtin/import_shadows_builtin.rego +++ b/bundle/regal/rules/imports/import-shadows-builtin/import_shadows_builtin.rego @@ -2,8 +2,6 @@ # description: Import shadows built-in namespace package regal.rules.imports["import-shadows-builtin"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/imports/import-shadows-builtin/import_shadows_builtin_test.rego b/bundle/regal/rules/imports/import-shadows-builtin/import_shadows_builtin_test.rego index 87e36a83..bc396709 100644 --- a/bundle/regal/rules/imports/import-shadows-builtin/import_shadows_builtin_test.rego +++ b/bundle/regal/rules/imports/import-shadows-builtin/import_shadows_builtin_test.rego @@ -1,7 +1,5 @@ package regal.rules.imports["import-shadows-builtin_test"] -import rego.v1 - import data.regal.ast import data.regal.capabilities import data.regal.config diff --git a/bundle/regal/rules/imports/import-shadows-import/import_shadows_import.rego b/bundle/regal/rules/imports/import-shadows-import/import_shadows_import.rego index 5a096497..d807218c 100644 --- a/bundle/regal/rules/imports/import-shadows-import/import_shadows_import.rego +++ b/bundle/regal/rules/imports/import-shadows-import/import_shadows_import.rego @@ -2,10 +2,18 @@ # description: Import shadows another import package regal.rules.imports["import-shadows-import"] -import rego.v1 - +import data.regal.capabilities import data.regal.result +# METADATA +# description: Since OPA 1.0, import-shadows-import enabled only when provided a v0 policy, +# custom: +# severity: none +notices contains result.notice(rego.metadata.chain()) if { + capabilities.is_opa_v1 + input.regal.file.rego_version != "v0" +} + # regular import _ident(imported) := regal.last(imported.path.value).value if not imported.alias diff --git a/bundle/regal/rules/imports/import-shadows-import/import_shadows_import_test.rego b/bundle/regal/rules/imports/import-shadows-import/import_shadows_import_test.rego index 411cb997..de51c3ea 100644 --- a/bundle/regal/rules/imports/import-shadows-import/import_shadows_import_test.rego +++ b/bundle/regal/rules/imports/import-shadows-import/import_shadows_import_test.rego @@ -1,7 +1,5 @@ package regal.rules.imports["import-shadows-import_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.imports["import-shadows-import"] as rule diff --git a/bundle/regal/rules/imports/prefer-package-imports/prefer_package_imports.rego b/bundle/regal/rules/imports/prefer-package-imports/prefer_package_imports.rego index eddcd31f..ba3553c1 100644 --- a/bundle/regal/rules/imports/prefer-package-imports/prefer_package_imports.rego +++ b/bundle/regal/rules/imports/prefer-package-imports/prefer_package_imports.rego @@ -2,8 +2,6 @@ # description: Prefer importing packages over rules package regal.rules.imports["prefer-package-imports"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/imports/prefer-package-imports/prefer_package_imports_test.rego b/bundle/regal/rules/imports/prefer-package-imports/prefer_package_imports_test.rego index e002b381..91e138ac 100644 --- a/bundle/regal/rules/imports/prefer-package-imports/prefer_package_imports_test.rego +++ b/bundle/regal/rules/imports/prefer-package-imports/prefer_package_imports_test.rego @@ -1,7 +1,5 @@ package regal.rules.imports["prefer-package-imports_test"] -import rego.v1 - import data.regal.config import data.regal.rules.imports["prefer-package-imports"] as rule diff --git a/bundle/regal/rules/imports/redundant-alias/redundant_alias.rego b/bundle/regal/rules/imports/redundant-alias/redundant_alias.rego index f78db4dc..71b2c440 100644 --- a/bundle/regal/rules/imports/redundant-alias/redundant_alias.rego +++ b/bundle/regal/rules/imports/redundant-alias/redundant_alias.rego @@ -2,8 +2,6 @@ # description: Redundant alias package regal.rules.imports["redundant-alias"] -import rego.v1 - import data.regal.result report contains violation if { diff --git a/bundle/regal/rules/imports/redundant-alias/redundant_alias_test.rego b/bundle/regal/rules/imports/redundant-alias/redundant_alias_test.rego index be11289a..d3278068 100644 --- a/bundle/regal/rules/imports/redundant-alias/redundant_alias_test.rego +++ b/bundle/regal/rules/imports/redundant-alias/redundant_alias_test.rego @@ -1,7 +1,5 @@ package regal.rules.imports["redundant-alias_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.imports["redundant-alias"] as rule diff --git a/bundle/regal/rules/imports/redundant-data-import/redundant_data_import.rego b/bundle/regal/rules/imports/redundant-data-import/redundant_data_import.rego index 420a5e69..d0a670ff 100644 --- a/bundle/regal/rules/imports/redundant-data-import/redundant_data_import.rego +++ b/bundle/regal/rules/imports/redundant-data-import/redundant_data_import.rego @@ -2,8 +2,6 @@ # description: Redundant import of data package regal.rules.imports["redundant-data-import"] -import rego.v1 - import data.regal.result report contains violation if { diff --git a/bundle/regal/rules/imports/redundant-data-import/redundant_data_import_test.rego b/bundle/regal/rules/imports/redundant-data-import/redundant_data_import_test.rego index 7d3cb3dd..d11a02c0 100644 --- a/bundle/regal/rules/imports/redundant-data-import/redundant_data_import_test.rego +++ b/bundle/regal/rules/imports/redundant-data-import/redundant_data_import_test.rego @@ -1,7 +1,5 @@ package regal.rules.imports["redundant-data-import_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.imports["redundant-data-import"] as rule diff --git a/bundle/regal/rules/imports/unresolved-import/unresolved_import.rego b/bundle/regal/rules/imports/unresolved-import/unresolved_import.rego index ae8a44f6..a8807e49 100644 --- a/bundle/regal/rules/imports/unresolved-import/unresolved_import.rego +++ b/bundle/regal/rules/imports/unresolved-import/unresolved_import.rego @@ -2,8 +2,6 @@ # description: Unresolved import package regal.rules.imports["unresolved-import"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/imports/unresolved-import/unresolved_import_test.rego b/bundle/regal/rules/imports/unresolved-import/unresolved_import_test.rego index b128ed03..da3e9bb1 100644 --- a/bundle/regal/rules/imports/unresolved-import/unresolved_import_test.rego +++ b/bundle/regal/rules/imports/unresolved-import/unresolved_import_test.rego @@ -1,7 +1,5 @@ package regal.rules.imports["unresolved-import_test"] -import rego.v1 - import data.regal.config import data.regal.rules.imports["unresolved-import"] as rule diff --git a/bundle/regal/rules/imports/use-rego-v1/use_rego_v1.rego b/bundle/regal/rules/imports/use-rego-v1/use_rego_v1.rego index d2cb8d9c..597ab5e5 100644 --- a/bundle/regal/rules/imports/use-rego-v1/use_rego_v1.rego +++ b/bundle/regal/rules/imports/use-rego-v1/use_rego_v1.rego @@ -2,8 +2,6 @@ # description: Use `import rego.v1` package regal.rules.imports["use-rego-v1"] -import rego.v1 - import data.regal.ast import data.regal.capabilities import data.regal.result @@ -12,7 +10,19 @@ import data.regal.result # description: Missing capability for `import rego.v1` # custom: # severity: warning -notices contains result.notice(rego.metadata.chain()) if not capabilities.has_rego_v1_feature +notices contains result.notice(rego.metadata.chain()) if { + not capabilities.has_rego_v1_feature + not capabilities.is_opa_v1 +} + +# METADATA +# description: Since OPA 1.0, use-rego-v1 enabled only when provided a v0 policy +# custom: +# severity: none +notices contains result.notice(rego.metadata.chain()) if { + capabilities.is_opa_v1 + input.regal.file.rego_version != "v0" +} report contains violation if { not ast.imports_has_path(ast.imports, ["rego", "v1"]) diff --git a/bundle/regal/rules/imports/use-rego-v1/use_rego_v1_test.rego b/bundle/regal/rules/imports/use-rego-v1/use_rego_v1_test.rego index 00420709..d9dd898d 100644 --- a/bundle/regal/rules/imports/use-rego-v1/use_rego_v1_test.rego +++ b/bundle/regal/rules/imports/use-rego-v1/use_rego_v1_test.rego @@ -1,7 +1,5 @@ package regal.rules.imports["use-rego-v1_test"] -import rego.v1 - import data.regal.capabilities import data.regal.config import data.regal.rules.imports["use-rego-v1"] as rule diff --git a/bundle/regal/rules/performance/defer-assignment/defer_assignment.rego b/bundle/regal/rules/performance/defer-assignment/defer_assignment.rego index 8673596c..4ddcae34 100644 --- a/bundle/regal/rules/performance/defer-assignment/defer_assignment.rego +++ b/bundle/regal/rules/performance/defer-assignment/defer_assignment.rego @@ -2,8 +2,6 @@ # description: Assignment can be deferred package regal.rules.performance["defer-assignment"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/performance/defer-assignment/defer_assignment_test.rego b/bundle/regal/rules/performance/defer-assignment/defer_assignment_test.rego index 66d96824..90820f26 100644 --- a/bundle/regal/rules/performance/defer-assignment/defer_assignment_test.rego +++ b/bundle/regal/rules/performance/defer-assignment/defer_assignment_test.rego @@ -1,7 +1,5 @@ package regal.rules.performance["defer-assignment_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/performance/walk-no-path/walk_no_path.rego b/bundle/regal/rules/performance/walk-no-path/walk_no_path.rego index 80fb22a1..1ae53c5f 100644 --- a/bundle/regal/rules/performance/walk-no-path/walk_no_path.rego +++ b/bundle/regal/rules/performance/walk-no-path/walk_no_path.rego @@ -2,8 +2,6 @@ # description: Call to `walk` can be optimized package regal.rules.performance["walk-no-path"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/performance/walk-no-path/walk_no_path_test.rego b/bundle/regal/rules/performance/walk-no-path/walk_no_path_test.rego index f8c89ac9..c58966b5 100644 --- a/bundle/regal/rules/performance/walk-no-path/walk_no_path_test.rego +++ b/bundle/regal/rules/performance/walk-no-path/walk_no_path_test.rego @@ -1,7 +1,5 @@ package regal.rules.performance["walk-no-path_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/performance/with-outside-test-context/with_outside_test_context.rego b/bundle/regal/rules/performance/with-outside-test-context/with_outside_test_context.rego index 4a7cf512..d9792224 100644 --- a/bundle/regal/rules/performance/with-outside-test-context/with_outside_test_context.rego +++ b/bundle/regal/rules/performance/with-outside-test-context/with_outside_test_context.rego @@ -2,8 +2,6 @@ # 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 diff --git a/bundle/regal/rules/performance/with-outside-test-context/with_outside_test_context_test.rego b/bundle/regal/rules/performance/with-outside-test-context/with_outside_test_context_test.rego index d066e798..6996857c 100644 --- a/bundle/regal/rules/performance/with-outside-test-context/with_outside_test_context_test.rego +++ b/bundle/regal/rules/performance/with-outside-test-context/with_outside_test_context_test.rego @@ -1,7 +1,5 @@ package regal.rules.performance["with-outside-test-context_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/style/avoid-get-and-list-prefix/avoid_get_and_list_prefix.rego b/bundle/regal/rules/style/avoid-get-and-list-prefix/avoid_get_and_list_prefix.rego index 50fc38ae..5b88242a 100644 --- a/bundle/regal/rules/style/avoid-get-and-list-prefix/avoid_get_and_list_prefix.rego +++ b/bundle/regal/rules/style/avoid-get-and-list-prefix/avoid_get_and_list_prefix.rego @@ -2,8 +2,6 @@ # description: Avoid `get_` and `list_` prefix for rules and functions package regal.rules.style["avoid-get-and-list-prefix"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/style/avoid-get-and-list-prefix/avoid_get_and_list_prefix_test.rego b/bundle/regal/rules/style/avoid-get-and-list-prefix/avoid_get_and_list_prefix_test.rego index ffac5271..db2dea8f 100644 --- a/bundle/regal/rules/style/avoid-get-and-list-prefix/avoid_get_and_list_prefix_test.rego +++ b/bundle/regal/rules/style/avoid-get-and-list-prefix/avoid_get_and_list_prefix_test.rego @@ -1,7 +1,5 @@ package regal.rules.style["avoid-get-and-list-prefix_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.style["avoid-get-and-list-prefix"] as rule diff --git a/bundle/regal/rules/style/chained-rule-body/chained_rule_body.rego b/bundle/regal/rules/style/chained-rule-body/chained_rule_body.rego index e08a7df8..d88a140e 100644 --- a/bundle/regal/rules/style/chained-rule-body/chained_rule_body.rego +++ b/bundle/regal/rules/style/chained-rule-body/chained_rule_body.rego @@ -2,8 +2,6 @@ # description: Avoid chaining rule bodies package regal.rules.style["chained-rule-body"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/style/chained-rule-body/chained_rule_body_test.rego b/bundle/regal/rules/style/chained-rule-body/chained_rule_body_test.rego index dde9adb5..ce05ceb1 100644 --- a/bundle/regal/rules/style/chained-rule-body/chained_rule_body_test.rego +++ b/bundle/regal/rules/style/chained-rule-body/chained_rule_body_test.rego @@ -1,14 +1,12 @@ package regal.rules.style["chained-rule-body_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.style["chained-rule-body"] as rule test_fail_chained_incremental_definition if { - module := ast.policy(`rule { + module := ast.policy(`rule if { input.x } { input.y @@ -38,11 +36,11 @@ test_fail_chained_incremental_definition if { test_success_not_chained_incremental_definition if { module := ast.policy(` - rule { + rule if { input.x } - rule { + rule if { input.y }`) diff --git a/bundle/regal/rules/style/comprehension-term-assignment/comprehension_term_assignment.rego b/bundle/regal/rules/style/comprehension-term-assignment/comprehension_term_assignment.rego index f9fd2589..5444ab84 100644 --- a/bundle/regal/rules/style/comprehension-term-assignment/comprehension_term_assignment.rego +++ b/bundle/regal/rules/style/comprehension-term-assignment/comprehension_term_assignment.rego @@ -2,8 +2,6 @@ # description: Assignment can be moved to comprehension term package regal.rules.style["comprehension-term-assignment"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/style/comprehension-term-assignment/comprehension_term_assignment_test.rego b/bundle/regal/rules/style/comprehension-term-assignment/comprehension_term_assignment_test.rego index 10980011..4ce8ae18 100644 --- a/bundle/regal/rules/style/comprehension-term-assignment/comprehension_term_assignment_test.rego +++ b/bundle/regal/rules/style/comprehension-term-assignment/comprehension_term_assignment_test.rego @@ -1,7 +1,5 @@ package regal.rules.style["comprehension-term-assignment_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/style/default-over-else/default_over_else.rego b/bundle/regal/rules/style/default-over-else/default_over_else.rego index 10bcc918..bf08dc92 100644 --- a/bundle/regal/rules/style/default-over-else/default_over_else.rego +++ b/bundle/regal/rules/style/default-over-else/default_over_else.rego @@ -2,8 +2,6 @@ # description: Prefer default assignment over fallback else package regal.rules.style["default-over-else"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/style/default-over-else/default_over_else_test.rego b/bundle/regal/rules/style/default-over-else/default_over_else_test.rego index fdde53ac..6fdf33bc 100644 --- a/bundle/regal/rules/style/default-over-else/default_over_else_test.rego +++ b/bundle/regal/rules/style/default-over-else/default_over_else_test.rego @@ -1,7 +1,5 @@ package regal.rules.style["default-over-else_test"] -import rego.v1 - import data.regal.ast import data.regal.config @@ -9,9 +7,9 @@ import data.regal.rules.style["default-over-else"] as rule test_fail_conditionless_else_simple_rule if { module := ast.policy(` - x := 1 { + x := 1 if { input.x - } else := 2 { + } else := 2 if { input.y } else := 3 `) @@ -31,7 +29,7 @@ test_fail_conditionless_else_simple_rule if { test_fail_conditionless_else_object_assignment if { module := ast.policy(` - x := {"foo": "bar"} { + x := {"foo": "bar"} if { input.x } else := {"bar": "foo"} `) @@ -53,7 +51,7 @@ test_success_conditionless_else_not_constant if { module := ast.policy(` y := input.y - x := {"foo": "bar"} { + x := {"foo": "bar"} if { input.x } else := {"bar": y} `) @@ -64,7 +62,7 @@ test_success_conditionless_else_not_constant if { test_success_conditionless_else_input_ref if { module := ast.policy(` - x := {"foo": "bar"} { + x := {"foo": "bar"} if { input.x } else := input.foo `) @@ -75,7 +73,7 @@ test_success_conditionless_else_input_ref if { test_success_conditionless_else_custom_function if { module := ast.policy(` - x(y) := y { + x(y) := y if { input.foo } else := 1 `) @@ -86,7 +84,7 @@ test_success_conditionless_else_custom_function if { test_fail_conditionless_else_custom_function_prefer_default_functions if { module := ast.policy(` - x(y) := y { + x(y) := y if { input.foo } else := 1 `) @@ -109,7 +107,7 @@ test_fail_conditionless_else_custom_function_prefer_default_functions if { test_success_conditionless_else_custom_function_not_constant if { module := ast.policy(` - x(y) := y + 1 { + x(y) := y + 1 if { input.foo } else := y `) diff --git a/bundle/regal/rules/style/default-over-not/default_over_not.rego b/bundle/regal/rules/style/default-over-not/default_over_not.rego index e69e8e93..3c8c8d34 100644 --- a/bundle/regal/rules/style/default-over-not/default_over_not.rego +++ b/bundle/regal/rules/style/default-over-not/default_over_not.rego @@ -2,8 +2,6 @@ # description: Prefer default assignment over negated condition package regal.rules.style["default-over-not"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/style/default-over-not/default_over_not_test.rego b/bundle/regal/rules/style/default-over-not/default_over_not_test.rego index 1b53d561..fa483dec 100644 --- a/bundle/regal/rules/style/default-over-not/default_over_not_test.rego +++ b/bundle/regal/rules/style/default-over-not/default_over_not_test.rego @@ -1,7 +1,5 @@ package regal.rules.style["default-over-not_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/style/detached-metadata/detached_metadata.rego b/bundle/regal/rules/style/detached-metadata/detached_metadata.rego index db4f3c7a..b7adcfc4 100644 --- a/bundle/regal/rules/style/detached-metadata/detached_metadata.rego +++ b/bundle/regal/rules/style/detached-metadata/detached_metadata.rego @@ -2,8 +2,6 @@ # description: Detached metadata annotation package regal.rules.style["detached-metadata"] -import rego.v1 - import data.regal.ast import data.regal.result import data.regal.util diff --git a/bundle/regal/rules/style/detached-metadata/detached_metadata_test.rego b/bundle/regal/rules/style/detached-metadata/detached_metadata_test.rego index 72a9f586..cb5cd7bf 100644 --- a/bundle/regal/rules/style/detached-metadata/detached_metadata_test.rego +++ b/bundle/regal/rules/style/detached-metadata/detached_metadata_test.rego @@ -1,7 +1,5 @@ package regal.rules.style["detached-metadata_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.style["detached-metadata"] as rule diff --git a/bundle/regal/rules/style/double-negative/double_negative.rego b/bundle/regal/rules/style/double-negative/double_negative.rego index 224c1c1e..855d9dab 100644 --- a/bundle/regal/rules/style/double-negative/double_negative.rego +++ b/bundle/regal/rules/style/double-negative/double_negative.rego @@ -7,8 +7,6 @@ # - input: schema.regal.ast package regal.rules.style["double-negative"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/style/double-negative/double_negative_test.rego b/bundle/regal/rules/style/double-negative/double_negative_test.rego index 85f72898..dbc58cb9 100644 --- a/bundle/regal/rules/style/double-negative/double_negative_test.rego +++ b/bundle/regal/rules/style/double-negative/double_negative_test.rego @@ -1,7 +1,5 @@ package regal.rules.style["double-negative_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/style/external-reference/external_reference.rego b/bundle/regal/rules/style/external-reference/external_reference.rego index 797ec869..a5e84ad1 100644 --- a/bundle/regal/rules/style/external-reference/external_reference.rego +++ b/bundle/regal/rules/style/external-reference/external_reference.rego @@ -2,8 +2,6 @@ # description: External reference in function package regal.rules.style["external-reference"] -import rego.v1 - import data.regal.ast import data.regal.result import data.regal.util diff --git a/bundle/regal/rules/style/external-reference/external_reference_test.rego b/bundle/regal/rules/style/external-reference/external_reference_test.rego index 2256e506..fe4b0c19 100644 --- a/bundle/regal/rules/style/external-reference/external_reference_test.rego +++ b/bundle/regal/rules/style/external-reference/external_reference_test.rego @@ -1,44 +1,42 @@ package regal.rules.style["external-reference_test"] -import rego.v1 - import data.regal.ast import data.regal.capabilities import data.regal.config import data.regal.rules.style["external-reference"] as rule test_fail_function_references_input if { - r := rule.report with input as ast.policy(`f(_) { input.foo }`) + r := rule.report with input as ast.policy(`f(_) if { input.foo }`) with data.internal.combined_config as {"capabilities": capabilities.provided} r == expected_with_location({ - "col": 8, + "col": 11, "file": "policy.rego", "row": 3, "end": { - "col": 13, + "col": 16, "row": 3, }, - "text": `f(_) { input.foo }`, + "text": `f(_) if { input.foo }`, }) } test_fail_function_references_data if { - r := rule.report with input as ast.policy(`f(_) { data.foo }`) + r := rule.report with input as ast.policy(`f(_) if { data.foo }`) with data.internal.combined_config as {"capabilities": capabilities.provided} r == expected_with_location({ - "col": 8, + "col": 11, "file": "policy.rego", "row": 3, "end": { - "col": 12, + "col": 15, "row": 3, }, - "text": `f(_) { data.foo }`, + "text": `f(_) if { data.foo }`, }) } test_fail_function_references_data_in_expr if { - r := rule.report with input as ast.policy(`f(x) { + r := rule.report with input as ast.policy(`f(x) if { x == data.foo }`) with data.internal.combined_config as {"capabilities": capabilities.provided} @@ -58,7 +56,7 @@ test_fail_function_references_rule if { r := rule.report with input as ast.policy(` foo := "bar" -f(x, y) { +f(x, y) if { x == 5 y == foo } @@ -107,55 +105,55 @@ test_fail_external_reference_in_head_terms if { } test_success_function_references_no_input_or_data if { - r := rule.report with input as ast.policy(`f(x) { x == true }`) + r := rule.report with input as ast.policy(`f(x) if { x == true }`) with data.internal.combined_config as {"capabilities": capabilities.provided} r == set() } test_success_function_references_no_input_or_data_reverse if { - r := rule.report with input as ast.policy(`f(x) { true == x }`) + r := rule.report with input as ast.policy(`f(x) if { true == x }`) with data.internal.combined_config as {"capabilities": capabilities.provided} r == set() } test_success_function_references_only_own_vars if { - r := rule.report with input as ast.policy(`f(x) { y := x; y == 10 }`) + r := rule.report with input as ast.policy(`f(x) if { y := x; y == 10 }`) with data.internal.combined_config as {"capabilities": capabilities.provided} r == set() } test_success_function_references_only_own_vars_nested if { - r := rule.report with input as ast.policy(`f(x, z) { y := x; y == [1, 2, z]}`) + r := rule.report with input as ast.policy(`f(x, z) if { y := x; y == [1, 2, z]}`) with data.internal.combined_config as {"capabilities": capabilities.provided} r == set() } test_success_function_references_only_own_vars_and_wildcard if { - r := rule.report with input as ast.policy(`f(x, y) { _ = x + y }`) + r := rule.report with input as ast.policy(`f(x, y) if { _ = x + y }`) with data.internal.combined_config as {"capabilities": capabilities.provided} r == set() } test_success_function_references_return_var if { - r := rule.report with input as ast.policy(`f(x) := y { y = true }`) + r := rule.report with input as ast.policy(`f(x) := y if { y = true }`) with data.internal.combined_config as {"capabilities": capabilities.provided} r == set() } test_success_function_references_return_vars if { - r := rule.report with input as ast.policy(`f(x) := [x, y] { x = false; y = true }`) + r := rule.report with input as ast.policy(`f(x) := [x, y] if { x = false; y = true }`) with data.internal.combined_config as {"capabilities": capabilities.provided} r == set() } test_success_function_references_external_function if { - r := rule.report with input as ast.policy(`f(x) { data.foo.bar(x) }`) + r := rule.report with input as ast.policy(`f(x) if { data.foo.bar(x) }`) with data.internal.combined_config as {"capabilities": capabilities.provided} r == set() } test_success_function_references_external_function_in_expr if { - r := rule.report with input as ast.policy(`f(x) := y { y := data.foo.bar(x) }`) + r := rule.report with input as ast.policy(`f(x) := y if { y := data.foo.bar(x) }`) with data.internal.combined_config as {"capabilities": capabilities.provided} r == set() } diff --git a/bundle/regal/rules/style/file-length/file_length.rego b/bundle/regal/rules/style/file-length/file_length.rego index c0cfc8ab..08e24e03 100644 --- a/bundle/regal/rules/style/file-length/file_length.rego +++ b/bundle/regal/rules/style/file-length/file_length.rego @@ -2,8 +2,6 @@ # description: Max file length exceeded package regal.rules.style["file-length"] -import rego.v1 - import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/style/file-length/file_length_test.rego b/bundle/regal/rules/style/file-length/file_length_test.rego index 7b5f273e..7b335669 100644 --- a/bundle/regal/rules/style/file-length/file_length_test.rego +++ b/bundle/regal/rules/style/file-length/file_length_test.rego @@ -1,7 +1,5 @@ package regal.rules.style["file-length_test"] -import rego.v1 - import data.regal.config import data.regal.rules.style["file-length"] as rule diff --git a/bundle/regal/rules/style/function-arg-return/function_arg_return.rego b/bundle/regal/rules/style/function-arg-return/function_arg_return.rego index 320208b8..21f2c297 100644 --- a/bundle/regal/rules/style/function-arg-return/function_arg_return.rego +++ b/bundle/regal/rules/style/function-arg-return/function_arg_return.rego @@ -2,8 +2,6 @@ # description: Function argument used for return value package regal.rules.style["function-arg-return"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/style/function-arg-return/function_arg_return_test.rego b/bundle/regal/rules/style/function-arg-return/function_arg_return_test.rego index 95ed9c2a..12765cf5 100644 --- a/bundle/regal/rules/style/function-arg-return/function_arg_return_test.rego +++ b/bundle/regal/rules/style/function-arg-return/function_arg_return_test.rego @@ -1,14 +1,12 @@ package regal.rules.style["function-arg-return_test"] -import rego.v1 - import data.regal.ast import data.regal.capabilities import data.regal.config import data.regal.rules.style["function-arg-return"] as rule test_fail_function_arg_return_value if { - r := rule.report with input as ast.policy(`foo := i { indexof("foo", "o", i) }`) + r := rule.report with input as ast.policy(`foo := i if { indexof("foo", "o", i) }`) with config.for_rule as {"level": "error"} with data.internal.combined_config as {"capabilities": capabilities.provided} @@ -17,14 +15,14 @@ test_fail_function_arg_return_value if { "description": "Function argument used for return value", "level": "error", "location": { - "col": 32, + "col": 35, "file": "policy.rego", "row": 3, "end": { - "col": 33, + "col": 36, "row": 3, }, - "text": "foo := i { indexof(\"foo\", \"o\", i) }", + "text": "foo := i if { indexof(\"foo\", \"o\", i) }", }, "related_resources": [{ "description": "documentation", @@ -35,7 +33,7 @@ test_fail_function_arg_return_value if { } test_fail_function_arg_return_value_multi_part_ref if { - r := rule.report with input as ast.policy(`foo := r { regex.match("foo", "foo", r) }`) + r := rule.report with input as ast.policy(`foo := r if { regex.match("foo", "foo", r) }`) with config.for_rule as {"level": "error"} with data.internal.combined_config as {"capabilities": capabilities.provided} r == {{ @@ -43,14 +41,14 @@ test_fail_function_arg_return_value_multi_part_ref if { "description": "Function argument used for return value", "level": "error", "location": { - "col": 38, + "col": 41, "file": "policy.rego", "row": 3, "end": { - "col": 39, + "col": 42, "row": 3, }, - "text": `foo := r { regex.match("foo", "foo", r) }`, + "text": `foo := r if { regex.match("foo", "foo", r) }`, }, "related_resources": [{ "description": "documentation", diff --git a/bundle/regal/rules/style/line-length/line_length.rego b/bundle/regal/rules/style/line-length/line_length.rego index 4155ac72..7f72f8ae 100644 --- a/bundle/regal/rules/style/line-length/line_length.rego +++ b/bundle/regal/rules/style/line-length/line_length.rego @@ -2,8 +2,6 @@ # description: Line too long package regal.rules.style["line-length"] -import rego.v1 - import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/style/line-length/line_length_test.rego b/bundle/regal/rules/style/line-length/line_length_test.rego index af5dba2f..3751d132 100644 --- a/bundle/regal/rules/style/line-length/line_length_test.rego +++ b/bundle/regal/rules/style/line-length/line_length_test.rego @@ -1,7 +1,5 @@ package regal.rules.style["line-length_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.style["line-length"] as rule @@ -94,7 +92,7 @@ test_fail_line_exceeds_120_characters_even_if_not_in_config if { } test_success_line_not_too_long if { - r := rule.report with input as ast.policy(`allow { "foo" == "bar" }`) + r := rule.report with input as ast.policy(`allow if { "foo" == "bar" }`) with config.for_rule as {"level": "error", "max-line-length": 80} r == set() } diff --git a/bundle/regal/rules/style/messy-rule/messy_rule.rego b/bundle/regal/rules/style/messy-rule/messy_rule.rego index 1ddeea4e..b9714b2a 100644 --- a/bundle/regal/rules/style/messy-rule/messy_rule.rego +++ b/bundle/regal/rules/style/messy-rule/messy_rule.rego @@ -2,8 +2,6 @@ # description: Messy incremental rule package regal.rules.style["messy-rule"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/style/messy-rule/messy_rule_test.rego b/bundle/regal/rules/style/messy-rule/messy_rule_test.rego index d0f8563e..9a61d612 100644 --- a/bundle/regal/rules/style/messy-rule/messy_rule_test.rego +++ b/bundle/regal/rules/style/messy-rule/messy_rule_test.rego @@ -1,7 +1,5 @@ package regal.rules.style["messy-rule_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/style/no-whitespace-comment/no_whitespace_comment.rego b/bundle/regal/rules/style/no-whitespace-comment/no_whitespace_comment.rego index fca53f8e..f10b60c5 100644 --- a/bundle/regal/rules/style/no-whitespace-comment/no_whitespace_comment.rego +++ b/bundle/regal/rules/style/no-whitespace-comment/no_whitespace_comment.rego @@ -2,8 +2,6 @@ # description: Comment should start with whitespace package regal.rules.style["no-whitespace-comment"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/style/no-whitespace-comment/no_whitespace_comment_test.rego b/bundle/regal/rules/style/no-whitespace-comment/no_whitespace_comment_test.rego index 23978fca..93250c3e 100644 --- a/bundle/regal/rules/style/no-whitespace-comment/no_whitespace_comment_test.rego +++ b/bundle/regal/rules/style/no-whitespace-comment/no_whitespace_comment_test.rego @@ -1,7 +1,5 @@ package regal.rules.style["no-whitespace-comment_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.style["no-whitespace-comment"] as rule diff --git a/bundle/regal/rules/style/pointless-reassignment/pointless_reassignment.rego b/bundle/regal/rules/style/pointless-reassignment/pointless_reassignment.rego index f9a6544f..dc41e933 100644 --- a/bundle/regal/rules/style/pointless-reassignment/pointless_reassignment.rego +++ b/bundle/regal/rules/style/pointless-reassignment/pointless_reassignment.rego @@ -2,8 +2,6 @@ # description: Pointless reassignment of variable package regal.rules.style["pointless-reassignment"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/style/pointless-reassignment/pointless_reassignment_test.rego b/bundle/regal/rules/style/pointless-reassignment/pointless_reassignment_test.rego index ee6f7570..6bc9fb91 100644 --- a/bundle/regal/rules/style/pointless-reassignment/pointless_reassignment_test.rego +++ b/bundle/regal/rules/style/pointless-reassignment/pointless_reassignment_test.rego @@ -1,7 +1,5 @@ package regal.rules.style["pointless-reassignment_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/style/prefer-snake-case/prefer_snake_case.rego b/bundle/regal/rules/style/prefer-snake-case/prefer_snake_case.rego index 0cf9f927..eef235da 100644 --- a/bundle/regal/rules/style/prefer-snake-case/prefer_snake_case.rego +++ b/bundle/regal/rules/style/prefer-snake-case/prefer_snake_case.rego @@ -2,8 +2,6 @@ # description: Prefer snake_case for names package regal.rules.style["prefer-snake-case"] -import rego.v1 - import data.regal.ast import data.regal.result import data.regal.util diff --git a/bundle/regal/rules/style/prefer-snake-case/prefer_snake_case_test.rego b/bundle/regal/rules/style/prefer-snake-case/prefer_snake_case_test.rego index 5f4d28cd..549c5b9b 100644 --- a/bundle/regal/rules/style/prefer-snake-case/prefer_snake_case_test.rego +++ b/bundle/regal/rules/style/prefer-snake-case/prefer_snake_case_test.rego @@ -1,7 +1,5 @@ package regal.rules.style["prefer-snake-case_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.style["prefer-snake-case"] as rule @@ -42,18 +40,18 @@ test_success_snake_cased_package_name if { } test_fail_camel_cased_some_declaration if { - r := rule.report with input as ast.policy(`p {some fooBar; input[_]}`) + r := rule.report with input as ast.policy(`p if {some fooBar; input[_]}`) r == expected_with_locations([{ - "col": 9, + "col": 12, "file": "policy.rego", "row": 3, - "text": `p {some fooBar; input[_]}`, - "end": {"col": 15, "row": 3}, + "text": `p if {some fooBar; input[_]}`, + "end": {"col": 18, "row": 3}, }]) } test_success_snake_cased_some_declaration if { - r := rule.report with input as ast.policy(`p {some foo_bar; input[foo_bar]}`) + r := rule.report with input as ast.policy(`p if {some foo_bar; input[foo_bar]}`) r == set() } @@ -71,7 +69,7 @@ test_fail_camel_cased_multiple_some_declaration if { } test_success_snake_cased_multiple_some_declaration if { - r := rule.report with input as ast.policy(`p {some x, foo_bar; x = 5; input[foo_bar]}`) + r := rule.report with input as ast.policy(`p if {some x, foo_bar; x = 5; input[foo_bar]}`) r == set() } @@ -92,29 +90,31 @@ test_success_not_camel_cased_function_argument if { } test_fail_camel_cased_var_assignment if { - r := rule.report with input as ast.policy(`allow { camelCase := 5 }`) + r := rule.report with input as ast.policy(`allow if { camelCase := 5 }`) + r == expected_with_locations([{ - "col": 9, + "col": 12, "file": "policy.rego", "row": 3, - "text": `allow { camelCase := 5 }`, - "end": {"col": 18, "row": 3}, + "text": `allow if { camelCase := 5 }`, + "end": {"col": 21, "row": 3}, }]) } test_fail_camel_cased_multiple_var_assignment if { - r := rule.report with input as ast.policy(`allow { snake_case := "foo"; camelCase := 5 }`) + r := rule.report with input as ast.policy(`allow if { snake_case := "foo"; camelCase := 5 }`) + r == expected_with_locations([{ - "col": 30, + "col": 33, "file": "policy.rego", "row": 3, - "text": `allow { snake_case := "foo"; camelCase := 5 }`, - "end": {"col": 39, "row": 3}, + "text": `allow if { snake_case := "foo"; camelCase := 5 }`, + "end": {"col": 42, "row": 3}, }]) } test_success_snake_cased_var_assignment if { - r := rule.report with input as ast.policy(`allow { snake_case := 5 }`) + r := rule.report with input as ast.policy(`allow if { snake_case := 5 }`) r == set() } diff --git a/bundle/regal/rules/style/prefer-some-in-iteration/prefer_some_in_iteration.rego b/bundle/regal/rules/style/prefer-some-in-iteration/prefer_some_in_iteration.rego index 98b48b79..9f0c6a5a 100644 --- a/bundle/regal/rules/style/prefer-some-in-iteration/prefer_some_in_iteration.rego +++ b/bundle/regal/rules/style/prefer-some-in-iteration/prefer_some_in_iteration.rego @@ -2,8 +2,6 @@ # description: Prefer `some .. in` for iteration package regal.rules.style["prefer-some-in-iteration"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/style/prefer-some-in-iteration/prefer_some_in_iteration_test.rego b/bundle/regal/rules/style/prefer-some-in-iteration/prefer_some_in_iteration_test.rego index 94e84b05..615bb2b5 100644 --- a/bundle/regal/rules/style/prefer-some-in-iteration/prefer_some_in_iteration_test.rego +++ b/bundle/regal/rules/style/prefer-some-in-iteration/prefer_some_in_iteration_test.rego @@ -1,7 +1,5 @@ package regal.rules.style["prefer-some-in-iteration_test"] -import rego.v1 - import data.regal.ast import data.regal.capabilities import data.regal.config diff --git a/bundle/regal/rules/style/rule-length/rule_length.rego b/bundle/regal/rules/style/rule-length/rule_length.rego index fce25e37..f3b607c1 100644 --- a/bundle/regal/rules/style/rule-length/rule_length.rego +++ b/bundle/regal/rules/style/rule-length/rule_length.rego @@ -2,8 +2,6 @@ # description: Max rule length exceeded package regal.rules.style["rule-length"] -import rego.v1 - import data.regal.config import data.regal.result import data.regal.util @@ -39,7 +37,7 @@ _line_count(cfg, rule, lines) := n if { # This does not take into account comments that are # on the same line as regular code - body_comments := sum([1 | + body_comments := count([1 | some comment in input.comments loc := util.to_location_object(comment.location) diff --git a/bundle/regal/rules/style/rule-length/rule_length_test.rego b/bundle/regal/rules/style/rule-length/rule_length_test.rego index 6f01468b..c40e25db 100644 --- a/bundle/regal/rules/style/rule-length/rule_length_test.rego +++ b/bundle/regal/rules/style/rule-length/rule_length_test.rego @@ -1,7 +1,5 @@ package regal.rules.style["rule-length_test"] -import rego.v1 - import data.regal.config import data.regal.rules.style["rule-length"] as rule @@ -11,7 +9,7 @@ import data.regal.rules.style["rule-length"] as rule test_fail_rule_longer_than_configured_max_length if { module := regal.parse_module("policy.rego", `package p - my_long_rule { + my_long_rule if { # this rule is longer than the configured max length # which in this case is only 3 lines # @@ -36,7 +34,7 @@ test_fail_rule_longer_than_configured_max_length if { "col": 14, "row": 3, }, - "text": "\tmy_long_rule {", + "text": "\tmy_long_rule if {", }, "related_resources": [{ "description": "documentation", @@ -49,7 +47,7 @@ test_fail_rule_longer_than_configured_max_length if { test_success_rule_not_longer_than_configured_max_length if { module := regal.parse_module("policy.rego", `package p - my_short_rule { + my_short_rule if { # this rule is not longer than the configured max length # which in this case is 30 lines # @@ -68,7 +66,7 @@ test_success_rule_not_longer_than_configured_max_length if { test_success_rule_longer_than_configured_max_length_but_comments if { module := regal.parse_module("policy.rego", `package p - my_short_rule { + my_short_rule if { # this rule is not longer than the configured max length # which in this case is 30 lines # diff --git a/bundle/regal/rules/style/rule-name-repeats-package/rule_name_repeats_package.rego b/bundle/regal/rules/style/rule-name-repeats-package/rule_name_repeats_package.rego index 940ffcdc..79001131 100644 --- a/bundle/regal/rules/style/rule-name-repeats-package/rule_name_repeats_package.rego +++ b/bundle/regal/rules/style/rule-name-repeats-package/rule_name_repeats_package.rego @@ -5,8 +5,6 @@ # ref: https://docs.styra.com/regal/rules/style/rule-name-repeats-package package regal.rules.style["rule-name-repeats-package"] -import rego.v1 - import data.regal.ast import data.regal.result import data.regal.util diff --git a/bundle/regal/rules/style/rule-name-repeats-package/rule_name_repeats_package_test.rego b/bundle/regal/rules/style/rule-name-repeats-package/rule_name_repeats_package_test.rego index e10cf3ae..a19b9a5d 100644 --- a/bundle/regal/rules/style/rule-name-repeats-package/rule_name_repeats_package_test.rego +++ b/bundle/regal/rules/style/rule-name-repeats-package/rule_name_repeats_package_test.rego @@ -1,7 +1,5 @@ package regal.rules.style["rule-name-repeats-package_test"] -import rego.v1 - import data.regal.config import data.regal.rules.style["rule-name-repeats-package"] as rule diff --git a/bundle/regal/rules/style/todo-comment/todo_comment.rego b/bundle/regal/rules/style/todo-comment/todo_comment.rego index 45bfc111..1bde0900 100644 --- a/bundle/regal/rules/style/todo-comment/todo_comment.rego +++ b/bundle/regal/rules/style/todo-comment/todo_comment.rego @@ -2,8 +2,6 @@ # description: Avoid TODO comments package regal.rules.style["todo-comment"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/style/todo-comment/todo_comment_test.rego b/bundle/regal/rules/style/todo-comment/todo_comment_test.rego index 4f02cdc8..3fead3dd 100644 --- a/bundle/regal/rules/style/todo-comment/todo_comment_test.rego +++ b/bundle/regal/rules/style/todo-comment/todo_comment_test.rego @@ -1,7 +1,5 @@ package regal.rules.style["todo-comment_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.style["todo-comment"] as rule diff --git a/bundle/regal/rules/style/trailing-default-rule/trailing_default_rule.rego b/bundle/regal/rules/style/trailing-default-rule/trailing_default_rule.rego index 1e9af6e5..08b9e5b4 100644 --- a/bundle/regal/rules/style/trailing-default-rule/trailing_default_rule.rego +++ b/bundle/regal/rules/style/trailing-default-rule/trailing_default_rule.rego @@ -2,8 +2,6 @@ # description: Default rule should be declared first package regal.rules.style["trailing-default-rule"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/style/trailing-default-rule/trailing_default_rule_test.rego b/bundle/regal/rules/style/trailing-default-rule/trailing_default_rule_test.rego index 549397c9..26081f53 100644 --- a/bundle/regal/rules/style/trailing-default-rule/trailing_default_rule_test.rego +++ b/bundle/regal/rules/style/trailing-default-rule/trailing_default_rule_test.rego @@ -1,7 +1,5 @@ package regal.rules.style["trailing-default-rule_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/style/unconditional-assignment/unconditional_assignment.rego b/bundle/regal/rules/style/unconditional-assignment/unconditional_assignment.rego index 1b23c753..13170f58 100644 --- a/bundle/regal/rules/style/unconditional-assignment/unconditional_assignment.rego +++ b/bundle/regal/rules/style/unconditional-assignment/unconditional_assignment.rego @@ -2,8 +2,6 @@ # description: Unconditional assignment in rule body package regal.rules.style["unconditional-assignment"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/style/unconditional-assignment/unconditional_assignment_test.rego b/bundle/regal/rules/style/unconditional-assignment/unconditional_assignment_test.rego index ef11e5df..70595a52 100644 --- a/bundle/regal/rules/style/unconditional-assignment/unconditional_assignment_test.rego +++ b/bundle/regal/rules/style/unconditional-assignment/unconditional_assignment_test.rego @@ -1,13 +1,11 @@ package regal.rules.style["unconditional-assignment_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.style["unconditional-assignment"] as rule test_fail_unconditional_assignment_in_body if { - r := rule.report with input as ast.policy(`x := y { + r := rule.report with input as ast.policy(`x := y if { y := 1 }`) @@ -34,7 +32,7 @@ test_fail_unconditional_assignment_in_body if { } test_fail_unconditional_eq_in_body if { - r := rule.report with input as ast.policy(`x = y { + r := rule.report with input as ast.policy(`x = y if { y = 1 }`) @@ -61,19 +59,19 @@ test_fail_unconditional_eq_in_body if { } test_success_conditional_assignment_in_body if { - r := rule.report with input as ast.policy(`x := y { input.foo == "bar"; y := 1 }`) + r := rule.report with input as ast.policy(`x := y if { input.foo == "bar"; y := 1 }`) r == set() } test_success_unconditional_assignment_but_with_in_body if { - r := rule.report with input as ast.policy(`x := y { y := 5 with input as 1 }`) + r := rule.report with input as ast.policy(`x := y if { y := 5 with input as 1 }`) r == set() } test_success_unconditional_assignment_but_else if { - r := rule.report with input as ast.policy(`msg := x { + r := rule.report with input as ast.policy(`msg := x if { x := input.foo } else := input.bar`) diff --git a/bundle/regal/rules/style/unnecessary-some/unnecessary_some.rego b/bundle/regal/rules/style/unnecessary-some/unnecessary_some.rego index 9b39adfb..4f2ff7bf 100644 --- a/bundle/regal/rules/style/unnecessary-some/unnecessary_some.rego +++ b/bundle/regal/rules/style/unnecessary-some/unnecessary_some.rego @@ -2,8 +2,6 @@ # description: Unnecessary use of `some` package regal.rules.style["unnecessary-some"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/style/unnecessary-some/unnecessary_some_test.rego b/bundle/regal/rules/style/unnecessary-some/unnecessary_some_test.rego index 1b3c9e0e..2eecfffd 100644 --- a/bundle/regal/rules/style/unnecessary-some/unnecessary_some_test.rego +++ b/bundle/regal/rules/style/unnecessary-some/unnecessary_some_test.rego @@ -1,7 +1,5 @@ package regal.rules.style["unnecessary-some_test"] -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/bundle/regal/rules/style/use-assignment-operator/use_assignment_operator.rego b/bundle/regal/rules/style/use-assignment-operator/use_assignment_operator.rego index 7822b36f..55179327 100644 --- a/bundle/regal/rules/style/use-assignment-operator/use_assignment_operator.rego +++ b/bundle/regal/rules/style/use-assignment-operator/use_assignment_operator.rego @@ -2,8 +2,6 @@ # description: Prefer := over = for assignment package regal.rules.style["use-assignment-operator"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/style/use-assignment-operator/use_assignment_operator_test.rego b/bundle/regal/rules/style/use-assignment-operator/use_assignment_operator_test.rego index 3ff54653..cafcc417 100644 --- a/bundle/regal/rules/style/use-assignment-operator/use_assignment_operator_test.rego +++ b/bundle/regal/rules/style/use-assignment-operator/use_assignment_operator_test.rego @@ -1,7 +1,5 @@ package regal.rules.style["use-assignment-operator_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.style["use-assignment-operator"] as rule @@ -31,7 +29,8 @@ test_fail_unification_in_regular_assignment if { } test_fail_not_implicit_boolean_assignment_with_body if { - r := rule.report with input as ast.policy(`allow = true { true }`) + r := rule.report with input as ast.policy(`allow = true if { true }`) + r == {{ "category": "style", "description": "Prefer := over = for assignment", @@ -48,7 +47,7 @@ test_fail_not_implicit_boolean_assignment_with_body if { "col": 8, "row": 3, }, - "text": "allow = true { true }", + "text": "allow = true if { true }", }, "level": "error", }} @@ -79,7 +78,7 @@ test_fail_not_implicit_boolean_assignment if { } test_success_implicit_boolean_assignment if { - r := rule.report with input as ast.policy(`allow { true }`) + r := rule.report with input as ast.policy(`allow if { true }`) r == set() } @@ -195,17 +194,17 @@ test_fail_unification_in_function_assignment if { } test_success_implicit_boolean_assignment_function if { - r := rule.report with input as ast.policy(`f(x) { 1 == 1 }`) + r := rule.report with input as ast.policy(`f(x) if { 1 == 1 }`) r == set() } test_success_assignment_operator_function if { - r := rule.report with input as ast.policy(`f(x) := true { 1 == 1 }`) + r := rule.report with input as ast.policy(`f(x) := true if { 1 == 1 }`) r == set() } test_success_partial_rule if { - r := rule.report with input as ast.policy(`partial["works"] { 1 == 1 }`) + r := rule.report with input as ast.policy(`partial["works"] if { 1 == 1 }`) r == set() } diff --git a/bundle/regal/rules/style/yoda-condition/yoda_condition.rego b/bundle/regal/rules/style/yoda-condition/yoda_condition.rego index d5ab4d28..df6048e0 100644 --- a/bundle/regal/rules/style/yoda-condition/yoda_condition.rego +++ b/bundle/regal/rules/style/yoda-condition/yoda_condition.rego @@ -2,8 +2,6 @@ # description: Yoda condition package regal.rules.style["yoda-condition"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/style/yoda-condition/yoda_condition_test.rego b/bundle/regal/rules/style/yoda-condition/yoda_condition_test.rego index 6b25184d..775c3b70 100644 --- a/bundle/regal/rules/style/yoda-condition/yoda_condition_test.rego +++ b/bundle/regal/rules/style/yoda-condition/yoda_condition_test.rego @@ -1,14 +1,12 @@ package regal.rules.style["yoda-condition_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.style["yoda-condition"] as rule test_fail_yoda_conditions if { - module := ast.policy(`rule { + module := ast.policy(`rule if { "foo" == input.bar nested := [foo | @@ -25,7 +23,7 @@ test_fail_yoda_conditions if { } test_fail_yoda_conditions_not_equals if { - module := ast.policy(`rule { + module := ast.policy(`rule if { "foo" != input.bar nested := [foo | @@ -41,7 +39,7 @@ test_fail_yoda_conditions_not_equals if { } test_success_no_yoda_condition if { - module := ast.policy(`rule { + module := ast.policy(`rule if { input.bar == "foo" }`) r := rule.report with input as module @@ -49,7 +47,7 @@ test_success_no_yoda_condition if { } test_success_constants_on_both_sides if { - module := ast.policy(`rule { + module := ast.policy(`rule if { "foo" == "foo" }`) r := rule.report with input as module @@ -57,7 +55,7 @@ test_success_constants_on_both_sides if { } test_success_exclude_ref_with_vars if { - module := ast.policy(`rule { + module := ast.policy(`rule if { "foo" == input.bar[_] }`) r := rule.report with input as module diff --git a/bundle/regal/rules/testing/dubious-print-sprintf/dubious_print_sprintf.rego b/bundle/regal/rules/testing/dubious-print-sprintf/dubious_print_sprintf.rego index 2b8554d4..421c39f9 100644 --- a/bundle/regal/rules/testing/dubious-print-sprintf/dubious_print_sprintf.rego +++ b/bundle/regal/rules/testing/dubious-print-sprintf/dubious_print_sprintf.rego @@ -2,8 +2,6 @@ # description: Dubious use of print and sprintf package regal.rules.testing["dubious-print-sprintf"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/testing/dubious-print-sprintf/dubious_print_sprintf_test.rego b/bundle/regal/rules/testing/dubious-print-sprintf/dubious_print_sprintf_test.rego index 3e2bd009..a4de46e6 100644 --- a/bundle/regal/rules/testing/dubious-print-sprintf/dubious_print_sprintf_test.rego +++ b/bundle/regal/rules/testing/dubious-print-sprintf/dubious_print_sprintf_test.rego @@ -1,7 +1,5 @@ package regal.rules.testing["dubious-print-sprintf_test"] -import rego.v1 - import data.regal.ast import data.regal.capabilities import data.regal.config @@ -9,7 +7,7 @@ import data.regal.config import data.regal.rules.testing["dubious-print-sprintf"] as rule test_fail_print_sprintf if { - module := ast.policy(`y { + module := ast.policy(`y if { print(sprintf("name is: %s domain is: %s", [input.name, input.domain])) }`) @@ -38,7 +36,7 @@ test_fail_print_sprintf if { } test_fail_bodies_print_sprintf if { - module := ast.policy(`y { + module := ast.policy(`y if { comprehension := [x | x := input[_] print(sprintf("x is: %s", [x])) diff --git a/bundle/regal/rules/testing/file-missing-test-suffix/file_missing_test_suffix.rego b/bundle/regal/rules/testing/file-missing-test-suffix/file_missing_test_suffix.rego index ccbd3b2f..b72f47a9 100644 --- a/bundle/regal/rules/testing/file-missing-test-suffix/file_missing_test_suffix.rego +++ b/bundle/regal/rules/testing/file-missing-test-suffix/file_missing_test_suffix.rego @@ -2,8 +2,6 @@ # description: Files containing tests should have a _test.rego suffix package regal.rules.testing["file-missing-test-suffix"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.result diff --git a/bundle/regal/rules/testing/file-missing-test-suffix/file_missing_test_suffix_test.rego b/bundle/regal/rules/testing/file-missing-test-suffix/file_missing_test_suffix_test.rego index 0f0d6f3c..6ee94ef9 100644 --- a/bundle/regal/rules/testing/file-missing-test-suffix/file_missing_test_suffix_test.rego +++ b/bundle/regal/rules/testing/file-missing-test-suffix/file_missing_test_suffix_test.rego @@ -1,7 +1,5 @@ package regal.rules.testing["file-missing-test-suffix_test"] -import rego.v1 - import data.regal.config import data.regal.rules.testing["file-missing-test-suffix"] as rule @@ -9,7 +7,7 @@ import data.regal.rules.testing["file-missing-test-suffix"] as rule test_fail_test_in_file_without_test_suffix if { ast := regal.parse_module("policy.rego", `package foo_test - test_foo { false } + test_foo if { false } `) r := rule.report with input as ast @@ -29,7 +27,7 @@ test_fail_test_in_file_without_test_suffix if { test_success_test_in_file_with_test_suffix if { ast := regal.parse_module("policy_test.rego", `package policy_test - test_foo { false } + test_foo if { false } `) r := rule.report with input as ast @@ -39,7 +37,7 @@ test_success_test_in_file_with_test_suffix if { test_success_test_in_file_named_test if { ast := regal.parse_module("test.rego", `package test - test_foo { false } + test_foo if { false } `) r := rule.report with input as ast diff --git a/bundle/regal/rules/testing/identically-named-tests/identically_named_tests.rego b/bundle/regal/rules/testing/identically-named-tests/identically_named_tests.rego index 3f10953b..fe4ab534 100644 --- a/bundle/regal/rules/testing/identically-named-tests/identically_named_tests.rego +++ b/bundle/regal/rules/testing/identically-named-tests/identically_named_tests.rego @@ -2,8 +2,6 @@ # description: Multiple tests with same name package regal.rules.testing["identically-named-tests"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/testing/identically-named-tests/identically_named_tests_test.rego b/bundle/regal/rules/testing/identically-named-tests/identically_named_tests_test.rego index ccaa05aa..d91db161 100644 --- a/bundle/regal/rules/testing/identically-named-tests/identically_named_tests_test.rego +++ b/bundle/regal/rules/testing/identically-named-tests/identically_named_tests_test.rego @@ -1,7 +1,5 @@ package regal.rules.testing["identically-named-tests_test"] -import rego.v1 - import data.regal.config import data.regal.rules.testing["identically-named-tests"] as rule @@ -9,8 +7,8 @@ test_fail_identically_named_tests if { ast := regal.parse_module("foo_test.rego", ` package foo_test - test_foo { false } - test_foo { true } + test_foo if { false } + test_foo if { true } `) r := rule.report with input as ast @@ -30,7 +28,7 @@ test_fail_identically_named_tests if { "row": 5, }, "file": "foo_test.rego", - "text": "\ttest_foo { true }", + "text": "\ttest_foo if { true }", }, "level": "error", }} @@ -40,9 +38,9 @@ test_success_differently_named_tests if { ast := regal.parse_module("foo_test.rego", ` package foo_test - test_foo { false } - test_bar { true } - test_baz { 1 == 1 } + test_foo if { false } + test_bar if { true } + test_baz if { 1 == 1 } `) r := rule.report with input as ast r == set() diff --git a/bundle/regal/rules/testing/metasyntactic-variable/metasyntactic_variable.rego b/bundle/regal/rules/testing/metasyntactic-variable/metasyntactic_variable.rego index 95e023a0..fb323cbe 100644 --- a/bundle/regal/rules/testing/metasyntactic-variable/metasyntactic_variable.rego +++ b/bundle/regal/rules/testing/metasyntactic-variable/metasyntactic_variable.rego @@ -2,8 +2,6 @@ # description: Metasyntactic variable name package regal.rules.testing["metasyntactic-variable"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/testing/metasyntactic-variable/metasyntactic_variable_test.rego b/bundle/regal/rules/testing/metasyntactic-variable/metasyntactic_variable_test.rego index c6fc8c31..461ff800 100644 --- a/bundle/regal/rules/testing/metasyntactic-variable/metasyntactic_variable_test.rego +++ b/bundle/regal/rules/testing/metasyntactic-variable/metasyntactic_variable_test.rego @@ -1,7 +1,5 @@ package regal.rules.testing["metasyntactic-variable_test"] -import rego.v1 - import data.regal.ast import data.regal.config @@ -24,7 +22,7 @@ test_fail_rule_named_foo if { } test_fail_metasyntactic_vars if { - module := ast.policy(`allow { + module := ast.policy(`allow if { fooBar := true input[baz] }`) diff --git a/bundle/regal/rules/testing/print-or-trace-call/print_or_trace_call.rego b/bundle/regal/rules/testing/print-or-trace-call/print_or_trace_call.rego index 28ee8adb..3fe9fcc6 100644 --- a/bundle/regal/rules/testing/print-or-trace-call/print_or_trace_call.rego +++ b/bundle/regal/rules/testing/print-or-trace-call/print_or_trace_call.rego @@ -2,8 +2,6 @@ # description: Call to print or trace function package regal.rules.testing["print-or-trace-call"] -import rego.v1 - import data.regal.ast import data.regal.result import data.regal.util diff --git a/bundle/regal/rules/testing/print-or-trace-call/print_or_trace_call_test.rego b/bundle/regal/rules/testing/print-or-trace-call/print_or_trace_call_test.rego index 835054cd..294b604c 100644 --- a/bundle/regal/rules/testing/print-or-trace-call/print_or_trace_call_test.rego +++ b/bundle/regal/rules/testing/print-or-trace-call/print_or_trace_call_test.rego @@ -1,13 +1,11 @@ package regal.rules.testing["print-or-trace-call_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.testing["print-or-trace-call"] as rule test_fail_call_to_print_and_trace if { - r := rule.report with input as ast.policy(`allow { + r := rule.report with input as ast.policy(`allow if { print("foo") x := [i | i = 0; trace("bar")] diff --git a/bundle/regal/rules/testing/test-outside-test-package/test_outside_test_package.rego b/bundle/regal/rules/testing/test-outside-test-package/test_outside_test_package.rego index ee4d9340..94467a3b 100644 --- a/bundle/regal/rules/testing/test-outside-test-package/test_outside_test_package.rego +++ b/bundle/regal/rules/testing/test-outside-test-package/test_outside_test_package.rego @@ -2,8 +2,6 @@ # description: Test outside of test package package regal.rules.testing["test-outside-test-package"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/testing/test-outside-test-package/test_outside_test_package_test.rego b/bundle/regal/rules/testing/test-outside-test-package/test_outside_test_package_test.rego index c5e6e7e4..5bae33ce 100644 --- a/bundle/regal/rules/testing/test-outside-test-package/test_outside_test_package_test.rego +++ b/bundle/regal/rules/testing/test-outside-test-package/test_outside_test_package_test.rego @@ -1,7 +1,5 @@ package regal.rules.testing["test-outside-test-package_test"] -import rego.v1 - import data.regal.ast import data.regal.config import data.regal.rules.testing["test-outside-test-package"] as rule diff --git a/bundle/regal/rules/testing/todo-test/todo_test.rego b/bundle/regal/rules/testing/todo-test/todo_test.rego index f1ac6028..4990b088 100644 --- a/bundle/regal/rules/testing/todo-test/todo_test.rego +++ b/bundle/regal/rules/testing/todo-test/todo_test.rego @@ -2,8 +2,6 @@ # description: TODO test encountered package regal.rules.testing["todo-test"] -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/bundle/regal/rules/testing/todo-test/todo_test_test.rego b/bundle/regal/rules/testing/todo-test/todo_test_test.rego index f22e78a2..d398961d 100644 --- a/bundle/regal/rules/testing/todo-test/todo_test_test.rego +++ b/bundle/regal/rules/testing/todo-test/todo_test_test.rego @@ -1,7 +1,5 @@ package regal.rules.testing["todo-test_test"] -import rego.v1 - import data.regal.config import data.regal.rules.testing["todo-test"] as rule @@ -9,9 +7,9 @@ test_fail_todo_test if { ast := regal.parse_module("foo_test.rego", ` package foo_test - todo_test_foo { false } + todo_test_foo if { false } - test_bar { true } + test_bar if { true } `) r := rule.report with input as ast @@ -31,7 +29,7 @@ test_fail_todo_test if { "col": 15, "row": 4, }, - "text": "\ttodo_test_foo { false }", + "text": "\ttodo_test_foo if { false }", }, "level": "error", }} diff --git a/bundle/regal/util/util.rego b/bundle/regal/util/util.rego index 99e66645..b6615f7f 100644 --- a/bundle/regal/util/util.rego +++ b/bundle/regal/util/util.rego @@ -2,8 +2,6 @@ # description: various utility functions for linter policies package regal.util -import rego.v1 - # METADATA # description: returns true if string is snake_case formatted is_snake_case(str) if str == lower(str) diff --git a/bundle/regal/util/util_test.rego b/bundle/regal/util/util_test.rego index e05eb349..ffedfebe 100644 --- a/bundle/regal/util/util_test.rego +++ b/bundle/regal/util/util_test.rego @@ -1,7 +1,5 @@ package regal.util_test -import rego.v1 - import data.regal.util test_find_duplicates if { diff --git a/cmd/capabilities.go b/cmd/capabilities.go index bb3c7300..519879f2 100644 --- a/cmd/capabilities.go +++ b/cmd/capabilities.go @@ -1,10 +1,10 @@ package cmd import ( + "encoding/json" "fmt" "os" - "github.com/anderseknert/roast/pkg/encoding" "github.com/spf13/cobra" "github.com/styrainc/regal/internal/compile" @@ -17,7 +17,7 @@ func init() { Short: "Print the capabilities of Regal", Long: "Show capabilities for Regal", RunE: func(*cobra.Command, []string) error { - bs, err := encoding.JSON().MarshalIndent(compile.Capabilities(), "", " ") + bs, err := json.MarshalIndent(compile.Capabilities(), "", " ") if err != nil { return fmt.Errorf("failed marshalling capabilities: %w", err) } diff --git a/cmd/debugger.go b/cmd/debugger.go index e99142c8..0aabe1d5 100644 --- a/cmd/debugger.go +++ b/cmd/debugger.go @@ -14,10 +14,10 @@ import ( godap "github.com/google/go-dap" "github.com/spf13/cobra" - "github.com/open-policy-agent/opa/ast/location" - "github.com/open-policy-agent/opa/debug" - "github.com/open-policy-agent/opa/logging" - "github.com/open-policy-agent/opa/rego" + "github.com/open-policy-agent/opa/v1/ast/location" + "github.com/open-policy-agent/opa/v1/debug" + "github.com/open-policy-agent/opa/v1/logging" + "github.com/open-policy-agent/opa/v1/rego" "github.com/styrainc/regal/internal/dap" "github.com/styrainc/regal/pkg/builtins" diff --git a/cmd/filter.go b/cmd/filter.go index 52624feb..2c2878d0 100644 --- a/cmd/filter.go +++ b/cmd/filter.go @@ -7,7 +7,7 @@ package cmd import ( "os" - "github.com/open-policy-agent/opa/loader" + "github.com/open-policy-agent/opa/v1/loader" ) type loaderFilter struct { diff --git a/cmd/fix.go b/cmd/fix.go index 32c46535..4a4f5f38 100644 --- a/cmd/fix.go +++ b/cmd/fix.go @@ -16,9 +16,6 @@ import ( "github.com/spf13/cobra" "gopkg.in/yaml.v3" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/format" - "github.com/styrainc/regal/internal/git" rio "github.com/styrainc/regal/internal/io" "github.com/styrainc/regal/internal/util" @@ -204,6 +201,8 @@ func fix(args []string, params *fixCommandParams) error { } else { regalDir, err = config.FindRegalDirectory(configSearchPath) if err == nil { + defer regalDir.Close() + customRulesPath := filepath.Join(regalDir.Name(), rio.PathSeparator, "rules") if _, err = os.Stat(customRulesPath); err == nil { customRulesDir = customRulesPath @@ -232,6 +231,10 @@ func fix(args []string, params *fixCommandParams) error { l = l.WithIgnore(params.ignoreFiles.v) } + if regalDir != nil { + l = l.WithPathPrefix(filepath.Dir(regalDir.Name())) + } + var userConfig config.Config userConfigFile, err := readUserConfig(params, regalDir) @@ -270,14 +273,6 @@ func fix(args []string, params *fixCommandParams) error { f := fixer.NewFixer() f.RegisterRoots(roots...) f.RegisterFixes(fixes.NewDefaultFixes()...) - f.RegisterMandatoryFixes( - &fixes.Fmt{ - NameOverride: "use-rego-v1", - OPAFmtOpts: format.Opts{ - RegoVersion: ast.RegoV0CompatV1, - }, - }, - ) if !slices.Contains([]string{"error", "rename"}, params.conflictMode) { return fmt.Errorf("invalid conflict mode: %s, expected 'error' or 'rename'", params.conflictMode) diff --git a/cmd/lint.go b/cmd/lint.go index dc58cccb..31ce4b62 100644 --- a/cmd/lint.go +++ b/cmd/lint.go @@ -17,9 +17,9 @@ import ( "github.com/spf13/cobra" "gopkg.in/yaml.v3" - "github.com/open-policy-agent/opa/bundle" - "github.com/open-policy-agent/opa/metrics" - "github.com/open-policy-agent/opa/topdown" + "github.com/open-policy-agent/opa/v1/bundle" + "github.com/open-policy-agent/opa/v1/metrics" + "github.com/open-policy-agent/opa/v1/topdown" rbundle "github.com/styrainc/regal/bundle" rio "github.com/styrainc/regal/internal/io" @@ -292,6 +292,10 @@ func lint(args []string, params *lintCommandParams) (report.Report, error) { regal = regal.WithInstrumentation(true) } + if regalDir != nil { + regal = regal.WithPathPrefix(filepath.Dir(regalDir.Name())) + } + var userConfig config.Config userConfigFile, err := readUserConfig(params, regalDir) diff --git a/cmd/parse.go b/cmd/parse.go index 9502fcb4..4010f824 100644 --- a/cmd/parse.go +++ b/cmd/parse.go @@ -10,8 +10,6 @@ import ( "github.com/anderseknert/roast/pkg/util" "github.com/spf13/cobra" - "github.com/open-policy-agent/opa/ast" - rp "github.com/styrainc/regal/internal/parse" ) @@ -54,7 +52,7 @@ func parse(args []string) error { content := util.ByteSliceToString(bs) - module, err := ast.ParseModuleWithOpts(filename, content, rp.ParserOptions()) + module, err := rp.ModuleUnknownVersionWithOpts(filename, content, rp.ParserOptions()) if err != nil { return err } diff --git a/cmd/table.go b/cmd/table.go index 02628670..4981fcef 100644 --- a/cmd/table.go +++ b/cmd/table.go @@ -14,8 +14,8 @@ import ( "github.com/olekukonko/tablewriter" "github.com/spf13/cobra" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/loader" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/loader" "github.com/styrainc/regal/internal/compile" "github.com/styrainc/regal/internal/docs" diff --git a/cmd/test.go b/cmd/test.go index db87bf87..5a0b9350 100644 --- a/cmd/test.go +++ b/cmd/test.go @@ -15,15 +15,15 @@ import ( "github.com/spf13/cobra" "github.com/spf13/pflag" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/bundle" - "github.com/open-policy-agent/opa/cover" - "github.com/open-policy-agent/opa/storage" - "github.com/open-policy-agent/opa/storage/inmem" - "github.com/open-policy-agent/opa/tester" - "github.com/open-policy-agent/opa/topdown" - "github.com/open-policy-agent/opa/util" - "github.com/open-policy-agent/opa/version" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/bundle" + "github.com/open-policy-agent/opa/v1/cover" + "github.com/open-policy-agent/opa/v1/storage" + "github.com/open-policy-agent/opa/v1/storage/inmem" + "github.com/open-policy-agent/opa/v1/tester" + "github.com/open-policy-agent/opa/v1/topdown" + "github.com/open-policy-agent/opa/v1/util" + "github.com/open-policy-agent/opa/v1/version" rbundle "github.com/styrainc/regal/bundle" "github.com/styrainc/regal/internal/compile" diff --git a/docs/custom-rules.md b/docs/custom-rules.md index 33760d80..b9448c84 100644 --- a/docs/custom-rules.md +++ b/docs/custom-rules.md @@ -133,8 +133,6 @@ An example policy to implement this requirement might look something like this: # - input: schema.regal.ast package custom.regal.rules.naming["acme-corp-package"] -import rego.v1 - import data.regal.result report contains violation if { @@ -268,8 +266,6 @@ from files, and one that actually lints and reports violations using that data. # - input: schema.regal.ast package custom.regal.rules.organizational["at-least-one-allow"] -import rego.v1 - import data.regal.ast import data.regal.result @@ -348,6 +344,8 @@ Works just like `rego.parse_module`, but provides an AST including location info by Regal, like the text representation of each line in the original policy. This is useful for authoring tests to assert linter rules work as expected. This is the built-in function equivalent of the `regal parse` command. +If the `filename` provided ends with `_v0.rego`, the policy will be parsed as a Rego v0 module. + ### `regal.last(array)` This built-in function is a much more performant way to express `array[count(array) - 1]`. This performance difference diff --git a/docs/opa-one-dot-zero.md b/docs/opa-one-dot-zero.md new file mode 100644 index 00000000..fa34a600 --- /dev/null +++ b/docs/opa-one-dot-zero.md @@ -0,0 +1,76 @@ +# OPA 1.0 and Regal + +While we always recommend using the latest version of OPA, we're well aware that there may be situations where — for +one reason or another — that might not be possible. As we want everyone to benefit from Regal, we do our very best to +ensure it works seamlessly with OPA versions both before and after 1.0, and even projects that use a mix of both! While +this should mostly work out of the box and without additional configuration, it's good to be aware of how Regal parses +and lints policies of different versions of Rego, and how you can tell Regal to target only a specific version. + +**Note:** This document does not cover the specifics of OPA 1.0, but rather how Regal works with it. If you want to +learn more about what OPA 1.0 is and how to upgrade, see the [related resources](#related-resources) at the bottom of +this page. + +## Telling Regal which Rego version to target + +While Regal pretty accurately guesses the Rego version of the policies it's linting — and will adapt how it parses and +asseses Rego files accordingly — telling Regal which version to target is always going to produce the most reliable +results — and much faster too! Guessing which Rego version to target often involves multiple passes of parsing, and +as some files are both valid Rego v0 and v1, there will always be some ambiguity. In order to avoid this, our +recommendation is to always provide Regal with the Rego version(s) targeted. This can be done in a couple of ways, and +the precedence of these methods is as listed below: + +1. Setting the `rego-version` configuration option under `project.roots` attribute +2. Setting the `rego-version` configuration option under `project` attribute +3. Setting the `rego_version` in a `.manifest` file in any directory (will apply to that directory and any below it) + +Note that it's is perfectly possible to use different `rego-version`s for different roots of a project: + +```yaml +project: + rego-version: 1 + roots: + # lib/legacy overriding project version to set versin 0 + - path: lib/legacy + rego-version: 0 + # main directory will inherit version 1 from project + - path: main +``` + +See the documentation covering Regal's [configuration](https://docs.styra.com/regal#configuration) for more information +on [configuring Rego version](https://docs.styra.com/regal#configuring-rego-version) for your project. + +Finally, Regal will automatically parse and lint any file with a `_v0.rego` suffix as Rego v0. This is intended only +for testing and development, where you sometimes may want to try something out using and older Rego version without +configuration. Note that this has lower precedence than Rego versions set by other means, and should not be considered +as anything but a convenience for testing. + +## Rules disabled with OPA 1.0 + +Some linter rules don't really make sense to enforce post OPA 1.0, as they are now either enforced by OPA itself or +otherwise no longer relevant. The following rules are now disabled by default, unless Regal is configured to target +Rego versions before 1.0, or in the case where no configuration is provided, Regal determines that the project being +linted is not yet using OPA 1.0: + +- [deprecated-builtin](https://docs.styra.com/regal/rules/bugs/deprecated-builtin) +- [import-shadows-import](https://docs.styra.com/regal/rules/imports/import-shadows-import) +- [rule-named-if](https://docs.styra.com/regal/rules/bugs/rule-named-if) +- [use-contains](https://docs.styra.com/regal/rules/idiomatic/use-contains) +- [use-if](https://docs.styra.com/regal/rules/idiomatic/use-if) +- [use-rego-v1](https://docs.styra.com/regal/rules/imports/use-rego-v1) + +Except for the `deprecated-bultin` rule — which is disabled simply because there currently are no deprecated built-ins +in OPA 1.0 — these rules are now enforced automatically by OPA, and so there's no reason for Regal to duplicate that +effort. + +## Related Resources + +- OPA Docs: [Upgrading to v1.0](https://www.openpolicyagent.org/docs/latest/v0-upgrade/) +- OPA Docs: [v0 Backwards Compatibility](https://www.openpolicyagent.org/docs/latest/v0-compatibility/) +- Styra Blog: [Renovating Rego](https://www.styra.com/blog/renovating-rego/) +- OPA Blog: [OPA 1.0 Is Coming, Here's What You Need to Know](https://blog.openpolicyagent.org/opa-1-0-is-coming-heres-what-you-need-to-know-c8fb0d258368) +- OPA Blog: [Announcing OPA 1.0: A New Standard for Policy as Code](https://blog.openpolicyagent.org/announcing-opa-1-0-a-new-standard-for-policy-as-code-a6d8427ee828) + +## Community + +If you have any questions related to OPA 1.0 and Regal, please join the Styra community on +[Slack](https://communityinviter.com/apps/styracommunity/signup) and we'll be happy to help you out! diff --git a/docs/rules/bugs/annotation-without-metadata.md b/docs/rules/bugs/annotation-without-metadata.md index d6cf4f32..3326f8ee 100644 --- a/docs/rules/bugs/annotation-without-metadata.md +++ b/docs/rules/bugs/annotation-without-metadata.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - # description: allow allows allow if { # ... some conditions @@ -20,8 +18,6 @@ allow if { ```rego package policy -import rego.v1 - # METADATA # description: allow allows allow if { diff --git a/docs/rules/bugs/argument-always-wildcard.md b/docs/rules/bugs/argument-always-wildcard.md index 3b47e6cd..1fc7d317 100644 --- a/docs/rules/bugs/argument-always-wildcard.md +++ b/docs/rules/bugs/argument-always-wildcard.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - # there's only one definition of the last_name function in # this package, and the second argument is never used last_name(name, _) := lname if { @@ -22,8 +20,6 @@ last_name(name, _) := lname if { ```rego package policy -import rego.v1 - last_name(name) := lname if { parts := split(name, " ") lname := parts[count(parts) - 1] @@ -39,8 +35,6 @@ are used in that definition of the function. This is particularly useful for inc ```rego package policy -import rego.v1 - default authorized(_, _) := false authorized(user, _) if { @@ -60,8 +54,6 @@ cleaner definition. More likely, the argument was meant to be _used_, if only in ```rego package policy -import rego.v1 - default authorized(_, _) := false authorized(user, _) if { diff --git a/docs/rules/bugs/constant-condition.md b/docs/rules/bugs/constant-condition.md index cb314092..e51bcfc8 100644 --- a/docs/rules/bugs/constant-condition.md +++ b/docs/rules/bugs/constant-condition.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - allow if { 1 == 1 } diff --git a/docs/rules/bugs/deprecated-builtin.md b/docs/rules/bugs/deprecated-builtin.md index 9d60d540..2782dda1 100644 --- a/docs/rules/bugs/deprecated-builtin.md +++ b/docs/rules/bugs/deprecated-builtin.md @@ -4,6 +4,19 @@ **Category**: Bugs +## Notice: Rule disabled with OPA 1.0 + +Since Regal v0.30.0, this rule is only enabled for projects that have either been explicitly configured to target +versions of OPA before 1.0, or if no configuration is provided — where Regal is able to determine that an older version +of OPA/Rego is being targeted. Consult the documentation on Regal's +[configuration](https://docs.styra.com/regal#configuration) for information on how to best work with older versions of +OPA and Rego. + +Since OPA v1.0, this rule is automatically disabled, as there currently are no deprecated built-in functions +in that version, and trying to use a previously deprecated function will result in a parser error. Note however that +this may change if later OPA versions deprecate current built-in functions. If/when that happens, this rule will be +re-enabled. + **Avoid** ```rego package policy diff --git a/docs/rules/bugs/duplicate-rule.md b/docs/rules/bugs/duplicate-rule.md index 666575b7..221c09a0 100644 --- a/docs/rules/bugs/duplicate-rule.md +++ b/docs/rules/bugs/duplicate-rule.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - allow if user.is_admin allow if user.is_developer @@ -22,8 +20,6 @@ allow if user.is_admin ```rego package policy -import rego.v1 - allow if user.is_admin allow if user.is_developer diff --git a/docs/rules/bugs/if-empty-object.md b/docs/rules/bugs/if-empty-object.md index e5e83bf7..65fed27a 100644 --- a/docs/rules/bugs/if-empty-object.md +++ b/docs/rules/bugs/if-empty-object.md @@ -12,8 +12,6 @@ the sake of posterity.** ```rego package policy -import rego.v1 - allow if {} ``` diff --git a/docs/rules/bugs/if-object-literal.md b/docs/rules/bugs/if-object-literal.md index 2ef7049c..d19e20a8 100644 --- a/docs/rules/bugs/if-object-literal.md +++ b/docs/rules/bugs/if-object-literal.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - # {} interpreted as object, not a rule body allow if {} diff --git a/docs/rules/bugs/impossible-not.md b/docs/rules/bugs/impossible-not.md index 395d3132..396cc61e 100644 --- a/docs/rules/bugs/impossible-not.md +++ b/docs/rules/bugs/impossible-not.md @@ -10,8 +10,6 @@ ```rego package policy -import rego.v1 - report contains violation if { # ... some conditions } @@ -20,8 +18,6 @@ report contains violation if { ```rego package policy_test -import rego.v1 - import data.policy test_report_is_empty { @@ -34,8 +30,6 @@ test_report_is_empty { ```rego package policy -import rego.v1 - report contains violation if { # ... some conditions } @@ -44,8 +38,6 @@ report contains violation if { ```rego package policy_test -import rego.v1 - import data.policy test_report_is_empty { diff --git a/docs/rules/bugs/inconsistent-args.md b/docs/rules/bugs/inconsistent-args.md index 21b27616..c68ad500 100644 --- a/docs/rules/bugs/inconsistent-args.md +++ b/docs/rules/bugs/inconsistent-args.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - find_vars(rule, node) if node in rule # Order of arguments changed, or at least it looks like it @@ -23,8 +21,6 @@ find_vars(node, rule) if { ```rego package policy -import rego.v1 - find_vars(rule, node) if node in rule find_vars(rule, node) if { @@ -46,8 +42,6 @@ Using wildcards (`_`) in place of unused arguments is always allowed, and in fac ```rego package policy -import rego.v1 - find_vars(rule, node) if node in rule # We don't use `node` here diff --git a/docs/rules/bugs/internal-entrypoint.md b/docs/rules/bugs/internal-entrypoint.md index 093615aa..a4a4f291 100644 --- a/docs/rules/bugs/internal-entrypoint.md +++ b/docs/rules/bugs/internal-entrypoint.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - # METADATA # entrypoint: true _authorized if { @@ -21,8 +19,6 @@ _authorized if { ```rego package policy -import rego.v1 - # METADATA # entrypoint: true allow if _authorized diff --git a/docs/rules/bugs/not-equals-in-loop.md b/docs/rules/bugs/not-equals-in-loop.md index 64bebe9c..64324529 100644 --- a/docs/rules/bugs/not-equals-in-loop.md +++ b/docs/rules/bugs/not-equals-in-loop.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - deny if { "admin" != input.user.roles[_] } @@ -19,8 +17,6 @@ deny if { ```rego package policy -import rego.v1 - deny if { not "admin" in input.user.roles } @@ -38,8 +34,6 @@ day. If it doesn't mean "not in", what does it mean? ```rego package policy -import rego.v1 - deny if { "admin" != input.user.roles[_] } diff --git a/docs/rules/bugs/redundant-existence-check.md b/docs/rules/bugs/redundant-existence-check.md index 3d51a55b..d50c62ca 100644 --- a/docs/rules/bugs/redundant-existence-check.md +++ b/docs/rules/bugs/redundant-existence-check.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - employee if { input.user.email endswith(input.user.email, "@acmecorp.com") @@ -25,8 +23,6 @@ is_admin(user) if { ```rego package policy -import rego.v1 - employee if { endswith(input.user.email, "@acmecorp.com") } diff --git a/docs/rules/bugs/rule-assigns-default.md b/docs/rules/bugs/rule-assigns-default.md index 75de767a..72e8a7a3 100644 --- a/docs/rules/bugs/rule-assigns-default.md +++ b/docs/rules/bugs/rule-assigns-default.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - default allow := false # this rule assigns the same value as the default @@ -23,8 +21,6 @@ allow := false if { ```rego package policy -import rego.v1 - default allow := false # or just `allow if {` as `true` is implicit diff --git a/docs/rules/bugs/rule-named-if.md b/docs/rules/bugs/rule-named-if.md index 226ea58b..d511e2f7 100644 --- a/docs/rules/bugs/rule-named-if.md +++ b/docs/rules/bugs/rule-named-if.md @@ -4,6 +4,17 @@ **Category**: Bugs +## Notice: Rule made obsolete by OPA 1.0 + +Since Regal v0.30.0, this rule is only enabled for projects that have either been explicitly configured to target +versions of OPA before 1.0, or if no configuration is provided — where Regal is able to determine that an older version +of OPA/Rego is being targeted. Consult the documentation on Regal's +[configuration](https://docs.styra.com/regal#configuration) for information on how to best work with older versions of +OPA and Rego. + +Since OPA v1.0, this rule is automatically disabled, as the parser itself will throw an error if a rule is named `if`, +as that is made a keyword in Rego v1.0. + **Avoid** ```rego package policy @@ -17,8 +28,6 @@ allow := true if { ```rego package policy -import rego.v1 - allow := true if { authorized } diff --git a/docs/rules/bugs/sprintf-arguments-mismatch.md b/docs/rules/bugs/sprintf-arguments-mismatch.md index a0751ddb..91412241 100644 --- a/docs/rules/bugs/sprintf-arguments-mismatch.md +++ b/docs/rules/bugs/sprintf-arguments-mismatch.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - max_issues := 1 report contains warning if { @@ -24,8 +22,6 @@ report contains warning if { ```rego package policy -import rego.v1 - max_issues := 1 report contains warning if { diff --git a/docs/rules/bugs/unassigned-return-value.md b/docs/rules/bugs/unassigned-return-value.md index 510eabd4..2fd8d366 100644 --- a/docs/rules/bugs/unassigned-return-value.md +++ b/docs/rules/bugs/unassigned-return-value.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - allow if { # return value not assigned lower(input.user.name) diff --git a/docs/rules/bugs/var-shadows-builtin.md b/docs/rules/bugs/var-shadows-builtin.md index 097ee8d7..0e8b97d1 100644 --- a/docs/rules/bugs/var-shadows-builtin.md +++ b/docs/rules/bugs/var-shadows-builtin.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - # variable `http` shadows `http.send` built-in function allow if { http := startswith(input.url, "http://") @@ -21,8 +19,6 @@ allow if { ```rego package policy -import rego.v1 - # variable `is_http` doesn't shadow any built-in function allow if { is_http := startswith(input.url, "http://") diff --git a/docs/rules/custom/missing-metadata.md b/docs/rules/custom/missing-metadata.md index f620404d..77dbb210 100644 --- a/docs/rules/custom/missing-metadata.md +++ b/docs/rules/custom/missing-metadata.md @@ -8,8 +8,6 @@ ```rego package acmecorp.authz -import rego.v1 - authorized_users contains user if { # logic to determine authorized users } @@ -21,8 +19,6 @@ authorized_users contains user if { # description: The `acmecorp.authz` module provides authorization logic for the AcmeCorp application. package acmecorp.authz -import rego.v1 - # METADATA # description: Provides a set of all authorized users given the conditions in `input`. # scope: document diff --git a/docs/rules/custom/one-liner-rule.md b/docs/rules/custom/one-liner-rule.md index 0b2e3051..a496f1d6 100644 --- a/docs/rules/custom/one-liner-rule.md +++ b/docs/rules/custom/one-liner-rule.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - allow if { is_admin } @@ -23,8 +21,6 @@ is_admin if { ```rego package policy -import rego.v1 - allow if is_admin is_admin if "admin" in input.user.roles diff --git a/docs/rules/custom/prefer-value-in-head.md b/docs/rules/custom/prefer-value-in-head.md index c5b70dec..42a30d85 100644 --- a/docs/rules/custom/prefer-value-in-head.md +++ b/docs/rules/custom/prefer-value-in-head.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - pin_as_number := val if { is_number(input.pin_code) val := to_number(input.pin_code) @@ -25,8 +23,6 @@ deny contains message if { ```rego package policy -import rego.v1 - pin_as_number := to_number(input.pin_code) if is_number(input.pin_code) deny contains "user attribute missing from input" if not input.user diff --git a/docs/rules/idiomatic/ambiguous-scope.md b/docs/rules/idiomatic/ambiguous-scope.md index 427fe781..c4ef442d 100644 --- a/docs/rules/idiomatic/ambiguous-scope.md +++ b/docs/rules/idiomatic/ambiguous-scope.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - # METADATA # description: allow is true if the user is admin, or the requested resource is public allow if user_is_admin @@ -21,8 +19,6 @@ allow if public_resource ```rego package policy -import rego.v1 - # METADATA # description: allow is true if the user is admin, or the requested resource is public # scope: document @@ -35,8 +31,6 @@ allow if public_resource ```rego package policy -import rego.v1 - # METADATA # description: allow is true if the user is admin allow if user_is_admin @@ -50,8 +44,6 @@ allow if public_resource ```rego package policy -import rego.v1 - # METADATA # description: allow is true if the user is admin # scope: rule diff --git a/docs/rules/idiomatic/boolean-assignment.md b/docs/rules/idiomatic/boolean-assignment.md index 1ff745b5..2ee04597 100644 --- a/docs/rules/idiomatic/boolean-assignment.md +++ b/docs/rules/idiomatic/boolean-assignment.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - more_than_one_member := count(input.members) > 1 ``` @@ -17,8 +15,6 @@ more_than_one_member := count(input.members) > 1 ```rego package policy -import rego.v1 - more_than_one_member if count(input.members) > 1 ``` @@ -33,8 +29,6 @@ input: ```rego package policy -import rego.v1 - default more_than_one_member := false # will be assigned `false` even if input.members is undefined diff --git a/docs/rules/idiomatic/custom-has-key-construct.md b/docs/rules/idiomatic/custom-has-key-construct.md index d1bbdd4a..239bd294 100644 --- a/docs/rules/idiomatic/custom-has-key-construct.md +++ b/docs/rules/idiomatic/custom-has-key-construct.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - mfa if has_key(input.claims, "mfa") has_key(map, key) if { @@ -21,8 +19,6 @@ has_key(map, key) if { ```rego package policy -import rego.v1 - mfa if "mfa" in object.keys(input.claims) ``` diff --git a/docs/rules/idiomatic/custom-in-construct.md b/docs/rules/idiomatic/custom-in-construct.md index 5ce1422c..540eb54c 100644 --- a/docs/rules/idiomatic/custom-in-construct.md +++ b/docs/rules/idiomatic/custom-in-construct.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - allow if has_value(input.user.roles, "admin") # This custom function was commonly seen before the introduction @@ -23,8 +21,6 @@ has_value(arr, item) if { ```rego package policy -import rego.v1 - allow if "admin" in input.user.roles ``` diff --git a/docs/rules/idiomatic/equals-pattern-matching.md b/docs/rules/idiomatic/equals-pattern-matching.md index b523d022..1d142df5 100644 --- a/docs/rules/idiomatic/equals-pattern-matching.md +++ b/docs/rules/idiomatic/equals-pattern-matching.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - readable_number(x) := "one" if x == 1 readable_number(x) := "two" if x == 2 ``` @@ -31,8 +29,6 @@ moving the equality check to match on the function call itself. This means that ```rego package policy -import rego.v1 - normalize_role(role) := "admin" if { role == "administrator" } @@ -48,8 +44,6 @@ the equality "pattern": ```rego package policy -import rego.v1 - normalize_role("administrator") := "admin" normalize_role("root") := "admin" @@ -60,8 +54,6 @@ Rules that evaluate to `true` may even have the assignment removed altogether, i ```rego package policy -import rego.v1 - is_admin(role) if role == "admin" is_admin(role) if role == "administrator" diff --git a/docs/rules/idiomatic/no-defined-entrypoint.md b/docs/rules/idiomatic/no-defined-entrypoint.md index b64408f5..10fd5d4d 100644 --- a/docs/rules/idiomatic/no-defined-entrypoint.md +++ b/docs/rules/idiomatic/no-defined-entrypoint.md @@ -10,8 +10,6 @@ ```rego package policy -import rego.v1 - default allow := false # Nothing wrong with this rule, but an @@ -34,8 +32,6 @@ public_resource_read if { ```rego package policy -import rego.v1 - default allow := false # METADATA diff --git a/docs/rules/idiomatic/non-raw-regex-pattern.md b/docs/rules/idiomatic/non-raw-regex-pattern.md index 11ad5197..f9cf488d 100644 --- a/docs/rules/idiomatic/non-raw-regex-pattern.md +++ b/docs/rules/idiomatic/non-raw-regex-pattern.md @@ -33,8 +33,6 @@ try to "resolve" patterns assigned to variables. The following example would as ```rego package policy -import rego.v1 - # Pattern assigned to variable pattern := "[\\d]+" diff --git a/docs/rules/idiomatic/prefer-set-or-object-rule.md b/docs/rules/idiomatic/prefer-set-or-object-rule.md index e654c38a..fc43a357 100644 --- a/docs/rules/idiomatic/prefer-set-or-object-rule.md +++ b/docs/rules/idiomatic/prefer-set-or-object-rule.md @@ -8,8 +8,6 @@ ````rego package policy -import rego.v1 - # top level set comprehension developers := {developer | some user in input.users @@ -28,8 +26,6 @@ user_roles_mapping := {user: roles | ````rego package policy -import rego.v1 - # set generating rule developers contains developer if { some user in input.users @@ -69,8 +65,6 @@ or unconditionally. ```rego package policy -import rego.v1 - # Getting developers from input developers contains developer if { some user in input.users @@ -99,8 +93,6 @@ than one rule contributing to a single key-value pair. ```rego package policy -import rego.v1 - novels[title] := content if { some document in input.documents document.type == "novel" @@ -130,8 +122,6 @@ This rule will also ignore simple comprehensions used solely for the purpose of ```rego package policy -import rego.v1 - # Convert set to array. This is fine. my_set := {item | some item in arr} ``` diff --git a/docs/rules/idiomatic/use-contains.md b/docs/rules/idiomatic/use-contains.md index f20bf26a..f9c5d7de 100644 --- a/docs/rules/idiomatic/use-contains.md +++ b/docs/rules/idiomatic/use-contains.md @@ -4,6 +4,17 @@ **Category**: Idiomatic +## Notice: Rule made obsolete by OPA 1.0 + +Since Regal v0.30.0, this rule is only enabled for projects that have either been explicitly configured to target +versions of OPA before 1.0, or if no configuration is provided — where Regal is able to determine that an older version +of OPA/Rego is being targeted. Consult the documentation on Regal's +[configuration](https://docs.styra.com/regal#configuration) for information on how to best work with older versions of +OPA and Rego. + +Since OPA v1.0, this rule is no longer needed as the Rego v1 syntax is now mandatory, and using `contains` is now the +de-facto way to define multi-value rules. + **Avoid** ```rego package policy diff --git a/docs/rules/idiomatic/use-if.md b/docs/rules/idiomatic/use-if.md index a87680d1..061d6a75 100644 --- a/docs/rules/idiomatic/use-if.md +++ b/docs/rules/idiomatic/use-if.md @@ -4,6 +4,15 @@ **Category**: Idiomatic +## Notice: Rule made obsolete by OPA 1.0 + +Since Regal v0.30.0, this rule is only enabled for projects explicitly configured to target versions of OPA before 1.0. +Consult the documentation on Regal's [configuration](https://docs.styra.com/regal#configuration) for information on how +to best work with older versions of OPA and Rego. + +Since OPA v1.0, this rule is no longer needed simply because the Rego v1 syntax is made mandatory, and the use of `if` +is now enforced before all rule bodies. + **Avoid** ```rego package policy diff --git a/docs/rules/idiomatic/use-in-operator.md b/docs/rules/idiomatic/use-in-operator.md index d3f27254..48716826 100644 --- a/docs/rules/idiomatic/use-in-operator.md +++ b/docs/rules/idiomatic/use-in-operator.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - # "Old" way of checking for membership - iteration + comparison allow if { "admin" == input.user.roles[_] @@ -20,8 +18,6 @@ allow if { ```rego package policy -import rego.v1 - allow if { "admin" in input.user.roles } diff --git a/docs/rules/idiomatic/use-strings-count.md b/docs/rules/idiomatic/use-strings-count.md index a4abce62..a4caea5e 100644 --- a/docs/rules/idiomatic/use-strings-count.md +++ b/docs/rules/idiomatic/use-strings-count.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - num_as := count(indexof_n("foobarbaz", "a")) ``` @@ -17,8 +15,6 @@ num_as := count(indexof_n("foobarbaz", "a")) ```rego package policy -import rego.v1 - num_as := strings.count("foobarbaz", "a") ``` diff --git a/docs/rules/imports/avoid-importing-input.md b/docs/rules/imports/avoid-importing-input.md index aabe7350..24ec136d 100644 --- a/docs/rules/imports/avoid-importing-input.md +++ b/docs/rules/imports/avoid-importing-input.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - # This is always redundant import input @@ -27,8 +25,6 @@ allow if { ```rego package policy -import rego.v1 - allow if "admin" in input.user.roles allow if { @@ -49,8 +45,6 @@ like a Terraform plan. Aliasing of specific input attributes should however be a ```rego package policy -import rego.v1 - # This is acceptable import input as tfplan diff --git a/docs/rules/imports/circular-import.md b/docs/rules/imports/circular-import.md index d45ab946..30da68fd 100644 --- a/docs/rules/imports/circular-import.md +++ b/docs/rules/imports/circular-import.md @@ -16,8 +16,6 @@ graph LR # authz.rego package authz -import rego.v1 - import data.shared admins := { @@ -63,8 +61,6 @@ graph LR # authz.rego package authz -import rego.v1 - import data.shared allow if { diff --git a/docs/rules/imports/ignored-import.md b/docs/rules/imports/ignored-import.md index 9b3ac7c6..262350b8 100644 --- a/docs/rules/imports/ignored-import.md +++ b/docs/rules/imports/ignored-import.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - import data.authz.roles allow if { @@ -23,8 +21,6 @@ allow if { ```rego package policy -import rego.v1 - import data.authz.roles allow if { diff --git a/docs/rules/imports/import-shadows-builtin.md b/docs/rules/imports/import-shadows-builtin.md index f7ddca0e..ed8abf36 100644 --- a/docs/rules/imports/import-shadows-builtin.md +++ b/docs/rules/imports/import-shadows-builtin.md @@ -39,8 +39,6 @@ longer form. Provided a simple policy like this: ```rego package policy -import rego.v1 - import data.http allow if { diff --git a/docs/rules/imports/import-shadows-import.md b/docs/rules/imports/import-shadows-import.md index 7d34b26a..a6bf4408 100644 --- a/docs/rules/imports/import-shadows-import.md +++ b/docs/rules/imports/import-shadows-import.md @@ -4,6 +4,17 @@ **Category**: Imports +## Notice: Rule made obsolete by OPA 1.0 + +Since Regal v0.30.0, this rule is only enabled for projects that have either been explicitly configured to target +versions of OPA before 1.0, or if no configuration is provided — where Regal is able to determine that an older version +of OPA/Rego is being targeted. Consult the documentation on Regal's +[configuration](https://docs.styra.com/regal#configuration) for information on how to best work with older versions of +OPA and Rego. + +Since OPA v1.0, this rule is automatically disabled as OPA itself now forbids this, and shadowed imports will result in +a parse error. + **Avoid** ```rego package policy diff --git a/docs/rules/imports/prefer-package-imports.md b/docs/rules/imports/prefer-package-imports.md index 0cc44de9..3a40050c 100644 --- a/docs/rules/imports/prefer-package-imports.md +++ b/docs/rules/imports/prefer-package-imports.md @@ -10,8 +10,6 @@ ```rego package policy -import rego.v1 - # Rule imported directly import data.users.first_names @@ -25,8 +23,6 @@ has_waldo if { ```rego package policy -import rego.v1 - # Package imported rather than rule import data.users diff --git a/docs/rules/imports/use-rego-v1.md b/docs/rules/imports/use-rego-v1.md index 4b739a6b..ca621c95 100644 --- a/docs/rules/imports/use-rego-v1.md +++ b/docs/rules/imports/use-rego-v1.md @@ -6,6 +6,17 @@ **Automatically fixable**: [Yes](/regal/fixing) +## Notice: Rule made obsolete by OPA 1.0 + +Since Regal v0.30.0, this rule is only enabled for projects that have either been explicitly configured to target +versions of OPA before 1.0, or if no configuration is provided — where Regal is able to determine that an older version +of OPA/Rego is being targeted. Consult the documentation on Regal's +[configuration](https://docs.styra.com/regal#configuration) for information on how to best work with older versions of +OPA and Rego. + +Since OPA v1.0, this rule is no longer needed simply because the Rego v1 syntax is made mandatory, and no additional +imports are required. + **Avoid** ```rego package policy @@ -23,7 +34,8 @@ report contains item if { ```rego package policy -# with OPA v0.59.0 and later, use this instead +# with OPA v0.59.0 and later, use import rego.v1 instead +# with OPA v1.0 and later, this import is unnecessary import rego.v1 report contains item if { diff --git a/docs/rules/performance/defer-assignment.md b/docs/rules/performance/defer-assignment.md index ca929c9c..1cf9d9ca 100644 --- a/docs/rules/performance/defer-assignment.md +++ b/docs/rules/performance/defer-assignment.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - allow if { resp := http.send({"method": "GET", "url": "http://example.com"}) @@ -28,8 +26,6 @@ allow if { ```rego package policy -import rego.v1 - allow if { input.user.name in allowed_users diff --git a/docs/rules/performance/walk-no-path.md b/docs/rules/performance/walk-no-path.md index 0f96c438..7778f08b 100644 --- a/docs/rules/performance/walk-no-path.md +++ b/docs/rules/performance/walk-no-path.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - allow if { # traverse potentially nested permissions structure looking # for an admin role, but notice how the path is never referenced @@ -25,8 +23,6 @@ allow if { ```rego package policy -import rego.v1 - allow if { # replacing `path` with a wildcard variable tells the evaluator that it won't # have to build the path array for each node `walk` traverses, thereby avoiding @@ -61,8 +57,6 @@ This rule can only optimize `walk` calls where the path/value array is provided ```rego package policy -import rego.v1 - allow if { # this can't be optimized, as the `walk` function can't # "see" the array assignment on the left hand side diff --git a/docs/rules/performance/with-outside-test-context.md b/docs/rules/performance/with-outside-test-context.md index a2bcc8d0..f759d442 100644 --- a/docs/rules/performance/with-outside-test-context.md +++ b/docs/rules/performance/with-outside-test-context.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - allow if { some user in data.users @@ -30,8 +28,6 @@ allowed_user := input.user if { ```rego package policy -import rego.v1 - allow if { some user in data.users diff --git a/docs/rules/style/comprehension-term-assignment.md b/docs/rules/style/comprehension-term-assignment.md index 44745e04..4db86279 100644 --- a/docs/rules/style/comprehension-term-assignment.md +++ b/docs/rules/style/comprehension-term-assignment.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - names := [name | some user in input.users name := user.name # redundant assignment @@ -20,8 +18,6 @@ names := [name | ```rego package policy -import rego.v1 - names := [user.name | some user in input.users ] diff --git a/docs/rules/style/default-over-else.md b/docs/rules/style/default-over-else.md index c98c1235..239934e0 100644 --- a/docs/rules/style/default-over-else.md +++ b/docs/rules/style/default-over-else.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - permissions := ["read", "write"] if { input.user == "admin" } else := ["read"] @@ -19,8 +17,6 @@ permissions := ["read", "write"] if { ```rego package policy -import rego.v1 - default permissions := ["read"] permissions := ["read", "write"] if { diff --git a/docs/rules/style/default-over-not.md b/docs/rules/style/default-over-not.md index 710cdc84..7dd83bb7 100644 --- a/docs/rules/style/default-over-not.md +++ b/docs/rules/style/default-over-not.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - username := input.user.name username := "anonymous" if not input.user.name diff --git a/docs/rules/style/detached-metadata.md b/docs/rules/style/detached-metadata.md index 3b2606b8..bd314ff4 100644 --- a/docs/rules/style/detached-metadata.md +++ b/docs/rules/style/detached-metadata.md @@ -8,8 +8,6 @@ ```rego package authz -import rego.v1 - # METADATA # description: allow any requests by admin users @@ -22,8 +20,6 @@ allow if { ```rego package authz -import rego.v1 - # METADATA # description: allow any requests by admin users allow if { diff --git a/docs/rules/style/double-negative.md b/docs/rules/style/double-negative.md index 9b260761..f4e381ed 100644 --- a/docs/rules/style/double-negative.md +++ b/docs/rules/style/double-negative.md @@ -8,8 +8,6 @@ ```rego package negative -import rego.v1 - fine if not not_fine with_friends if not without_friends @@ -23,8 +21,6 @@ without_friends if count(input.friends) == 0 ```rego package negative -import rego.v1 - fine if input.fine == true with_friends if count(input.friends) > 0 diff --git a/docs/rules/style/external-reference.md b/docs/rules/style/external-reference.md index 21408e7d..05f83489 100644 --- a/docs/rules/style/external-reference.md +++ b/docs/rules/style/external-reference.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - # Depends on both `input` and `data` is_preferred_login_method(method) if { preferred_login_methods := {login_method | @@ -24,8 +22,6 @@ is_preferred_login_method(method) if { ```rego package policy -import rego.v1 - # Depends only on function arguments is_preferred_login_method(method, user, all_login_methods) if { preferred_login_methods := {login_method | @@ -53,8 +49,6 @@ other way to import them into the function body. ```rego package policy -import rego.v1 - first_name(full_name) := capitalized { first_name := split(full_name, " ")[0] diff --git a/docs/rules/style/function-arg-return.md b/docs/rules/style/function-arg-return.md index c0e34b44..954c826b 100644 --- a/docs/rules/style/function-arg-return.md +++ b/docs/rules/style/function-arg-return.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - has_email(user) if { indexof(user.email, "@", i) i != -1 @@ -21,8 +19,6 @@ has_email(user) if { ```rego package policy -import rego.v1 - has_email(user) if { i := indexof(user.email, "@") i != -1 diff --git a/docs/rules/style/no-whitespace-comment.md b/docs/rules/style/no-whitespace-comment.md index de027c4f..bbeaae75 100644 --- a/docs/rules/style/no-whitespace-comment.md +++ b/docs/rules/style/no-whitespace-comment.md @@ -11,8 +11,6 @@ ```rego package policy -import rego.v1 - #Deny by default default allow := false @@ -25,8 +23,6 @@ allow if "admin" in input.user.roles ```rego package policy -import rego.v1 - # Deny by default default allow := false diff --git a/docs/rules/style/prefer-snake-case.md b/docs/rules/style/prefer-snake-case.md index 3e583db5..f311697d 100644 --- a/docs/rules/style/prefer-snake-case.md +++ b/docs/rules/style/prefer-snake-case.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - # camelCase rule name userIsAdmin if "admin" in input.user.roles ``` @@ -18,8 +16,6 @@ userIsAdmin if "admin" in input.user.roles ```rego package policy -import rego.v1 - # snake_case rule name user_is_admin if "admin" in input.user.roles ``` diff --git a/docs/rules/style/prefer-some-in-iteration.md b/docs/rules/style/prefer-some-in-iteration.md index bf9bbb72..f46b0a7b 100644 --- a/docs/rules/style/prefer-some-in-iteration.md +++ b/docs/rules/style/prefer-some-in-iteration.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - engineering_roles := {"engineer", "dba", "developer"} engineers contains employee if { @@ -22,8 +20,6 @@ engineers contains employee if { ```rego package policy -import rego.v1 - engineering_roles := {"engineer", "dba", "developer"} engineers contains employee if { @@ -80,8 +76,6 @@ Deeply nested iteration is often easier to read using the more compact form. ```rego package policy -import rego.v1 - # These rules are equivalent, but the more compact form is arguably easier to read any_user_is_admin if { @@ -109,8 +103,6 @@ one of the variables (including wildcards: `_`) is an output variable bound in i ```rego package policy -import rego.v1 - example_users contains user if { domain := "example.com" user := input.sites[domain].users[_] diff --git a/docs/rules/style/rule-name-repeats-package.md b/docs/rules/style/rule-name-repeats-package.md index 5bdb163f..013fd9e6 100644 --- a/docs/rules/style/rule-name-repeats-package.md +++ b/docs/rules/style/rule-name-repeats-package.md @@ -8,8 +8,6 @@ ```rego package policy.authz -import rego.v1 - authz_allow if { user.is_admin } @@ -19,8 +17,6 @@ authz_allow if { ```rego package policy.authz -import rego.v1 - allow if { user.is_admin } diff --git a/docs/rules/style/trailing-default-rule.md b/docs/rules/style/trailing-default-rule.md index ddd19fd2..3cbb4d98 100644 --- a/docs/rules/style/trailing-default-rule.md +++ b/docs/rules/style/trailing-default-rule.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - allow if { # some conditions } @@ -21,8 +19,6 @@ default allow := false ```rego package policy -import rego.v1 - default allow := false allow if { diff --git a/docs/rules/style/unconditional-assignment.md b/docs/rules/style/unconditional-assignment.md index d77cd2f5..e1f93c7a 100644 --- a/docs/rules/style/unconditional-assignment.md +++ b/docs/rules/style/unconditional-assignment.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - full_name := name if { name := concat(", ", [input.first_name, input.last_name]) } @@ -27,8 +25,6 @@ names contains name if { ```rego package policy -import rego.v1 - full_name := concat(", ", [input.first_name, input.last_name]) divide_by_ten(x) := x / 10 diff --git a/docs/rules/style/unnecessary-some.md b/docs/rules/style/unnecessary-some.md index 199ce4d2..a2884dc4 100644 --- a/docs/rules/style/unnecessary-some.md +++ b/docs/rules/style/unnecessary-some.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - is_developer if some "developer" in input.user.roles ``` @@ -18,8 +16,6 @@ is_developer if some "developer" in input.user.roles ```rego package policy -import rego.v1 - is_developer if "developer" in input.user.roles ``` @@ -36,8 +32,6 @@ should match for the loop assignment to succeed. This is not commonly needed, bu ```rego package policy -import rego.v1 - developers contains name if { # name will only be bound when the value is "developer" some name, "developer" in {"alice": "developer", "bob": "developer", "charlie": "manager"} diff --git a/docs/rules/style/use-assignment-operator.md b/docs/rules/style/use-assignment-operator.md index 196e3f68..4c9652b8 100644 --- a/docs/rules/style/use-assignment-operator.md +++ b/docs/rules/style/use-assignment-operator.md @@ -10,8 +10,6 @@ ```rego package policy -import rego.v1 - default allow = false first_name(name) = split(name, " ")[0] @@ -26,8 +24,6 @@ allow if { ```rego package policy -import rego.v1 - default allow := false first_name(full_name) := split(full_name, " ")[0] diff --git a/docs/rules/style/yoda-condition.md b/docs/rules/style/yoda-condition.md index b3d34ae8..121e8482 100644 --- a/docs/rules/style/yoda-condition.md +++ b/docs/rules/style/yoda-condition.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - allow if { "GET" == input.request.method "users" == input.request.path[0] @@ -20,8 +18,6 @@ allow if { ```rego package policy -import rego.v1 - allow if { input.request.method == "GET" input.request.path[0] == "users" diff --git a/docs/rules/testing/print-or-trace-call.md b/docs/rules/testing/print-or-trace-call.md index f2657e50..bf4468f5 100644 --- a/docs/rules/testing/print-or-trace-call.md +++ b/docs/rules/testing/print-or-trace-call.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - reasons contains sprintf("%q is a dog!", [user.name]) if { some user in input.users user.species == "canine" diff --git a/docs/rules/testing/test-outside-test-package.md b/docs/rules/testing/test-outside-test-package.md index 39218121..0365378a 100644 --- a/docs/rules/testing/test-outside-test-package.md +++ b/docs/rules/testing/test-outside-test-package.md @@ -8,8 +8,6 @@ ```rego package policy -import rego.v1 - allow if { "admin" in input.user.roles } @@ -25,8 +23,6 @@ test_allow_if_admin { # Tests in separate package with _test suffix package policy_test -import rego.v1 - import data.policy test_allow_if_admin { diff --git a/docs/rules/testing/todo-test.md b/docs/rules/testing/todo-test.md index 1cddaf80..6245f79b 100644 --- a/docs/rules/testing/todo-test.md +++ b/docs/rules/testing/todo-test.md @@ -8,8 +8,6 @@ ```rego package policy_test -import rego.v1 - import data.policy # Make sure this passes diff --git a/e2e/cli_test.go b/e2e/cli_test.go index 112c2fb1..52e8d7dc 100644 --- a/e2e/cli_test.go +++ b/e2e/cli_test.go @@ -20,7 +20,7 @@ import ( "github.com/google/go-cmp/cmp" "gopkg.in/yaml.v3" - "github.com/open-policy-agent/opa/tester" + "github.com/open-policy-agent/opa/v1/tester" "github.com/styrainc/regal/internal/testutil" "github.com/styrainc/regal/pkg/config" @@ -146,30 +146,43 @@ func TestLintProposeToRunFix(t *testing.T) { cwd := testutil.Must(os.Getwd())(t) // using a test rego file that only yields a few violations - err := regal(&stdout, &stderr)("lint", cwd+filepath.FromSlash("/testdata/violations/rule_named_if.rego")) + err := regal(&stdout, &stderr)( + "lint", + "--config-file", filepath.Join(cwd, "e2e_conf.yaml"), + cwd+filepath.FromSlash("/testdata/v0/rule_named_if.rego")) expectExitCode(t, err, 3, &stdout, &stderr) if exp, act := "", stderr.String(); exp != act { - t.Errorf("expected stderr %q, got %q", exp, act) + t.Fatalf("expected stderr %q, got %q", exp, act) } act := strings.Split(stdout.String(), "\n") act = act[len(act)-5:] - exp := []string{"1 file linted. 5 violations found.", "", "Hint: 2/5 violations can be automatically fixed (directory-package-mismatch, use-rego-v1)", " Run regal fix --help for more details.", ""} + exp := []string{ + "1 file linted. 2 violations found.", + "", + "Hint: 2/2 violations can be automatically fixed (directory-package-mismatch, opa-fmt)", + " Run regal fix --help for more details.", + "", + } if diff := cmp.Diff(act, exp); diff != "" { t.Errorf("unexpected stdout trailer: (-want, +got):\n%s", diff) } } -func TestLintAllViolations(t *testing.T) { +func TestLintV1Violations(t *testing.T) { t.Parallel() stdout, stderr := bytes.Buffer{}, bytes.Buffer{} cwd := testutil.Must(os.Getwd())(t) - cfg := readProvidedConfig(t) - err := regal(&stdout, &stderr)("lint", "--format", "json", cwd+filepath.FromSlash("/testdata/violations")) + err := regal(&stdout, &stderr)( + "lint", + "--format", "json", + "--config-file", filepath.Join(cwd, "e2e_conf.yaml"), + cwd+filepath.FromSlash("/testdata/violations"), + ) expectExitCode(t, err, 3, &stdout, &stderr) @@ -190,8 +203,14 @@ func TestLintAllViolations(t *testing.T) { "use-contains": {}, "internal-entrypoint": {}, "file-length": {}, + "rule-named-if": {}, + "use-rego-v1": {}, + "deprecated-builtin": {}, + "import-shadows-import": {}, } + cfg := readProvidedConfig(t) + for _, category := range cfg.Rules { for ruleName, rule := range category { if _, isExcluded := excludedRules[ruleName]; !isExcluded && rule.Level != "ignore" { @@ -216,7 +235,7 @@ func TestLintAllViolations(t *testing.T) { } } -func TestLintNotRegoV1Violations(t *testing.T) { +func TestLintV0NoRegoV1ImportViolations(t *testing.T) { t.Parallel() stdout, stderr := bytes.Buffer{}, bytes.Buffer{} @@ -224,8 +243,8 @@ func TestLintNotRegoV1Violations(t *testing.T) { cwd := testutil.Must(os.Getwd())(t) err := regal(&stdout, &stderr)("lint", "--format", "json", "--config-file", - cwd+filepath.FromSlash("/testdata/configs/not_rego_v1.yaml"), - cwd+filepath.FromSlash("/testdata/not_rego_v1")) + cwd+filepath.FromSlash("/testdata/configs/v0.yaml"), + cwd+filepath.FromSlash("/testdata/v0/")) expectExitCode(t, err, 3, &stdout, &stderr) @@ -260,6 +279,52 @@ func TestLintNotRegoV1Violations(t *testing.T) { } } +func TestLintV0WithRegoV1ImportViolations(t *testing.T) { + t.Parallel() + + stdout, stderr := bytes.Buffer{}, bytes.Buffer{} + + cwd := testutil.Must(os.Getwd())(t) + + err := regal(&stdout, &stderr)( + "lint", "--format", "json", + "--config-file", cwd+filepath.FromSlash("/testdata/configs/v0-with-import-rego-v1.yaml"), + cwd+filepath.FromSlash("/testdata/v0/")) + + expectExitCode(t, err, 3, &stdout, &stderr) + + if exp, act := "", stderr.String(); exp != act { + t.Errorf("expected stderr %q, got %q", exp, act) + } + + var rep report.Report + if err = json.Unmarshal(stdout.Bytes(), &rep); err != nil { + t.Fatalf("expected JSON response, got %v", stdout.String()) + } + + expected := map[string]struct{}{ + "use-if": {}, + "use-contains": {}, + "use-rego-v1": {}, + "rule-named-if": {}, + } + + // Note that some violations occur more than one time. + violationNames := make(map[string]struct{}) + + for _, violation := range rep.Violations { + violationNames[violation.Title] = struct{}{} + } + + if len(expected) != len(violationNames) { + for ruleName := range expected { + if _, ok := violationNames[ruleName]; !ok { + t.Errorf("expected violation for rule %q", ruleName) + } + } + } +} + func TestLintFailsNonExistentConfigFile(t *testing.T) { t.Parallel() @@ -381,7 +446,7 @@ func TestAggregatesAreCollectedAndUsed(t *testing.T) { t.Run("two policies — no violations expected", func(t *testing.T) { stdout, stderr := bytes.Buffer{}, bytes.Buffer{} - err := regal(&stdout, &stderr)("lint", "--format", "json", "--rules", + err := regal(&stdout, &stderr)("lint", "--format", "json", basedir+filepath.FromSlash("/custom/regal/rules/testcase/aggregates/custom_rules_using_aggregates.rego"), basedir+filepath.FromSlash("/two_policies")) @@ -409,7 +474,9 @@ func TestAggregatesAreCollectedAndUsed(t *testing.T) { t.Run("three policies - violation expected", func(t *testing.T) { stdout, stderr := bytes.Buffer{}, bytes.Buffer{} - err := regal(&stdout, &stderr)("lint", "--format", "json", "--rules", + err := regal(&stdout, &stderr)("lint", "--format", "json", + "--config-file", filepath.Join(cwd, "e2e_conf.yaml"), + "--rules", basedir+filepath.FromSlash("/custom/regal/rules/testcase/aggregates/custom_rules_using_aggregates.rego"), basedir+filepath.FromSlash("/three_policies")) @@ -433,7 +500,9 @@ func TestAggregatesAreCollectedAndUsed(t *testing.T) { t.Run("custom policy where nothing aggregate is a violation", func(t *testing.T) { stdout, stderr := bytes.Buffer{}, bytes.Buffer{} - err := regal(&stdout, &stderr)("lint", "--format", "json", "--rules", + err := regal(&stdout, &stderr)("lint", "--format", "json", + "--config-file", filepath.Join(cwd, "e2e_conf.yaml"), + "--rules", basedir+filepath.FromSlash("/custom/regal/rules/testcase/empty_aggregate/"), basedir+filepath.FromSlash("/two_policies")) @@ -461,8 +530,13 @@ func TestLintAggregateIgnoreDirective(t *testing.T) { stdout, stderr := bytes.Buffer{}, bytes.Buffer{} cwd := testutil.Must(os.Getwd())(t) - err := regal(&stdout, &stderr)("lint", "--format", "json", - cwd+filepath.FromSlash("/testdata/aggregates/ignore_directive")) + err := regal(&stdout, &stderr)( + "lint", + "--config-file", filepath.Join(cwd, "e2e_conf.yaml"), + "--format", + "json", + cwd+filepath.FromSlash("/testdata/aggregates/ignore_directive"), + ) expectExitCode(t, err, 3, &stdout, &stderr) @@ -762,7 +836,13 @@ func TestLintPprof(t *testing.T) { _ = os.Remove(pprofFile) }) - err := regal(&stdout, &stderr)("lint", "--pprof", "clock", cwd+filepath.FromSlash("/testdata/violations")) + err := regal(&stdout, &stderr)( + "lint", + // this overrides the ignore directives for e2e loaded from the config file + "--ignore-files=none", + "--pprof", "clock", + cwd+filepath.FromSlash("/testdata/violations"), + ) expectExitCode(t, err, 3, &stdout, &stderr) @@ -778,11 +858,17 @@ func TestFix(t *testing.T) { td := t.TempDir() initialState := map[string]string{ - ".regal/config.yaml": "", // needed to find the root in the right place + ".regal/config.yaml": ` +project: + rego-version: 1 + roots: + - path: v0 + rego-version: 0 + - path: v1 + rego-version: 0 +`, "foo/main.rego": `package wow -import rego.v1 - #comment allow if { @@ -791,14 +877,12 @@ allow if { `, "foo/main_test.rego": `package wow_test -test_allow { +test_allow if { true } `, "foo/foo.rego": `package foo -import rego.v1 - # present and correct allow if { @@ -806,13 +890,21 @@ allow if { } `, "bar/main.rego": `package wow["foo-bar"].baz - -import rego.v1 `, "bar/main_test.rego": `package wow["foo-bar"].baz_test -test_allow { +test_allow if { true } +`, + "v0/main.rego": `package v0 + +#comment +allow { true } +`, + "v1/main.rego": `package v1 + +#comment +allow if { true } `, "unrelated.txt": `foobar`, } @@ -822,29 +914,46 @@ test_allow { } // --force is required to make the changes when there is no git repo - err := regal(&stdout, &stderr)("fix", "--force", filepath.Join(td, "foo"), filepath.Join(td, "bar")) + err := regal(&stdout, &stderr)( + "fix", + "--force", + filepath.Join(td, "foo"), + filepath.Join(td, "bar"), + filepath.Join(td, "v0"), + filepath.Join(td, "v1"), + ) // 0 exit status is expected as all violations should have been fixed expectExitCode(t, err, 0, &stdout, &stderr) - exp := fmt.Sprintf(`8 fixes applied: -In project root: %s + exp := fmt.Sprintf(`12 fixes applied: +In project root: %[1]s bar/main.rego -> wow/foo-bar/baz/main.rego: - directory-package-mismatch bar/main_test.rego -> wow/foo-bar/baz/main_test.rego: - directory-package-mismatch -- use-rego-v1 +- opa-fmt foo/main.rego -> wow/main.rego: - directory-package-mismatch -- use-rego-v1 +- opa-fmt - no-whitespace-comment foo/main_test.rego -> wow/main_test.rego: - directory-package-mismatch -- use-rego-v1 +- opa-fmt + +In project root: %[1]s/v0 +main.rego: +- opa-fmt +- no-whitespace-comment + +In project root: %[1]s/v1 +main.rego: +- opa-fmt +- no-whitespace-comment `, td) if act := stdout.String(); exp != act { @@ -858,8 +967,6 @@ foo/main_test.rego -> wow/main_test.rego: expectedState := map[string]string{ "foo/foo.rego": `package foo -import rego.v1 - # present and correct allow if { @@ -867,28 +974,32 @@ allow if { } `, "wow/foo-bar/baz/main.rego": `package wow["foo-bar"].baz - -import rego.v1 `, "wow/foo-bar/baz/main_test.rego": `package wow["foo-bar"].baz_test -import rego.v1 - test_allow := true `, "wow/main.rego": `package wow -import rego.v1 - # comment allow := true `, "wow/main_test.rego": `package wow_test +test_allow := true +`, + "v0/main.rego": `package v0 + import rego.v1 -test_allow := true +# comment +allow := true +`, + "v1/main.rego": `package v1 + +# comment +allow := true `, "unrelated.txt": `foobar`, } @@ -1100,6 +1211,7 @@ func TestLintAnnotationCustomAttributeMultipleItems(t *testing.T) { err := regal(&stdout, &stderr)( "lint", + "--config-file", filepath.Join(cwd, "e2e_conf.yaml"), "--disable=directory-package-mismatch", filepath.Join(cwd, "testdata", "bugs", "issue_1082.rego"), ) diff --git a/e2e/e2e_conf.yaml b/e2e/e2e_conf.yaml new file mode 100644 index 00000000..a0402e0f --- /dev/null +++ b/e2e/e2e_conf.yaml @@ -0,0 +1,5 @@ +project: + rego-version: 1 + roots: + - path: v0 + rego-version: 0 diff --git a/e2e/testdata/aggregates/custom/regal/rules/testcase/aggregates/custom_rules_using_aggregates.rego b/e2e/testdata/aggregates/custom/regal/rules/testcase/aggregates/custom_rules_using_aggregates.rego index 2dd846c5..a0bb5140 100644 --- a/e2e/testdata/aggregates/custom/regal/rules/testcase/aggregates/custom_rules_using_aggregates.rego +++ b/e2e/testdata/aggregates/custom/regal/rules/testcase/aggregates/custom_rules_using_aggregates.rego @@ -2,8 +2,6 @@ # description: Collect data in aggregates and validate it package custom.regal.rules.testcase["aggregates"] -import rego.v1 - import data.regal.result aggregate contains result.aggregate(rego.metadata.chain(), {}) diff --git a/e2e/testdata/aggregates/custom/regal/rules/testcase/empty_aggregate/empty_aggregate.rego b/e2e/testdata/aggregates/custom/regal/rules/testcase/empty_aggregate/empty_aggregate.rego index 3c280318..4cfab484 100644 --- a/e2e/testdata/aggregates/custom/regal/rules/testcase/empty_aggregate/empty_aggregate.rego +++ b/e2e/testdata/aggregates/custom/regal/rules/testcase/empty_aggregate/empty_aggregate.rego @@ -6,8 +6,6 @@ # ref: https://github.com/StyraInc/regal/issues/1259 package custom.regal.rules.testcase.empty_aggregates -import rego.v1 - import data.regal.result aggregate contains result.aggregate(rego.metadata.chain(), {}) if { diff --git a/e2e/testdata/ast_type_failure/custom_type_fail.rego b/e2e/testdata/ast_type_failure/custom_type_fail.rego index eb212761..dcf0639a 100644 --- a/e2e/testdata/ast_type_failure/custom_type_fail.rego +++ b/e2e/testdata/ast_type_failure/custom_type_fail.rego @@ -4,8 +4,6 @@ # - input: schema.regal.ast package custom.regal.rules.naming.type_fail -import rego.v1 - report contains foo if { # There is no "foo" attribute in the AST, # so this should fail at compile time diff --git a/e2e/testdata/configs/v0-with-import-rego-v1.yaml b/e2e/testdata/configs/v0-with-import-rego-v1.yaml new file mode 100644 index 00000000..76f68cab --- /dev/null +++ b/e2e/testdata/configs/v0-with-import-rego-v1.yaml @@ -0,0 +1,6 @@ +project: + rego-version: 0 +capabilities: + from: + engine: opa + version: v0.59.0 diff --git a/e2e/testdata/configs/not_rego_v1.yaml b/e2e/testdata/configs/v0.yaml similarity index 100% rename from e2e/testdata/configs/not_rego_v1.yaml rename to e2e/testdata/configs/v0.yaml diff --git a/e2e/testdata/not_rego_v1/not_rego_v1.rego b/e2e/testdata/v0/not_rego_v1.rego similarity index 100% rename from e2e/testdata/not_rego_v1/not_rego_v1.rego rename to e2e/testdata/v0/not_rego_v1.rego diff --git a/e2e/testdata/violations/rule_named_if.rego b/e2e/testdata/v0/rule_named_if.rego similarity index 100% rename from e2e/testdata/violations/rule_named_if.rego rename to e2e/testdata/v0/rule_named_if.rego diff --git a/e2e/testdata/violations/circular_import.rego b/e2e/testdata/violations/circular_import.rego index 109d9667..c49910f4 100644 --- a/e2e/testdata/violations/circular_import.rego +++ b/e2e/testdata/violations/circular_import.rego @@ -1,3 +1,5 @@ package circular_import import data.all_violations + +x := 2 diff --git a/e2e/testdata/violations/most_violations.rego b/e2e/testdata/violations/most_violations.rego index 427847bc..5304cc2e 100644 --- a/e2e/testdata/violations/most_violations.rego +++ b/e2e/testdata/violations/most_violations.rego @@ -29,7 +29,7 @@ import data.http # prefer-package-imports # aggregate rule, so will only fail if more than one file is linted -import data.rule_named_if.allow +import data.circular_import.x rule := "here" @@ -68,7 +68,7 @@ top_level_iteration := input[_] unassigned_return_value if indexof("foo", "o") -zero_arity_function := true +zero_arity_function() := true inconsistent_args(a, b) if { a == b @@ -93,9 +93,9 @@ impossible_not if { not partial } -argument_always_wildcard(_) = true +argument_always_wildcard(_) if true -argument_always_wildcard(_) = true +argument_always_wildcard(_) if true # title: annotation without metadata some_rule := true @@ -184,9 +184,7 @@ use_assignment = "oparator" chained_rule_body if { input.x -} - -chained_rule_body if { +} { input.y } diff --git a/go.mod b/go.mod index 5891298b..da213ff0 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/styrainc/regal -go 1.22.5 +go 1.22.7 + +toolchain go1.23.3 require ( dario.cat/mergo v1.0.1 @@ -15,7 +17,7 @@ require ( github.com/jstemmer/go-junit-report/v2 v2.1.0 github.com/mitchellh/mapstructure v1.5.0 github.com/olekukonko/tablewriter v0.0.5 - github.com/open-policy-agent/opa v0.70.0 + github.com/open-policy-agent/opa v1.0.0 github.com/owenrumney/go-sarif/v2 v2.3.3 github.com/pdevine/go-asciisprite v0.1.6 github.com/pkg/profile v1.7.0 @@ -49,7 +51,6 @@ require ( github.com/google/pprof v0.0.0-20211214055906-6f57359322fd // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/mux v1.8.1 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -76,18 +77,17 @@ require ( github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/yashtewari/glob-intersection v0.2.0 // indirect - go.opentelemetry.io/otel v1.28.0 // indirect - go.opentelemetry.io/otel/metric v1.28.0 // indirect - go.opentelemetry.io/otel/sdk v1.28.0 // indirect - go.opentelemetry.io/otel/trace v1.28.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/otel v1.33.0 // indirect + go.opentelemetry.io/otel/metric v1.33.0 // indirect + go.opentelemetry.io/otel/sdk v1.33.0 // indirect + go.opentelemetry.io/otel/trace v1.33.0 // indirect golang.org/x/crypto v0.31.0 // indirect golang.org/x/net v0.33.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/tools v0.24.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240820151423-278611b39280 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240820151423-278611b39280 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/protobuf v1.35.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 4b02c4fc..62a042ca 100644 --- a/go.sum +++ b/go.sum @@ -120,8 +120,8 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= @@ -170,8 +170,8 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= -github.com/open-policy-agent/opa v0.70.0 h1:B3cqCN2iQAyKxK6+GI+N40uqkin+wzIrM7YA60t9x1U= -github.com/open-policy-agent/opa v0.70.0/go.mod h1:Y/nm5NY0BX0BqjBriKUiV81sCl8XOjjvqQG7dXrggtI= +github.com/open-policy-agent/opa v1.0.0 h1:fZsEwxg1knpPvUn0YDJuJZBcbVg4G3zKpWa3+CnYK+I= +github.com/open-policy-agent/opa v1.0.0/go.mod h1:+JyoH12I0+zqyC1iX7a2tmoQlipwAEGvOhVJMhmy+rM= github.com/owenrumney/go-sarif v1.1.1/go.mod h1:dNDiPlF04ESR/6fHlPyq7gHKmrM0sHUvAGjsoh8ZH0U= github.com/owenrumney/go-sarif/v2 v2.3.3 h1:ubWDJcF5i3L/EIOER+ZyQ03IfplbSU1BLOE26uKQIIU= github.com/owenrumney/go-sarif/v2 v2.3.3/go.mod h1:MSqMMx9WqlBSY7pXoOZWgEsVB4FDNfhcaXDA1j6Sr+w= @@ -200,8 +200,8 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= @@ -241,22 +241,24 @@ github.com/yashtewari/glob-intersection v0.2.0/go.mod h1:LK7pIC3piUjovexikBbJ26Y github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= -go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= -go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= +go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw= +go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 h1:Vh5HayB/0HHfOQA7Ctx69E/Y/DcQSMPpKANYVMQ7fBA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0/go.mod h1:cpgtDBaqD/6ok/UG0jT15/uKjAY8mRA53diogHBg3UI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 h1:5pojmb1U1AogINhN3SurB+zm/nIcusopeBNp42f45QM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0/go.mod h1:57gTHJSE5S1tqg+EKsLPlTWhpHMsWlVmer+LA926XiA= +go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ= +go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M= +go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM= +go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM= +go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= +go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= +go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= +go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= @@ -298,14 +300,14 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto/googleapis/api v0.0.0-20240820151423-278611b39280 h1:YDFM9oOjiFhaMAVgbDxfxW+66nRrsvzQzJ51wp3OxC0= -google.golang.org/genproto/googleapis/api v0.0.0-20240820151423-278611b39280/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240820151423-278611b39280 h1:XQMA2e105XNlEZ8NRF0HqnUOZzP14sUSsgL09kpdNnU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240820151423-278611b39280/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= -google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q= +google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU= +google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= +google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= +google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/ast/ref.go b/internal/ast/ref.go index d70e893b..f1de4135 100644 --- a/internal/ast/ref.go +++ b/internal/ast/ref.go @@ -3,7 +3,7 @@ package ast import ( "strings" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" ) // RefToString converts an ast.Ref to a readable string, e.g. data.foo[bar]. diff --git a/internal/ast/ref_test.go b/internal/ast/ref_test.go index 2380eaba..0e66f519 100644 --- a/internal/ast/ref_test.go +++ b/internal/ast/ref_test.go @@ -3,7 +3,7 @@ package ast import ( "testing" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" ) func TestRefToString(t *testing.T) { diff --git a/internal/ast/rule.go b/internal/ast/rule.go index 94fa68ce..558aa745 100644 --- a/internal/ast/rule.go +++ b/internal/ast/rule.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" ) // GetRuleDetail returns a short descriptive string value for a given rule stating diff --git a/internal/ast/rule_test.go b/internal/ast/rule_test.go index b328f0ac..9c2eb14b 100644 --- a/internal/ast/rule_test.go +++ b/internal/ast/rule_test.go @@ -3,7 +3,7 @@ package ast import ( "testing" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/lsp/rego" "github.com/styrainc/regal/internal/parse" @@ -42,7 +42,7 @@ func TestGetRuleDetail(t *testing.T) { t.Run(tc.input, func(t *testing.T) { t.Parallel() - mod := parse.MustParseModule("package example\nimport rego.v1\n" + tc.input) + mod := parse.MustParseModule("package example\n" + tc.input) if len(mod.Rules) != 1 { t.Fatalf("Expected 1 rule, got %d", len(mod.Rules)) diff --git a/internal/capabilities/capabilities.go b/internal/capabilities/capabilities.go index 3ec854cb..e5968ce8 100644 --- a/internal/capabilities/capabilities.go +++ b/internal/capabilities/capabilities.go @@ -16,7 +16,7 @@ import ( "github.com/coreos/go-semver/semver" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/capabilities/embedded" ) diff --git a/internal/capabilities/embedded/embedded.go b/internal/capabilities/embedded/embedded.go index c05cde1b..70ebd356 100644 --- a/internal/capabilities/embedded/embedded.go +++ b/internal/capabilities/embedded/embedded.go @@ -26,7 +26,7 @@ import ( "fmt" "strings" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" ) //go:embed */*.json diff --git a/internal/compile/compile.go b/internal/compile/compile.go index d1ac27fd..73c2da99 100644 --- a/internal/compile/compile.go +++ b/internal/compile/compile.go @@ -1,8 +1,9 @@ package compile import ( - "github.com/open-policy-agent/opa/ast" - opaUtil "github.com/open-policy-agent/opa/util" + "github.com/anderseknert/roast/pkg/encoding" + + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/embeds" "github.com/styrainc/regal/internal/util" @@ -27,12 +28,15 @@ func Capabilities() *ast.Capabilities { func RegalSchemaSet() *ast.SchemaSet { schemaSet := ast.NewSchemaSet() astSchema := util.Must(embeds.SchemasFS.ReadFile("schemas/regal-ast.json")) + aggSchema := util.Must(embeds.SchemasFS.ReadFile("schemas/aggregate.json")) - schemaSet.Put(ast.MustParseRef("schema.regal.ast"), opaUtil.MustUnmarshalJSON(astSchema)) + var astSchemaAny, aggSchemaAny any - aggregateSchema := util.Must(embeds.SchemasFS.ReadFile("schemas/aggregate.json")) + util.Must0(encoding.JSON().Unmarshal(astSchema, &astSchemaAny)) + schemaSet.Put(ast.MustParseRef("schema.regal.ast"), astSchemaAny) - schemaSet.Put(ast.MustParseRef("schema.regal.aggregate"), opaUtil.MustUnmarshalJSON(aggregateSchema)) + util.Must0(encoding.JSON().Unmarshal(aggSchema, &aggSchemaAny)) + schemaSet.Put(ast.MustParseRef("schema.regal.aggregate"), aggSchemaAny) return schemaSet } diff --git a/internal/dap/dap.go b/internal/dap/dap.go index aca2de97..366a65bc 100644 --- a/internal/dap/dap.go +++ b/internal/dap/dap.go @@ -10,8 +10,8 @@ import ( godap "github.com/google/go-dap" - "github.com/open-policy-agent/opa/debug" - "github.com/open-policy-agent/opa/logging" + "github.com/open-policy-agent/opa/v1/debug" + "github.com/open-policy-agent/opa/v1/logging" ) type MessageHandler func(ctx context.Context, request godap.Message) (bool, godap.ResponseMessage, error) diff --git a/internal/dap/logger.go b/internal/dap/logger.go index 533732b7..ed758075 100644 --- a/internal/dap/logger.go +++ b/internal/dap/logger.go @@ -3,7 +3,7 @@ package dap import ( strFmt "fmt" - "github.com/open-policy-agent/opa/logging" + "github.com/open-policy-agent/opa/v1/logging" ) type DebugLogger struct { diff --git a/internal/embeds/schemas/regal-ast.json b/internal/embeds/schemas/regal-ast.json index 025de3ac..98b52e85 100644 --- a/internal/embeds/schemas/regal-ast.json +++ b/internal/embeds/schemas/regal-ast.json @@ -377,6 +377,11 @@ "items": { "type": "string" } + }, + "rego_version": { + "type": "integer", + "minimum": 0, + "maximum": 1 } }, "type": "object" @@ -408,6 +413,11 @@ }, "input_dot_json_path": { "type": "string" + }, + "rego_version": { + "type": "integer", + "minimum": 0, + "maximum": 3 } } } diff --git a/internal/embeds/templates/builtin/builtin.rego.tpl b/internal/embeds/templates/builtin/builtin.rego.tpl index c05984d0..60b57aa0 100644 --- a/internal/embeds/templates/builtin/builtin.rego.tpl +++ b/internal/embeds/templates/builtin/builtin.rego.tpl @@ -2,8 +2,6 @@ # description: Add description of rule here! package regal.rules.{{.Category}}{{.Name}} -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/internal/embeds/templates/builtin/builtin_test.rego.tpl b/internal/embeds/templates/builtin/builtin_test.rego.tpl index 10b38189..3b882240 100644 --- a/internal/embeds/templates/builtin/builtin_test.rego.tpl +++ b/internal/embeds/templates/builtin/builtin_test.rego.tpl @@ -1,7 +1,5 @@ package regal.rules.{{.Category}}{{.NameTest}} -import rego.v1 - import data.regal.ast import data.regal.config diff --git a/internal/embeds/templates/custom/custom.rego.tpl b/internal/embeds/templates/custom/custom.rego.tpl index 2fe7513d..2ebc8bf0 100644 --- a/internal/embeds/templates/custom/custom.rego.tpl +++ b/internal/embeds/templates/custom/custom.rego.tpl @@ -4,8 +4,6 @@ # - input: schema.regal.ast package custom.regal.rules.{{.Category}}{{.Name}} -import rego.v1 - import data.regal.ast import data.regal.result diff --git a/internal/embeds/templates/custom/custom_test.rego.tpl b/internal/embeds/templates/custom/custom_test.rego.tpl index e71c8f55..dd516eb8 100644 --- a/internal/embeds/templates/custom/custom_test.rego.tpl +++ b/internal/embeds/templates/custom/custom_test.rego.tpl @@ -1,7 +1,5 @@ package custom.regal.rules.{{.Category}}{{.NameTest}} -import rego.v1 - import data.custom.regal.rules.{{.Category}}{{.Name}} as rule # Example test, replace with your own diff --git a/internal/explorer/stages.go b/internal/explorer/stages.go index 32263366..c02d3b5a 100644 --- a/internal/explorer/stages.go +++ b/internal/explorer/stages.go @@ -7,10 +7,10 @@ import ( "github.com/anderseknert/roast/pkg/encoding" "github.com/anderseknert/roast/pkg/util" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/bundle" - "github.com/open-policy-agent/opa/compile" - "github.com/open-policy-agent/opa/ir" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/bundle" + "github.com/open-policy-agent/opa/v1/compile" + "github.com/open-policy-agent/opa/v1/ir" compile2 "github.com/styrainc/regal/internal/compile" ) diff --git a/internal/io/io.go b/internal/io/io.go index 8b7c6be1..a5e9fe14 100644 --- a/internal/io/io.go +++ b/internal/io/io.go @@ -8,12 +8,16 @@ import ( "os" "path/filepath" "strings" + "sync" "github.com/anderseknert/roast/pkg/encoding" "gopkg.in/yaml.v3" - "github.com/open-policy-agent/opa/bundle" - "github.com/open-policy-agent/opa/loader/filter" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/bundle" + "github.com/open-policy-agent/opa/v1/loader/filter" + "github.com/open-policy-agent/opa/v1/rego" + "github.com/open-policy-agent/opa/v1/types" ) const PathSeparator = string(os.PathSeparator) @@ -27,6 +31,7 @@ func LoadRegalBundleFS(fs files.FS) (bundle.Bundle, error) { //nolint:wrapcheck return bundle.NewCustomReader(embedLoader.WithFilter(ExcludeTestFilter())). + WithCapabilities(Capabilities()). WithSkipBundleVerification(true). WithProcessAnnotations(true). WithBundleName("regal"). @@ -37,6 +42,7 @@ func LoadRegalBundleFS(fs files.FS) (bundle.Bundle, error) { func LoadRegalBundlePath(path string) (bundle.Bundle, error) { //nolint:wrapcheck return bundle.NewCustomReader(bundle.NewDirectoryLoader(path).WithFilter(ExcludeTestFilter())). + WithCapabilities(Capabilities()). WithSkipBundleVerification(true). WithProcessAnnotations(true). WithBundleName("regal"). @@ -174,3 +180,53 @@ func FindManifestLocations(root string) ([]string, error) { return foundBundleRoots, nil } + +// NOTE: These are mirrored here merely to provide correct capabilities for the +// parser. Can't import other packages from here as almost all of them depend on +// this package. We should probably move these definitions to somewhere where all +// packages can import them from. + +//nolint:gochecknoglobals +var regalParseModuleMeta = ®o.Function{ + Name: "regal.parse_module", + Decl: types.NewFunction( + types.Args( + types.Named("filename", types.S).Description("file name to attach to AST nodes' locations"), + types.Named("rego", types.S).Description("Rego module"), + ), + types.Named("output", types.NewObject(nil, types.NewDynamicProperty(types.S, types.A))), + ), +} + +//nolint:gochecknoglobals +var regalLastMeta = ®o.Function{ + Name: "regal.last", + Decl: types.NewFunction( + types.Args( + types.Named("array", types.NewArray(nil, types.A)). + Description("performance optimized last index retrieval"), + ), + types.Named("element", types.A), + ), +} + +//nolint:gochecknoglobals +var OPACapabilities = ast.CapabilitiesForThisVersion() + +//nolint:gochecknoglobals +var Capabilities = sync.OnceValue(capabilities) + +func capabilities() *ast.Capabilities { + cpy := *OPACapabilities + cpy.Builtins = append(cpy.Builtins, + &ast.Builtin{ + Name: regalParseModuleMeta.Name, + Decl: regalParseModuleMeta.Decl, + }, + &ast.Builtin{ + Name: regalLastMeta.Name, + Decl: regalLastMeta.Decl, + }) + + return &cpy +} diff --git a/internal/io/io_test.go b/internal/io/io_test.go index 9b95c869..55ba624b 100644 --- a/internal/io/io_test.go +++ b/internal/io/io_test.go @@ -4,7 +4,7 @@ import ( "slices" "testing" - "github.com/open-policy-agent/opa/util/test" + "github.com/open-policy-agent/opa/v1/util/test" ) func TestFindManifestLocations(t *testing.T) { diff --git a/internal/lsp/bundles/bundles.go b/internal/lsp/bundles/bundles.go index 47e26a55..b2ba88bc 100644 --- a/internal/lsp/bundles/bundles.go +++ b/internal/lsp/bundles/bundles.go @@ -6,7 +6,7 @@ import ( "path/filepath" "slices" - "github.com/open-policy-agent/opa/bundle" + "github.com/open-policy-agent/opa/v1/bundle" ) // LoadDataBundle loads a bundle from the given path but only includes data diff --git a/internal/lsp/bundles/cache.go b/internal/lsp/bundles/cache.go index 70f1c865..e3f36c8e 100644 --- a/internal/lsp/bundles/cache.go +++ b/internal/lsp/bundles/cache.go @@ -12,7 +12,7 @@ import ( "slices" "strings" - "github.com/open-policy-agent/opa/bundle" + "github.com/open-policy-agent/opa/v1/bundle" rio "github.com/styrainc/regal/internal/io" "github.com/styrainc/regal/internal/util" diff --git a/internal/lsp/cache/cache.go b/internal/lsp/cache/cache.go index 2cdbf337..fdf0c124 100644 --- a/internal/lsp/cache/cache.go +++ b/internal/lsp/cache/cache.go @@ -6,7 +6,7 @@ import ( "github.com/anderseknert/roast/pkg/util" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/lsp/types" "github.com/styrainc/regal/internal/util/concurrent" diff --git a/internal/lsp/commands/parse.go b/internal/lsp/commands/parse.go index c64c15a8..bff47d42 100644 --- a/internal/lsp/commands/parse.go +++ b/internal/lsp/commands/parse.go @@ -5,7 +5,7 @@ import ( "fmt" "strconv" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/lsp/types" ) diff --git a/internal/lsp/commands/parse_test.go b/internal/lsp/commands/parse_test.go index 3a670932..81dc5419 100644 --- a/internal/lsp/commands/parse_test.go +++ b/internal/lsp/commands/parse_test.go @@ -3,7 +3,7 @@ package commands import ( "testing" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/lsp/types" ) diff --git a/internal/lsp/completions/manager.go b/internal/lsp/completions/manager.go index 4d1c5983..71882db6 100644 --- a/internal/lsp/completions/manager.go +++ b/internal/lsp/completions/manager.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/open-policy-agent/opa/storage" + "github.com/open-policy-agent/opa/v1/storage" "github.com/styrainc/regal/internal/lsp/cache" "github.com/styrainc/regal/internal/lsp/completions/providers" diff --git a/internal/lsp/completions/manager_test.go b/internal/lsp/completions/manager_test.go index 5dc18a78..f109f18a 100644 --- a/internal/lsp/completions/manager_test.go +++ b/internal/lsp/completions/manager_test.go @@ -4,7 +4,7 @@ import ( "context" "testing" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/lsp/cache" "github.com/styrainc/regal/internal/lsp/completions/providers" diff --git a/internal/lsp/completions/providers/builtins_test.go b/internal/lsp/completions/providers/builtins_test.go index 7b97ea98..bcb592e2 100644 --- a/internal/lsp/completions/providers/builtins_test.go +++ b/internal/lsp/completions/providers/builtins_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/lsp/cache" "github.com/styrainc/regal/internal/lsp/rego" diff --git a/internal/lsp/completions/providers/options.go b/internal/lsp/completions/providers/options.go index a5f30a58..8f20f634 100644 --- a/internal/lsp/completions/providers/options.go +++ b/internal/lsp/completions/providers/options.go @@ -1,7 +1,7 @@ package providers import ( - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/lsp/clients" ) @@ -12,4 +12,5 @@ type Options struct { Builtins map[string]*ast.Builtin RootURI string ClientIdentifier clients.Identifier + RegoVersion ast.RegoVersion } diff --git a/internal/lsp/completions/providers/packagerefs_test.go b/internal/lsp/completions/providers/packagerefs_test.go index 7d32885b..643d0cb7 100644 --- a/internal/lsp/completions/providers/packagerefs_test.go +++ b/internal/lsp/completions/providers/packagerefs_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/lsp/cache" "github.com/styrainc/regal/internal/lsp/completions/refs" diff --git a/internal/lsp/completions/providers/policy.go b/internal/lsp/completions/providers/policy.go index ee0969e5..44a3b47c 100644 --- a/internal/lsp/completions/providers/policy.go +++ b/internal/lsp/completions/providers/policy.go @@ -7,9 +7,9 @@ import ( "github.com/anderseknert/roast/pkg/encoding" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/rego" - "github.com/open-policy-agent/opa/storage" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/rego" + "github.com/open-policy-agent/opa/v1/storage" rbundle "github.com/styrainc/regal/bundle" rio "github.com/styrainc/regal/internal/io" @@ -67,6 +67,7 @@ func (p *Policy) Run( inputContext["client_identifier"] = opts.ClientIdentifier inputContext["workspace_root"] = uri.ToPath(opts.ClientIdentifier, opts.RootURI) inputContext["path_separator"] = rio.PathSeparator + inputContext["rego_version"] = opts.RegoVersion workspacePath := uri.ToPath(opts.ClientIdentifier, opts.RootURI) diff --git a/internal/lsp/completions/providers/policy_test.go b/internal/lsp/completions/providers/policy_test.go index af764864..36a829d0 100644 --- a/internal/lsp/completions/providers/policy_test.go +++ b/internal/lsp/completions/providers/policy_test.go @@ -7,8 +7,8 @@ import ( "github.com/anderseknert/roast/pkg/encoding" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/storage/inmem" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/storage/inmem" "github.com/styrainc/regal/internal/lsp/cache" "github.com/styrainc/regal/internal/lsp/clients" @@ -21,8 +21,6 @@ func TestPolicyProvider_Example1(t *testing.T) { policy := `package p -import rego.v1 - allow if { user := data.users[0] # try completion on next line @@ -53,7 +51,7 @@ allow if { URI: testCaseFileURI, }, Position: types.Position{ - Line: 7, + Line: 5, Character: 11, }, } @@ -84,14 +82,10 @@ func TestPolicyProvider_Example2(t *testing.T) { file1 := ast.MustParseModule(`package example -import rego.v1 - foo := true `) file2 := ast.MustParseModule(`package example2 -import rego.v1 - import data.example `) @@ -111,8 +105,6 @@ import data.example locals := NewPolicy(context.Background(), store) fileEdited := `package example2 -import rego.v1 - import data.example allow if { @@ -128,7 +120,7 @@ allow if { URI: "file:///file2.rego", }, Position: types.Position{ - Line: 7, + Line: 5, Character: 11, }, } diff --git a/internal/lsp/completions/providers/rulehead_test.go b/internal/lsp/completions/providers/rulehead_test.go index 11394608..2f91a15c 100644 --- a/internal/lsp/completions/providers/rulehead_test.go +++ b/internal/lsp/completions/providers/rulehead_test.go @@ -5,7 +5,7 @@ import ( "slices" "testing" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/lsp/cache" "github.com/styrainc/regal/internal/lsp/completions/refs" @@ -22,8 +22,6 @@ func TestRuleHead(t *testing.T) { regoFiles := map[string]string{ "file:///foo/foo.rego": `package foo -import rego.v1 - default allow := false allow if count(deny) == 0 diff --git a/internal/lsp/completions/refs/defined.go b/internal/lsp/completions/refs/defined.go index b690e759..07ba48e1 100644 --- a/internal/lsp/completions/refs/defined.go +++ b/internal/lsp/completions/refs/defined.go @@ -9,7 +9,7 @@ import ( "github.com/anderseknert/roast/pkg/util" "gopkg.in/yaml.v3" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" rast "github.com/styrainc/regal/internal/ast" "github.com/styrainc/regal/internal/lsp/types" diff --git a/internal/lsp/completions/refs/defined_test.go b/internal/lsp/completions/refs/defined_test.go index ddbac2bd..32102092 100644 --- a/internal/lsp/completions/refs/defined_test.go +++ b/internal/lsp/completions/refs/defined_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/lsp/rego" "github.com/styrainc/regal/internal/lsp/types" @@ -106,8 +106,6 @@ func TestRefsForModule_Rules(t *testing.T) { mod := rparse.MustParseModule(`package example -import rego.v1 - # METADATA # title: An allow rule # description: A rule for things that should be allowed diff --git a/internal/lsp/completions/refs/used.go b/internal/lsp/completions/refs/used.go index de6108da..9a438442 100644 --- a/internal/lsp/completions/refs/used.go +++ b/internal/lsp/completions/refs/used.go @@ -7,9 +7,9 @@ import ( "github.com/anderseknert/roast/pkg/transform" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/bundle" - "github.com/open-policy-agent/opa/rego" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/bundle" + "github.com/open-policy-agent/opa/v1/rego" rbundle "github.com/styrainc/regal/bundle" rio "github.com/styrainc/regal/internal/io" @@ -19,21 +19,11 @@ import ( _ "embed" ) -// pq is a prepared query that finds ref names used in a module. -// pq is prepared at init time to make this functionality more -// efficient. In local testing, this reduced time by ~95%. -// -//nolint:gochecknoglobals -var pq *rego.PreparedEvalQuery - -//nolint:gochecknoglobals -var pqInitOnce sync.Once - // initialize prepares the rego query for finding ref names used in a module. // This is run and the resulting prepared query stored for performance reasons. // This function is only used by language server code paths and so init() is not // used. -func initialize() { +func prepareQuery() (*rego.PreparedEvalQuery, error) { dataBundle := bundle.Bundle{ Manifest: bundle.Manifest{ Roots: &[]string{"internal"}, @@ -58,24 +48,30 @@ func initialize() { preparedQuery, err := rego.New(regoArgs...).PrepareForEval(context.Background()) if err != nil { - panic(err) + return nil, err //nolint:wrapcheck } - pq = &preparedQuery + return &preparedQuery, nil } +//nolint:gochecknoglobals +var pqOnce = sync.OnceValues(prepareQuery) + // UsedInModule returns a list of ref names suitable for completion that are // used in the module's code. // See the rego above for more details on what's included and excluded. // This function is run when the parse completes for a module. func UsedInModule(ctx context.Context, module *ast.Module) ([]string, error) { - pqInitOnce.Do(initialize) - inputValue, err := transform.ToOPAInputValue(module) if err != nil { return nil, fmt.Errorf("failed converting input to value: %w", err) } + pq, err := pqOnce() + if err != nil { + return nil, fmt.Errorf("failed to prepare rego query: %w", err) + } + rs, err := pq.Eval(ctx, rego.EvalParsedInput(inputValue)) if err != nil { return nil, fmt.Errorf("failed to evaluate rego query: %w", err) diff --git a/internal/lsp/completions/refs/used_test.go b/internal/lsp/completions/refs/used_test.go index a5f7e679..583ae34c 100644 --- a/internal/lsp/completions/refs/used_test.go +++ b/internal/lsp/completions/refs/used_test.go @@ -14,8 +14,6 @@ func TestUsedInModule(t *testing.T) { mod := rparse.MustParseModule(` package example -import rego.v1 - import data.foo as wow import data.bar diff --git a/internal/lsp/documentsymbol.go b/internal/lsp/documentsymbol.go index a3fda91c..14e79369 100644 --- a/internal/lsp/documentsymbol.go +++ b/internal/lsp/documentsymbol.go @@ -5,7 +5,7 @@ import ( "fmt" "strings" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" rast "github.com/styrainc/regal/internal/ast" "github.com/styrainc/regal/internal/lsp/types" diff --git a/internal/lsp/documentsymbol_test.go b/internal/lsp/documentsymbol_test.go index 1d291813..71f8e033 100644 --- a/internal/lsp/documentsymbol_test.go +++ b/internal/lsp/documentsymbol_test.go @@ -3,7 +3,7 @@ package lsp import ( "testing" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/lsp/rego" "github.com/styrainc/regal/internal/lsp/types" diff --git a/internal/lsp/eval.go b/internal/lsp/eval.go index aea6d7d6..59587b67 100644 --- a/internal/lsp/eval.go +++ b/internal/lsp/eval.go @@ -8,10 +8,10 @@ import ( "github.com/anderseknert/roast/pkg/transform" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/bundle" - "github.com/open-policy-agent/opa/rego" - "github.com/open-policy-agent/opa/topdown/print" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/bundle" + "github.com/open-policy-agent/opa/v1/rego" + "github.com/open-policy-agent/opa/v1/topdown/print" rbundle "github.com/styrainc/regal/bundle" "github.com/styrainc/regal/internal/lsp/log" diff --git a/internal/lsp/eval_test.go b/internal/lsp/eval_test.go index 98331061..ee990915 100644 --- a/internal/lsp/eval_test.go +++ b/internal/lsp/eval_test.go @@ -24,8 +24,6 @@ func TestEvalWorkspacePath(t *testing.T) { policy1 := `package policy1 - import rego.v1 - import data.policy2 default allow := false @@ -35,8 +33,6 @@ func TestEvalWorkspacePath(t *testing.T) { policy2 := `package policy2 - import rego.v1 - allow if input.exists ` diff --git a/internal/lsp/foldingrange.go b/internal/lsp/foldingrange.go index dff631ec..6c83ee8c 100644 --- a/internal/lsp/foldingrange.go +++ b/internal/lsp/foldingrange.go @@ -3,7 +3,7 @@ package lsp import ( "strings" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/lsp/opa/scanner" "github.com/styrainc/regal/internal/lsp/opa/tokens" diff --git a/internal/lsp/foldingrange_test.go b/internal/lsp/foldingrange_test.go index a0c85d50..529bb470 100644 --- a/internal/lsp/foldingrange_test.go +++ b/internal/lsp/foldingrange_test.go @@ -9,8 +9,6 @@ func TestTokenFoldingRanges(t *testing.T) { policy := `package p - import rego.v1 - rule if { arr := [ 1, @@ -32,32 +30,32 @@ rule if { arr := foldingRanges[0] - if arr.StartLine != 5 || *arr.StartCharacter != 9 { - t.Errorf("Expected start line 5 and start character 9, got %d and %d", arr.StartLine, *arr.StartCharacter) + if arr.StartLine != 3 || *arr.StartCharacter != 9 { + t.Errorf("Expected start line 3 and start character 9, got %d and %d", arr.StartLine, *arr.StartCharacter) } - if arr.EndLine != 8 { - t.Errorf("Expected end line 8, got %d", arr.EndLine) + if arr.EndLine != 6 { + t.Errorf("Expected end line 6, got %d", arr.EndLine) } parens := foldingRanges[1] - if parens.StartLine != 10 || *parens.StartCharacter != 9 { - t.Errorf("Expected start line 10 and start character 9, got %d and %d", parens.StartLine, *parens.StartCharacter) + if parens.StartLine != 8 || *parens.StartCharacter != 9 { + t.Errorf("Expected start line 8 and start character 9, got %d and %d", parens.StartLine, *parens.StartCharacter) } - if parens.EndLine != 13 { - t.Errorf("Expected end line 13, got %d", parens.EndLine) + if parens.EndLine != 11 { + t.Errorf("Expected end line 11, got %d", parens.EndLine) } rule := foldingRanges[2] - if rule.StartLine != 4 || *rule.StartCharacter != 9 { - t.Errorf("Expected start line 4 and start character 9, got %d and %d", rule.StartLine, *rule.StartCharacter) + if rule.StartLine != 2 || *rule.StartCharacter != 9 { + t.Errorf("Expected start line 2 and start character 9, got %d and %d", rule.StartLine, *rule.StartCharacter) } - if rule.EndLine != 14 { - t.Errorf("Expected end line 7, got %d", rule.EndLine) + if rule.EndLine != 12 { + t.Errorf("Expected end line 12, got %d", rule.EndLine) } } diff --git a/internal/lsp/hover/hover.go b/internal/lsp/hover/hover.go index 587d902c..1dade7d2 100644 --- a/internal/lsp/hover/hover.go +++ b/internal/lsp/hover/hover.go @@ -7,8 +7,8 @@ import ( "strconv" "strings" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/types" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/types" "github.com/styrainc/regal/internal/lsp/cache" "github.com/styrainc/regal/internal/lsp/examples" diff --git a/internal/lsp/hover/hover_test.go b/internal/lsp/hover/hover_test.go index c512905f..9b5abca9 100644 --- a/internal/lsp/hover/hover_test.go +++ b/internal/lsp/hover/hover_test.go @@ -4,8 +4,8 @@ import ( "os" "testing" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/types" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/types" ) func TestCreateHoverContent(t *testing.T) { diff --git a/internal/lsp/hover/testdata/hover/jsonfilter.md b/internal/lsp/hover/testdata/hover/jsonfilter.md index 5a77ebe0..ebe5f726 100644 --- a/internal/lsp/hover/testdata/hover/jsonfilter.md +++ b/internal/lsp/hover/testdata/hover/jsonfilter.md @@ -9,7 +9,7 @@ Filters the object. For example: `json.filter({"a": {"b": "x", "c": "y"}}, ["a/b #### Arguments -- `object` object[any: any] +- `object` object[any: any] — object to filter - `paths` any], set[any]> — JSON string paths diff --git a/internal/lsp/inlayhint.go b/internal/lsp/inlayhint.go index c64d6054..c11217f0 100644 --- a/internal/lsp/inlayhint.go +++ b/internal/lsp/inlayhint.go @@ -3,8 +3,8 @@ package lsp import ( "fmt" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/types" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/types" "github.com/styrainc/regal/internal/lsp/rego" types2 "github.com/styrainc/regal/internal/lsp/types" diff --git a/internal/lsp/inlayhint_test.go b/internal/lsp/inlayhint_test.go index 6d0243e7..141c6428 100644 --- a/internal/lsp/inlayhint_test.go +++ b/internal/lsp/inlayhint_test.go @@ -3,7 +3,7 @@ package lsp import ( "testing" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/lsp/rego" ) @@ -34,8 +34,8 @@ func TestGetInlayHintsAstCall(t *testing.T) { inlayHints[0].Position.Line, inlayHints[0].Position.Character) } - if inlayHints[0].Tooltip.Value != "Type: `object[any: any]`" { - t.Errorf("Expected tooltip to be 'Type: `object[any: any]`, got %s", inlayHints[0].Tooltip.Value) + if inlayHints[0].Tooltip.Value != "object to filter\n\nType: `object[any: any]`" { + t.Errorf("Expected tooltip to be 'object to filter\n\nType: `object[any: any]`, got %s", inlayHints[0].Tooltip.Value) } if inlayHints[1].Label != "paths:" { @@ -60,8 +60,6 @@ func TestGetInlayHintsAstTerms(t *testing.T) { policy := `package p - import rego.v1 - allow if { is_string("yes") }` @@ -85,7 +83,7 @@ func TestGetInlayHintsAstTerms(t *testing.T) { inlayHints[0].Position.Line, inlayHints[0].Position.Character) } - if inlayHints[0].Tooltip.Value != "Type: `any`" { - t.Errorf("Expected tooltip to be 'Type: `any`, got %s", inlayHints[0].Tooltip.Value) + if inlayHints[0].Tooltip.Value != "input value\n\nType: `any`" { + t.Errorf("Expected tooltip to be 'input value\n\nType: `any`, got %s", inlayHints[0].Tooltip.Value) } } diff --git a/internal/lsp/lint.go b/internal/lsp/lint.go index 7bdf16bb..11fb8838 100644 --- a/internal/lsp/lint.go +++ b/internal/lsp/lint.go @@ -7,8 +7,8 @@ import ( "fmt" "strings" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/storage" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/storage" "github.com/styrainc/regal/internal/lsp/cache" "github.com/styrainc/regal/internal/lsp/completions/refs" @@ -38,11 +38,16 @@ func updateParse( lines := strings.Split(content, "\n") - module, err := rparse.Module(fileURI, content) + var ( + err error + module *ast.Module + ) + + // TODO: IF not set in config, or from .manifest + module, err = rparse.ModuleUnknownVersionWithOpts(fileURI, content, rparse.ParserOptions()) if err == nil { // if the parse was ok, clear the parse errors cache.SetParseErrors(fileURI, []types.Diagnostic{}) - cache.SetModule(fileURI, module) if err := PutFileMod(ctx, store, fileURI, module); err != nil { @@ -164,7 +169,10 @@ func updateFileDiagnostics( return fmt.Errorf("failed to get file contents for uri %q", fileURI) } - input := rules.NewInput(map[string]string{fileURI: contents}, map[string]*ast.Module{fileURI: module}) + input := rules.NewInput( + map[string]string{fileURI: contents}, + map[string]*ast.Module{fileURI: module}, + ) regalInstance := linter.NewLinter(). // needed to get the aggregateData for this file diff --git a/internal/lsp/lint_test.go b/internal/lsp/lint_test.go index 2b6bca52..5f345e0f 100644 --- a/internal/lsp/lint_test.go +++ b/internal/lsp/lint_test.go @@ -83,7 +83,7 @@ func TestLintWithConfigIgnoreWildcards(t *testing.T) { }, } - contents := "package p\n\nimport rego.v1\n\ncamelCase := 1\n" + contents := "package p\n\ncamelCase := 1\n" module := parse.MustParseModule(contents) workspaceRootURI := "file:///workspace" fileURI := "file:///workspace/ignore/p.rego" diff --git a/internal/lsp/opa/oracle/oracle.go b/internal/lsp/opa/oracle/oracle.go index e621be8d..d85aa18d 100644 --- a/internal/lsp/opa/oracle/oracle.go +++ b/internal/lsp/opa/oracle/oracle.go @@ -9,7 +9,7 @@ import ( "github.com/anderseknert/roast/pkg/util" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/compile" ) diff --git a/internal/lsp/rego/builtins.go b/internal/lsp/rego/builtins.go index 262ebe0d..5bfc97a2 100644 --- a/internal/lsp/rego/builtins.go +++ b/internal/lsp/rego/builtins.go @@ -3,7 +3,7 @@ package rego import ( "strings" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" ) // BuiltinsForCapabilities returns a list of builtins from the provided capabilities. diff --git a/internal/lsp/rego/rego.go b/internal/lsp/rego/rego.go index d831ec5c..b9ffc646 100644 --- a/internal/lsp/rego/rego.go +++ b/internal/lsp/rego/rego.go @@ -10,8 +10,8 @@ import ( "github.com/anderseknert/roast/pkg/encoding" "github.com/anderseknert/roast/pkg/transform" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/rego" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/rego" rbundle "github.com/styrainc/regal/bundle" "github.com/styrainc/regal/internal/lsp/clients" diff --git a/internal/lsp/rego/rego_test.go b/internal/lsp/rego/rego_test.go index 2a1ff70f..68828605 100644 --- a/internal/lsp/rego/rego_test.go +++ b/internal/lsp/rego/rego_test.go @@ -12,8 +12,6 @@ func TestCodeLenses(t *testing.T) { contents := `package p - import rego.v1 - allow if "foo" in input.bar` module := parse.MustParseModule(contents) @@ -35,8 +33,6 @@ func TestAllRuleHeadLocations(t *testing.T) { contents := `package p - import rego.v1 - default allow := false allow if 1 @@ -70,7 +66,7 @@ func TestAllKeywords(t *testing.T) { contents := `package p - import rego.v1 + import data.foo my_set contains "x" if true ` diff --git a/internal/lsp/server.go b/internal/lsp/server.go index c4846695..94dc5a30 100644 --- a/internal/lsp/server.go +++ b/internal/lsp/server.go @@ -20,9 +20,9 @@ import ( "github.com/sourcegraph/jsonrpc2" "gopkg.in/yaml.v3" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/format" - "github.com/open-policy-agent/opa/storage" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/format" + "github.com/open-policy-agent/opa/v1/storage" rbundle "github.com/styrainc/regal/bundle" "github.com/styrainc/regal/internal/capabilities" @@ -88,20 +88,21 @@ func NewLanguageServer(ctx context.Context, opts *LanguageServerOptions) *Langua var ls *LanguageServer ls = &LanguageServer{ - cache: c, - regoStore: store, - logWriter: opts.LogWriter, - logLevel: opts.LogLevel, - lintFileJobs: make(chan lintFileJob, 10), - lintWorkspaceJobs: make(chan lintWorkspaceJob, 10), - builtinsPositionJobs: make(chan lintFileJob, 10), - commandRequest: make(chan types.ExecuteCommandParams, 10), - templateFileJobs: make(chan lintFileJob, 10), - configWatcher: lsconfig.NewWatcher(&lsconfig.WatcherOpts{LogFunc: ls.logf}), - completionsManager: completions.NewDefaultManager(ctx, c, store), - webServer: web.NewServer(c), - loadedBuiltins: concurrent.MapOf(make(map[string]map[string]*ast.Builtin)), - workspaceDiagnosticsPoll: opts.WorkspaceDiagnosticsPoll, + cache: c, + regoStore: store, + logWriter: opts.LogWriter, + logLevel: opts.LogLevel, + lintFileJobs: make(chan lintFileJob, 10), + lintWorkspaceJobs: make(chan lintWorkspaceJob, 10), + builtinsPositionJobs: make(chan lintFileJob, 10), + commandRequest: make(chan types.ExecuteCommandParams, 10), + templateFileJobs: make(chan lintFileJob, 10), + configWatcher: lsconfig.NewWatcher(&lsconfig.WatcherOpts{LogFunc: ls.logf}), + completionsManager: completions.NewDefaultManager(ctx, c, store), + webServer: web.NewServer(c), + loadedBuiltins: concurrent.MapOf(make(map[string]map[string]*ast.Builtin)), + workspaceDiagnosticsPoll: opts.WorkspaceDiagnosticsPoll, + loadedConfigAllRegoVersions: concurrent.MapOf(make(map[string]ast.RegoVersion)), } return ls @@ -114,10 +115,13 @@ type LanguageServer struct { regoStore storage.Store conn *jsonrpc2.Conn - configWatcher *lsconfig.Watcher - loadedConfig *config.Config + configWatcher *lsconfig.Watcher + loadedConfig *config.Config + // this is also used to lock the updates to the cache of enabled rules + loadedConfigLock sync.Mutex loadedConfigEnabledNonAggregateRules []string loadedConfigEnabledAggregateRules []string + loadedConfigAllRegoVersions *concurrent.Map[string, ast.RegoVersion] loadedBuiltins *concurrent.Map[string, map[string]*ast.Builtin] clientInitializationOptions types.InitializationOptions @@ -138,9 +142,6 @@ type LanguageServer struct { workspaceRootURI string clientIdentifier clients.Identifier - // this is also used to lock the updates to the cache of enabled rules - loadedConfigLock sync.Mutex - workspaceDiagnosticsPoll time.Duration } @@ -551,6 +552,22 @@ func (l *LanguageServer) StartConfigWorker(ctx context.Context) { l.loadedConfig = &mergedConfig l.loadedConfigLock.Unlock() + // Rego versions may have changed, so reload them. + allRegoVersions, err := config.AllRegoVersions( + uri.ToPath(l.clientIdentifier, l.workspaceRootURI), + l.getLoadedConfig(), + ) + if err != nil { + l.logf(log.LevelMessage, "failed to reload rego versions: %s", err) + } + + l.loadedConfigAllRegoVersions.Clear() + + for k, v := range allRegoVersions { + l.loadedConfigAllRegoVersions.Set(k, v) + } + + // Enabled rules might have changed with the new config, so reload. err = l.loadEnabledRulesFromConfig(ctx, mergedConfig) if err != nil { l.logf(log.LevelMessage, "failed to cache enabled rules: %s", err) @@ -1096,6 +1113,32 @@ func (l *LanguageServer) StartWebServer(ctx context.Context) { l.webServer.Start(ctx) } +func (l *LanguageServer) determineVersionForFile(fileURI string) ast.RegoVersion { + var versionedDirs []string + + // if we have no information, then we can return the default + if l.loadedConfigAllRegoVersions.Len() == 0 { + return ast.RegoV1 + } + + versionedDirs = util.Keys(l.loadedConfigAllRegoVersions.Clone()) + slices.Sort(versionedDirs) + slices.Reverse(versionedDirs) + + path := strings.TrimPrefix(fileURI, l.workspaceRootURI+"/") + + for _, versionedDir := range versionedDirs { + if strings.HasPrefix(path, versionedDir) { + val, ok := l.loadedConfigAllRegoVersions.Get(versionedDir) + if ok { + return val + } + } + } + + return ast.RegoV1 +} + func (l *LanguageServer) templateContentsForFile(fileURI string) (string, error) { // this function should not be called with files in the root, but if it is, // then it is an error to prevent unwanted behavior. @@ -1185,7 +1228,13 @@ func (l *LanguageServer) templateContentsForFile(fileURI string) (string, error) pkg += "_test" } - return fmt.Sprintf("package %s\n\nimport rego.v1\n", pkg), nil + version := l.determineVersionForFile(fileURI) + + if version == ast.RegoV0 { + return fmt.Sprintf("package %s\n\nimport rego.v1\n", pkg), nil + } + + return fmt.Sprintf("package %s\n\n", pkg), nil } func (l *LanguageServer) fixEditParams( @@ -1715,6 +1764,7 @@ func (l *LanguageServer) handleTextDocumentCompletion( ClientIdentifier: l.clientIdentifier, RootURI: l.workspaceRootURI, Builtins: l.builtinsForCurrentCapabilities(), + RegoVersion: l.determineVersionForFile(params.TextDocument.URI), }) if err != nil { return nil, fmt.Errorf("failed to find completions: %w", err) @@ -2080,8 +2130,7 @@ func (l *LanguageServer) handleTextDocumentFormatting( oldContent, _ = l.cache.GetFileContents(params.TextDocument.URI) } - // if the file is empty, then the formatters will fail, so we template - // instead + // if the file is empty, then the formatters will fail, so we template instead if oldContent == "" { // disable the templating feature for files in the workspace root. if filepath.Dir(uri.ToPath(l.clientIdentifier, params.TextDocument.URI)) == @@ -2095,7 +2144,6 @@ func (l *LanguageServer) handleTextDocumentFormatting( } l.cache.ClearFileDiagnostics() - l.cache.SetFileContents(params.TextDocument.URI, newContent) updateEvent := lintFileJob{ @@ -2119,7 +2167,10 @@ func (l *LanguageServer) handleTextDocumentFormatting( switch formatter { case "opa-fmt", "opa-fmt-rego-v1": - opts := format.Opts{} + opts := format.Opts{ + RegoVersion: l.determineVersionForFile(params.TextDocument.URI), + } + if formatter == "opa-fmt-rego-v1" { opts.RegoVersion = ast.RegoV0CompatV1 } @@ -2158,14 +2209,7 @@ func (l *LanguageServer) handleTextDocumentFormatting( f := fixer.NewFixer() f.RegisterFixes(fixes.NewDefaultFormatterFixes()...) - f.RegisterMandatoryFixes( - &fixes.Fmt{ - NameOverride: "use-rego-v1", - OPAFmtOpts: format.Opts{ - RegoVersion: ast.RegoV0CompatV1, - }, - }, - ) + f.RegisterMandatoryFixes([]fixes.Fix{&fixes.Fmt{}}...) if roots, err := config.GetPotentialRoots( l.workspacePath(), diff --git a/internal/lsp/server_all_rego_versions_test.go b/internal/lsp/server_all_rego_versions_test.go new file mode 100644 index 00000000..856967c1 --- /dev/null +++ b/internal/lsp/server_all_rego_versions_test.go @@ -0,0 +1,148 @@ +package lsp + +import ( + "context" + "os" + "path/filepath" + "testing" + "time" + + "github.com/open-policy-agent/opa/v1/ast" + + "github.com/styrainc/regal/internal/lsp/clients" + "github.com/styrainc/regal/internal/lsp/log" + "github.com/styrainc/regal/internal/lsp/uri" + "github.com/styrainc/regal/pkg/config" +) + +func TestAllRegoVersions(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + FileKey string + ExpectedVersion ast.RegoVersion + DiskContents map[string]string + }{ + "unknown version": { + FileKey: "foo/bar.rego", + DiskContents: map[string]string{ + "foo/bar.rego": "package foo", + ".regal/config.yaml": "", + }, + ExpectedVersion: ast.RegoV1, + }, + "version set in project config": { + FileKey: "foo/bar.rego", + DiskContents: map[string]string{ + "foo/bar.rego": "package foo", + ".regal/config.yaml": ` +project: + rego-version: 0 +`, + }, + ExpectedVersion: ast.RegoV0, + }, + "version set in root config": { + FileKey: "foo/bar.rego", + DiskContents: map[string]string{ + "foo/bar.rego": "package foo", + ".regal/config.yaml": ` +project: + rego-version: 1 + roots: + - path: foo + rego-version: 0 +`, + }, + ExpectedVersion: ast.RegoV0, + }, + "version set in manifest": { + FileKey: "foo/bar.rego", + DiskContents: map[string]string{ + "foo/bar.rego": "package foo", + "foo/.manifest": `{"rego_version": 0}`, + ".regal/config.yaml": ``, + }, + ExpectedVersion: ast.RegoV0, + }, + "version set in manifest, overridden by config": { + FileKey: "foo/bar.rego", + DiskContents: map[string]string{ + "foo/bar.rego": "package foo", + "foo/.manifest": `{"rego_version": 1}`, + ".regal/config.yaml": ` +project: + roots: + - path: foo + rego-version: 0 +`, + }, + ExpectedVersion: ast.RegoV0, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + t.Parallel() + + td := t.TempDir() + + // init the state on disk + for f, c := range tc.DiskContents { + dir := filepath.Dir(f) + + if err := os.MkdirAll(filepath.Join(td, dir), 0o755); err != nil { + t.Fatalf("failed to create directory %s: %s", dir, err) + } + + if err := os.WriteFile(filepath.Join(td, f), []byte(c), 0o600); err != nil { + t.Fatalf("failed to write file %s: %s", f, err) + } + } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + ls := NewLanguageServer(ctx, &LanguageServerOptions{LogWriter: newTestLogger(t), LogLevel: log.LevelDebug}) + ls.workspaceRootURI = uri.FromPath(clients.IdentifierGeneric, td) + + // have the server load the config + go ls.StartConfigWorker(ctx) + + configFile, err := config.FindConfig(td) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + ls.configWatcher.Watch(configFile.Name()) + + // wait for ls.loadedConfig to be set + timeout := time.NewTimer(determineTimeout()) + defer timeout.Stop() + + for success := false; !success; { + select { + default: + if ls.getLoadedConfig() != nil { + success = true + + break + } + + time.Sleep(500 * time.Millisecond) + case <-timeout.C: + t.Fatalf("timed out waiting for config to be set") + } + } + + // check it has the correct version for the file of interest + fileURI := uri.FromPath(clients.IdentifierGeneric, filepath.Join(td, tc.FileKey)) + + version := ls.determineVersionForFile(fileURI) + + if version != tc.ExpectedVersion { + t.Errorf("expected version %v, got %v", tc.ExpectedVersion, version) + } + }) + } +} diff --git a/internal/lsp/server_config_test.go b/internal/lsp/server_config_test.go index f2af5fc6..20d8a993 100644 --- a/internal/lsp/server_config_test.go +++ b/internal/lsp/server_config_test.go @@ -32,7 +32,7 @@ func TestLanguageServerParentDirConfig(t *testing.T) { mainRegoContents := `package main -import rego.v1 +import data.test allow := true ` diff --git a/internal/lsp/server_template_test.go b/internal/lsp/server_template_test.go index dc8b77b9..441044ca 100644 --- a/internal/lsp/server_template_test.go +++ b/internal/lsp/server_template_test.go @@ -12,22 +12,26 @@ import ( "github.com/sourcegraph/jsonrpc2" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/styrainc/regal/internal/lsp/clients" "github.com/styrainc/regal/internal/lsp/log" "github.com/styrainc/regal/internal/lsp/types" "github.com/styrainc/regal/internal/lsp/uri" + "github.com/styrainc/regal/internal/util/concurrent" ) func TestTemplateContentsForFile(t *testing.T) { t.Parallel() testCases := map[string]struct { - FileKey string - CacheFileContents string - DiskContents map[string]string - RequireConfig bool - ExpectedContents string - ExpectedError string + FileKey string + CacheFileContents string + DiskContents map[string]string + RequireConfig bool + ServerAllRegoVersions *concurrent.Map[string, ast.RegoVersion] + ExpectedContents string + ExpectedError string }{ "existing contents in file": { FileKey: "foo/bar.rego", @@ -49,7 +53,7 @@ func TestTemplateContentsForFile(t *testing.T) { "foo/bar.rego": "", ".regal/config.yaml": "", }, - ExpectedContents: "package foo\n\nimport rego.v1\n", + ExpectedContents: "package foo\n\n", }, "empty test file is templated based on root": { FileKey: "foo/bar_test.rego", @@ -59,7 +63,7 @@ func TestTemplateContentsForFile(t *testing.T) { ".regal/config.yaml": "", }, RequireConfig: true, - ExpectedContents: "package foo_test\n\nimport rego.v1\n", + ExpectedContents: "package foo_test\n\n", }, "empty deeply nested file is templated based on root": { FileKey: "foo/bar/baz/bax.rego", @@ -68,8 +72,32 @@ func TestTemplateContentsForFile(t *testing.T) { "foo/bar/baz/bax.rego": "", ".regal/config.yaml": "", }, + ExpectedContents: "package foo.bar.baz\n\n", + }, + "v0 templating using rego version setting": { + FileKey: "foo/bar/baz/bax.rego", + CacheFileContents: "", + ServerAllRegoVersions: concurrent.MapOf(map[string]ast.RegoVersion{ + "foo": ast.RegoV0, + }), + DiskContents: map[string]string{ + "foo/bar/baz/bax.rego": "", + ".regal/config.yaml": "", // we manually set the versions, config not loaded in these tests + }, ExpectedContents: "package foo.bar.baz\n\nimport rego.v1\n", }, + "v1 templating using rego version setting": { + FileKey: "foo/bar/baz/bax.rego", + CacheFileContents: "", + ServerAllRegoVersions: concurrent.MapOf(map[string]ast.RegoVersion{ + "foo": ast.RegoV1, + }), + DiskContents: map[string]string{ + "foo/bar/baz/bax.rego": "", + ".regal/config.yaml": "", // we manually set the versions, config not loaded in these tests + }, + ExpectedContents: "package foo.bar.baz\n\n", + }, } for name, tc := range testCases { @@ -100,6 +128,8 @@ func TestTemplateContentsForFile(t *testing.T) { ls.workspaceRootURI = uri.FromPath(clients.IdentifierGeneric, td) + ls.loadedConfigAllRegoVersions = tc.ServerAllRegoVersions + fileURI := uri.FromPath(clients.IdentifierGeneric, filepath.Join(td, tc.FileKey)) ls.cache.SetFileContents(fileURI, tc.CacheFileContents) @@ -188,7 +218,6 @@ func TestTemplateContentsForFileWithUnknownRoot(t *testing.T) { exp := `package foo -import rego.v1 ` if exp != newContents { t.Errorf("unexpected content: %s, want %s", newContents, exp) @@ -279,7 +308,7 @@ func TestNewFileTemplating(t *testing.T) { { "edits": [ { - "newText": "package foo.bar_test\n\nimport rego.v1\n", + "newText": "package foo.bar_test\n\n", "range": { "end": { "character": 0, diff --git a/internal/lsp/store.go b/internal/lsp/store.go index 1e510f95..49fb4364 100644 --- a/internal/lsp/store.go +++ b/internal/lsp/store.go @@ -7,9 +7,9 @@ import ( "github.com/anderseknert/roast/pkg/encoding" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/storage" - "github.com/open-policy-agent/opa/storage/inmem" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/storage" + "github.com/open-policy-agent/opa/v1/storage/inmem" ) func NewRegalStore() storage.Store { diff --git a/internal/lsp/store_test.go b/internal/lsp/store_test.go index a7775520..e5bfb714 100644 --- a/internal/lsp/store_test.go +++ b/internal/lsp/store_test.go @@ -6,7 +6,7 @@ import ( "slices" "testing" - "github.com/open-policy-agent/opa/storage" + "github.com/open-policy-agent/opa/v1/storage" "github.com/styrainc/regal/internal/parse" ) diff --git a/internal/lsp/types/internal.go b/internal/lsp/types/internal.go index c6756894..e4c1b718 100644 --- a/internal/lsp/types/internal.go +++ b/internal/lsp/types/internal.go @@ -1,6 +1,6 @@ package types -import "github.com/open-policy-agent/opa/ast" +import "github.com/open-policy-agent/opa/v1/ast" // Ref is a generic construct for an object found in a Rego module. // Ref is designed to be used in completions and provides information diff --git a/internal/lsp/types/types.go b/internal/lsp/types/types.go index 9adf2865..5c67b77e 100644 --- a/internal/lsp/types/types.go +++ b/internal/lsp/types/types.go @@ -1,6 +1,8 @@ package types import ( + "github.com/open-policy-agent/opa/v1/ast" + "github.com/styrainc/regal/internal/lsp/types/completion" "github.com/styrainc/regal/internal/lsp/types/symbols" ) @@ -129,6 +131,7 @@ type CompletionParams struct { TextDocument TextDocumentIdentifier `json:"textDocument"` Context CompletionContext `json:"context"` Position Position `json:"position"` + RegoVersion ast.RegoVersion `json:"regoVersion"` } type CompletionContext struct { diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index bc3868cf..64ca2e09 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -1,7 +1,7 @@ package metrics import ( - "github.com/open-policy-agent/opa/profiler" + "github.com/open-policy-agent/opa/v1/profiler" "github.com/styrainc/regal/pkg/report" ) diff --git a/internal/parse/parse.go b/internal/parse/parse.go index 88326b84..78de2e0d 100644 --- a/internal/parse/parse.go +++ b/internal/parse/parse.go @@ -7,7 +7,7 @@ import ( "github.com/anderseknert/roast/pkg/encoding" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" rio "github.com/styrainc/regal/internal/io" ) @@ -18,15 +18,108 @@ import ( func ParserOptions() ast.ParserOptions { return ast.ParserOptions{ ProcessAnnotation: true, + // If not provided, OPA's parser will call ast.CapabilitiesForCurrentVersion() + // on each Parse() call, which is a waste of resources as it builds the whole + // structure from scratch each time. That should probably be fixed in OPA, but + // we do this here for now. + Capabilities: rio.Capabilities(), } } +//nolint:gochecknoglobals +var ( + attemptVersionOrder = [2]ast.RegoVersion{ast.RegoV1, ast.RegoV0} +) + +// ModuleWithOpts parses a module with the given options. If the Rego version is unknown, the function +// may attempt to run several parser versions to determine the correct version. Setting the Rego version +// in the parser options will skip this step, and is recommended whenever possible. +func ModuleWithOpts(path, policy string, opts ast.ParserOptions) (*ast.Module, error) { + var ( + module *ast.Module + err error + ) + + if opts.RegoVersion == ast.RegoUndefined && strings.HasSuffix(path, "_v0.rego") { + opts.RegoVersion = ast.RegoV0 + } + + if opts.RegoVersion != ast.RegoUndefined { + module, err = ast.ParseModuleWithOpts(path, policy, opts) + if err != nil { + return nil, err //nolint:wrapcheck + } + } else { + // We are parsing for an unknown Rego version + module, err = ModuleUnknownVersionWithOpts(path, policy, opts) + if err != nil { + return nil, err + } + } + + return module, nil +} + +// ModuleUnknownVersionWithOpts attempts to parse a module with an unknown Rego version. The function will +// attempt to parse the module with different parser versions, and determine the version of Rego based on +// which parser was successful. Note that this is not 100% accurate, and the conditions for determining the +// version may change over time. If the version is known beforehand, use ModuleWithOpts instead, and provide +// the target Rego version in the parser options. +func ModuleUnknownVersionWithOpts( + filename string, + policy string, + opts ast.ParserOptions, +) (*ast.Module, error) { + var ( + err error + mod *ast.Module + ) + + // Iterate over RegoV1 and RegoV0 in that order + // If `import rego.v1`` is present in module, RegoV0CompatV1 is used + for i := range attemptVersionOrder { + version := attemptVersionOrder[i] + + opts.RegoVersion = version + + mod, err = ast.ParseModuleWithOpts(filename, policy, opts) + if err == nil { + if hasRegoV1Import(mod.Imports) { + mod.SetRegoVersion(ast.RegoV0CompatV1) + + return mod, nil + } + + mod.SetRegoVersion(version) + + return mod, nil + } + } + + // TODO: We probably need to return the errors from each parse attempt ? + // as otherwise there could be very skewed error messages.. + + return nil, err //nolint:wrapcheck +} + +func hasRegoV1Import(imports []*ast.Import) bool { + for _, imp := range imports { + if path, ok := imp.Path.Value.(ast.Ref); ok && path.Equal(ast.RegoV1CompatibleRef) { + return true + } + } + + return false +} + // MustParseModule works like ast.MustParseModule but with the Regal parser options applied. func MustParseModule(policy string) *ast.Module { return ast.MustParseModuleWithOpts(policy, ParserOptions()) } // Module works like ast.ParseModule but with the Regal parser options applied. +// Note that this function will parse using the RegoV1 parser version. If the version of +// the policy is unknown, use ModuleUnknownVersionWithOpts instead. func Module(filename, policy string) (*ast.Module, error) { mod, err := ast.ParseModuleWithOpts(filename, policy, ParserOptions()) if err != nil { @@ -48,9 +141,10 @@ func PrepareAST(name string, content string, module *ast.Module) (map[string]any preparedAST["regal"] = map[string]any{ "file": map[string]any{ - "name": name, - "lines": strings.Split(strings.ReplaceAll(content, "\r\n", "\n"), "\n"), - "abs": abs, + "name": name, + "lines": strings.Split(strings.ReplaceAll(content, "\r\n", "\n"), "\n"), + "abs": abs, + "rego_version": module.RegoVersion().String(), }, "environment": map[string]any{ "path_separator": rio.PathSeparator, diff --git a/internal/parse/parse_test.go b/internal/parse/parse_test.go index ba20f2c7..4bdae69f 100644 --- a/internal/parse/parse_test.go +++ b/internal/parse/parse_test.go @@ -1,8 +1,11 @@ package parse import ( + "strings" "testing" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/styrainc/regal/internal/testutil" ) @@ -15,3 +18,70 @@ func TestParseModule(t *testing.T) { t.Errorf("expected %q, got %q", exp, got) } } + +func TestModuleUnknownVersionWithOpts(t *testing.T) { + t.Parallel() + + cases := []struct { + note string + policy string + exp ast.RegoVersion + expErr string + }{ + { + note: "v1", + policy: `package p + + allow if true`, + exp: ast.RegoV1, + }, + { + note: "v1 compatible", + policy: `package p + + import rego.v1 + + allow if true`, + exp: ast.RegoV0CompatV1, + }, + { + note: "v0", + policy: `package p + + deny["foo"] { + true + }`, + exp: ast.RegoV0, + }, + { + note: "unknown / parse error", + policy: `pecakge p`, + expErr: "var cannot be used for rule name", + }, + } + + for _, tc := range cases { + t.Run(tc.note, func(t *testing.T) { + t.Parallel() + + parsed, err := ModuleUnknownVersionWithOpts("p.rego", tc.policy, ParserOptions()) + if err != nil { + if tc.expErr == "" { + t.Fatalf("unexpected error: %v", err) + } else { + if exp, got := tc.expErr, err.Error(); !strings.Contains(got, exp) { + t.Errorf("expected %q, got %q", exp, got) + } + } + } + + if parsed == nil && tc.expErr == "" { + t.Fatal("expected parsed module") + } + + if tc.expErr == "" && parsed.RegoVersion() != tc.exp { + t.Errorf("expected version %d, got %d", tc.exp, parsed.RegoVersion()) + } + }) + } +} diff --git a/internal/test/test.go b/internal/test/test.go index 71100dcc..73a85cda 100644 --- a/internal/test/test.go +++ b/internal/test/test.go @@ -1,7 +1,7 @@ package test import ( - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/parse" "github.com/styrainc/regal/pkg/rules" diff --git a/internal/update/update.go b/internal/update/update.go index 4baae03a..e7c9a4e5 100644 --- a/internal/update/update.go +++ b/internal/update/update.go @@ -14,8 +14,8 @@ import ( "github.com/anderseknert/roast/pkg/encoding" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/rego" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/rego" _ "embed" ) diff --git a/internal/update/update.rego b/internal/update/update.rego index fecb4669..0d1a7a38 100644 --- a/internal/update/update.rego +++ b/internal/update/update.rego @@ -2,8 +2,6 @@ # description: utility module to help determine if an update of Regal should be recommended package update -import rego.v1 - default needs_update := false # METADATA diff --git a/internal/util/concurrent/map.go b/internal/util/concurrent/map.go index c4bcf396..f0f8bf71 100644 --- a/internal/util/concurrent/map.go +++ b/internal/util/concurrent/map.go @@ -86,6 +86,10 @@ func (cm *Map[K, V]) Values() []V { } func (cm *Map[K, V]) Len() int { + if cm == nil { + return 0 + } + cm.murw.RLock() l := len(cm.m) diff --git a/internal/util/util.go b/internal/util/util.go index 6e278924..12daac58 100644 --- a/internal/util/util.go +++ b/internal/util/util.go @@ -57,6 +57,13 @@ func SearchMap(object map[string]any, path []string) (any, error) { return current, nil } +// Must0 an error (as commonly returned by Go functions) and panics if the error is not nil. +func Must0(err error) { + if err != nil { + panic(err) + } +} + // Must takes a value and an error (as commonly returned by Go functions) and panics if the error is not nil. func Must[T any](v T, err error) T { if err != nil { diff --git a/pkg/builtins/builtins.go b/pkg/builtins/builtins.go index 2c4067df..5104a31e 100644 --- a/pkg/builtins/builtins.go +++ b/pkg/builtins/builtins.go @@ -3,14 +3,15 @@ package builtins import ( "errors" + "strings" "github.com/anderseknert/roast/pkg/encoding" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/rego" - "github.com/open-policy-agent/opa/tester" - "github.com/open-policy-agent/opa/topdown/builtins" - "github.com/open-policy-agent/opa/types" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/rego" + "github.com/open-policy-agent/opa/v1/tester" + "github.com/open-policy-agent/opa/v1/topdown/builtins" + "github.com/open-policy-agent/opa/v1/types" "github.com/styrainc/regal/internal/parse" ) @@ -41,22 +42,33 @@ var RegalLastMeta = ®o.Function{ // RegalParseModule regal.parse_module, like rego.parse_module but with location data included in AST. func RegalParseModule(_ rego.BuiltinContext, filename *ast.Term, policy *ast.Term) (*ast.Term, error) { - filenameStr, err := builtins.StringOperand(filename.Value, 1) + filenameValue, err := builtins.StringOperand(filename.Value, 1) if err != nil { return nil, err } - policyStr, err := builtins.StringOperand(policy.Value, 2) + policyValue, err := builtins.StringOperand(policy.Value, 2) if err != nil { return nil, err } - module, err := ast.ParseModuleWithOpts(string(filenameStr), string(policyStr), parse.ParserOptions()) + filenameStr := string(filenameValue) + policyStr := string(policyValue) + + opts := parse.ParserOptions() + + // Allow testing Rego v0 modules. We could provide a separate builtin for this, + // but the need for this will likely diminish over time, so let's start simple. + if strings.HasSuffix(filenameStr, "_v0.rego") { + opts.RegoVersion = ast.RegoV0 + } + + module, err := ast.ParseModuleWithOpts(filenameStr, policyStr, opts) if err != nil { return nil, err } - enhancedAST, err := parse.PrepareAST(string(filenameStr), string(policyStr), module) + enhancedAST, err := parse.PrepareAST(filenameStr, policyStr, module) if err != nil { return nil, err } diff --git a/pkg/config/bundle.go b/pkg/config/bundle.go index 2546aede..7665a2f0 100644 --- a/pkg/config/bundle.go +++ b/pkg/config/bundle.go @@ -7,7 +7,7 @@ import ( "dario.cat/mergo" - "github.com/open-policy-agent/opa/bundle" + "github.com/open-policy-agent/opa/v1/bundle" "github.com/styrainc/regal/internal/util" ) diff --git a/pkg/config/config.go b/pkg/config/config.go index ffa880c5..46657239 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -12,7 +12,8 @@ import ( "github.com/anderseknert/roast/pkg/encoding" "gopkg.in/yaml.v3" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/bundle" "github.com/styrainc/regal/internal/capabilities" rio "github.com/styrainc/regal/internal/io" @@ -38,8 +39,18 @@ type Config struct { Ignore Ignore `json:"ignore,omitempty" yaml:"ignore,omitempty"` } +type Root struct { + Path string + // Note that contrary to ast.RegoVersion, we'll only accept 0 or 1 here currently. + // This aligns with the Rego versioning scheme used in .manifest files, which is + // the alternative way to provide this for a specific directory. + RegoVersion *int `json:"rego-version,omitempty" yaml:"rego-version,omitempty"` +} + type Project struct { - Roots []string `json:"roots" yaml:"roots"` + Roots *[]Root `json:"roots,omitempty" yaml:"roots,omitempty"` + // Set the Rego version for the whole project or workspace. Individual roots may override this. + RegoVersion *int `json:"rego-version,omitempty" yaml:"rego-version,omitempty"` } type Category map[string]Rule @@ -250,8 +261,10 @@ func rootsFromRegalDirectory(regalDir *os.File) ([]string, error) { return nil, fmt.Errorf("failed to unmarshal config file: %w", err) } - if conf.Project != nil { - foundBundleRoots = append(foundBundleRoots, util.Map(util.FilepathJoiner(parent), conf.Project.Roots)...) + if conf.Project != nil && conf.Project.Roots != nil { + for _, root := range *conf.Project.Roots { + foundBundleRoots = append(foundBundleRoots, filepath.Join(parent, root.Path)) + } } } @@ -291,6 +304,72 @@ func FromMap(confMap map[string]any) (Config, error) { return conf, nil } +// AllRegoVersions returns a map of all Rego versions found in the provided config and .manifest files, +// keyed by the path of the directory for which the version applies. Config file has higher precedence +// than .manifest files. +func AllRegoVersions(root string, conf *Config) (map[string]ast.RegoVersion, error) { + versionsMap := make(map[string]ast.RegoVersion) + + manifestLocations, err := rio.FindManifestLocations(root) + if err != nil { + return nil, fmt.Errorf("failed to find manifest locations: %w", err) + } + + for _, dir := range manifestLocations { + manifestPath := filepath.Join(root, dir, ".manifest") + + f, err := os.ReadFile(manifestPath) + if err != nil { + return nil, fmt.Errorf("failed to read manifest file: %w", err) + } + + var manifest bundle.Manifest + + err = encoding.JSON().Unmarshal(f, &manifest) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal manifest file: %w", err) + } + + if manifest.RegoVersion != nil { + versionsMap[dir] = regoVersionFromConfigValue(manifest.RegoVersion) + } + } + + if conf.Project != nil { + if conf.Project.RegoVersion != nil { + // empty string is used to denote the project root + // and all other paths are relative to that + versionsMap[""] = regoVersionFromConfigValue(conf.Project.RegoVersion) + } + + if conf.Project.Roots != nil { + for _, root := range *conf.Project.Roots { + if root.RegoVersion != nil { + versionsMap[root.Path] = regoVersionFromConfigValue(root.RegoVersion) + } + } + } + } + + return versionsMap, nil +} + +// Translate integer value 0 or 1 as found in config or .manifest to ast.RegoVersion. +func regoVersionFromConfigValue(version *int) ast.RegoVersion { + if version == nil { + return ast.RegoUndefined + } + + switch *version { + case 0: + return ast.RegoV0 + case 1: + return ast.RegoV1 + default: + return ast.RegoUndefined + } +} + func (config Config) MarshalYAML() (any, error) { var unstructuredConfig map[string]any @@ -361,6 +440,28 @@ type marshallingIntermediary struct { } `yaml:"features"` } +func (p *Project) UnmarshalYAML(value *yaml.Node) error { + var result map[string]any + + if err := value.Decode(&result); err != nil { + return fmt.Errorf("unmarshalling project failed %w", err) + } + + if result["roots"] != nil { + // A project root can either be provided as a string or an object. If it's a string, we'll + // convert it to an object with the path as the only value. + if roots, ok := result["roots"].([]any); ok { + for key, val := range roots { + if root, ok := val.(string); ok { + roots[key] = Root{Path: root} + } + } + } + } + + return encoding.JSONRoundTrip(result, p) //nolint:wrapcheck +} + func (config *Config) UnmarshalYAML(value *yaml.Node) error { var result marshallingIntermediary @@ -451,7 +552,7 @@ func (config *Config) UnmarshalYAML(value *yaml.Node) error { return fmt.Errorf("failed to load capabilities: %w", err) } - config.Capabilities = fromOPACapabilities(*opaCaps) + config.Capabilities = fromOPACapabilities(opaCaps) // This is used in the LSP to load the OPA capabilities, since the // capabilities version in the user-facing config does not contain all @@ -556,7 +657,7 @@ func extractDefaults(c *Config, result *marshallingIntermediary) error { // CapabilitiesForThisVersion returns the capabilities for the current OPA version Regal depends on. func CapabilitiesForThisVersion() *Capabilities { - return fromOPACapabilities(*ast.CapabilitiesForThisVersion()) + return fromOPACapabilities(rio.OPACapabilities) } func fromOPABuiltin(builtin ast.Builtin) *Builtin { @@ -577,7 +678,7 @@ func fromOPABuiltin(builtin ast.Builtin) *Builtin { return rb } -func fromOPACapabilities(capabilities ast.Capabilities) *Capabilities { +func fromOPACapabilities(capabilities *ast.Capabilities) *Capabilities { var result Capabilities result.Builtins = make(map[string]*Builtin) diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 20e775bb..0d4dc27a 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -1,6 +1,7 @@ package config import ( + "maps" "os" "path/filepath" "slices" @@ -8,8 +9,8 @@ import ( "gopkg.in/yaml.v3" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/util/test" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/util/test" rio "github.com/styrainc/regal/internal/io" "github.com/styrainc/regal/internal/testutil" @@ -424,3 +425,92 @@ capabilities: t.Errorf("expected error, got %v", err) } } + +func TestUnmarshalProjectRootsAsStringOrObject(t *testing.T) { + t.Parallel() + + bs := []byte(`project: + roots: + - foo/bar + - baz + - path: bar/baz + - path: v1 + rego-version: 1 +`) + + var conf Config + + if err := yaml.Unmarshal(bs, &conf); err != nil { + t.Fatal(err) + } + + version1 := 1 + + expRoots := []Root{ + {Path: "foo/bar"}, + {Path: "baz"}, + {Path: "bar/baz"}, + {Path: "v1", RegoVersion: &version1}, + } + + roots := *conf.Project.Roots + + if len(roots) != len(expRoots) { + t.Errorf("expected %d roots, got %d", len(expRoots), len(roots)) + } + + for i, expRoot := range expRoots { + if roots[i].Path != expRoot.Path { + t.Errorf("expected root path %v, got %v", expRoot.Path, roots[i].Path) + } + + if expRoot.RegoVersion != nil { + if roots[i].RegoVersion == nil { + t.Errorf("expected root %v to have a rego version", expRoot.Path) + } else if *roots[i].RegoVersion != *expRoot.RegoVersion { + t.Errorf( + "expected root %v rego version %v, got %v", + expRoot.Path, *expRoot.RegoVersion, *roots[i].RegoVersion, + ) + } + } + } +} + +func TestAllRegoVersions(t *testing.T) { + t.Parallel() + + bs := []byte(`project: + rego-version: 0 + roots: + - path: foo + rego-version: 1 +`) + + var conf Config + + if err := yaml.Unmarshal(bs, &conf); err != nil { + t.Fatal(err) + } + + fs := map[string]string{ + "bar/baz/.manifest": `{"rego_version": 1}`, + } + + test.WithTempFS(fs, func(root string) { + versions, err := AllRegoVersions(root, &conf) + if err != nil { + t.Fatal(err) + } + + expected := map[string]ast.RegoVersion{ + "": ast.RegoV0, + "foo": ast.RegoV1, + "bar/baz": ast.RegoV1, + } + + if !maps.Equal(versions, expected) { + t.Errorf("expected %v, got %v", expected, versions) + } + }) +} diff --git a/pkg/config/filter.go b/pkg/config/filter.go index 55d96dec..e8c9bbe2 100644 --- a/pkg/config/filter.go +++ b/pkg/config/filter.go @@ -9,7 +9,7 @@ import ( "github.com/gobwas/glob" - "github.com/open-policy-agent/opa/bundle" + "github.com/open-policy-agent/opa/v1/bundle" rio "github.com/styrainc/regal/internal/io" ) diff --git a/pkg/fixer/fileprovider/inmem.go b/pkg/fixer/fileprovider/inmem.go index 53cef4c1..babb3fd1 100644 --- a/pkg/fixer/fileprovider/inmem.go +++ b/pkg/fixer/fileprovider/inmem.go @@ -6,7 +6,7 @@ import ( rutil "github.com/anderseknert/roast/pkg/util" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/parse" "github.com/styrainc/regal/internal/util" @@ -123,22 +123,26 @@ func (p *InMemoryFileProvider) DeletedFiles() []string { return util.Keys(p.deletedFiles) } +// TODO: We need a way to specify the Rego version for the files here and avoid +// relying on the parser to infer those. func (p *InMemoryFileProvider) ToInput() (rules.Input, error) { + strContents := make(map[string]string) modules := make(map[string]*ast.Module) for filename, content := range p.files { var err error - modules[filename], err = parse.Module(filename, rutil.ByteSliceToString(content)) + strContents[filename] = rutil.ByteSliceToString(content) + + modules[filename], err = parse.ModuleWithOpts( + filename, + strContents[filename], + parse.ParserOptions(), + ) if err != nil { return rules.Input{}, fmt.Errorf("failed to parse module %s: %w", filename, err) } } - strContents := make(map[string]string) - for filename, content := range p.files { - strContents[filename] = rutil.ByteSliceToString(content) - } - return rules.NewInput(strContents, modules), nil } diff --git a/pkg/fixer/fixer.go b/pkg/fixer/fixer.go index 3f9c29ce..5824f0a3 100644 --- a/pkg/fixer/fixer.go +++ b/pkg/fixer/fixer.go @@ -8,7 +8,7 @@ import ( "path/filepath" "slices" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/util" "github.com/styrainc/regal/pkg/fixer/fileprovider" diff --git a/pkg/fixer/fixer_test.go b/pkg/fixer/fixer_test.go index 83de0651..bd9f1681 100644 --- a/pkg/fixer/fixer_test.go +++ b/pkg/fixer/fixer_test.go @@ -6,9 +6,10 @@ import ( "slices" "testing" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/format" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/format" + "github.com/styrainc/regal/pkg/config" "github.com/styrainc/regal/pkg/fixer/fileprovider" "github.com/styrainc/regal/pkg/fixer/fixes" "github.com/styrainc/regal/pkg/linter" @@ -20,10 +21,9 @@ func TestFixer(t *testing.T) { policies := map[string][]byte{ "test/main.rego": []byte(`package test -allow { +allow if { true #no space } - deny = true `), } @@ -48,14 +48,12 @@ deny = true } expectedFileFixedViolations := map[string][]string{ - // use-assignment-operator is not expected since use-rego-v1 also addresses this in this example - "test/main.rego": {"no-whitespace-comment", "use-rego-v1"}, + // use-assigment-operator is correct in formatting so does not appear. + "test/main.rego": {"no-whitespace-comment", "opa-fmt"}, } expectedFileContents := map[string][]byte{ "test/main.rego": []byte(`package test -import rego.v1 - allow := true # no space @@ -65,7 +63,7 @@ deny := true } if got, exp := fixReport.TotalFixes(), uint(2); got != exp { - t.Fatalf("expected %d fixed files, got %d", exp, got) + t.Fatalf("expected a total of %d fixes, got %d", exp, got) } fpFiles, err := memfp.List() @@ -95,19 +93,21 @@ deny := true // check that the fixed violations are correct fxs := fixReport.FixesForFile(file) + var fixes []string + for _, fx := range fxs { + fixes = append(fixes, fx.Title) + } + expectedFixes, ok := expectedFileFixedViolations[file] if !ok { - t.Fatalf("unexpected file waas fixed %s", file) + t.Fatalf("unexpected file was fixed %s", file) } - if len(fxs) != len(expectedFixes) { - t.Fatalf("unexpected number of fixes for %s:\ngot: %v\nexpected: %v", file, fxs, expectedFixes) - } + slices.Sort(expectedFixes) + slices.Sort(fixes) - for _, fx := range fxs { - if !slices.Contains(expectedFixes, fx.Title) { - t.Fatalf("expected fixes to contain %s:\ngot: %v", fx.Title, expectedFixes) - } + if !slices.Equal(expectedFixes, fixes) { + t.Fatalf("unexpected fixes for %s:\ngot: %v\nexpected: %v", file, fixes, expectedFixes) } } } @@ -135,7 +135,12 @@ deny = true l := linter.NewLinter(). WithEnableAll(true). - WithInputModules(&input) + WithInputModules(&input). + WithUserConfig(config.Config{ + Capabilities: &config.Capabilities{ + Features: []string{"rego_v1_import"}, + }, + }) f := NewFixer() // No fixes are registered here, we are only testing the functionality of @@ -173,7 +178,7 @@ deny := true } if got, exp := fixReport.TotalFixes(), uint(1); got != exp { - t.Fatalf("expected %d fixed files, got %d", exp, got) + t.Fatalf("expected %d fixes, got %d", exp, got) } fpFiles, err := memfp.List() @@ -200,22 +205,24 @@ deny := true string(expectedContent)) } - // check that the fixed violations are correct fxs := fixReport.FixesForFile(file) + // check that the fixed violations are correct + var fixes []string + for _, fx := range fxs { + fixes = append(fixes, fx.Title) + } + expectedFixes, ok := expectedFileFixedViolations[file] if !ok { - t.Fatalf("unexpected file waas fixed %s", file) + t.Fatalf("unexpected file was fixed %s", file) } - if len(fxs) != len(expectedFixes) { - t.Fatalf("unexpected number of fixes for %s:\ngot: %v\nexpected: %v", file, fxs, expectedFixes) - } + slices.Sort(expectedFixes) + slices.Sort(fixes) - for _, fx := range fxs { - if !slices.Contains(expectedFixes, fx.Title) { - t.Fatalf("expected fixes to contain %s:\ngot: %v", fx.Title, expectedFixes) - } + if !slices.Equal(expectedFixes, fixes) { + t.Fatalf("unexpected fixes for %s:\ngot: %v\nexpected: %v", file, fixes, expectedFixes) } } } diff --git a/pkg/fixer/fixes/directorypackagemismatch.go b/pkg/fixer/fixes/directorypackagemismatch.go index 016289ae..2d66c718 100644 --- a/pkg/fixer/fixes/directorypackagemismatch.go +++ b/pkg/fixer/fixes/directorypackagemismatch.go @@ -8,7 +8,7 @@ import ( "github.com/anderseknert/roast/pkg/util" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/pkg/config" ) diff --git a/pkg/fixer/fixes/fixes.go b/pkg/fixer/fixes/fixes.go index 1465dcf7..f09430a1 100644 --- a/pkg/fixer/fixes/fixes.go +++ b/pkg/fixer/fixes/fixes.go @@ -1,8 +1,7 @@ package fixes import ( - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/format" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/lsp/clients" "github.com/styrainc/regal/pkg/config" @@ -12,11 +11,11 @@ import ( // When a new fix is added, it should be added to this list. func NewDefaultFixes() []Fix { return []Fix{ + &Fmt{}, &Fmt{ + // this effectively maps the fix for violations from the + // use-rego-v1 rule to just format the file. NameOverride: "use-rego-v1", - OPAFmtOpts: format.Opts{ - RegoVersion: ast.RegoV0CompatV1, - }, }, &UseAssignmentOperator{}, &NoWhitespaceComment{}, @@ -28,12 +27,7 @@ func NewDefaultFixes() []Fix { // Notably, this does not include fixers that move files around. func NewDefaultFormatterFixes() []Fix { return []Fix{ - &Fmt{ - NameOverride: "use-rego-v1", - OPAFmtOpts: format.Opts{ - RegoVersion: ast.RegoV0CompatV1, - }, - }, + &Fmt{}, &UseAssignmentOperator{}, &NoWhitespaceComment{}, } @@ -60,8 +54,9 @@ type RuntimeOptions struct { // FixCandidate is the input to a Fix method and represents a file in need of fixing. type FixCandidate struct { - Filename string - Contents []byte + Filename string + Contents []byte + RegoVersion ast.RegoVersion } // Rename represents a file that has been moved (renamed). diff --git a/pkg/fixer/fixes/fmt.go b/pkg/fixer/fixes/fmt.go index 857270d0..199fd6cd 100644 --- a/pkg/fixer/fixes/fmt.go +++ b/pkg/fixer/fixes/fmt.go @@ -4,9 +4,11 @@ import ( "bytes" "errors" "fmt" - "path/filepath" - "github.com/open-policy-agent/opa/format" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/format" + + "github.com/styrainc/regal/internal/parse" ) type Fmt struct { @@ -37,7 +39,23 @@ func (f *Fmt) Fix(fc *FixCandidate, opts *RuntimeOptions) ([]FixResult, error) { return nil, errors.New("filename is required when formatting") } - formatted, err := format.SourceWithOpts(filepath.Base(fc.Filename), fc.Contents, f.OPAFmtOpts) + popts := parse.ParserOptions() + if fc.RegoVersion != ast.RegoUndefined { + popts.RegoVersion = fc.RegoVersion + } + + module, err := parse.ModuleWithOpts(fc.Filename, string(fc.Contents), popts) + if err != nil { + return nil, fmt.Errorf("failed to parse module: %w", err) + } + + f.OPAFmtOpts.RegoVersion = module.RegoVersion() + + if f.OPAFmtOpts.RegoVersion == ast.RegoV0 { + f.OPAFmtOpts.RegoVersion = ast.RegoV0CompatV1 + } + + formatted, err := format.AstWithOpts(module, f.OPAFmtOpts) if err != nil { return nil, fmt.Errorf("failed to format: %w", err) } diff --git a/pkg/fixer/fixes/fmt_test.go b/pkg/fixer/fixes/fmt_test.go index 11c227f7..0816342d 100644 --- a/pkg/fixer/fixes/fmt_test.go +++ b/pkg/fixer/fixes/fmt_test.go @@ -3,8 +3,8 @@ package fixes import ( "testing" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/format" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/format" ) func TestFmt(t *testing.T) { @@ -34,20 +34,100 @@ func TestFmt(t *testing.T) { fmt: &Fmt{}, fixExpected: true, }, - "rego v1": { - fc: &FixCandidate{Filename: "test.rego", Contents: []byte("package testutil\nallow := true")}, + "rego version unknown, ambigous syntax": { + fc: &FixCandidate{ + Filename: "test.rego", + Contents: []byte("package testutil\nallow := true"), + RegoVersion: ast.RegoUndefined, + }, + fmt: &Fmt{}, + fixExpected: true, + contentAfterFix: []byte(`package testutil + +allow := true +`), + }, + "rego version unknown, v0 syntax": { + fc: &FixCandidate{ + Filename: "test.rego", + Contents: []byte("package testutil\nallow[msg] { msg := 1}"), + RegoVersion: ast.RegoUndefined, + }, + fmt: &Fmt{}, + fixExpected: true, + contentAfterFix: []byte(`package testutil + +import rego.v1 + +allow contains msg if msg := 1 +`), + }, + "rego version unknown, v0v1 compat syntax": { + fc: &FixCandidate{ + Filename: "test.rego", + Contents: []byte(`package testutil +import rego.v1 +allow contains msg if msg :=1 + `), + RegoVersion: ast.RegoUndefined, + }, + fmt: &Fmt{}, + fixExpected: true, + contentAfterFix: []byte(`package testutil + +import rego.v1 + +allow contains msg if msg := 1 +`), + }, + "rego version unknown, v1 syntax": { + fc: &FixCandidate{ + Filename: "test.rego", + Contents: []byte(`package testutil + +allow contains msg if msg :=1 + `), + RegoVersion: ast.RegoUndefined, + }, + fmt: &Fmt{}, + fixExpected: true, + contentAfterFix: []byte(`package testutil + +allow contains msg if msg := 1 +`), + }, + "rego v1 (rego version 0)": { + fc: &FixCandidate{ + Filename: "test.rego", + Contents: []byte("package testutil\nallow := true"), + RegoVersion: ast.RegoV0, + }, + fmt: &Fmt{}, + fixExpected: true, contentAfterFix: []byte(`package testutil import rego.v1 allow := true `), + }, + "rego v1 (rego version > 1)": { + fc: &FixCandidate{Filename: "test.rego", Contents: []byte("package testutil\n\nallow := true\n")}, fmt: &Fmt{ OPAFmtOpts: format.Opts{ RegoVersion: ast.RegoV0CompatV1, }, }, - fixExpected: true, + fixExpected: false, + }, + "rego v1, version known": { + fc: &FixCandidate{Filename: "test.rego", Contents: []byte("package testutil\n\nallow := true\n")}, + fmt: &Fmt{ + OPAFmtOpts: format.Opts{ + RegoVersion: ast.RegoV1, + }, + }, + fixExpected: false, }, } diff --git a/pkg/fixer/fixes/nowhitespacecomment_test.go b/pkg/fixer/fixes/nowhitespacecomment_test.go index 71c457e1..0c8425ca 100644 --- a/pkg/fixer/fixes/nowhitespacecomment_test.go +++ b/pkg/fixer/fixes/nowhitespacecomment_test.go @@ -3,7 +3,7 @@ package fixes import ( "testing" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" ) func TestNoWhitespaceComment(t *testing.T) { diff --git a/pkg/fixer/fixes/useassignmentoperator_test.go b/pkg/fixer/fixes/useassignmentoperator_test.go index 9a6a124d..f84d5f0d 100644 --- a/pkg/fixer/fixes/useassignmentoperator_test.go +++ b/pkg/fixer/fixes/useassignmentoperator_test.go @@ -3,7 +3,7 @@ package fixes import ( "testing" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" ) func TestUseAssignmentOperator(t *testing.T) { diff --git a/pkg/linter/linter.go b/pkg/linter/linter.go index b4bbfa05..3be7cd3f 100644 --- a/pkg/linter/linter.go +++ b/pkg/linter/linter.go @@ -18,13 +18,13 @@ import ( "github.com/gobwas/glob" "gopkg.in/yaml.v3" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/bundle" - "github.com/open-policy-agent/opa/metrics" - "github.com/open-policy-agent/opa/profiler" - "github.com/open-policy-agent/opa/rego" - "github.com/open-policy-agent/opa/topdown" - "github.com/open-policy-agent/opa/topdown/print" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/bundle" + "github.com/open-policy-agent/opa/v1/metrics" + "github.com/open-policy-agent/opa/v1/profiler" + "github.com/open-policy-agent/opa/v1/rego" + "github.com/open-policy-agent/opa/v1/topdown" + "github.com/open-policy-agent/opa/v1/topdown/print" rbundle "github.com/styrainc/regal/bundle" rio "github.com/styrainc/regal/internal/io" @@ -290,7 +290,19 @@ func (l Linter) Lint(ctx context.Context) (report.Report, error) { l.stopTimer(regalmetrics.RegalFilterIgnoredFiles) l.startTimer(regalmetrics.RegalInputParse) - inputFromPaths, err := rules.InputFromPaths(filtered) + var versionsMap map[string]ast.RegoVersion + + // TODO: How should we deal with this in the language server? + // AllRegoVersions will call WalkDir on the root to find manifests, but that's obviously not + // going to work for a file:// path.. + if l.pathPrefix != "" && !strings.HasPrefix(l.pathPrefix, "file://") { + versionsMap, err = config.AllRegoVersions(l.pathPrefix, conf) + if err != nil && l.debugMode { + log.Printf("failed to get configured Rego versions: %v", err) + } + } + + inputFromPaths, err := rules.InputFromPaths(filtered, versionsMap) if err != nil { return report.Report{}, fmt.Errorf("errors encountered when reading files to lint: %w", err) } @@ -451,6 +463,7 @@ func (l Linter) DetermineEnabledRules(ctx context.Context) ([]string, error) { queryStr := `[rule | data.regal.rules[cat][rule] + object.get(data.regal.rules[cat][rule], "notices", set()) == set() data.regal.config.for_rule(cat, rule).level != "ignore" ]` diff --git a/pkg/linter/linter_test.go b/pkg/linter/linter_test.go index c8cf7f6d..0d0856e3 100644 --- a/pkg/linter/linter_test.go +++ b/pkg/linter/linter_test.go @@ -10,8 +10,8 @@ import ( "gopkg.in/yaml.v3" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/topdown" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/topdown" "github.com/styrainc/regal/internal/parse" "github.com/styrainc/regal/internal/test" @@ -26,8 +26,6 @@ func TestLintWithDefaultBundle(t *testing.T) { input := test.InputPolicy("p/p.rego", `package p -import rego.v1 - # TODO: fix this camelCase if { input.one == 1 @@ -47,7 +45,7 @@ camelCase if { t.Errorf("expected first violation to be 'todo-comments', got %s", result.Violations[0].Title) } - if result.Violations[0].Location.Row != 5 { + if result.Violations[0].Location.Row != 3 { t.Errorf("expected first violation to be on line 3, got %d", result.Violations[0].Location.Row) } @@ -63,7 +61,7 @@ camelCase if { t.Errorf("expected second violation to be 'prefer-snake-case', got %s", result.Violations[1].Title) } - if result.Violations[1].Location.Row != 6 { + if result.Violations[1].Location.Row != 4 { t.Errorf("expected second violation to be on line 4, got %d", result.Violations[1].Location.Row) } @@ -762,15 +760,50 @@ import data.unresolved`, } func BenchmarkRegalLintingItself(b *testing.B) { - linter := NewLinter().WithInputPaths([]string{"../../bundle"}).WithEnableAll(true) + linter := NewLinter(). + WithInputPaths([]string{"../../bundle"}). + WithEnableAll(true) + + b.ResetTimer() + b.ReportAllocs() + + var err error + + var rep report.Report + + for range b.N { + rep, err = linter.Lint(context.Background()) + if err != nil { + b.Fatal(err) + } + } + + if len(rep.Violations) != 0 { + _ = rep.Violations + } +} + +// BenchmarkRegalNoEnabledRules-10 4 283181990 ns/op 504195068 B/op 9537285 allocs/op. +func BenchmarkRegalNoEnabledRules(b *testing.B) { + linter := NewLinter(). + WithInputPaths([]string{"../../bundle"}). + WithDisableAll(true) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { - _, err := linter.Lint(context.Background()) + var err error + + var rep report.Report + + for range b.N { + rep, err = linter.Lint(context.Background()) if err != nil { b.Fatal(err) } } + + if len(rep.Violations) != 0 { + _ = rep.Violations + } } diff --git a/pkg/linter/testdata/custom.rego b/pkg/linter/testdata/custom.rego index 523b8211..93254f24 100644 --- a/pkg/linter/testdata/custom.rego +++ b/pkg/linter/testdata/custom.rego @@ -5,8 +5,6 @@ # ref: https://www.acmecorp.example.org/docs/regal/package package custom.regal.rules.naming["acme-corp-package"] -import rego.v1 - import data.regal.result report contains violation if { diff --git a/pkg/linter/testdata/printer.rego b/pkg/linter/testdata/printer.rego index 90138d59..5b5a78f9 100644 --- a/pkg/linter/testdata/printer.rego +++ b/pkg/linter/testdata/printer.rego @@ -5,8 +5,6 @@ # ref: https://www.acmecorp.example.org/docs/regal/package package custom.regal.rules.utils["printer"] -import rego.v1 - report contains "never happens" if { print(input.regal.file.name) diff --git a/pkg/report/report.go b/pkg/report/report.go index d4ff0b9d..14e65ec7 100644 --- a/pkg/report/report.go +++ b/pkg/report/report.go @@ -162,7 +162,7 @@ func (r *Report) AggregateProfileToSortedProfile(numResults int) { } // ViolationsFileCount returns the number of files containing violations. -func (r Report) ViolationsFileCount() map[string]int { +func (r *Report) ViolationsFileCount() map[string]int { fc := map[string]int{} for _, violation := range r.Violations { fc[violation.Location.File]++ diff --git a/pkg/rules/fmt.go b/pkg/rules/fmt.go index ab40db02..0a6e61ee 100644 --- a/pkg/rules/fmt.go +++ b/pkg/rules/fmt.go @@ -7,7 +7,8 @@ import ( "github.com/anderseknert/roast/pkg/util" - "github.com/open-policy-agent/opa/format" + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/format" "github.com/styrainc/regal/internal/docs" "github.com/styrainc/regal/pkg/config" @@ -46,8 +47,10 @@ func (f *OpaFmtRule) Run(ctx context.Context, input Input) (*report.Report, erro default: module := input.Modules[filename] unformatted := util.StringToByteSlice(input.FileContent[filename]) + opts := format.Opts{RegoVersion: ast.RegoUndefined} + opts.RegoVersion = module.RegoVersion() - formatted, err := format.Ast(module) + formatted, err := format.AstWithOpts(module, opts) if err != nil { return nil, fmt.Errorf("failed to format module %s: %w", filename, err) } diff --git a/pkg/rules/rules.go b/pkg/rules/rules.go index 78327870..cb19a39b 100644 --- a/pkg/rules/rules.go +++ b/pkg/rules/rules.go @@ -5,13 +5,15 @@ import ( "fmt" "io" "os" + "path/filepath" + "slices" "sort" + "strings" "sync" rutil "github.com/anderseknert/roast/pkg/util" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/loader" + "github.com/open-policy-agent/opa/v1/ast" "github.com/styrainc/regal/internal/parse" "github.com/styrainc/regal/internal/util" @@ -45,6 +47,12 @@ type Rule interface { Config() config.Rule } +type regoFile struct { + name string + parsed *ast.Module + raw []byte +} + // NewInput creates a new Input from a set of modules. func NewInput(fileContent map[string]string, modules map[string]*ast.Module) Input { // Maintain order across runs @@ -60,8 +68,10 @@ func NewInput(fileContent map[string]string, modules map[string]*ast.Module) Inp // InputFromPaths creates a new Input from a set of file or directory paths. Note that this function assumes that the // paths point to valid Rego files. Use config.FilterIgnoredPaths to filter out unwanted content *before* calling this -// function. -func InputFromPaths(paths []string) (Input, error) { +// function. When the versionsMap is not nil/empty, files in a directory matching a key in the map will be parsed with +// the corresponding Rego version. If not provided, the file may be parsed multiple times in order to determine the +// version (best-effort and may include false positives). +func InputFromPaths(paths []string, versionsMap map[string]ast.RegoVersion) (Input, error) { if len(paths) == 1 && paths[0] == "-" { return inputFromStdin() } @@ -69,6 +79,15 @@ func InputFromPaths(paths []string) (Input, error) { fileContent := make(map[string]string, len(paths)) modules := make(map[string]*ast.Module, len(paths)) + var versionedDirs []string + + if len(versionsMap) > 0 { + versionedDirs = util.Keys(versionsMap) + // Sort directories by length, so that the most specific path is found first + slices.Sort(versionedDirs) + slices.Reverse(versionedDirs) + } + var mu sync.Mutex var wg sync.WaitGroup @@ -77,11 +96,32 @@ func InputFromPaths(paths []string) (Input, error) { errors := make([]error, 0, len(paths)) + parserOptions := parse.ParserOptions() + for _, path := range paths { go func(path string) { defer wg.Done() - result, err := loader.RegoWithOpts(path, parse.ParserOptions()) + parserOptions.RegoVersion = ast.RegoUndefined + + // Check if the path matches any directory where a specific Rego version is set, + // and if so use that instead of having to parse the file (potentially multiple times) + // in order to determine the Rego version. + // If a project-wide version has been set, it'll be found under the path "", which will + // always be the last entry in versionedDirs, and only match if no specific directory + // matches. + if len(versionsMap) > 0 { + dir := filepath.Dir(path) + for _, versionedDir := range versionedDirs { + if strings.HasPrefix(dir, versionedDir) { + parserOptions.RegoVersion = versionsMap[versionedDir] + + break + } + } + } + + result, err := regoWithOpts(path, parserOptions) mu.Lock() defer mu.Unlock() @@ -92,8 +132,8 @@ func InputFromPaths(paths []string) (Input, error) { return } - fileContent[result.Name] = rutil.ByteSliceToString(result.Raw) - modules[result.Name] = result.Parsed + fileContent[result.name] = rutil.ByteSliceToString(result.raw) + modules[result.name] = result.parsed }(path) } @@ -106,6 +146,31 @@ func InputFromPaths(paths []string) (Input, error) { return NewInput(fileContent, modules), nil } +func regoWithOpts(path string, opts ast.ParserOptions) (*regoFile, error) { + path = filepath.Clean(path) + + bs, err := os.ReadFile(path) + if err != nil { + return nil, err //nolint:wrapcheck + } + + regoFile := regoFile{ + name: path, + raw: bs, + } + + policy := rutil.ByteSliceToString(bs) + + mod, err := parse.ModuleWithOpts(path, policy, opts) + if err != nil { + return nil, err //nolint:wrapcheck + } + + regoFile.parsed = mod + + return ®oFile, nil +} + func inputFromStdin() (Input, error) { // Ideally, we'd just pass the reader to OPA, but as the parser materializes // the input immediately anyway, there's currently no benefit to doing so. @@ -114,14 +179,17 @@ func inputFromStdin() (Input, error) { return Input{}, fmt.Errorf("failed to read from reader: %w", err) } - policy := string(bs) + policy := rutil.ByteSliceToString(bs) - module, err := parse.Module("stdin", policy) + module, err := parse.ModuleUnknownVersionWithOpts("stdin", policy, parse.ParserOptions()) if err != nil { return Input{}, fmt.Errorf("failed to parse module from stdin: %w", err) } - return NewInput(map[string]string{"stdin": policy}, map[string]*ast.Module{"stdin": module}), nil + return Input{ + FileContent: map[string]string{"stdin": policy}, + Modules: map[string]*ast.Module{"stdin": module}, + }, nil } // InputFromText creates a new Input from raw Rego text. diff --git a/pkg/rules/rules_test.go b/pkg/rules/rules_test.go index f41c9c74..20604cf4 100644 --- a/pkg/rules/rules_test.go +++ b/pkg/rules/rules_test.go @@ -3,7 +3,7 @@ package rules import ( "testing" - "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/v1/ast" ) func TestInputFromTextWithOptions(t *testing.T) {