open policy agent 语法总结
OPA 文档模型
OPA将从外部加载的数据成为基本文档(base documents),有规则产生的值成为虚拟文档(virtual documents),此处"虚拟"的意思表示文档由策略进行了计算,且不是外部加载的。Rego中可以使用名为data的全局变量访问这两种数据。
异步加载的基本文档可以通过data全局变量进行访问。另一方面,如果软件需要查询OPA来获取策略决策时,也可以将基础文档同步推入或拉入OPA,此时需要通过input全局变量来引用同步推送的基本文档。同步加载的数据保存在data之外,防止命名冲突。
逻辑与
{
    "servers": [
        {"id": "app", "protocols": ["https", "ssh"], "ports": ["p1", "p2", "p3"]},
        {"id": "db", "protocols": ["mysql"], "ports": ["p3"]},
        {"id": "cache", "protocols": ["memcache"], "ports": ["p3"]},
        {"id": "ci", "protocols": ["http"], "ports": ["p1", "p2"]},
        {"id": "busybox", "protocols": ["telnet"], "ports": ["p1"]}
    ],
    "networks": [
        {"id": "net1", "public": false},
        {"id": "net2", "public": false},
        {"id": "net3", "public": true},
        {"id": "net4", "public": true}
    ],
    "ports": [
        {"id": "p1", "network": "net1"},
        {"id": "p2", "network": "net3"},
        {"id": "p3", "network": "net2"}
    ]
}
OPA使用;来表示逻辑AND
input.servers[0].id == "app"; input.servers[0].protocols[0] == "https"
$ true
也可以使用多行来忽略;
input.servers[0].id == "app"
input.servers[0].protocols[0] == "https"
$ rue
如果引用的内容不存在或匹配失败,则返回的结果为undefined
s := input.servers[0]
s.id == "app1"
$undefined decision
s := input.servers[1110]
s.id == "app1"
$ undefined decision
变量
OPA的变量一旦赋值之后就是不可变的:
s := input.servers[0]
s := input.servers[1]
$ 1 error occurred: 2:1: rego_compile_error: var s assigned above
迭代
找出连接到public网络的ports的id,下面使用some关键字定义循环的变量,使用id变量提取符合要求的ports的id,最后一行input.networks[j].public也可以写为input.networks[j].public==true,同时注意条件之间是逻辑与的关系
some i, j
id := input.ports[i].id
input.ports[i].network == input.networks[j].id
input.networks[j].public
$ +---+------+---+
  | i |  id  | j |
  +---+------+---+
  | 1 | "p2" | 2 |
  +---+------+---+
可以使用下划线_(通配符)进行遍历,使用下划线来表示实例的单独变量。如使用如下方式找出input.servers中协议为http的id
s := input.servers[_]
id := s.id
s.protocols[_] == "http"
$ true
规则(Rules)
使用规则可以重用判定逻辑,可以看作是一种函数实现。规则可以是"完整(complete)"或"部分(partial)"的。
完整规则
每个规则都包含一个head和一个body,如下head为any_public_networks = true ,body为net := input.networks[_]; net.public。如果忽略= <value>部分(= <value>用于使用右值赋予左边的变量,如apps_by_hostname[hostname] = app,key为hostname,value为app),则默认为true。
package example.rules
any_public_networks = true {  # is true if...
    net := input.networks[_]  # some network exists and..
    net.public                # it is public.
}
可以为规则定义默认值,这样在结果返回"undefined decision"时,会将any_public_networks置为false
package example.rules
default any_public_networks = false
any_public_networks = true {  # is true if...
    net := input.no_exist_networks[_]  # some network exists and..
    net.public                # it is public.
}
any_public_networks
$ false
可以使用如下方式进行访问:
any_public_networks
$ true
也可以使用全局变量data进行访问,访问方式为data.<package-path>.<rule-name>
data.example.rules.any_public_networks
$ true
可以使用如下方式定义常量
package example.constants
pi := 3.14
部分规则
head为public_network[net.id],body为net := input.networks[_]; net.public,可以看作是带返回值的函数
package example.rules
public_network[net.id] {      # net.id is in the public_network set if...
    net := input.networks[_]  # some network exists and...
    net.public                # it is public.
}
可以遍历返回值
public_network[_]
$ +-------------------+
  | public_network[_] |
  +-------------------+
  | "net3"            |
  | "net4"            |
  +-------------------+
