#language #query-language #policy #query-engine #bindings #wrapper #rego

regorust

Rust 对 rego-cpp Rego 编译器和解释器的绑定

6 个版本

0.4.0 2024年6月18日
0.3.11 2024年1月22日
0.3.10 2023年9月23日

#816数据库接口

Download history 3/week @ 2024-04-03 2/week @ 2024-05-22 92/week @ 2024-06-12 47/week @ 2024-06-19

每月305 次下载

MIT 许可证

59KB
856

regorust

Rego 是 Open Policy Agent 项目的本地查询语言。如果您想了解更多关于 Rego 语言的详细信息以及其各种用法,请参阅 OPA 提供的语言文档。

本 crate 是围绕 Microsoft 开发和维护的开源跨平台 C++ 实现 Rego 语言编译器和运行时的 rego-cpp 的包装器。您可以在 这里 了解更多关于该项目的信息。在这个包装器中,我们尽可能提供符合 Rust 语言的 Rego 查询引擎接口。我们希望这个项目对希望在 Rust 环境中利用 Rego 的力量的人有所帮助。

警告 虽然该项目已经发展到支持完整的 Rego 语言(见下文 语言支持),但我们不支持所有内置函数。尽管如此,我们已经验证了与 OPA Rego 测试套件的兼容性。即使如此,它仍应被视为实验性软件,并谨慎使用。

示例用法

use regorust::Interpreter;

fn main() {
    // The Interpreter is the main interface into the library
    let rego = Interpreter::new();
    match rego.query("x=5;y=x + (2 - 4 * 0.25) * -3 + 7.4") {
      Ok(result) => {
        let x = result.binding("x").expect("cannot get x");
        let y = result.binding("y").expect("cannot get y");
        println!("x = {}", x.json().unwrap());
        println!("y = {}", y.json().unwrap());
      }
      Err(e) => {
        panic!("error: {}", e);
      }
    }
}
use regorust::Interpreter;

fn main() {
  let input = r#"
    {
      "a": 10,
      "b": "20",
      "c": 30.0,
      "d": true
    }
  "#;
  let data0 = r#"
    {
      "one": {
        "bar": "Foo",
        "baz": 5,
        "be": true,
        "bop": 23.4
      },
      "two": {
        "bar": "Bar",
        "baz": 12.3,
        "be": false,
        "bop": 42
      }
    }
  "#;
  let data1 = r#"
    {
      "three": {
        "bar": "Baz",
        "baz": 15,
        "be": true,
        "bop": 4.23
      }
    }        
  "#;
  let module = 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"]                
  "#;
  let rego = Interpreter::new();
  rego.set_input_json(input);
  rego.add_data_json(data0);
  rego.add_data_json(data1);
  rego.add_module("objects", module);
  match rego.query("x=[data.one, input.b, data.objects.sites[1]]") {
    Ok(result) => {
      println!("{}", result.to_str().unwrap());
      let x = result.binding("x").expect("cannot get x");
      let data_one = x.index(0).unwrap();
      if let NodeValue::String(bar) = data_one
          .lookup("bar")
          .unwrap()
          .value()
          .unwrap()
      {
        println!("data.one.bar = {}", bar);
      }
    }
    Err(e) => {
      panic!("error: {}", e);
    }
  }
}

语言支持

目前我们支持 OPA 定义的 Rego v0.65.0 版本,语法如下

