Perform Rego queries from multiple languages with rego-cpp
A Rego language interpreter in C++ with wrappers for C, Rust, and Python.
Currently v0.4.5ยทAll releases
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.68.0 of the language. You can learn more about our implementation here.
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.
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
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.
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
We provide a Rust crate called regorust which exposes the C API in idiomatic Rust. This example shows a CLI interpreter implemented in Rust.
[dependencies]
regorust = "0.4.5"
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
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