Агент открытой политики удовлетворяет условию для всех элементов массива
Пытаюсь на время осмыслить эту проблему - у меня есть вход JSON, содержащий массив, скажем что-то вроде этого:
{
"array" : [
{"foo": "bar"},
{"foo": "buzz"},
{"misbehaving": "object"}
]
}
Моя цель - убедиться, что все объекты в массиве удовлетворяют условию наличия поля с именем foo (фактический вариант использования - убедиться, что все ресурсы в облачном развертывании имеют теги). Моя проблема в том, что стандартные выражения rego оцениваются как "как минимум", а не "все", что означает, что такие выражения, как:
all_have_foo_field {
input.array.foo
}
Всегда возвращают истину, даже если некоторые объекты этому не удовлетворяют. Я смотрел на это, но оценка регулярного выражения возвращаетtrue
или false
в то время как моя политика проверяет, существует ли поле, то есть, если это не так, я получаю ошибку var_is_unsafe.
Есть идеи?
1 ответ
Есть два способа сказать "все поля элементов в X должны соответствовать этим условиям" (ДЛЯ ВСЕХ).
TL; DR:
all_have_foo_field {
# use negation and a helper rule
not any_missing_foo_field
}
any_missing_foo_field {
some i
input.array[i]
not input.array[i].foo
}
ИЛИ
all_have_foo_field {
# use a comprehension
having_foo := {i | input.array[i].foo}
count(having_foo) == count(input.array)
}
Подход зависит от конкретного случая. Если вы хотите знать, какие элементы не удовлетворяют условиям, понимание будет приятным, потому что вы можете использовать арифметику с наборами, например,{i | input.array[i]} - {i | input.array[i].foo}
производит набор индексов массива, не имеющих поля "foo". Возможно, вы захотите назначить эти выражения локальным переменным для удобства чтения. Подробнее см. В этом разделе документации: https://www.openpolicyagent.org/docs/latest/policy-language/.
В этом случае (в отличие от ответа, на который вы ссылаетесь) нам не нужно использовать регулярное выражение или что-либо подобное, поскольку ссылки на отсутствующие / неопределенные поля приводят к неопределенным, а неопределенное распространяется наружу на выражение, запрос, правило и т. Д. в некоторой степени освещается во введении.
Все, что нам нужно сделать, это просто обратиться к рассматриваемому полю. Обратите внимание, техническиnot input.array[i].foo
будет ИСТИНА, если значение поля "foo" false
однако во многих случаях undefined и false
можно рассматривать как взаимозаменяемые (они не совсем одинаковые -false
- допустимое значение JSON, тогда как undefined представляет отсутствие значения.) Если вам нужно сопоставить только undefined, вам нужно присвоить результат ссылки локальной переменной. В случае понимания мы можем написать:
# the set will contain all values i where field "foo" exists regardless
{i | _ = input.array[i].foo}
В случае отрицания нам понадобится дополнительное вспомогательное правило, поскольку not _ = input.array[i].foo
было бы "небезопасно". Мы можем написать:
exists(value, key) { value[key] = _ }`
И сейчас not exists(input[i], "foo")
имеет значение ИСТИНА, только если поле "foo" отсутствует.
Обратите внимание, что различие между undefined и false
часто не стоит - рекомендую делать это только при необходимости.