逻辑或
完整规则的逻辑或
使用逻辑或时,要求多条规则的名称相同。如下用于校验servers是否暴露了telnet或ssh协议:
package example.logical_or
default shell_accessible = false
shell_accessible = true {
    input.servers[_].protocols[_] == "telnet"
}
shell_accessible = true {
    input.servers[_].protocols[_] == "ssh"
}
部分规则的逻辑或
如下规则用于找出协议为telnet或ssh的server的id:
package example.logical_or
shell_accessible[server.id] {
    server := input.servers[_]
    server.protocols[_] == "telnet"
}
shell_accessible[server.id] {
    server := input.servers[_]
    server.protocols[_] == "ssh"
}
rego语法
标量
rego支持字符串、数字、布尔和null
greeting   := "Hello"
max_height := 42
pi         := 3.14159
allowed    := true
location   := null
字符串
支持两种类型的字符串:双引号包围的字符串和原始字符串,后者一般用于正则表达式。
复合值
定义了数值集合
cube := {"width": 3, "height": 4, "depth":true}
cube.depth
$ true
对象
可以看作golang的map
ips_by_port := {
    80: ["1.1.1.1", "1.1.1.2"],
    443: ["2.2.2.1"],
}
ips_by_port[80]
$ [
    "1.1.1.1",
    "1.1.1.2"
  ]
数组
数组使用下标进行索引
s1 := [1, 2, 3]
s2 := [2, 1, 3]
s1[1]
$ 2
s1 == s2
$ false
集合
它是唯一值的无序集合。它没有key,且无法使用下标进行索引。注意在解析为JSON格式时,集合体现为数组格式。
s1 := {1, 2, 3}
s2 := {2, 1, 3}
s1 == s2
$ true
变量
变量位于规则的head和body,规则head中的变量可以认为是输入或输出,如果提供了确定的值,则认为是输入,否则认为是输出。例如:
sites := [
    {"name": "prod"},
    {"name": "smoke1"},
    {"name": "dev"}
]
q[name] { name := sites[_].name }
如下x并没有绑定到某个值,则返回所有x和q[x]的值
q[x]
$ +----------+----------+
  |    x     |   q[x]   |
  +----------+----------+
  | "dev"    | "dev"    |
  | "prod"   | "prod"   |
  | "smoke1" | "smoke1" |
  +----------+----------+
如下"dev"是一个确定的值,作为输入,用于判断name中是否存在该值
q["dev"]
$ "dev"
引用
有两种方式访问嵌套文档:点访问方式和方括号访问方式,如下:
sites[0].servers[1].hostname
sites[0]["servers"][1]["hostname"]
变量键
引用可以使用变量作为键,这种方式用于选择所有元素的值
sites[i].servers[j].hostname
$ +---+---+------------------------------+
  | i | j | sites[i].servers[j].hostname |
  +---+---+------------------------------+
  | 0 | 0 | "hydrogen"                   |
  | 0 | 1 | "helium"                     |
  | 0 | 2 | "lithium"                    |
  | 1 | 0 | "beryllium"                  |
  | 1 | 1 | "boron"                      |
  | 1 | 2 | "carbon"                     |
  | 2 | 0 | "nitrogen"                   |
  | 2 | 1 | "oxygen"                     |
  +---+---+------------------------------+
如果迭代时不需要用到变量,则可以使用下划线_
sites[_].servers[_].hostname
$ +------------------------------+
  | sites[_].servers[_].hostname |
  +------------------------------+
  | "hydrogen"                   |
  | "helium"                     |
  | "lithium"                    |
  | "beryllium"                  |
  | "boron"                      |
  | "carbon"                     |
  | "nitrogen"                   |
  | "oxygen"                     |
  +------------------------------+
复合键
s := {[1, 2], [1, 4], [2, 6]}
s[[1, 2]]
$ [
    1,
    2
  ]
