Skip to content

Partial Evaluation

The TAM appliance has now been enhanced to include a compile endpoint that supports Partial Evaluation

What is Partial Evaluation?

Partial evaluation is a technique used in Open Policy Agent (OPA) to enhance policy evaluation efficiency. It involves precomputing parts of a policy decision that do not depend on specific input data, thereby minimizing the computational load during runtime when the actual input is provided

The key difference between partial evaluation and normal evaluation is in their outcomes. Normal evaluation results in a decision that can be immediately enforced (e.g., allow or deny). In contrast, partial evaluation produces new policies that can be evaluated later when the previously unknown inputs become available.

Instead of asking TAM to fully evaluate a policy, you can identify certain terms in your policy as unknown and use TAM’s compile API for partial evaluation. TAM will then return the remaining logic as an Abstract Syntax Tree (AST), which is easier to process programmatically and can be converted into other query languages, such as SQL or Elasticsearch DSL.

TAM Compile API requests contain the following fields:
FieldTypeRequiredDescription
inputanyYesThe input document to use during partial evaluation (default: undefined).
unknownsarray[string]NoThe terms to treat as unknown during partial evaluation (default: [“input”]]).

Partially Evaluate a Query

POST: /v1/compile/<<Package Namespace>>/<<Rule Name>>
Content-Type: application/json

An example usecase

However, if the service needs to generate a report that lists all devices with outdated firmware, the policy engine would have to evaluate the firmware version of every device record in the database to filter out those with outdated versions. This process, which requires the policy engine to assess each record individually, would not be efficient for databases with a larger number of records

To address this issue, we would have the policy engine partially evaluate the policy using all known information (in our example, the method). The remaining logic, focused solely on the firmware version, would then be sent to the database for data filtering. By delegating the data filtering to the database, performance concerns would be effectively mitigated.

Sample Policy

package tam.example
default allow := false
allow {
input.method == "GET"
data.device.firmware_version <= input.firmware_version
}

The input passed to the policy looks like:

Example Request

POST: /v1/compile/tam.example/allow
Content-Type: application/json

Request Body

{
"query": "data.{namespace}.{rule}{condition}", // This is an optional field if not provided it will take the default value of `data.{namespace}.{rule}==true`
"input":{
"method":"GET",
"firmware_version":12
},
"unknowns":["data.device"]
}

Result

{
"decision": {
"id": "efff0ba0-ea43-4926-8889-7f9582faf60e",
"result": {
"queries": [
[
{
"index": 0,
"terms": [
{
"type": "ref",
"value": [
{
"type": "var",
"value": "lte"
}
]
},
{
"type": "ref",
"value": [
{
"type": "var",
"value": "data"
},
{
"type": "string",
"value": "device"
},
{
"type": "string",
"value": "firmware_version"
}
]
},
{
"type": "number",
"value": 12
}
]
}
]
]
}
}
}