Native OCaml Rego/OPA policy engine
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

OCaml 98.0%
Dune 0.7%
Other 1.4%
35 1 0

Clone this repository

https://tangled.org/gazagnaire.org/ocaml-rego https://tangled.org/did:plc:jhift2vwcxhou52p3sewcrpx/ocaml-rego
git@git.recoil.org:gazagnaire.org/ocaml-rego git@git.recoil.org:did:plc:jhift2vwcxhou52p3sewcrpx/ocaml-rego

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

rego -- native OCaml Rego/OPA policy engine#

Pure OCaml implementation of the Rego policy language (Open Policy Agent). Evaluates Rego policies against JSON input/data documents.

Installation#

Install with opam:

$ opam install rego

If opam cannot find the package, it may not yet be released in the public opam-repository. Add the overlay repository, then install it:

$ opam repo add samoht https://tangled.org/gazagnaire.org/opam-overlay.git
$ opam update
$ opam install rego

Quick Start#

let engine = Rego.engine ()

let () =
  match
    Rego.add_policy engine ~name:"example.rego"
      {|
        package authz
        default allow = false
        allow { input.user == "admin" }
      |}
  with
  | Ok () -> ()
  | Error e -> failwith (Format.asprintf "%a" Rego.pp_error e)

let input =
  Result.get_ok (Rego.Value.of_json_string {|{"user":"admin"}|})

let () =
  match Rego.eval engine ~input "data.authz.allow" with
  | Ok v -> assert (Rego.Value.equal v (Rego.Value.Bool true))
  | Error e -> failwith (Format.asprintf "%a" Rego.pp_error e)

Features#

  • Complete rules: allow { body }, x = value if { body }
  • Default rules: default allow = false
  • Partial set rules: s contains x if { body }
  • User-defined function rules: double(x) = y if { y := x * 2 }
  • Iteration: _ wildcard, unbound index variables, some ... in, every ... in, and array/set/object comprehensions
  • with input/data modifiers
  • Path resolution: input.a.b, data.pkg.rule (with longest-prefix package matching), same-package rule references
  • Expressions: literals, references, arithmetic, comparisons, set union and intersection, unary minus, := and = unification assignment
  • Builtins: count, sum, product, min, max, sort, startswith, endswith, contains, upper, lower, concat, split, replace, trim, trim_left, trim_right, trim_space, substring, indexof, sprintf, to_number, abs, ceil, floor, round, type_name, is_string, is_number, is_boolean, is_null, is_array, is_object, is_set, array.concat, array.slice, array.reverse, object.keys, object.values, object.get, print

API#

  • Rego.engine -- create a new policy engine
  • Rego.add_policy -- load a Rego policy module by name
  • Rego.add_data / Rego.add_data_json -- set the data document
  • Rego.eval -- evaluate a query against the loaded policies and input
  • Rego.eval_query -- evaluate a query as a body expression, returning the list of satisfying binding sets
  • Rego.parse_module / Rego.parse_expr -- parse Rego source to AST

OPA conformance#

test/opa_suite/ contains upstream test files pulled from OPA's own conformance suite at v1/test/cases/testdata/v0, converted from YAML to JSON. They run as part of dune runtest, one alcotest case per category plus an aggregate that reports the pass/total count.

Known reasons for current failures, roughly ordered by impact:

  • regex.*, glob.*, json.patch, json.filter, time.*, crypto.*, net.cidr*, rego.metadata_* -- entire builtin families not yet implemented
  • in as a free-standing membership operator (x in collection) -- parser supports some x in c / every x in c only
  • Many OPA tests use count(x, out), abs(x, out) style output-arg unification with compound patterns (e.g. array destructuring in the output slot) -- the simple variable case works, richer patterns don't
  • Numeric precision -- OCaml float can't represent OPA's arbitrary-precision integers
  • Strict-mode errors, schema annotations, and metadata blocks

License#

ISC