s[[1, x]]
$ +---+-----------+
  | x | s[[1, x]] |
  +---+-----------+
  | 2 | [1,2]     |
  | 4 | [1,4]     |
  +---+-----------+
多表达式
规则通常是多表达式的,包含到documents的引用。下面定义了一个数组,每个数组包含一个服务的应用名称和主机名称
apps_and_hostnames[[name, hostname]] {
    some i, j, k
    name := apps[i].name
    server := apps[i].servers[_]
    sites[j].servers[k].name == server
    hostname := sites[j].servers[k].hostname
}
apps_and_hostnames[x]
$ +----------------------+-----------------------+
  |          x           | apps_and_hostnames[x] |
  +----------------------+-----------------------+
  | ["mongodb","oxygen"] | ["mongodb","oxygen"]  |
  | ["mysql","carbon"]   | ["mysql","carbon"]    |
  | ["mysql","lithium"]  | ["mysql","lithium"]   |
  | ["web","beryllium"]  | ["web","beryllium"]   |
  | ["web","boron"]      | ["web","boron"]       |
  | ["web","helium"]     | ["web","helium"]      |
  | ["web","hydrogen"]   | ["web","hydrogen"]    |
  | ["web","nitrogen"]   | ["web","nitrogen"]    |
  +----------------------+-----------------------+
推导式
与规则类似,推导式有一个head和一个body。
region := "west"
names := [name | sites[i].region == region; name := sites[i].name]
$ +-----------------+--------+
  |      names      | region |
  +-----------------+--------+
  | ["smoke","dev"] | "west" |
  +-----------------+--------+
这与python中的推导式类似
# Python equivalent of Rego comprehension shown above.
names = [site.name for site in sites if site.region == "west"]
数组推导式
格式如下:
[ <term> | <body> ]
app_to_hostnames[app_name] = hostnames {
    app := apps[_]
    app_name := app.name
    hostnames := [hostname | name := app.servers[_]
                            s := sites[_].servers[_]
                            s.name == name
                            hostname := s.hostname]
}
app_to_hostnames[app]
$ +-----------+------------------------------------------------------+
  |    app    |                app_to_hostnames[app]                 |
  +-----------+------------------------------------------------------+
  | "mongodb" | ["oxygen"]                                           |
  | "mysql"   | ["lithium","carbon"]                                 |
  | "web"     | ["hydrogen","helium","beryllium","boron","nitrogen"] |
  +-----------+------------------------------------------------------+
对象推导式
格式如下:
{ <key>: <term> | <body> }
注意key不能有冲突
app_to_hostnames := {app.name: hostnames |
    app := apps[_]
    hostnames := [hostname |
                    name := app.servers[_]
                    s := sites[_].servers[_]
                    s.name == name
                    hostname := s.hostname]
}
app_to_hostnames[app]
$ +-----------+------------------------------------------------------+
  |    app    |                app_to_hostnames[app]                 |
  +-----------+------------------------------------------------------+
  | "mongodb" | ["oxygen"]                                           |
  | "mysql"   | ["lithium","carbon"]                                 |
  | "web"     | ["hydrogen","helium","beryllium","boron","nitrogen"] |
  +-----------+------------------------------------------------------+
集合推导式
格式如下:
{ <term> | <body> }
a := [1, 2, 3, 4, 3, 4, 3, 4, 5]
b := {x | x = a[_]}
$ +---------------------+-------------+
  |          a          |      b      |
  +---------------------+-------------+
  | [1,2,3,4,3,4,3,4,5] | [1,2,3,4,5] |
  +---------------------+-------------+
规则
集合
返回结果是一个集合
hostnames[name] { name := sites[_].servers[_].hostname }
hostnames[name]
$ +-------------+-----------------+
  |    name     | hostnames[name] |
  +-------------+-----------------+
  | "beryllium" | "beryllium"     |
  | "boron"     | "boron"         |
  | "carbon"    | "carbon"        |
  +-------------+-----------------+
