Агент открытой политики удовлетворяет условию для всех элементов массива

Пытаюсь на время осмыслить эту проблему - у меня есть вход 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 часто не стоит - рекомендую делать это только при необходимости.

Другие вопросы по тегам