Minka Ledger Docs
Explanations

About Status Policies

DateResponsibleChanges
July 15, 2024@Luis FidelisInitial version

What is a status policy?

Status policies are used to define which custom statuses a record can have as well as the required quorum to change to these statuses. They have schema status which defines a specific structure of policy rules contained in values of the policy.

POST /v2/policies
 
{
  ...,
  data: {
    handle: '...',
    schema: 'status',
    record: '<record>',
    filter: { ... },
    values: [ ... ]
  }
}

At root level, the status policy can have fields which limit the policy to specific records:

  • record - defines that policy is only for specific record type, optional, if not defined policy applies to all record types
  • filter - record must match the filter in order for policy to be applied to it, optional, if not defined policy applies to all records
POST /v2/policies
 
{
    ...,
    "data": {
        "handle": "fintech-wallet-status",
        "schema": "status",
        "record": "wallet",
        "filter": { "data.schema": "fintech" }
        "values": [ ... ]
        }]
    }
}

The principle open unless whitelisted which we follow in all kinds of ledger rules is valid here also. So if for a record whose status is to be changed there is not any matching status policy (by record and filter) then the operation will be accepted. Otherwise the operation needs to be explicitly granted by one of applicable policy rules.

Property filter represents standard ledger filtering concept where language used in filter expression is mongo-compatible. This concept is already used in: access rules and effects.

Statuses policies are exposed on the same endpoint as access policies with distinction that the schema property is equal to status while for access policies schema is access. Schema of the policy record defines the structure of values array in policy.

Constraining quorum for statuses

POST /v2/policies
 
{
    ...,
    "data": {
    "handle": "wallet-status",
    "schema": "status",
    "record": "wallet",
    "values": [{
        "quorum": [{
            "public": "WAweF9PHlboQoW0z8NqhZXFmzUTaV74NRFAd/aILprE="
        }]
    }]
    }
}

In the above case, in order for status to be changed there must be a proof with custom.status made by a signer with public key WAweF9PHlboQoW0z8NqhZXFmzUTaV74NRFAd/aILprE= as specified in the quorum field of a policy. Quorum is array of signer references which follows the same structure as the signer references in access rules and policies. For example record owner can also be referenced in policy by using "quorum": [{ "$record": "owner" }] .

If based on policies, the signer is not in quorum required to set a status, or if additional proofs are required by quorum list, there will be no error. Only side effect will be that proof with status will be stored in record proofs but record status will not be changed.

Except quorum, the rule in status policy has optional field status which makes a rule applicable only to specific status. The policy below will requires a proof from signer(public) AweF9PHlboQoW0z8NqhZXFmzUTaV74NRFAd/aILprE= to change wallet status to "active". Setting other statuses to wallet will not be allowed unless there is another policy/rule which grants that explicitly.

POST /v2/policies
 
{
    ...,
    "data": {
        "handle": "wallet-active",
        "schema": "status",
        "record": "wallet",
        "values": [{
            "status": "active",
            "quorum": [{
                "public": "WAweF9PHlboQoW0z8NqhZXFmzUTaV74NRFAd/aILprE="
            }]
        }]
    }
}

By default the status in policy rule is string and in this form it represents equality. It can also be a valid mongo compatible sub-expression for matching single object field as shown below by using $in.

POST /v2/policies
 
{
    ...,
    "data": {
        "handle": "wallet-active-inactive",
        "schema": "status",
        "record": "wallet",
        "values": [{
            "status": { $in: ["active", "inactive"] },
            "quorum": [{
                "public": "WAweF9PHlboQoW0z8NqhZXFmzUTaV74NRFAd/aILprE="
            }]
        }]
    }
}

To define a quorum for removing a label from a record, there is special value null. The same value is used in proofs for requesting the status removal.

POST /v2/policies
 
{
    ...,
    "data": {
        "handle": "wallet-remove-status",
        "schema": "status",
        "record": "wallet",
        "values": [{
            "status": null,
            "quorum": [{
                "public": "WAweF9PHlboQoW0z8NqhZXFmzUTaV74NRFAd/aILprE="
            }]
        }]
    }
}

A rule can also allow combination of removing and setting specific statuses, for example: "status": { $in: ["active", "inactive", null] }

Status policies evaluation

When evaluating status policies for setting a status to record there can be multiple matching policies with multiple values and multiple signers in quorum. To easier understand how they are combined the following rules are applied top-down:

  1. If there is at least one status policy which matches the record by record and filter then, in order to allow setting the status of record, at least one policy must be found which allows setting this specific status based on policy rules. If there are no matching policies, then setting of status is allowed to anyone.

  2. Policy can have multiple rules in values field and it is considered that the policy grants setting status to record if at least one rule is found which grants this for this specific status. Empty values array grants nothing.

  3. Single rule can have status field which when exists will make rule applicable only if the desired status matches. If status field is omitted then the rule allows all statuses - according to quorum.

    If there is any policy which matches record/filter for a record but none of them explicitly allows setting specific status then the proof which is to be added is not valid and will be rejected. Proof will not be stored and error response will be returned to caller. Restrictive nature of field status in policy rule is opposite than fields wallet, filter in policy. While setting specific wallet and/or filter in the policy will narrow status restrictions only to records which matches them, setting the specific status in policy rule will narrow the set of acceptable statuses this rule can apply to. So interpretation that rule with status: 'active' implies that quorum is required only for status active is wrong. Correct interpretation is that this rule with its quorum can be used only to grant setting status active.

  4. Rule also has quorum array of signer references and it is used to determine when the status from the proof can be persisted to a record. Quorum step will be evaluated only after all previous steps are executed successfully and the specific status from proof is allowed. Status will be persisted to a record only when all signers referenced in quorum had signed the record with a proof which has the desired status in custom.status. Empty quorum array means that quorum is not required and will cause that status is persisted to record immediately.

    If a proof with status passes steps 1.-4. but the key used in this proof is not in the quorum or if another key is required to fulfill the quorum then the proof will be stored successfully, error will not be returned to caller, but status will not be persisted to record until the quorum of the rule which allows this status is achieved.

  5. When taking existing proofs from a record to evaluate quorum there is special constraint that only last N signatures with same status are taken into consideration. This is required so that proofs used in past to set some status cannot be reused to set this status again in future. This rule is easy to demonstrate and remember with this example: ~~activated activated deactivated deactivated~~ activated

When a record is modified, it may fall under a policy that it does not satisfy. For example, there could be a wallet status policy that requires a signature from a specific key, but only if the wallet record has a schema like fintech. In this scenario, someone could first create a wallet without a schema or with a schema such as bank, then set the status to active and afterward change the schema to fintech. As a result, the wallet status is now subject to the policy, but the status was set without enforcing this policy.

On this page