对象
返回结果是一个可检索的对象
apps_by_hostname[hostname] = app {
    some i
    server := sites[_].servers[_]
    hostname := server.hostname
    apps[i].servers[_] == server.name
    app := apps[i].name
}
apps_by_hostname["helium"]
$ "web"
增量定义
增量定义实际就是逻辑或
如下,将servers 和containers 数据抽象为 instances:
instances[instance] {
    server := sites[_].servers[_]
    instance := {"address": server.hostname, "name": server.name}
}
instances[instance] {
    container := containers[_]
    instance := {"address": container.ipaddress, "name": container.name}
}
完整定义
除了使用部分规则定义集合和对象,还可以使用完整规则,完整规则忽略了head中的key,通常用于表示常量
pi := 3.14159
完整定义一次性赋予一个值,如下将32和4赋值给max_memory就会发生错误
# Power users get 32GB memory.
max_memory = 32 
# Restricted users get 4GB memory.
max_memory = 4 
$ module.rego:8: eval_conflict_error: complete rules must not produce multiple outputs
使用:=时,每个包中只能声明一个相同名称的完整定义:
package example
pi := 3.14
# some other rules...
pi := 3.14156   # Redeclaration error because 'pi' already declared above.
函数
Rego支持自定义函数,这些函数可以与内置函数一样调用。函数可以有任意多个输入,但只能有一个输出
trim_and_split(s) = x {
     t := trim(s, " ")
     x := split(t, ".")
}
trim_and_split(" foo.bar ")
$ [
    "foo",
    "bar"
  ]
