Core ConceptsPolicy Engine

Policy Engine


title: Policy Engine description: Deny-by-default движок, который до подписи решает, можно ли двигать деньги и с чьим подтверждением: дерево условий, лимиты, whitelist и m-of-n.

Policy Engine — это контур, через который проходит каждое действие с деньгами, прежде чем что-либо будет подписано: перевод, создание адреса, изменение контрагента. Он отвечает на вопрос «можно ли это сделать и на каких условиях» — и делает это до того, как MPC-ноды соберут подпись.

Движок работает по принципу deny-by-default: по умолчанию не разрешено ничего, действие проходит только если его разрешает политика.

Как принимается решение

Ядро движка — эндпоинт POST /api/v1/evaluate. Он собирает применимые к пользователю политики и выносит вердикт:

Собираются политики пользователя

Все политики, доступные пользователю в этом Vault'е через его членства в группах. Ваши права — это объединение политик ваших групп.

Отбираются подходящие

Остаются только включённые (enabled) политики с типом действия, равным запрошенному (actionType = action).

Проверяется применимость

У каждой политики — булево дерево условий (condition: and / or / not / лист). condition=null означает «применима всегда».

Считается итог (deny-overrides)

Если хотя бы одна применимая политика блокирует — итог block, что бы ни разрешали остальные. Запрет всегда сильнее разрешения.

Поскольку evaluate ничего не меняет, его удобно вызывать заранее — чтобы проверить перевод до создания.

Три исхода: allow, queue, block

Движок возвращает один из трёх вердиктов:

  • allow — действие можно выполнять сразу.
  • queue — нужно подтверждение; операция ждёт как заявка, а сумма остаётся в reserved.
  • block — действие запрещено.

Вместе с решением приходит объяснение — не «отказано», а почему:

{
  "decision": "block",
  "reason": "AMOUNT_EXCEEDED",
  "policyId": "...",
  "policyCode": "...",
  "trace": [
    { "policyCode": "...", "policyName": "...", "effect": "block" }
  ]
}

reason — машиночитаемая причина, trace — список сработавших политик с их effect. Поэтому на вопрос «почему заблокировано» вы отвечаете запросом, а не расследованием.

Из чего состоит политика

У политики есть эффект (allow или block), применимость (дерево условий), правила с селекторами, лимиты, а также owner-группа и approver-группа.

Селекторы сопоставляют действие по осям — сеть, актив, назначение, отправитель, получатель. Это те же сегменты, что и в дереве Vault'а (см. Vault и деривация), поэтому правило пишется по смыслу, а не перечислением адресов.

  • GET /api/v1/policies/{id} — политика со всеми правилами и селекторами, owner- и approver-группами.
  • GET /api/v1/me/allowed-segments — какие значения сегментов разрешены вам для действия. Это объединение по всем вашим allow-политикам: из селекторов отправителя (senderPattern) извлекаются разрешённые значения; политика без senderPattern разрешает всё (*), а block-политики здесь не учитываются.

Лимиты и whitelist

  • Лимиты ограничивают суммы — например, на одну операцию, за период или накопительно. При превышении движок возвращает block или queue с причиной вроде AMOUNT_EXCEEDED.
  • Whitelist — это allow-правило с селектором получателя: разрешены только перечисленные получатели, всё остальное запрещено (следствие deny-by-default).

Точная схема лимитов и селекторов — в Справочнике API. Здесь описан смысл правил, а не формат их записи.

Подтверждения (m-of-n)

Когда итог — queue, решение несёт параметры одобрения:

  • threshold — сколько подтверждений нужно (m из n).
  • approver-группа — кто вправе подтверждать.
  • adminBypass — админ-инициатор выполняет действие без заявки.
  • allowInitiatorApproval — может ли инициатор голосовать за собственную заявку.

Один reject — это вето. Несколько связанных действий можно оформить композитной заявкой: каждый шаг гейтится своей политикой, а отклонение любого шага отклоняет всю цепочку. Жизненный цикл заявок разбирается отдельно, в разделе про аппрувалы.

Версии: ничего не теряется

Политики не перезаписываются «поверх» — каждое изменение фиксируется как новая редакция:

  • GET /api/v1/policies/{id}/versions — append-only история. Любая правка (лимиты, одобряющие, условие) порождает версию со снапшотом решающей части: effect, condition, approval, limits, approvers. Поле reason показывает причину версии (created / updated / backfill).

Заявка запоминает правило на момент своего создания. Поэтому поздние изменения политики не переписывают уже созданные заявки задним числом — подписанты и порог остаются такими, какими были в момент запроса.

Где действует движок

Policy Engine гейтит не только переводы. У каждого действия свой actionType — создание адреса (create_address), архивация контрагента (counterparty_archive) и другие; все проходят через один движок. Списки политик:

  • GET /api/v1/policies?vaultId=... (admin) или GET /api/v1/vaults/{code}/policies — политики Vault'а.
  • GET /api/v1/policy-groups/{id}/policies и /access — политики и доступ группы.

Что дальше