rego-cpp
rego-cpp

Perform Rego queries from multiple languages with rego-cpp

A Rego language interpreter in C++ with wrappers for C, Rust, and Python.

Currently v0.3.9ยทAll releases

Open Policy Agent

What is Rego?

Rego is a language developed by Open Policy Agent (OPA) for use in defining policies in cloud systems.

We think Rego is a great language, and you can learn more about it here. However, it has some limitations. Primarily, the interpreter is only accessible via the command line or a web server. Further, the only option for using the language in-process is via an interface in Go.

The rego-cpp project provides the ability to integrate Rego natively into a wider range of languages. We currrently support C, C++, Rust, and Python, and are largely compatible with v0.55.0 of the language. You can learn more about our implementation here.

Take a look at our examples

A great way to get started is by looking at one of our code examples.

c++

You can compile rego-cpp directly into your C++ program, which gives you full access to our API. We recommend using CMake FetchContent to add rego-cpp to your project.

Learn more about the C++ API

                        FetchContent_Declare(
  regocpp
  GIT_REPOSITORY https://github.com/microsoft/rego-cpp.git
  GIT_TAG        main
)
       
FetchContent_MakeAvailable(regocpp)

# ...

target_link_libraries(myproject PRIVATE regocpp::rego)
CMakeLists.txt
                        #include <rego/rego.hh>

int main()
{
    rego::Interpreter rego;
    rego.add_module("objects", R"(package objects

rect := {`width`: 2, "height": 4}
cube := {"width": 3, `height`: 4, "depth": 5}
a := 42
b := false
c := null
d := {"a": a, "x": [b, c]}
index := 1
shapes := [rect, cube]
names := ["prod", `smoke1`, "dev"]
sites := [{"name": "prod"}, {"name": names[index]}, {"name": "dev"}]
e := {
    a: "foo",
    "three": c,
    names[2]: b,
    "four": d,
}
f := e["dev"])");
    rego.add_data_json(R"({
    "one": {
        "bar": "Foo",
        "baz": 5,
        "be": true,
        "bop": 23.4
    },
    "two": {
        "bar": "Bar",
        "baz": 12.3,
        "be": false,
        "bop": 42
    }
})");
    rego.add_data_json(R"({
    "three": {
        "bar": "Baz",
        "baz": 15,
        "be": true,
        "bop": 4.23
    }
})");
    rego.set_input_json(R"({
    "a": 10,
    "b": "20",
    "c": 30.0,
    "d": true
})");
    std::cout << rego.query("[data.one, input.b, data.objects.sites[1]] = x") << std::endl;
}
example.cc
C

You can also compile rego-cpp directly into your C program. The C API provides most of the functionality of the full C++ API while providing a stable interface which is amenable to FFI. We recommend using CMake FetchContent to add rego-cpp to your project.

Learn more about the C API

FetchContent_Declare(
  regocpp
  GIT_REPOSITORY https://github.com/microsoft/rego-cpp.git
  GIT_TAG        main
)
       
FetchContent_MakeAvailable(regocpp)

# ...

target_link_libraries(myproject PRIVATE regocpp::rego)
CMakeLists.txt
                        #include <rego/rego_c.h>
#include <stdlib.h>
#include <stdio.h>

int main()
{
    regoEnum err;
    int rc = EXIT_SUCCESS;
    regoOutput* output = NULL;
    regoInterpreter* rego = regoNew();

    err = regoAddModuleFile(rego, "examples/objects.rego");
    if (err != REGO_OK)
    {
        goto error;
    }

    err = regoAddDataJSONFile(rego, "examples/data0.json");
    if (err != REGO_OK)
    {
        goto error;
    }

    err = regoAddDataJSONFile(rego, "examples/data1.json");
    if (err != REGO_OK)
    {
        goto error;
    }

    err = regoSetInputJSONFile(rego, "examples/input0.json");
    if (err != REGO_OK)
    {
        goto error;
    }

    output = regoQuery(rego, "[data.one, input.b, data.objects.sites[1]] = x");
    if(output == NULL)
    {
        goto error;
    }

    printf("%s\n", regoOutputString(output));
    goto exit;
    
error:
  printf("%s\n", regoGetError(rego));
  rc = EXIT_FAILURE;

exit:
  if (output != NULL)
  {
    regoFreeOutput(output);
  }

  if (rego != NULL)
  {
    regoFree(rego);
  }

  return rc;
}
example.c
Rust

We provide a Rust crate called regorust which exposes the C API in idiomatic Rust. This example shows a CLI interpreter implemented in Rust.

Learn more about the Rust API

                        [dependencies]
regorust = "0.3.9"
Cargo.toml
                        use clap::Parser;
use regorust::Interpreter;

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Args {
    #[arg(short, long)]
    data: Vec<std::path::PathBuf>,

    #[arg(short, long)]
    input: Option<std::path::PathBuf>,

    query: String,
}

fn main() {
    let args = Args::parse();
    let rego = Interpreter::new();
    if let Some(input) = args.input {
        rego.set_input_json_file(input.as_path())
            .expect("Failed to read input file");
    }

    for data in args.data {
        if data.extension().unwrap() == "rego" {
            rego.add_module_file(data.as_path())
                .expect("Failed to load module file");
        } else {
            rego.add_data_json_file(data.as_path())
                .expect("Failed to load data file");
        }
    }

    println!(
        "{}",
        rego.query(args.query.as_str())
            .expect("Failed to evaluate query")
    );
}
main.rs
Python

We provide a Python wheel called regopy which exposes the C API in a pythonic way.

Learn more about the Python API

                        $ pip install regopy
                        from regopy import Interpreter

rego = Interpreter()
with open("examples/objects.rego") as f:
    rego.add_module("objects", f.read())

rego.add_data({
    "one": {
        "bar": "Foo",
        "baz": 5,
        "be": True,
        "bop": 23.4
    },
    "two": {
        "bar": "Bar",
        "baz": 12.3,
        "be": False,
        "bop": 42
    }
})

rego.add_data({
    "three": {
        "bar": "Baz",
        "baz": 15,
        "be": True,
        "bop": 4.23
    }
})

rego.set_input({
    "a": 10,
    "b": "20",
    "c": 30.0,
    "d": True
})

print(rego.query("[data.one, input.b, data.objects.sites[1]] = x"))
example.py