一个函数可以定义多次,用于实现通过条件来选择所要执行的函数:
q(1, x) = y {
    y := x
}
q(2, x) = y {
    y := x*4
}
q(1, 2)
$ 2
q(2, 2)
$ 8
但在调用时需要注意,入参不能匹配多个函数
r(1, x) = y {
    y := x
}
r(x, 2) = y {
    y := x*4
}
r(1, 2)
$ module.rego:3: eval_conflict_error: functions must not produce multiple outputs for same inputs
注意,如果无法匹配到函数,则结果是未定义的:
s(x, 2) = y {
    y := x * 4
}
s(5, 3)
$ undefined decision
否定
t {
    greeting := "hello"
    not greeting == "goodbye"
}
t
$ true
下面用于分别找出在和不在prod环境的app:
prod_servers[name] {
    site := sites[_]
    site.name == "prod"
    name := site.servers[_].name
}
apps_in_prod[name] {
    app := apps[_]
    server := app.servers[_]
    prod_servers[server] #过滤出在prod的app,行与行之间是与的关系,如果不存在则不会执行下一个语句,即name不会被赋值
    name := app.name
}
apps_not_in_prod[name] {
    name := apps[_].name
    not apps_in_prod[name]
}
全量(FOR ALL)
Rego没有直接的方式来表示全量("FOR ALL")。例如需要找出名称非"bitcoin-miner"的app时,使用如下方式是错误的,无论apps中是否存在名为"bitcoin-miner"的app,最终都会返回true
no_bitcoin_miners {
    app := apps[_]
    app.name != "bitcoin-miner"  # THIS IS NOT CORRECT.
}
可以使用如下方式来实现上述目的:
no_bitcoin_miners_using_negation {
    not any_bitcoin_miners
}
any_bitcoin_miners {
    some i
    app := apps[i]
    app.name == "bitcoin-miner"
}
此外还可以使用推导式实现:
no_bitcoin_miners_using_comprehension {
    bitcoin_miners := {app | app := apps[_]; app.name == "bitcoin-miner"}
    count(bitcoin_miners) == 0
}
模块
在rego中,策略被定义在模块中,一个模块需要包含:
注释
使用#进行注释
package
包可以将一个或多个模块中的规则打包到特定的命名空间中。
import
模块中可以使用data和input引用文本
如在 kubernetes.admission中定义了一个规则 deny:
package kubernetes.admission
deny[msg] {
    input.request.kind.kind == "Pod"
    some i
    image := input.request.object.spec.containers[i].image
    not startswith(image, "hooli.com/")
    msg := sprintf("image '%v' comes from untrusted registry", [image])
}
在另一个包中可以通过如下方式引用deny规则:
{
    "user": "alice",
    "action": "read",
    "object": "id123",
    "type": "dog"
}
package app.rbac
import data.kubernetes.admission
deny[input.user]
some关键字
With 关键字
with关键字允许查询以编程方式指定嵌套在input 文档 和data 文档下的值。with关键字充当表达式的修饰符。一个表达式可以有零或多个with修饰符。
格式如下,必须是对input文档或data文档中的值的引用。当应用于data文档时,不能尝试部分定义虚拟文档(例如一个给定的虚拟文档路径为data.foo.bar,如果策略试图替换data.foo.bar.baz,那么编译器将产生错误)。
<expr> with <target-1> as <value-1> [with <target-2> as <value-2> [...]]
举例如下:
allow with input as {"user": "charlie", "method": "GET"} with data.roles as {"dev": ["charlie"]}
with关键字仅影响连接表达符,后续表达式将看到未修改的值。下面是一种例外(input.foo=1,input.bar=2),outer中的输入在middle中进行了计算
inner := [x, y] {
    x := input.foo
    y := input.bar
}
middle := [a, b] {
    a := inner with input.foo as 100
    b := input
}
outer := result {
    result := middle with input as {"foo": 200, "bar": 300} #middle中修改了a
}
{
    "inner": [
        1,
        2
    ],
    "middle": [
        [
            100,
            2
        ],
        {
            "bar": 2,
            "foo": 1
        }
    ],
    "outer": [
        [
            100,
            300
        ],
        {
            "bar": 300,
            "foo": 200
        }
    ]
}
Default 关键字
default关键字允许策略为具有完整定义的规则生成的文档定义默认值。格式如下:
default <name> = <term>
用法如下,如果没有default,则会返回undefined
default allow = false
allow {
    input.user == "bodddb"
    input.method == "GEdddT"
}
allow {
    input.user == "aliddce"
}
Else 关键字
与编程语言中的else类似
authorize = "allow" {
    input.user == "superuser"           # allow 'superuser' to perform any operation.
} else = "deny" {
    input.path[0] == "admin"            # disallow 'admin' operations...
    input.source_network == "external"  # from external networks.
} # ... more rules
操作符
成员和迭代:in
需要import future.keywords。成员操作符in用于检查一个元素是否存在于array, set, 或 object中,返回true或false。
import future.keywords.in
p = [x, y, z] {
    x := 3 in [1, 2, 3]            # array
    y := 3 in {1, 2, 3}            # set
    z := 3 in {"foo": 1, "bar": 3} # object
}
{
  "p": [
    true,
    true,
    true
  ]
}
当在in操作符左侧提供两个参数,且右侧为object或array,则第一个参数作为key(object)或index(array):
import future.keywords.in
p := [ x, y ] {
    x := "foo", "bar" in {"foo": "bar"}    # key, val with object
    y := 2, "baz" in ["foo", "bar", "baz"] # key, val with array
}
{
  "p": [
    true,
    true
  ]
}
注意在列表(如集合或数组以及函数参数)上下文中需要使用圆括号来让两侧参数一一对应
import future.keywords.in
p := x {
    x := { 0, 2 in [2] } #这是一个集合,表示0和2 in [2]
}
q := x {
    x := { (0, 2 in [2]) }#这是一个集合,但计算的是0, 2 in [2]
}
w := x {
    x := g((0, 2 in [2]))#g(x)只有一个参数,需要使用圆括号括起来
}
z := x {
    x := f(0, 2 in [2])#f(x)有两个参数,第一个参数是0,第二个参数是2 in [2]
}
f(x, y) = sprintf("two function arguments: %v, %v", [x, y])
g(x) = sprintf("one function argument: %v", [x])
与not结合使用,可以很方便地断言一个元素是否是数组的成员:
import future.keywords.in
deny {
    not "admin" in input.user.roles
}
test_deny {
    deny with input.user.roles as ["operator", "user"]
}
{
  "test_deny": true
}
使用some,可以根据不同的类型引入新的变量
import future.keywords.in
p[x] {
    some x in ["a", "r", "r", "a", "y"]
}
q[x] {
    some x in {"s", "e", "t"}
}
r[x] {
    some x in {"foo": "bar", "baz": "quz"}
}
{
  "p": [
    "a",
    "r",
    "y"
  ],
  "q": [
    "e",
    "s",
    "t"
  ],
  "r": [
    "bar",
    "quz"
  ]
}
使用两个参数可以检索object的关键字和array的索引
import future.keywords.in
p[x] {
    some x, "r" in ["a", "r", "r", "a", "y"] # key variable, value constant
}
q[x] = y {
     some x, y in ["a", "r", "r", "a", "y"] # both variables
}
r[y] = x {
    some x, y in {"foo": "bar", "baz": "quz"}
}
{
  "p": [
    1,
    2
  ],
  "q": {
    "0": "a",
    "1": "r",
    "2": "r",
    "3": "a",
    "4": "y"
  },
  "r": {
    "bar": "foo",
    "quz": "baz"
  }
}
some变量的任何参数都可以是复合的非基础值:
import future.keywords.in
p[x] = y {
    some x, {"foo": y} in [{"foo": 100}, {"bar": 200}]#x为key为foo的数组索引,y为key为foo的值
}
p[x] = y {
    some {"bar": x}, {"foo": y} in {{"bar": "b"}: {"foo": "f"}} # x为bar的值,y为foo的值
}
{
  "p": {
    "0": 100,
    "b": "f"
  }
}
等式:赋值,比较和联合
Rego支持三种等式:赋值(:=),比较()和联合(=)。建议使用赋值(:=)和比较()。
赋值 :=
可以使用一种简单的解构形式将数组中的值解包并将其分配给变量
address := ["3 Abbey Road", "NW8 9AY", "London", "England"]
in_london {
    [_, _, city, country] := address
    city == "London"
    country == "England"
}
{
  "address": [
    "3 Abbey Road",
    "NW8 9AY",
    "London",
    "England"
  ],
  "in_london": true
}
比较 ==
联合 =
Rego会将比较为真的值赋于变量。联合可以赋予变量使表达式为true的值。
sites[i].servers[j].name = apps[k].servers[m]
+---+---+---+---+
| i | j | k | m |
+---+---+---+---+
| 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 1 |
| 0 | 2 | 1 | 0 |
| 1 | 0 | 0 | 2 |
| 1 | 1 | 0 | 3 |
| 1 | 2 | 1 | 1 |
| 2 | 0 | 0 | 4 |
| 2 | 1 | 2 | 0 |
+---+---+---+---+
比较表达式
a  ==  b  #  `a` is equal to `b`.
a  !=  b  #  `a` is not equal to `b`.
a  <   b  #  `a` is less than `b`.
a  <=  b  #  `a` is less than or equal to `b`.
a  >   b  #  `a` is greater than `b`.
a  >=  b  #  `a` is greater than or equal to `b`.
内置函数
内置函数的格式如下:
<name>(<arg-1>, <arg-2>, ..., <arg-n>)
错误
默认情况下,遇到运行时错误的内置函数调用会将结果设为undefined (通常可以被视为false),且不会停止策略计算。这种方式可以保证在使用调用内置函数时,输入无效参数不会导致整个策略停止计算。
策略相关
Assignment and Equality
# assign variable x to value of field foo.bar.baz in input
x := input.foo.bar.baz
# check if variable x has same value as variable y
x == y
# check if variable x is a set containing "foo" and "bar"
x == {"foo", "bar"}
# OR
{"foo", "bar"} == x
Lookup
Arrays
# lookup value at index 0
val := arr[0]
 # check if value at index 0 is "foo"