module          = package { import } policy
package         = "package" ref
import          = "import" ref [ "as" var ]
policy          = { rule }
rule            = [ "default" ] rule-head { rule-body }
rule-head       = ( ref | var ) ( rule-head-set | rule-head-obj | rule-head-func | rule-head-comp )
rule-head-comp  = [ assign-operator term ] [ "if" ]
rule-head-obj   = "[" term "]" [ assign-operator term ] [ "if" ]
rule-head-func  = "(" rule-args ")" [ assign-operator term ] [ "if" ]
rule-head-set   = "contains" term [ "if" ] | "[" term "]"
rule-args       = term { "," term }
rule-body       = [ "else" [ assign-operator term ] [ "if" ] ] ( "{" query "}" ) | literal
query           = literal { ( ";" | ( [CR] LF ) ) literal }
literal         = ( some-decl | expr | "not" expr ) { with-modifier }
with-modifier   = "with" term "as" term
some-decl       = "some" term { "," term } { "in" expr }
expr            = term | expr-call | expr-infix | expr-every | expr-parens | unary-expr
expr-call       = var [ "." var ] "(" [ expr { "," expr } ] ")"
expr-infix      = expr infix-operator expr
expr-every      = "every" var { "," var } "in" ( term | expr-call | expr-infix ) "{" query "}"
expr-parens     = "(" expr ")"
unary-expr      = "-" expr
membership      = term [ "," term ] "in" term
term            = ref | var | scalar | array | object | set | membership | array-compr | object-compr | set-compr
array-compr     = "[" term "|" query "]"
set-compr       = "{" term "|" query "}"
object-compr    = "{" object-item "|" query "}"
infix-operator  = assign-operator | bool-operator | arith-operator | bin-operator
bool-operator   = "==" | "!=" | "<" | ">" | ">=" | "<="
arith-operator  = "+" | "-" | "*" | "/" | "%"
bin-operator    = "&" | "|"
assign-operator = ":=" | "="
ref             = ( var | array | object | set | array-compr | object-compr | set-compr | expr-call ) { ref-arg }
ref-arg         = ref-arg-dot | ref-arg-brack
ref-arg-brack   = "[" ( scalar | var | array | object | set | "_" ) "]"
ref-arg-dot     = "." var
var             = ( ALPHA | "_" ) { ALPHA | DIGIT | "_" }
scalar          = string | NUMBER | TRUE | FALSE | NULL
string          = STRING | raw-string
raw-string      = "`" { CHAR-"`" } "`"
array           = "[" term { "," term } "]"
object          = "{" object-item { "," object-item } "}"
object-item     = ( scalar | ref | var ) ":" term
set             = empty-set | non-empty-set
non-empty-set   = "{" term { "," term } "}"
empty-set       = "set(" ")"

[!NOTE] 此语法对应于启用了 rego.v1 的 Rego(更多信息请参阅 OPA v1.0)。

定义

[]     optional (zero or one instances)
{}     repetition (zero or more instances)
|      alternation (one of the instances)
()     grouping (order of expansion)
STRING JSON string
NUMBER JSON number
TRUE   JSON true
FALSE  JSON false
NULL   JSON null
CHAR   Unicode character
ALPHA  ASCII characters A-Z and a-z
DIGIT  ASCII characters 0-9
CR     Carriage Return
LF     Line Feed

内置函数

目前仅支持少数内置函数,但我们正在积极添加所有标准内置函数。以下是目前支持的内置函数:

  • 聚合
  • 数组
  • 位运算
  • 类型转换
  • 编码
  • 数字
  • 对象
  • 正则表达式
  • 语义版本
  • 集合
  • 字符串
  • 类型
  • 单位
  • 杂项
    • opa.运行时
    • 打印
    • 时间.now_ns

与 OPA Rego Go 实现的兼容性

我们的目标是实现并与参考Go实现保持完全兼容。我们已经开发了一个测试驱动程序,它运行相同的测试并验证我们产生的输出是否相同。在这个阶段,我们通过了所有非内建特定的测试套件,这些测试套件是从OPA仓库克隆的。要使用可用的OPA测试进行构建,请使用以下预设之一

  • release-clang-opa
  • release-opa

目前,我们还没有完全通过以下测试套件

  • crypto*
  • glob*
  • graphql
  • invalidkeyerror
  • json*(除了jsonbuiltins
  • jwt*
  • net*
  • planner-ir
  • providers-aws
  • 时间
  • walkbuiltin

无运行时依赖

~0–1.8MB
~36K SLoC