And update code to conform to the rule.
- Replace unnecessary fmt.Sprintf with string concatenation
- Replace fmt.Sprint with more efficient strconv.Itoa
- Replace static fmt.Errorf calls with more efficient errors.New
Thanks @srenatus for pushing me down this rabbit hole!
Signed-off-by: Anders Eknert <anders@styra.com>
All packages, except for `cmd` and `internal`, have been moved into a new `v1` root package.
Old packages are kept for backwards-compatibility reasons. All contained code is replaced with simple type aliases and proxy functions to `v1` implementations.
Old packages default to the Rego v0 syntax, new `v1` packages default to the Rego v1 syntax.
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
The previous version has been failing without any good reason for me,
so let's try this.
About the version pick: It's not the latest version (v1.62.0 at the
moment), because that would introduce a new revive rule,
redeclares-builtin-id, and that flags every variable called `min` or
`max` in the code base. I had started addressing these, but they were
just too many.
The new issues related to this version are mostly that it complains
whenever it finds a non-static string that makes its way into a printf-
like function. However, that's a common pattern in some place here, so
I've sprinkled some nolint:govet on it.
Signed-off-by: Stephan Renatus <stephan@styra.com>
Also making some updates to the repl implementation to properly deal with v1 as the default rego-version.
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
Also deprecating `ParserOptions.EffectiveRegoVersion()`, which will be removed in a future release.
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
In addition to those commands already supported:
* build
* check
* eval
* fmt
* test
support has been added to the following commands:
* `bench`
* `deps`
* `exec`
* `inspect`
* `parse`
* `run` (command `server` and `REPL`)
Fixes: #6520
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
* ast+cmd+rego: Adding `--rego-v1` flag to `opa eval`
Fixes: #6463
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
* Adding `--rego-v1` flag to `opa build`
Fixes: #6463
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
* Formatting PE support modules to comply with rego-v1 when required
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
* Removing rego.v1 import when formatting for rego-v1 (not rego-v0-compat-v1)
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
* touch up
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
* Fixing linting issues
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
* Consolidating `Bundle.FormatModules()` and `Bundle.FormatModulesForRegoVersion()`
Suggested by @ashutosh-narkar
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
* Adding descriptions to `RegoVersion`
Requested by @ashutosh-narkar
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
* Using `--v1-compatible` flag instead of `--rego-v1`
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
* Updating docs
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
* Reintroducing `ParserOptions.RegoV1Compatible` to avoid breaking change
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
* cmd & tester
Adding `--v1-compatible` flag to `opa test`
Fixes: #6463
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
* Adding `--v1-compatible` flag to `opa fmt`
Fixes: #6463
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
* Adding `--v1-compatible` flag to `opa check`
Fixes: #6463
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
* Making linter happy
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
* Review modifications suggested by @ashutosh-narkar
* Changing `ParserOptions.RegoV1Compatible` take precedence over `ParserOptions.RegoVersion`
* Fixing comment in test
* Updating `fmt --rego-v1` CLI description
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
* Review modifications suggested by @ashutosh-narkar
* Changing `ParserOptions.RegoV1Compatible` take precedence over `ParserOptions.RegoVersion`
* Fixing comment in test
* Updating `fmt --rego-v1` CLI description
* Adding back `Opts.RegoV1` and deprecating.
* Making `Opts.RegoV1` take precedence over `Opts.RegoVersion`
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
* Review modifications suggested by @ashutosh-narkar
* Changing `ParserOptions.RegoV1Compatible` take precedence over `ParserOptions.RegoVersion`
* Fixing comment in test
* Updating `fmt --rego-v1` CLI description
* Adding back `Opts.RegoV1` and deprecating.
* Making `Opts.RegoV1` take precedence over `Opts.RegoVersion`
* `TestPartialWitRegoV1` -> `TestPartialWithRegoV1`
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
* Review modifications suggested by @ashutosh-narkar
* Changing `ParserOptions.RegoV1Compatible` take precedence over `ParserOptions.RegoVersion`
* Fixing comment in test
* Updating `fmt --rego-v1` CLI description
* Adding back `Opts.RegoV1` and deprecating.
* Making `Opts.RegoV1` take precedence over `Opts.RegoVersion`
* `TestPartialWitRegoV1` -> `TestPartialWithRegoV1`
* removing `Println` in test
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
* Review modifications suggested by @ashutosh-narkar
* Changing `ParserOptions.RegoV1Compatible` take precedence over `ParserOptions.RegoVersion`
* Fixing comment in test
* Updating `fmt --rego-v1` CLI description
* Adding back `Opts.RegoV1` and deprecating.
* Making `Opts.RegoV1` take precedence over `Opts.RegoVersion`
* `TestPartialWitRegoV1` -> `TestPartialWithRegoV1`
* removing `Println` in test
* Updating docs with per-command behavioural descriptions for `--v1-compatible`.
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
---------
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
The `rego.v1` import requires the `if` keyword before
the rule body. We should make an exception for default
rules.
Signed-off-by: Ashutosh Narkar <anarkar4387@gmail.com>
This change renames the `future.compat` import to `rego.v1`.
The latter is clear that it's a declaration that
a module is compatible with a v1 version of OPA.
Signed-off-by: Ashutosh Narkar <anarkar4387@gmail.com>
Adding `future.compat` import for enforcing strict-mode checks and additional `1.0` behavior for the module.
Fixes: #6247
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
Prior to this commit, when the AST information
were serialized to JSON, rules expressed as
discussed in #5790 included only the location
of their value and not the one of the rule
ref var itself. Now the AST serialized to
JSON includes this information.
Fixes: #5790
Signed-off-by: Gianluca Oldani <oldanigianluca@gmail.com>
This fixes some nightly fuzzer findings.
Also:
* ast/compile_test: backfill some ref-cap test cases
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
This change allows rules to have string prefixes in their heads -- we've
come to call them "ref heads".
String prefixes means that where before, you had
package a.b.c
allow = true
you can now have
package a
b.c.allow = true
This allows for more concise policies, and different ways to structure
larger rule corpuses.
Backwards-compatibility:
- There are code paths that accept ast.Module structs that don't necessarily
come from the parser -- so we're backfilling the rule's Head.Reference
field from the Name when it's not present.
This is exposed through (Head).Ref() which always returns a Ref.
This also affects the `opa parse` "pretty" output:
With x.rego as
package x
import future.keywords
a.b.c.d if true
e[x] if true
we get
$ opa parse x rego
module
package
ref
data
"x"
import
ref
future
"keywords"
rule
head
ref
a
"b"
"c"
"d"
true
body
expr index=0
true
rule
head
ref
e
x
true
body
expr index=0
true
Note that
Name: e
Key: x
becomes
Reference: e[x]
in the output above (since that's how we're parsing it, back-compat edge cases aside)
- One special case for backcompat is `p[x] { ... }`:
rule | ref | key | value | name
------------------------+-------+-----+-------+-----
p[x] { ... } | p | x | nil | "p"
p contains x if { ... } | p | x | nil | "p"
p[x] if { ... } | p[x] | nil | true | ""
For interpreting a rule, we now have the following procedure:
1. if it has a Key, it's a multi-value rule; and its Ref defines the set:
Head{Key: x, Ref: p} ~> p is a set
^-- we'd get this from `p contains x if true`
or `p[x] { true }` (back compat)
2. if it has a Value, it's a single-value rule; its Ref may contain vars:
Head{Ref: p.q.r[s], Value: 12} ~> body determines s, `p.q.r.[s]` is 12
^-- we'd get this from `p.q.r[s] = 12 { s := "whatever" }`
Head{Key: x, Ref: p[x], Value: 3} ~> `p[x]` has value 3, `x` is determined
by the rule body
^-- we'd get this from `p[x] = 3 if x := 2`
or `p[x] = 3 { x := 2 }` (back compat)
Here, the Key isn't used, it's present for backwards compatibility: for ref-
less rule heads, `p[x] = 3` used to be a partial object: key x, value 3,
name "p"
- The destinction between complete rules and partial object rules disappears.
They're both single-value rules now.
- We're now outputting the refs of the rules completely in error messages, as
it's hard to make sense of "rule r" when there's rule r in package a.b.c and
rule b.c.r in package a.
Restrictions/next steps:
- Support for ref head rules in the REPL is pretty poor so far. Anything that
works does so rather accidentally. You should be able to work with policies
that contain ref heads, but you cannot interactively define them.
This is because before, we'd looked at REPL input like
p.foo.bar = true
and noticed that it cannot be a rule, so it's got to be a query. This is no
longer the case with ref heads.
- Currently vars in Refs are only allowed in the last position. This is expected
to change in the future.
- Also, for multi-value rules, we can not have a var at all -- so the following
isn't supported yet:
p.q.r[s] contains t if { ... }
-----
Most of the work happens when the RuleTree is derived from the ModuleTree -- in
the RuleTree, it doesn't matter if a rule was `p` in `package a.b.c` or `b.c.p`
in `package a`.
As such, the planner and wasm compiler hasn't seen that many adaptations:
- We're putting rules into the ruletree _including_ the var parts, so
p.q.a = 1
p.q.[x] = 2 { x := "b" }
end up in two different leaves:
p
`-> q
`-> a = 1
`-> [x] = 2`
- When planing a ref, we're checking if a rule tree node's children have
var keys, and plan "one level higher" accordingly:
Both sets of rules, p.q.a and p.q[x] will be planned into one function
(same as before); and accordingly return an object {"a": 1, "b": 2}
- When we don't have vars in the last ref part, we'll end up planning
the rules separately. This will have an effect on the IR.
p.q = 1
p.r = 2
Before, these would have been one function; now, it's two. As a result,
in Wasm, some "object insertion" conflicts can become "var assignment
conflicts", but that's in line with the now-new view of "multi-value"
and "single-value" rules, not partial {set/obj} vs complete.
* planner: only check ref.GroundPrefix() for optimizations
In a previous commit, we've only mapped
p.q.r[7]
as p.q.r; and as such, also need to lookup the ref
p.q.r[__local0__]
via p.q.r
(I think. Full disclosure: there might be edge cases here that are unaccounted
for, but right now, I'm aiming for making the existing tests green...)
New compiler stage:
In the compiler, we're having a new early rewriting step to ensure that the
RuleTree's keys are comparible. They're ast.Value, but some of them cause us
grief:
- ast.Object cannot be compared structurally; so
_, ok := map[ast.Value]bool{ast.NewObject([2]*ast.Term{ast.StringTerm("foo"), ast.StringTerm("bar")}): true}[ast.NewObject([2]*ast.Term{ast.StringTerm("foo"), ast.StringTerm("bar")})]
`ok` will never be true here.
- ast.Ref is a slice type, not hashable, so adding that to the RuleTree would
cause a runtime panic:
p[y.z] { y := input }
is now rewritten to
p[__local0__] { y := input; __local0__ := y.z }
This required moving the InitLocalVarGen stage up the chain, but as it's still
below ResolveRefs, we should be OK.
As a consequence, we've had to adapt `oracle` to cope with that rewriting:
1. The compiler rewrites rule head refs early because the rule tree expects
only simple vars, no refs, in rule head refs. So `p[x.y]` becomes
`p[local] { local = x.y }`
2. The oracle circles in on the node it's finding the definition for based
on source location, and the logic for doing that depends on unaltered
modules.
So here, (2.) is relaxed: the logic for building the lookup node stack can
now cope with generated statements that have been appended to the rule bodies.
There is a peculiarity about ref rules and extents:
See the added tests: having a ref rule implies that we get an empty object
in the full extent:
package p
foo.bar if false
makes the extent of data.p: {"foo": {}}
This is somewhat odd, but also follows from the behaviour we have right now
with empty modules:
package p.foo
bar if false
this also gives data.p the extent {"foo": {}}.
This could be worked around by recording, in the rule tree, when a node was
added because it's an intermediary with no values, but only children.
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
* ast.ParserOptions got a new field: SkipRules (bool).
It's used from ParseBody() (and some of its sibling functions with opts) to
instruct the parser to NOT attempt to parse the token stream as ast.Rule.
Using this, we gain more leeway in dealing with tricky ambiguous cases.
Previously, the queries
set(); {1}
and
set()
{1}
haven't been equivalent, because the latter ended up being parsed as a rule.
Now, we can follow the caller intent: if that input string was parsed with
ParseBody(), we'll return the two expressions, same as is the case when parsing
with the (disambiguating) semicolon. If we have not been given ParserOptions
with SkipRules: true -- i.e., the default behaviour -- then it will be just
like before.
Also adds a panic to NewExpr to ensure we never construct anything unexpected
using it.
* ast.ParseBodyWithOpts, will NOT change popts.SkipRules
* rego: skip rules for parsing query
This is underlying the code flow for
cat query | opa eval --stdin
and now does what you'd expect: treat the input as query, and parse it as such.
Previously, we'd been using the parser opts from the future imports helper, and
would have missed setting SkipRules.
This seems to be the only non-test caller of ParseBodyWithOpts (in OPA).
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
This package is deprecated, archived, and in maintenance mode, since Go
errors support wrapping natively.
For #2152.
Signed-off-by: Jason Hall <jason@chainguard.dev>
New functions:
* rego.metadata.chain(): returns the chain of metadata, starting from the active rule, going outward
* rego.metadata.rule(): returns the metadata for the active rule
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
This commit covers the compiler doing it's job on "every":
- resolve refs
- rewriting other declared vars in domain
- rewriting its declared vars and others in its body
- rewriting dynamics in the body
- expanding expressions
- safety body reordering and var checking
No evaluation happening yet. That's future work.
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
* ast: add 'every' future keyword, parser support, scaffolding
With this commit, "every x in xs { ... }" and "every k, v in { ... }"
will be parsed into a new struct, which is basically
Every {
Key, Value *Term
Domain *Term
Body Body
}
This includes the required to changes to visitors, comparisons, copy, ...
all the ceremony required to introduce a new keyword.
* format: format every statements
* ast: hide 'every' from capabilities for now
With this change,
- capabilities.json will NOT mention "every"
- "import future.keywords" will NOT get you "every"
- "import future.keywords.every" will complain about "every" being unknown
In tests, we're passing an unexported field in `ast.ParserOptions`,
which makes the parser treat "every" like it would eventually be
treated when unveiled.
The formatting tests are bluntly SKIPPED for now, to be re-enabled later.
---------------
NB: The work on "every" is ongoing.
Rewriting and evaluation follows. When it's documented, we'll unhide it.
---------------
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
This commit updates the capabilities structure to include the set of
supported future keywords and enhances the parser to accept the
capabilities structure so that callers can restrict what keywords can
be opted into in the first place. This ensures that callers can verify
that policies will parse for a particular version of OPA.
Signed-off-by: Torin Sandall <torinsandall@gmail.com>
There are four variants to this: with or without 'some', and with
only one or two lhs arguments:
a) x in xs
b) k, v in xs
c) some x in xs
d) some k, v in xs
(a) and (b) are handled in the parser, and end up in the AST as
calls to `internal.member_2` and `internal.member_3`:
a) internal.member_2(x, xs)
b) internal.member_4(k, v, xs)
The backing builtin functions iterate over their last arguments,
trying to find a match. If they do, they will return `true`.
In all other cases -- no match, or a type in the last argument that
can't be iterated over (not an array, object or set), it will
return `false`.
As such, they can be used with `not` without any restrictions.
(c) and (d) are rewritten in the compiler, where x', v', and k' are
fresh local vars:
c) x' = xs[_]
d) v' = xs[k']
Since `in` is a new keyword, it's enabled gradually: for now, a new
mechanism of future keyword imports is added. There are new option
arguments in the parser methods, and there's a hook in the parser
code updating its set of enabled future keywords whenever it
encounters an import statement like
import future.keywords.in # enables only "in"
import future.keywords # enables all future keywords
Functionally, these are identical right now: there is only one
future keyword, "in".
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
The specific combination where the first character is a tab, and the rest
are falling under `unicode.IsSpace()` would lead to strings.Repeat being
fed an empty count (to determine the position of the error pointer).
Displaying different "spaces" in a discernable way isn't solved here,
but I think it's also an edge case we can accept as-is.
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
golint is deprecated. The author of the code no longer supports the
codebase. golangci-lint is faster than golint, and is in use by other
opa repositories (e.g. Gatekeeper).
This commit changes tools.go to reference golangci (so it ends up in
vendor) and modifies check-lint to use golangci instead.
Breaking API Changes:
- plugins/rest/rest.go: Fix typo "AllowInsureTLS" -> "AllowInsecureTLS"
- storage/errors.go: Removed unused IndexingNotSupportedErr
Signed-off-by: Will Beason <willbeason@google.com>
Previously the parser would panic if the annotation was unattached
because no scope can be unattached currently.
Signed-off-by: Torin Sandall <torinsandall@gmail.com>
This field does not have to be exposed and since we may replace it
with a statement identifier (e.g., a globally unique rule ID) in the
future, it will be better not to expose it.
Signed-off-by: Torin Sandall <torinsandall@gmail.com>
This commit updates the parser and checker to support additional
annotation scopes:
- `document` for attaching metadata at the document-level which covers
all rules with the same name in the package.
- `package` for attaching metadata at the package-level which covers
all rules in the same package.
- `subpackages` which is the same `package` but also applies to all
subpackages (recursively).
This commit also makes the 'scope' field optional in the METADATA
block. If not specified, the scope will default to the attached node.
Signed-off-by: Torin Sandall <torinsandall@gmail.com>
This commit combines a bunch of refactoring on annotations to support
future work.
Specifically:
* Annotations are now normal AST nodes/statements. This means that
annotations store locations and also implement String() and
Compare(). Annotations are now correctly compared during module
comparison and annotations are included in the module string
representation (before annotations would be dropped when the module
String() function was called.) Also, the visitor and transformer
functions support annotations now.
* Annotations are no longer hidden behind an interface. Instead, there
is a single annotation struct that we can evolve over
time. It was unclear how the Annotations interface was going to work
in the long-term (e.g., callers would not be able to define their
own annotation types since the parser needs to be aware of them.)
With this change, Annotations are just structs now. We can extend
the struct as needed going forward. Custom data can be stored in a
dedicated field.
* Annotation parsing has been refactored. We now attach annotations to
the statement following the annotation. The parser will reject
METADATA blocks that contain whitespace between the METADATA hint
and the YAML block. Similarly, we no longer support trailing
unindented comments that follow the METADATA block. Users can inject
whitespace after the YAML block if they want to include trailing
comments.
* The opa parse subcommand now enables annotation processing.
Signed-off-by: Torin Sandall <torinsandall@gmail.com>
Also, there is new support for adding annotations on Rules to specify the schemas to be used specifically for type checking the expressions within the scope of that Rule. It helps address issues with schema overloading, and provides even more precise type error reports for a Rego developer.
Also, added support for annotation processing when loading via bundles.
Co-authored-by: @vazirim Mandana Vaziri mvaziri@us.ibm.com
Co-authored-by: @aavarghese Ansu Varghese avarghese@us.ibm.com
Co-authored-by: @tsandall Torin Sandall torinsandall@gmail.com
Signed-off-by: Mandana Vaziri <mvaziri@us.ibm.com>
This commit fixes a panic caught in the fuzzer due to misuse of
operands returned by expr.Operand().
Fixes#2714
Signed-off-by: Torin Sandall <torinsandall@gmail.com>
The safety check was corrupting object and set values that contained
comprehension as object keys or set elements because the comprehension
values themselves were mutated in place. This change fixes the issue
by copying object/set values like we do in other places.
This change also removes the setExprIndices function which was also
mutating values inside of a visitor.
Signed-off-by: Torin Sandall <torinsandall@gmail.com>
This post-processing code was used by old the PEG parser but since the
parser was rewritten by hand, we no longer need this.
Signed-off-by: Torin Sandall <torinsandall@gmail.com>
The parser was accepting rules that contained args and key terms in
the head. This was causing a panic during type checking because later
stages do expect this. This change just updates the parser to not emit
a rule in this case. Note, the parser was already dealing with this
correctly when the body was omitted.
Fixes#2662
Signed-off-by: Torin Sandall <torinsandall@gmail.com>
The location info on rules parsed from exprs was not ideal--it was
being set to the value of the rhs term (which is not accurate.)
This commit updates the parser helper function to reset the location
to the original expr location.
This commit also fixes an issue in the parser helper test case that
was introduced in 49a963f16a when we
used a tool to roundtrip the policy examples in the OPA codebase
to move away from the old datalog if-then syntax (":-").
Signed-off-by: Torin Sandall <torinsandall@gmail.com>
This commit replaces the existing PEG generated parser with a parser
implemented by hand. The new parser is more efficient (avoiding old
problems with pathological input cases like {{{{{{{{{}}}}}}}} and
deeply-nested composites in general) and offers better opportunities
for improved error reporting (which has been improved already but
there is still room to grow.)
During the test process of implementing the new parser, we identified
a few issues that were present in the old parser. Those issues are
fixed by this commit.
Fixes#1251Fixes#501Fixes#2198Fixes#2199Fixes#2200Fixes#2201Fixes#2202Fixes#2203
Co-authored-by: Torin Sandall <torinsandall@gmail.com>
Co-authored-by: Patrick East <east.patrick@gmail.com>
Signed-off-by: Torin Sandall <torinsandall@gmail.com>
Signed-off-by: Patrick East <east.patrick@gmail.com>
The documentation is pretty clear that a module must at least contain
a package, so it is safe to say that an empty file isn't valid.
Previously the helper would just return a nil module and nil error, it
will now return an error.
Fixes: #2054
Signed-off-by: Patrick East <east.patrick@gmail.com>
If the module contained a some statement the parser would panic. This
change fixes the parser to just return an error indicating the some
statement cannot be interpreted as a rule.
Signed-off-by: Torin Sandall <torinsandall@gmail.com>
Previously if the errors passed into the presentation Output were not
structured w/ JSON tags for marshaling the error would be an empty
string.
This changes to wrap the errors with a struct in cases where they
would otherwise not be formatted. We do this by forcing every error
into a structure and translating known error types into it.
Fixes: #1726Fixes: #1724
Signed-off-by: Patrick East <east.patrick@gmail.com>
The parser was accumulating comments in a parser-global slice. If the
parser backtracked, the comments were not thrown away. Because most
successful parses seem to backtrack, this meant that most ASTs contained
duplicated comments.
This change simply modifies the parser to accumulate the comments in a
set that just gets sorted at the end.
Fixes#426
Signed-off-by: Torin Sandall <torinsandall@gmail.com>
Fixes#1129 for the most part.
What still is wrongly put, but also harder to fix, is the case where
there's tabs INSIDE the line:
p = TAB true TAB { TAB as }
or a space before the tab, like
SPACE TAB p = true { as }
will still have a misaligned "^", as in that case, not all tabs are
fully expanded.
This merely trims leading tabs, and fixes the error maker location if
there's no other tabs used in the line.
However, that should fit common usage: Leading tabs is what `opa fmt`
proposes; and I'm doubtful of too many uses of tabs in other places
in Rego code.
Signed-off-by: Stephan Renatus <srenatus@chef.io>