"foo" == arr[0]
# find all indices i that have value "foo"
"foo" == arr[i]
# lookup last value
val := arr[count(arr)-1]
# with `import future.keywords.in`
some 0, val in arr   # lookup value at index 0
0, "foo" in arr      # check if value at index 0 is "foo"
some i, "foo" in arr # find all indices i that have value "foo"
Objects
# lookup value for key "foo"
val := obj["foo"]
# check if value for key "foo" is "bar"
"bar" == obj["foo"]
# OR
"bar" == obj.foo
# check if key "foo" exists and is not false
obj.foo
# check if key assigned to variable k exists
k := "foo"
obj[k]
# check if path foo.bar.baz exists and is not false
obj.foo.bar.baz
# check if path foo.bar.baz, foo.bar, or foo does not exist or is false
not obj.foo.bar.baz
# with `import future.keywords.in`
o := {"foo": false}
# check if value exists: the expression will be true
false in o
# check if value for key "foo" is false
"foo", false in o
Sets
# check if "foo" belongs to the set
a_set["foo"]
# check if "foo" DOES NOT belong to the set
not a_set["foo"]
# check if the array ["a", "b", "c"] belongs to the set
a_set[["a", "b", "c"]]
# find all arrays of the form [x, "b", z] in the set
a_set[[x, "b", z]]
# with `import future.keywords.in`
"foo" in a_set
not "foo" in a_set
some ["a", "b", "c"] in a_set
some [x, "b", z] in a_set
Iteration
Arrays
# iterate over indices i
arr[i]
# iterate over values
val := arr[_]
# iterate over index/value pairs
val := arr[i]
# with `import future.keywords.in`
some val in arr    # iterate over values
some i, _ in arr   # iterate over indices
some i, val in arr # iterate over index/value pairs
Objects
# iterate over keys
obj[key]
# iterate over values
val := obj[_]
# iterate over key/value pairs
val := obj[key]
# with `import future.keywords.in`
some val in obj      # iterate over values
some key, _ in obj   # iterate over keys
some key, val in obj # key/value pairs
Sets
# iterate over values
set[val]
# with `import future.keywords.in`
some val in set
Advanced
# nested: find key k whose bar.baz array index i is 7
foo[k].bar.baz[i] == 7
# simultaneous: find keys in objects foo and bar with same value
foo[k1] == bar[k2]
# simultaneous self: find 2 keys in object foo with same value
foo[k1] == foo[k2]; k1 != k2
# multiple conditions: k has same value in both conditions
foo[k].bar.baz[i] == 7; foo[k].qux > 3
For All
# assert no values in set match predicate
count({x | set[x]; f(x)}) == 0
# assert all values in set make function f true
count({x | set[x]; f(x)}) == count(set)
# assert no values in set make function f true (using negation and helper rule)
not any_match
# assert all values in set make function f true (using negation and helper rule)
not any_not_match
any_match {
    set[x]
    f(x)
}
any_not_match {
    set[x]
    not f(x)
}
Rules
In the examples below ... represents one or more conditions.
Constants
a = {1, 2, 3}
b = {4, 5, 6}
c = a | b
Conditionals (Boolean)
# p is true if ...
p = true { ... }
# OR
p { ... }
Conditionals
default a = 1
a = 5 { ... }
a = 100 { ... }
Incremental
# a_set will contain values of x and values of y
a_set[x] { ... }
a_set[y] { ... }
# a_map will contain key->value pairs x->y and w->z
a_map[x] = y { ... }
a_map[w] = z { ... }
Ordered (Else)
default a = 1
a = 5 { ... }
else = 10 { ... }
Functions (Boolean)
f(x, y) {
    ...
}
# OR
f(x, y) = true {
    ...
}
Functions (Conditionals)
f(x) = "A" { x >= 90 }
f(x) = "B" { x >= 80; x < 90 }
f(x) = "C" { x >= 70; x < 80 }
open policy agent 语法总结的更多相关文章
- Dapr 集成 Open Policy Agent
		大型项目中基本都包含有复杂的访问控制策略,特别是在一些多租户场景中,例如Kubernetes中就支持RBAC,ABAC等多种授权类型.Dapr 的 中间件 Open Policy Agent 将Reg ... 
