37 Commits

Author SHA1 Message Date
Stephan Renatus dce01172d7 ast+rego+topdown: external rule source support (#8600)
External rule sources let wrapping projects inject rules at evaluation
time instead of compile time. The compiler marks external packages in
the rule tree but doesn't index them. When topdown hits an external
node, it calls Lookup to get rules, compiles them on the fly with a
scoped compiler, grafts the result into the tree, and caches it for the
duration of the evaluation.

Sources can be isolated (default, no access to surrounding policy) or
non-isolated (can reference static rules and other external sources).
The ExternalRuleIndexCloser interface handles cleanup after evaluation.
Precompiled rules can skip compiler stages via SkippedStages to avoid
redundant work.

This includes:
* hooks: add BundlePreActivate hook This one is handy when registering
external sources.

* topdown: catch `ir == nil` rule index result
This wouldn't ordinarily happen: the compiler is checking refs before.
But in our use case, the SP rules may be configured to be able to reach
into the surrounding Rego (non-isolated mode). If that happens, the IR
lookup may indeed end up as `nil, nil`.

Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
2026-05-05 09:48:50 +02:00
Johan Fylling 9b330379f7 ast,format,planner: Add not block syntax (#8562)
Expanding the Rego syntax to support not-bodies (not blocks?): `not {...}`

For a not block to successfully evaluate, its body must not successfully evaluate. If evaluation causes iteration, all evaluation paths must fail.

Fixes: #8402

Signed-off-by: Johan Fylling <johan.dev@fylling.se>
2026-04-24 16:35:39 +00:00
Johan Fylling fcb377212e chore: Remove unnecessary comment from bundle JWT verification impl (#8354)
The concern expressed in this comment has been determined to be unwarranted, so removing it to not cause future confusion.

Signed-off-by: Johan Fylling <johan.dev@fylling.se>
2026-02-21 15:24:11 +01:00
Stephan Renatus 0d7e509613 ci: bump golangci-lint (v2.9.0), fix issues
https://github.com/golangci/golangci-lint/releases/tag/v2.9.0

Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
2026-02-12 08:42:05 +01:00
Stephan Renatus b15601876e go: cleanup old build flags
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
2026-02-12 08:42:05 +01:00
Anders Eknert 372af639ea dev: Clean up bundle storage tests (#8267)
Not the best side quest I've been on, but for random reasons I wanted to
test which was covered here and I had one of those "people live like this?"
moments. I resisted the temptation of writing a custom DSL for testing, which
while it had made this a *fun* side quest also a rabbit hole. I do like the
cusom `unpack` function for tests though, and I think we should have that
spread to other tests!

Anyway, 2500+ lines of code less to maintain, any my LOC-based salary
increasingly looking like a bad deal.

Signed-off-by: Anders Eknert <anders.eknert@apple.com>
2026-02-01 20:25:10 +00:00
Anders Eknert 3e1af3bd6a perf: String() implementations using appenders (#8192)
Some work I did during the holidays as part of improving the performance
of interpolated strings. This change is however not isolated to those, but
updates the `String()` implementation of all AST node types (term values
and policy components). This change also lays the groundwork for migrating
OPA to the `json/v2` package once that's stable. The `json/v2` package
provides low-level functions for zero alloc marshalling via appenders — and
well, here they are. The appenders here should be usable for that purpose with
only a few tweaks needed for the few cases where our `String()` implementations
aren't also valid JSON.

Creating perfectly sized buffers requires knowing the expected length beforehand.
In order to do this, each component now implements not only `encoding.AppendText`
but a new custom `StringLengther` interface, which allows asking any AST node about
its `StringLength()` before `make`ing a buffer of that length.

We could definitely consider adding these to e.g. the `Value` or `Node` interfaces,
but I've left that out of this PR as it's an easy thing to do later should we want
to, and I guess there's always some concerns about changing public interfaces even
when they're not meant to be implemented by external code.

While no `Value` appenders allocate and almost none of the policy appenders do either,
one notable exception is `Module` when there are annotations present, as they are
a bit of a (YAML) special case. It's doable, but as serializing full modules isn't
on a hot path anywhere, I have chosen to defer that work to the future.

Signed-off-by: Anders Eknert <anders.eknert@apple.com>
2026-01-08 10:14:53 +01:00
Anders Eknert 5a0dc476be Template string performance improvements and more (#8143)
A mixed bag of improvements I have had around for a while, and would
like to see included in v1.12.0 if possible. I have about twice the
amount of changes **not** included here as they could use some more
testing. These changes should be low risk, I believe.. but obviously
do let me know if you see any potential risks that I don't!

- Add template string benchmarks
- Faster template strings / print eval by not passing bctx in recursion
- Allow passing nil value to `Query.WithQueryTracer` (no-op)
- Reduce allocations in rego v1 compiler stages
- Intern a few more common var name `Value`s
- Remove redundant switch on `scope` in annotations code
- Add a few more benchmarks in the `ast` package
- Performance improvements in type checker, most notably removing
  a function literal for checking expression, which only ever had
  one implementation. We can extend this later if needed.
- Prefer `NewGenericTransformer` over `&GenericTransformer` for
  easier tracking in pprof

Signed-off-by: Anders Eknert <anders.eknert@apple.com>
2025-12-18 11:04:18 +00:00
Anders Eknert 51a50ca042 Concurrent Rego parsing in bundle loader (#8067)
Parsing is generally fast, so this mainly improves performance
of creating big bundles with many Rego files in them. For Regal's
embedded bundle, loading it from memory would previously take 16
ms on my laptop, and now it takes 9 ms. There are other things
in this process that could be concurrent too, like JSON unmarshalling
of multiple data files. But starting with parsing modules.

This PR adds `errgroup` as a direct dependency (previously indirect)
as it is a nicer way to work with wait groups, and one that can be
useful elsewhere in the codebase (like in the compiler).

Also, and as usual, went off on a bit of a tangent refactoring code
related to the bundle build process, and made sure to use some common
helpers in code where available.

Signed-off-by: Anders Eknert <anders.eknert@apple.com>
2025-11-21 08:42:43 +01:00
Anders Eknert e03ac2f200 Bump golangci-lint, more gocritic linters (#8052)
- Bump golangci-lint -> 2.6.2
- Fix all `deprecatedComment` "notices should be in a dedicated paragraph, separated from the rest" reports
- Enable `appendCombine` and fix all "appendCombine: can combine chain of X appends into one" notices
- Enable `preferFprint` and fix the few reported issues
- Fix various issues reported only once or twice, like `zeroByteRepeat`

Signed-off-by: Anders Eknert <anders.eknert@apple.com>
2025-11-17 11:08:39 +01:00
Anders Eknert d3f34a3387 Modernize analyzer fixes (#7965)
Have done this some time in the past, but there was a few
new issues this would highlight now that we're on Go 1.24.

Mostly:
- Use `b.Loop()` in benchmarks
- Use `strings.SplitSeq` where possible
- Remove `omitempty` tag for types that can't be empty

Signed-off-by: Anders Eknert <anders@eknert.com>
2025-10-10 17:51:02 +02:00
Anders Eknert 48f76fd2aa Improve performance of storage operations (#7957)
And the default inmem storage implementation(s) in particular.

- Avoid creating expensive references for data which isn't in need of that, like strings or booleans.
- Avoid expensive roundtrips of data which doesn't need it, for the same reasons.
- Never roundtrip AST store items being written — unknown values will be roundtripped by `ast.InterfaceToValue` already
- Convert numbers to json.Number directly and without a roundtrip
- Avoid AST -> Go type conversion which is done for triggers... when no triggers have been registered
- Greatly reduce cost of not found lookups by using a static NotFound error that does not include the path — the path is already known by the caller so that information adds nothing they can't add themselves.
- Improve interning to make it easier to get interned `Value`'s without a *Term
- Use interned numbers when possible in `ast.InterfaceToValue`
- Much improved benchmarking framework for inmem storage, and many new benchmarks added.
- A few general improvements of error handling

**Benchstat**
```
goos: darwin
goarch: arm64
pkg: github.com/open-policy-agent/opa/v1/storage/inmem
cpu: Apple M4 Max
                                                             │    v1.9.0    │                 now                 │
                                                             │    sec/op    │   sec/op     vs base                │
NewTransaction/write-16                                         44.60n ± 1%   17.12n ± 1%  -61.61% (p=0.000 n=10)
NewTransaction/read-16                                          44.62n ± 0%   17.04n ± 0%  -61.80% (p=0.000 n=10)
ReadOne/Go-16                                                  126.95n ± 0%   98.93n ± 0%  -22.07% (p=0.000 n=10)
ReadOne/Go_(roundtrip)-16                                      127.65n ± 0%   99.04n ± 0%  -22.41% (p=0.000 n=10)
ReadOne/AST-16                                                  151.1n ± 0%   121.7n ± 0%  -19.40% (p=0.000 n=10)
ReadOneNested/Go-16                                             138.0n ± 0%   109.5n ± 0%  -20.69% (p=0.000 n=10)
ReadOneNested/Go_(roundtrip)-16                                 139.1n ± 0%   110.1n ± 1%  -20.85% (p=0.000 n=10)
ReadOneNested/AST-16                                            207.6n ± 1%   177.2n ± 0%  -14.64% (p=0.000 n=10)
ReadNotFound/Go-16                                             127.70n ± 0%   73.22n ± 1%  -42.67% (p=0.000 n=10)
ReadNotFound/Go_(roundtrip)-16                                 128.00n ± 0%   73.35n ± 1%  -42.70% (p=0.000 n=10)
ReadNotFound/AST-16                                            148.90n ± 0%   99.38n ± 0%  -33.26% (p=0.000 n=10)
WriteOneString/Go-16                                            240.1n ± 0%   184.5n ± 0%  -23.16% (p=0.000 n=10)
WriteOneString/Go_(roundtrip)-16                                655.2n ± 0%   185.3n ± 0%  -71.72% (p=0.000 n=10)
WriteOneString/AST-16                                           803.4n ± 0%   325.4n ± 0%  -59.49% (p=0.000 n=10)
WriteSameValue/Go-16                                           138.75n ± 1%   77.56n ± 2%  -44.10% (p=0.000 n=10)
WriteSameValue/Go_(roundtrip)-16                               557.95n ± 1%   77.86n ± 2%  -86.05% (p=0.000 n=10)
WriteSameValue/AST-16                                          615.65n ± 1%   79.25n ± 1%  -87.13% (p=0.000 n=10)
WriteIncrementingValueSamePath/Go-16                            6.312µ ± 0%   6.462µ ± 0%   +2.38% (p=0.000 n=10)
WriteIncrementingValueSamePath/Go_(roundtrip)-16               48.825µ ± 1%   7.860µ ± 0%  -83.90% (p=0.000 n=10)
WriteIncrementingValueSamePath/AST-16                          53.723µ ± 1%   8.718µ ± 1%  -83.77% (p=0.000 n=10)
WriteIncrementingValueSamePathInterned/Go-16                    6.351µ ± 1%   6.511µ ± 1%   +2.52% (p=0.000 n=10)
WriteIncrementingValueSamePathInterned/Go_(roundtrip)-16       49.804µ ± 1%   7.907µ ± 0%  -84.12% (p=0.000 n=10)
WriteIncrementingValueSamePathInterned/AST-16                  51.806µ ± 2%   6.663µ ± 1%  -87.14% (p=0.000 n=10)
PathAndValueInternedAndNoRoundtripRequired/Go-16                96.23µ ± 4%   43.83µ ± 4%  -54.45% (p=0.000 n=10)
PathAndValueInternedAndNoRoundtripRequired/Go_(roundtrip)-16   135.08µ ± 1%   43.01µ ± 3%  -68.16% (p=0.000 n=10)
PathAndValueInternedAndNoRoundtripRequired/AST-16              145.67µ ± 1%   43.19µ ± 3%  -70.35% (p=0.000 n=10)
WriteCollection/Go-16                                           136.8n ± 1%   137.0n ± 1%        ~ (p=0.643 n=10)
WriteCollection/Go_(roundtrip)-16                               1.304µ ± 0%   1.304µ ± 2%        ~ (p=0.629 n=10)
WriteCollection/AST-16                                         2034.0n ± 0%   772.5n ± 2%  -62.02% (p=0.000 n=10)
WriteAndCommit/Go-16                                            54.00µ ± 3%   47.63µ ± 1%  -11.80% (p=0.000 n=10)
WriteAndCommit/Go_(roundtrip)-16                                94.63µ ± 1%   47.19µ ± 3%  -50.13% (p=0.000 n=10)
WriteAndCommit/AST-16                                           239.6µ ± 1%   192.7µ ± 1%  -19.59% (p=0.000 n=10)
WriteAndCommitWithTriggers/Go-16                                54.08µ ± 1%   47.87µ ± 2%  -11.47% (p=0.000 n=10)
WriteAndCommitWithTriggers/Go_(roundtrip)-16                    94.75µ ± 1%   47.41µ ± 2%  -49.97% (p=0.000 n=10)
WriteAndCommitWithTriggers/AST-16                               247.2µ ± 0%   192.2µ ± 1%  -22.27% (p=0.000 n=10)

                                                             │      v1.9.0      │                    now                    │
                                                             │       B/op       │     B/op      vs base                     │
NewTransaction/write-16                                           144.00 ± 0%       48.00 ± 0%   -66.67% (p=0.000 n=10)
NewTransaction/read-16                                            144.00 ± 0%       48.00 ± 0%   -66.67% (p=0.000 n=10)
ReadOne/Go-16                                                     144.00 ± 0%       48.00 ± 0%   -66.67% (p=0.000 n=10)
ReadOne/Go_(roundtrip)-16                                         144.00 ± 0%       48.00 ± 0%   -66.67% (p=0.000 n=10)
ReadOne/AST-16                                                    160.00 ± 0%       64.00 ± 0%   -60.00% (p=0.000 n=10)
ReadOneNested/Go-16                                               144.00 ± 0%       48.00 ± 0%   -66.67% (p=0.000 n=10)
ReadOneNested/Go_(roundtrip)-16                                   144.00 ± 0%       48.00 ± 0%   -66.67% (p=0.000 n=10)
ReadOneNested/AST-16                                              192.00 ± 0%       96.00 ± 0%   -50.00% (p=0.000 n=10)
ReadNotFound/Go-16                                                 72.00 ± 0%        0.00 ± 0%  -100.00% (p=0.000 n=10)
ReadNotFound/Go_(roundtrip)-16                                     72.00 ± 0%        0.00 ± 0%  -100.00% (p=0.000 n=10)
ReadNotFound/AST-16                                                88.00 ± 0%       16.00 ± 0%   -81.82% (p=0.000 n=10)
WriteOneString/Go-16                                               368.0 ± 0%       240.0 ± 0%   -34.78% (p=0.000 n=10)
WriteOneString/Go_(roundtrip)-16                                  2818.0 ± 0%       240.0 ± 0%   -91.48% (p=0.000 n=10)
WriteOneString/AST-16                                             2938.0 ± 0%       360.0 ± 0%   -87.75% (p=0.000 n=10)
WriteSameValue/Go-16                                               128.0 ± 0%         0.0 ± 0%  -100.00% (p=0.000 n=10)
WriteSameValue/Go_(roundtrip)-16                                 2.518Ki ± 0%     0.000Ki ± 0%  -100.00% (p=0.000 n=10)
WriteSameValue/AST-16                                            2.572Ki ± 0%     0.000Ki ± 0%  -100.00% (p=0.000 n=10)
WriteIncrementingValueSamePath/Go-16                             12.50Ki ± 0%     12.50Ki ± 0%         ~ (p=1.000 n=10) ¹
WriteIncrementingValueSamePath/Go_(roundtrip)-16                251.73Ki ± 0%     14.06Ki ± 0%   -94.41% (p=0.000 n=10)
WriteIncrementingValueSamePath/AST-16                           255.63Ki ± 0%     13.28Ki ± 0%   -94.80% (p=0.000 n=10)
WriteIncrementingValueSamePathInterned/Go-16                     12.50Ki ± 0%     12.50Ki ± 0%         ~ (p=1.000 n=10) ¹
WriteIncrementingValueSamePathInterned/Go_(roundtrip)-16        251.73Ki ± 0%     14.06Ki ± 0%   -94.41% (p=0.000 n=10)
WriteIncrementingValueSamePathInterned/AST-16                  251.722Ki ± 0%     9.375Ki ± 0%   -96.28% (p=0.000 n=10)
PathAndValueInternedAndNoRoundtripRequired/Go-16                14.062Ki ± 0%     1.562Ki ± 0%   -88.89% (p=0.000 n=10)
PathAndValueInternedAndNoRoundtripRequired/Go_(roundtrip)-16   253.267Ki ± 0%     1.562Ki ± 0%   -99.38% (p=0.000 n=10)
PathAndValueInternedAndNoRoundtripRequired/AST-16              254.870Ki ± 0%     1.562Ki ± 0%   -99.39% (p=0.000 n=10)
WriteCollection/Go-16                                              128.0 ± 0%       128.0 ± 0%         ~ (p=1.000 n=10) ¹
WriteCollection/Go_(roundtrip)-16                                2.243Ki ± 0%     2.243Ki ± 0%         ~ (p=1.000 n=10) ¹
WriteCollection/AST-16                                           3.472Ki ± 0%     1.320Ki ± 0%   -61.97% (p=0.000 n=10)
WriteAndCommit/Go-16                                             29.58Ki ± 0%     11.08Ki ± 0%   -62.55% (p=0.000 n=10)
WriteAndCommit/Go_(roundtrip)-16                                268.80Ki ± 0%     11.08Ki ± 0%   -95.88% (p=0.000 n=10)
WriteAndCommit/AST-16                                           272.77Ki ± 0%     15.06Ki ± 0%   -94.48% (p=0.000 n=10)
WriteAndCommitWithTriggers/Go-16                                 29.58Ki ± 0%     15.83Ki ± 0%   -46.49% (p=0.000 n=10)
WriteAndCommitWithTriggers/Go_(roundtrip)-16                    268.80Ki ± 0%     15.83Ki ± 0%   -94.11% (p=0.000 n=10)
WriteAndCommitWithTriggers/AST-16                               279.09Ki ± 0%     26.12Ki ± 0%   -90.64% (p=0.000 n=10)

                                                             │    v1.9.0     │                   now                   │
                                                             │   allocs/op   │ allocs/op   vs base                     │
NewTransaction/write-16                                         3.000 ± 0%     1.000 ± 0%   -66.67% (p=0.000 n=10)
NewTransaction/read-16                                          3.000 ± 0%     1.000 ± 0%   -66.67% (p=0.000 n=10)
ReadOne/Go-16                                                   3.000 ± 0%     1.000 ± 0%   -66.67% (p=0.000 n=10)
ReadOne/Go_(roundtrip)-16                                       3.000 ± 0%     1.000 ± 0%   -66.67% (p=0.000 n=10)
ReadOne/AST-16                                                  4.000 ± 0%     2.000 ± 0%   -50.00% (p=0.000 n=10)
ReadOneNested/Go-16                                             3.000 ± 0%     1.000 ± 0%   -66.67% (p=0.000 n=10)
ReadOneNested/Go_(roundtrip)-16                                 3.000 ± 0%     1.000 ± 0%   -66.67% (p=0.000 n=10)
ReadOneNested/AST-16                                            6.000 ± 0%     4.000 ± 0%   -33.33% (p=0.000 n=10)
ReadNotFound/Go-16                                              3.000 ± 0%     0.000 ± 0%  -100.00% (p=0.000 n=10)
ReadNotFound/Go_(roundtrip)-16                                  3.000 ± 0%     0.000 ± 0%  -100.00% (p=0.000 n=10)
ReadNotFound/AST-16                                             4.000 ± 0%     1.000 ± 0%   -75.00% (p=0.000 n=10)
WriteOneString/Go-16                                            9.000 ± 0%     5.000 ± 0%   -44.44% (p=0.000 n=10)
WriteOneString/Go_(roundtrip)-16                               16.000 ± 0%     5.000 ± 0%   -68.75% (p=0.000 n=10)
WriteOneString/AST-16                                           22.00 ± 0%     11.00 ± 0%   -50.00% (p=0.000 n=10)
WriteSameValue/Go-16                                            4.000 ± 0%     0.000 ± 0%  -100.00% (p=0.000 n=10)
WriteSameValue/Go_(roundtrip)-16                                11.00 ± 0%      0.00 ± 0%  -100.00% (p=0.000 n=10)
WriteSameValue/AST-16                                           14.00 ± 0%      0.00 ± 0%  -100.00% (p=0.000 n=10)
WriteIncrementingValueSamePath/Go-16                            400.0 ± 0%     400.0 ± 0%         ~ (p=1.000 n=10) ¹
WriteIncrementingValueSamePath/Go_(roundtrip)-16               1090.0 ± 0%     500.0 ± 0%   -54.13% (p=0.000 n=10)
WriteIncrementingValueSamePath/AST-16                          1290.0 ± 0%     400.0 ± 0%   -68.99% (p=0.000 n=10)
WriteIncrementingValueSamePathInterned/Go-16                    400.0 ± 0%     400.0 ± 0%         ~ (p=1.000 n=10) ¹
WriteIncrementingValueSamePathInterned/Go_(roundtrip)-16       1090.0 ± 0%     500.0 ± 0%   -54.13% (p=0.000 n=10)
WriteIncrementingValueSamePathInterned/AST-16                  1090.0 ± 0%     200.0 ± 0%   -81.65% (p=0.000 n=10)
PathAndValueInternedAndNoRoundtripRequired/Go-16                500.0 ± 0%     100.0 ± 0%   -80.00% (p=0.000 n=10)
PathAndValueInternedAndNoRoundtripRequired/Go_(roundtrip)-16   1190.0 ± 0%     100.0 ± 0%   -91.60% (p=0.000 n=10)
PathAndValueInternedAndNoRoundtripRequired/AST-16              1292.0 ± 0%     100.0 ± 0%   -92.26% (p=0.000 n=10)
WriteCollection/Go-16                                           4.000 ± 0%     4.000 ± 0%         ~ (p=1.000 n=10) ¹
WriteCollection/Go_(roundtrip)-16                               35.00 ± 0%     35.00 ± 0%         ~ (p=1.000 n=10) ¹
WriteCollection/AST-16                                          63.00 ± 0%     30.00 ± 0%   -52.38% (p=0.000 n=10)
WriteAndCommit/Go-16                                            512.0 ± 0%     303.0 ± 0%   -40.82% (p=0.000 n=10)
WriteAndCommit/Go_(roundtrip)-16                               1202.0 ± 0%     303.0 ± 0%   -74.79% (p=0.000 n=10)
WriteAndCommit/AST-16                                          1406.0 ± 0%     507.0 ± 0%   -63.94% (p=0.000 n=10)
WriteAndCommitWithTriggers/Go-16                                512.0 ± 0%     304.0 ± 0%   -40.62% (p=0.000 n=10)
WriteAndCommitWithTriggers/Go_(roundtrip)-16                   1202.0 ± 0%     304.0 ± 0%   -74.71% (p=0.000 n=10)
WriteAndCommitWithTriggers/AST-16                              1507.0 ± 0%     609.0 ± 0%   -59.59% (p=0.000 n=10)
```

Signed-off-by: Anders Eknert <anders@eknert.com>
2025-10-02 14:54:14 +02:00
Sebastian Spaink 8c0079f551 Bump golangci-lint to v2.4.0 (#7878)
Signed-off-by: Sebastian Spaink <sebastianspaink@gmail.com>
2025-09-03 15:21:30 -05:00
Ville Vesilehto f77322b3fb build: bump Go version requirement to 1.24 (#7839)
Go 1.23 is no longer supported as per Go release policy.

Changes:

- Use Go v1.24.6 as the project SDK requirement
- Apply lint fixes for Go 1.24
- Fix "non-constant format string in call" issues as seen in CI.

Signed-off-by: Ville Vesilehto <ville@vesilehto.fi>
2025-08-24 09:02:09 +02:00
lestrrat b08a1df858 Upgrade interned jwx (0.9.x) with github.com/lestrrat-go/jwx/v3 (#7733)
Fixes: #7638

Signed-off-by: Daisuke Maki <lestrrat+github@gmail.com>
2025-08-04 16:41:09 +02:00
Charlie Egan d0132ee99b store: Improve conflicting root error message (#7808)
Fixes #7806

```
{
  "errors": [
    {
      "message": "detected overlapping roots in bundle manifest with: [b2.tar.gz b1.tar.gz]"
    }
  ]
}
{
  "errors": [
    {
      "message": "bundles [b1.tar.gz, b2.tar.gz] have overlapping roots and cannot be activated simultaneously because bundle(s) [b1.tar.gz] specify empty root paths ('') which overlap with any other bundle root"
    }
  ]
}
```

Signed-off-by: Charlie Egan <charlie@styra.com>
2025-07-31 12:16:12 +01:00
Anders Eknert 4c13c6cc9f perf: AST compiler optimizations (#7740)
Funnily, this started out as an attempt to look into issues reported
with compiling large policy sets... before I realized that it isn't
likely *this* compiler that has perf issues, but the one that "compiles"
bundles as part of activation. So while these fixes likely does little
to address that, there are still some rather nice improvements here, where
the big ones as ususal are mostly just wins from avoiding work where it's
possible.

For benchmarking I've used Regal's embedded bundle, which isn't great to
use over time, as it's a moving target. But since it's a pretty extensive
bundle and one that covers most features of OPA, it's at least good for
1:1 comparisons when testing perf improvements.

```
// 66555594 ns/op	50239492 B/op	 1083664 allocs/op - main
// 62569440 ns/op	38723015 B/op	  944277 allocs/op - compiler-optimizations pr
```
The B/op / alloc_space improvement is particularly nice here. What's noteworthy
is how relatively little impact that has on performance in this case. That may
be surprising but aligns pretty well with my previous experience of Go code where
a lot of time is spend in recursive walks — that simply takes time, no matter how
much you optimize. Oh well, less memory allocated for this is more memory to spend
elsewhere.

(I'm adding the benchmark used below to Regal in a parallel PR)

Signed-off-by: Anders Eknert <anders@styra.com>
2025-07-25 14:21:53 +02:00
Philip Conrad 5a872a4166 bundle: Add support for bundle store and activation plugins. (#7771)
This commit adds support for changing out how bundle storage and
activation work. To allow swapping out bundle activation, two new
`bundle` package functions are provided:

 - `RegisterActivator`: Registers a bundle.Activator with a string ID.
 - `RegisterDefaultBundleActivator`: Sets the default bundle.Activator to
   use by ID.

Behind the scenes, a few new `bundle` package variables are used to
track what bundle activators are available, and which is the preferred
default.

This system allows registering many activators, and allows choosing the
bundle activator to use at activation time. The activator to use is
decided in the following order:

 - `(bundle.ActivateOpts).Plugin` is used when non-nil.
 - `bundle.bundleExtActivator` is used when an ID was set with
   `RegisterDefaultBundleActivator`.
 - The default/original bundle activator is used if no other selection
   was made.

To support swapping out bundle storage (useful when testing new bundle
designs), a new `bundle` package function is provided:

 - `RegisterStoreFunc`: Sets the function to use for creating bundle
   storage.

These two features together allow swapping out most of the bundle
activation flow, without requiring deep modification of the `bundle`
package. Lazy bundle loading mode is also enabled across many CLI
commands and other bundle loading points now when a non-default bundle
activator is set.

Signed-off-by: Philip Conrad <philip@chariot-chaser.net>
Co-authored-by: Ashutosh Narkar <anarkar4387@gmail.com>
2025-07-17 17:23:12 +00:00
Anders Eknert e61e638fe8 Benchmark fixes (#7765)
A number of benchmarks did not have a `for range b.N` (or equivalent) loop in
them, leading to nothing being measured. This PR fixes that, along with some
cleanups in benchmarks found along the way.

Also remove `b.StopTimer` where not absolutely necessary, as that is
[notoriously buggy](https://github.com/golang/go/issues/27217), and had some
benchmarks hang for a very long time.

Signed-off-by: Anders Eknert <anders@styra.com>
2025-07-11 13:17:30 +02:00
Johan Fylling 817b6635a8 ast,format: Allowing keywords in Rego references (#7709)
Updating the parser and formatter to allow keywords in refs.

Signed-off-by: Johan Fylling <johan.dev@fylling.se>
2025-06-25 15:19:21 +02:00
Johan Fylling aa81e31d17 bundle: Setting default rego-version in bundle API (#7630)
Applying default rego-version for `bundle.Activate()` and `bundle.Deactivate()`.

Fixes: #7588

Signed-off-by: Johan Fylling <johan.dev@fylling.se>
2025-05-28 21:07:40 +02:00
Anders Eknert 8ba08ac80c Apply modernize linter fixes (#7599)
Following up on #7566, and now applying the more exciting
modernizations. fmt.Appendf was new to me! But especially
the contains checks are so much better IMHO. I have reviewed
all changes myself and did a few manual changes where it
became obvious that things could be improved a little further.

(the modernize analyzer still has some issues running against
OPA, and I have manually worked around those for the time being)

Signed-off-by: Anders Eknert <anders@styra.com>
2025-05-20 23:12:13 +02:00
Anders Eknert e43ef0a979 Use any in place of interface{} (#7566)
Earlier this evening I tried to run the Go
[modernize](https://pkg.go.dev/golang.org/x/tools/gopls/internal/analysis/modernize)
analyzer on OPA. That didn't go as planned:

- https://github.com/golang/go/issues/73661
- https://github.com/golang/go/issues/73663

While we wait for that to be fixed, I figured an old-fashioned
search-and-replace across the repo may work for at least the
`interface{}` to `any` conversion. That should help make it easier
to see the other fixes as applied by the modernize tool once it has
had those issues resolved.

Signed-off-by: Anders Eknert <anders@styra.com>
2025-05-12 13:57:48 +02:00
Johan Fylling 93c177449c ast: Adding rego_v1 feature to --v0-compatible capabilities (#7474)
to allow for using Rego v1 bundles in `opa build`/`check`/`eval`/`test`.

Before this change, a bundle with `1` as `rego_version`/`file_rego_versions` would be rejected when evaluated with the `--v0-compatible` flag with the error:

```
rego_parse_error: illegal capabilities: rego_v1 feature required for parsing v1 Rego
```

This is fixed by adding the `rego_v1` feature to the `v0` default capabilities applied when using the `--v0-compatible` flag. Note: this allows OPA to accept Rego `v1` modules inside bundles, but modules without a specified Rego version, such as freestanding non-bundle modules or modules inside bundles with no specified Rego version, are parsed as `v0`.

Signed-off-by: Johan Fylling <johan.dev@fylling.se>
2025-04-03 11:30:53 +02:00
Anders Eknert afb30d3f9d Add gocritic linter, fix a bunch of stuff (#7377)
Brace yourselves! For there are many touched files here. No changes
in semantics however.

Spent a long time trying out the various optional rules gocritic
provides, and settled for a few of them. There are more I really
like, but that would take many hours to address across the codebase.

Perhaps others find gocritic too pedantic? If so, we can merge the
fixes without enabling the rule.

Signed-off-by: Anders Eknert <anders@styra.com>
2025-02-24 16:28:41 +01:00
Johan Fylling bb12354f58 bundle: Fixing issue where --v0-compatible isn't respected for custom bundles (#7338)
where the bundle has been manually constructed containing v0 Rego modules and
no `rego_version`/`file_rego_versions` fields are declared in the bundle manifest.

This affects bundle deactivation in the bundle store lifecycle used when for
`opa run` in server mode (`-s`).

Signed-off-by: Johan Fylling <johan.dev@fylling.se>
2025-02-05 12:49:59 +01:00
Anders Eknert 55e87e79ae Add perfsprint linter (#7334)
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>
2025-01-31 20:24:05 +01:00
Anders Eknert b942136a4a Use Go 1.22+ int ranges (#7328)
With "some" help from `golangci-lint run --fix ./...`

Signed-off-by: Anders Eknert <anders@styra.com>
2025-01-30 09:57:27 +01:00
Johan Fylling b032e3bfc0 Fixing issue where bundle plugin could panic on reconfiguration (SDK use) (#7300)
Fixing issue where bundle plugin would panic on reconfiguration if module rego-version is missing in bundle manifest.

* Passing runtime rego-version to deactivation options
* Preferring to pull rego-version from parsed modules if present

This solves an edge case when using the OPA SDK, and should not affect standalone OPA.

Fixes: #7297
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
2025-01-24 13:47:16 +01:00
Johan Fylling e47bd4f9a8 bundle: Optimizing rego-version management in bundle activation (#7296)
Only writing a module's rego-version to storage if it diverges from the runtime rego-version.

Signed-off-by: Johan Fylling <johan.dev@fylling.se>
2025-01-24 10:55:15 +01:00
Anders Eknert 0b94dd873e Remove jsonOptions from AST nodes and terms (#7281)
This was originally added to allow Regal to get a serialized AST that included
location data wherever that was possible. Regal is however no longer using OPA's
JSON serialization but its own custom encoder. Attaching these options to every
AST node and term comes with a cost attached, and without any known users of this
feature vs. the many users who care about resource utilization, this feels like
an easy choice.

While it seems unlikely to be users depending on this functionality — in case
someone needs it, the options for serializing AST nodes to JSON can now be set
globally instead. Global state is always awkward, but since JSON marshalling
methods only have access to the node being marshalled and of course, global
state, there's not a whole lot of options if we intend to keep this feature.

Signed-off-by: Anders Eknert <anders@styra.com>
2025-01-22 09:24:58 +00:00
Ashutosh Narkar 5d5329dffb bundle: Add info about the correct rego version to parse modules on the store (#7278)
Fixing an issue where the rego-version for individual modules was lost during bundle deactivation (bundle lifecycle) if this version diverged from the active runtime rego-version. This could cause reloading of v0 bundles to fail when OPA was not running with the `--v0-compatible` flag.

Signed-off-by: Ashutosh Narkar <anarkar4387@gmail.com>
Co-authored-by: Johan Fylling <johan.dev@fylling.se>
2025-01-21 13:05:01 +01:00
Anders Eknert b0100a66cd testing: replace reflect.DeepEqual where possible (#7286)
And a few other small fixes in tests. This i not so much
about performance but about choosing the best tool for a
given task :) But that the alternatives are also faster
doesn't hurt either.

Signed-off-by: Anders Eknert <anders@styra.com>
2025-01-21 10:34:53 +01:00
Anders Eknert 622434d113 Add util.Keys and util.KeysSorted (#7285)
And use them to reduce imperative boilerplate throughout
the codebase.

Additionally, replace use of sort.Slice with slices.SortFunc
which is more efficient since it is generic and as such avoids
allocations related to `interface{}` casts.

Also a few performance-related minor fixes, but not the main
theme of this PR.

```
BenchmarkRegalLintingItself-10 before / after
1832684458 ns/op    3453470360 B/op    66125422 allocs/op
1826601250 ns/op    3449619024 B/op    65999164 allocs/op
````

Signed-off-by: Anders Eknert <anders@styra.com>
2025-01-21 08:30:19 +01:00
Johan Fylling 563321d26b Rego v1 capabilities and keywords update (#7216)
* Separating v0- and v1 keywords
* Adding `rego_v1` capability feature

Signed-off-by: Johan Fylling <johan.dev@fylling.se>
2024-12-17 11:50:11 +01:00
Johan Fylling a179a24c48 v1 API
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>
2024-12-12 15:27:34 +01:00
Johan Fylling 7bb6dbe36b Preparing for v1 API
Moving (most) source to v1 root package to prepare for v0/v1 API separation.

Signed-off-by: Johan Fylling <johan.dev@fylling.se>
2024-12-12 15:09:03 +01:00