3 Commits

Author SHA1 Message Date
Philip Conrad 63e1877c48 linters+testdata: Reformat all yaml testcases for linting. (#6511)
This commit adds a config for yamllint, mass-reformats all of
the existing Yaml testcases to pass linting, and adds a Yaml
linting job to the pull-request Github Actions workflow. A few 
careful exceptions and ignores were added to the linter's
config to allow keeping our existing Yaml files with minimal
reformatting.

Signed-off-by: Philip Conrad <philipaconrad@gmail.com>
2024-01-10 13:16:01 -05:00
Philip Conrad 47a13c4f8c internal+json.filter: Add EditTree data structure. (#5494)
This commit adds a new `EditTree` data structure, which is built
for applying in-place modifications to a Term, and can render the
final result of all the edits efficiently.

The goal is to use this data structure to apply *all* of the patches in
a JSON-Patch sequence rapidly, and then collapse all of the edits at
the end with minimal wasted Term copying.

The `EditTree` data structure supports the following core operations:

 - Insert
 - Delete
 - Unfold
 - Render

It is designed to work across all core Rego data types, with special-
case handling for scalars versus composite types.

It also vendors in a bit-vector library to allow for ease-of-
bookkeeping for in-place Array modifications.

As an example of usage, `json.filter`'s builtin implementation has been
replaced with an `EditTree`-based design, which scales well on
deeply-nested paths, relative to the original implementation.

Signed-off-by: Philip Conrad <philipaconrad@gmail.com>
2023-02-14 15:30:59 -05:00
Jasper Van der Jeugt 1e17cc0c62 Add json.patch builtin
This is an implementation of the `json.patch` builtin.  Previous discussions
about this include #2839 and #2167.

It does not use an external dependency but rather implements [RFC 6902] directly
on AST terms.  This avoids a conversion to JSON as well as the dependency; and
as an added bonus we can make `json.patch` work for sets as well, covering the
full space of AST terms.

In my first implementation I used a mutable approach by first creating a deep
copy and then modifying it in-place.  However, this leads to issues with
the cached `hash` values in objects on the path.  I replaced this with an
implementation that creates shallow copies.  The performance tradeoff is that
smaller patches should be faster; but replacing parts will be slower.  Since we
don't know about too many people using this, I think both sides are acceptable.

I vendored the [json-patch-tests] into the test suite in a way that should
make updating them fairly easy.  I am also testing the cases disabled there
(since they do work for us!) but I disabled two test cases by adding a new
`opa_disabled` key.  These are:

 -  Us allowing `"foo"` as path (which should be `"/foo"` if you interpret
    the RFC strictly).
 -  A duplicate entry in the JSON patch object which isn't caught by OPA
    since it's consistent.

I added some additional tests for sets and things seem to work.  I'm going
to try out this new functionality in our larger codebase to see if any issues
come up, but I expect it to hold up.  Update: we've been using this builtin
and haven't seen any issues so far.

[RFC 6902]: https://tools.ietf.org/html/rfc6902#section-4.4
[json-patch-tests]: https://github.com/json-patch/json-patch-tests

Signed-off-by: Jasper Van der Jeugt <jasper@fugue.co>
2020-11-24 14:54:58 -05:00