- Policy Gradient Algorithms
		Policy Gradient Algorithms 2019-10-02 17:37:47 This blog is from: https://lilianweng.github.io/lil-l ... 
- 用sc命令查询系统状态
		用sc命令查询系统状态 sc query 语法 sc query - Enumerates status for active services & driver ... 
- vpn找不到设备,win7建立新的VPN总时显示错误711,无法启动 Remote Access Connection Manager 及 Remote Access Auto Connection Manager 错误1068
		试试相关服务!一.remote access connection manager是网络连接的服务,它依赖于Technology服务,现在你的这个服务已经启动,而Secure Socket Tunne ... 
- [讨论] win7封装时如何直接开通局域网共享
		ekincheng 发表于 2016-10-31 20:17:54 https://www.itsk.com/thread-371838-1-5.html Win7封装时不能像XP那样直接开启局域网共 ... 
- 终极优化_详解Win7旗舰版系统中可以关闭的服务
		Win7旗舰版系统是一款功能强大的系统,不过对于很多用户很多功能却使用不上,而支持功能的很多服务也多少占用了系统资源,那么我们可以通过关闭一些不使用的服务来达到让win7系统运行速度加快的目的.下面小 ... 
- Secure Socket Tunneling Protocol Service服务无法启动(win7)
		第一种方法: 1.确认一下服务都开启: Base Filtering Engine IKE and Authip IPsec Keying Module Ipsec Policy Agent Wind ... 
- win2003 服务器安全设置详细介绍
		第一步:一.先关闭不需要的端口 我比较小心,先关了端口.只开了3389 21 80 1433(MYSQL)有些人一直说什么默认的3389不安全,对此我不否认,但是利用的途径也只能一个一个的穷举爆破, ... 
- Win7 服务优化个人单机版
		我的PC设备比较旧了,为了系统能流畅点,不必要的服务就不开启了.然而,服务那么多,每次重装,都要从头了解一下一边,浪费时间. 个人在网络上收集信息并结合自己的摸索,整理如下,以备查找. 服务名称 显 ... 
随机推荐
- Redis 的 3 种集群方案对比
			数据持久化 主从复制 自动故障恢复 集群化 数据持久化本质上是为了做数据备份,有了数据持久化,当Redis宕机时,我们可以把数据从磁盘上恢复回来,但在数据恢复之前,服务是不可用的,而且数据恢复的时间取 ... 
- Orthogonal Convolutional Neural Networks
			目录 概 主要内容 符号说明 的俩种表示 kernel orthogonal regularization orthogonal convolution Wang J, Chen Y, Chakrab ... 
- 利用 jQuery 操作页面元素的方法,实现电商网站购物车页面商品数量的增加和减少操作,要求单项价格和总价随着数量的改变而改变
			查看本章节 查看作业目录 需求说明: 利用 jQuery 操作页面元素的方法,实现电商网站购物车页面商品数量的增加和减少操作,要求单项价格和总价随着数量的改变而改变 当用户单击"+" ... 
- Docker | dockerfile 文件编写
			dockerfile 的作用 dockerfile 作用就是制作镜像,保持开发,测试,生产环境的一致性. 直接将容器制作为镜像 制作新的镜像 # 把容器按照自己的需求个性完之后,就可以创建自己的镜像的 ... 
- openmesh - impl - Remove Duplicated Vertices
			openmesh - impl - Remove Duplicated Vertices 关于openmesh元素删除实现的介绍参见:openmesh - src - trimesh delete a ... 
- Fuchsia OS入门官方文档
			Fuchsia Pink + Purple == Fuchsia (a new Operating System) Welcome to Fuchsia! This document has ever ... 
- LINUX学习-PHP安装
			一.安装环境 操作系统CentOS6.8 关闭SeLinux和iptables防火墙 二.网络yum源 将下面的软件下载到 /etc/yum.repos.d/ 的目录下 官方基础:http:// ... 
- WAFW00F waf识别工具 源码学习
			我实习工作的第一个任务根据已有的java waf识别工具 实现了一个python的waf识别工具 代码结构非常乱 仅仅达到了能用的水平. 顶头svp推荐这个项目当时我已经写好了开始用了自己的 稍微看了 ... 
- EF4中多表关联查询Include的写法
			大家好,好久没有写作了,最近遇到了个问题,最终是靠自己的尝试写出来的,希望可以帮到有需要的人. 在我们查询时通常会遇到多级表关联的情况,很多时候有人会想写一个from LINQ语句来解决,那么冗长的代 ... 
- Solon 开发,七、自定义注解开发汇总
			Solon 开发 一.注入或手动获取配置 二.注入或手动获取Bean 三.构建一个Bean的三种方式 四.Bean 扫描的三种方式 五.切面与环绕拦截 六.提取Bean的函数进行定制开发 七.自定义注 ... 
