Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.formal.ai/llms.txt

Use this file to discover all available pages before exploring further.

Policies are evaluated at three stages: session (connection time), request (before query execution), and response (after data retrieval). Each stage provides different input data for making policy decisions.
For available enforcement actions at each stage, see Enforcement. If you have existing policies using pre_request / post_request, see Legacy Stage Names.

Policy Scope

By default, policies apply universally to all users, resources, and data locations. You can narrow the scope within each policy using conditions.

User Context Quick Reference

Access user information via input.user and input.end_user:
FieldTypeDescription
usernameStringUnique username
emailStringEmail address (human users only)
groups[]StringGroups the user belongs to
typeStringhuman or machine

Resource Context Quick Reference

Filter by resource via input.resource:
FieldTypeDescription
idStringResource ID
nameStringResource name
technologyStringpostgres, mongodb, snowflake, etc.
hostnameStringResource hostname
environmentStringEnvironment tag

Policy stages

Session stage

Available inputs

NameTypeDescription
policy_idSTRINGID of the policy evaluated.
applicationSTRINGName of the application.
client_ip_addressSTRINGIP address of the client.
tlsBOOLEANTells if the connection between Proxy and client is encrypted with TLS.
db_nameSTRINGName of the database.
native_userSTRINGNative user making a connection to the database.
native_user_assignmentSTRINGHow the native user was assigned: user-requested, user, group, default, or resource-hostname.
userUser ObjectThe user making a connection to the database. User object includes name, email and groups.
end_userUser ObjectIf the user is a machine user, the end user is the user behind the application, otherwise the end user has the same value as the user.
deviceDevice ObjectDevice information.
agentAgent ObjectAI agent context. Populated when the connection originates from an AI coding agent via the Formal Desktop App.
resourceResource ObjectThe Resource being queried.
connectorConnector ObjectThe current Connector.
httpHTTP ObjectHTTP request details. Populated for HTTP-based resources, including LLM.
awsAWS ObjectAWS resources for SSH and Kubernetes.
kubernetesKubernetes ObjectKubernetes resource context for Kubernetes.
snowflakeSnowflake ObjectSnowflake specific information.
spaceSpace ObjectSpace specific information.

Available actions

For this policy stage, two types of actions are possible: allow and block.

Request stage

Request rules are evaluated by the proxy when it intercepts a request (query) just before sending it to the resource. This evaluation stage is especially useful in blocking write requests.

Available inputs

NameTypeDescription
policy_idSTRINGID of the policy evaluated.
application.nameSTRINGName of the application.
client_ip_addressSTRINGIP address of the client.
sql_querySQL Query ObjectSQL query.
querySQL Query ObjectSQL query. (alias)
db_nameSTRINGName of the database.
user_typeENUMUnderlying type used by the user to connect to the database, can be formal or native.
schema_paths[]STRINGList of the schema paths that are accessed by a query.
table_paths[]STRINGList of the table paths that are accessed by a query.
userUser ObjectThe user making a connection to the database. User object includes name, email and groups.
end_userUser ObjectIf the user is a machine user, the end user is the user behind the application, otherwise the end user has the same value as the user.
deviceDevice ObjectDevice information.
agentAgent ObjectAI agent context. Populated when the connection originates from an AI coding agent via the Formal Desktop App.
spaceSpace ObjectSpace information.
row[]Column ObjectRows of data being queried.
resourceResource ObjectThe Resource being queried.
connectorConnector ObjectThe current Connector.
httpHTTP ObjectHTTP request details. Populated for HTTP-based resources, including LLM.
snowflakeSnowflake ObjectSnowflake specific information.

Available actions

For this policy stage, three types of actions are possible: allow, block, and rewrite.

Response stage

Response rules are evaluated by the proxy when it intercepts data received from the resource. This evaluation stage is particularly useful in the context of masking or filtering read requests.

Available inputs

NameTypeDescription
policy_idSTRINGID of the policy evaluated.
applicationSTRINGName of the application.
client_ip_addressSTRINGIP address of the client.
sql_querySQL Query ObjectSQL query.
querySQL Query ObjectSQL query. (alias)
db_nameSTRINGName of the database.
schema_paths[]STRINGList of the schema paths that are accessed by a query.
table_paths[]STRINGList of the table paths that are accessed by a query.
table_names[]STRINGList of the table names that are accessed by a query.
row[]Column ObjectRows of data being queried.
userUser ObjectThe user making a connection to the database. User object includes name, email and groups.
end_userUser ObjectIf the user is a machine user, the end user is the user behind the application, otherwise the end user has the same value as the user.
deviceDevice ObjectDevice information.
agentAgent ObjectAI agent context. Populated when the connection originates from an AI coding agent via the Formal Desktop App.
resourceResource ObjectThe Resource being queried.
connectorConnector ObjectThe current Connector.
httpHTTP ObjectHTTP response details. Populated for HTTP-based resources, including LLM.
snowflakeSnowflake ObjectSnowflake specific information.
spaceSpace ObjectSpace specific information.

Available actions

For this policy stage, four types of actions are possible: allow, filter, mask, decrypt.

Standard input data

Policies can access various data types, including user information, resource information, SQL query information, and HTTP request information. The following sections describe the available data types.

User object

ValueTypeDescription
usernameSTRINGUsername of the user
emailSTRINGIf it’s a human user, their email address
groups[]STRINGGroups in which the user is included
typeSTRINGType of the user, can be either human or machine

Connector object

ValueTypeDescription
idSTRINGID of the Connector
nameSTRINGName of the Connector

Resource object

ValueTypeDescription
idSTRINGID of the Resource
nameSTRINGName of the Resource
technologySTRINGTechnology of the Resource
hostnameSTRINGHostname of the Resource
hostname_nameSTRINGName of the Hostname of the Resource
environmentSTRINGEnvironment of the Resource
portSTRINGPort of the Resource

Column object

ValueTypeDescription
nameSTRINGName of the column
data_labelSTRINGLabel assigned to the column
json_pathSTRINGJSON path of the column
data_typeSTRINGData type of the column
valueSTRINGValue of the column
in_functions[]Function ObjectList of functions that the column is used in
input.row lists all columns extracted from your SQL query. A single returned column can come from multiple source columns (e.g. when using wildcards, joins, or unions), and thus result in several policy columns. When the Connector cannot resolve a source, the returned column itself stands in as its own policy column. This column lineage mapping is then used by the Connector’s policy engine: a response rule that masks a policy column will be able to mask every returned column whose lineage includes it. For example, in SELECT email FROM users UNION SELECT email FROM customers, the returned email column has two source columns: users.email and customers.email. Either one alone is enough to mask it for the entire result.

Function object

ValueTypeDescription
nameSTRINGName of the function (e.g. MAX)
categories[]STRINGCategories of the function (e.g. ["aggregate", "window"])
Function categories are used to group functions into different categories. The following categories are available: aggregate, bitwise, conditional, context, conversion, data_generation, date_time, differential_privacy, encryption, file, geospatial, hash, metadata, notification, numeric, scalar, semi_structured, string_and_binary, system, table, vector_similarity, window. These categories are inspired by the Snowflake documentation.

Space object

ValueTypeDescription
nameSTRINGName of the space
idSTRINGID of the space

HTTP object

ValueTypeDescription
hostnameSTRINGUpstream hostname (e.g. api.anthropic.com)
methodSTRINGHTTP method
pathSTRINGRequest path
headersOBJECTHTTP headers as a map from header name to string array. Header names are normalized to lowercase in policy input.
bodySTRINGRaw HTTP body, when available
jsonOBJECTParsed JSON body, when the body is valid JSON and the content type is JSON

Native users

You can enforce policies on native users, the user used by the proxy to connect to the underlying resource. For example, here is a policy that allows the connection only if the native user is reader:
package formal.v2

import future.keywords.if
import future.keywords.in

default session := { "action": "block", "type": "block_with_formal_message" }

session := { "action": "allow", "reason": "reader native user" } if {
	input.native_user == "reader"
}

Native user assignment

The native_user_assignment field tells you how the native user was resolved for the current session. Possible values are:
ValueDescription
user-requestedThe user explicitly specified the native user in the connection
userAssigned via a user identity link
groupAssigned via a group membership link
resource-hostnameAssigned via a resource hostname link
defaultUsing the default native user for the resource
For example, the following policy blocks connections where the user explicitly overrides their native user assignment:
package formal.v2

import future.keywords.if

default session := { "action": "allow" }

session := { "action": "block", "type": "block_with_formal_message", "message": "Manual native user override is not allowed" } if {
	input.native_user_assignment == "user-requested"
}

Snowflake resources

You can enforce policies on Snowflake resources based on the role used to connect to the resource.

Snowflake object

ValueTypeDescription
roleSTRINGRole used to connect to the Snowflake resource

SQL resources

Formal can also enforce policies specific to SQL queries. SQL Query Object
ValueTypeDescription
querySTRINGSQL query
statement_typeSTRINGType of the SQL statement
command_typeSTRINGType of the SQL command
limitINTLimit of the SQL query
transaction_in_progressBOOLEANWhether a transaction is currently in progress. Postgres only.
transaction_history[]STRINGList of the most recent statements executed in the current transaction (up to 15). Postgres only.

Example: Run all SQL statements in a transaction in order

You can use a workflow to create a policy suspension that ensures a sequence of SQL statements is executed in the correct order within a transaction. The workflow below accepts a list of ordered statements via its API trigger and creates a suspension that validates each statement matches the expected sequence using transaction_history.
trigger:
  type: api-request
  name: my_workflow_trigger
  args:
    allow: <allow expression here>
actions:
- type: formal-app-command
  name: create_policy_suspension
  args:
    app: Policies
    command:
      name: PolicySuspension
      type: Create
    machine_user_id: <machine user id>
    input:
      policy_id: <policy id>
      identity_type: user
      identity_id: ${{trigger.user.id}}
      input_condition: "input.sql_query.transaction_in_progress && size(input.sql_query.transaction_history) < size(${{trigger.payload.transaction}}) && lists.range(size(input.sql_query.transaction_history)).all(i, ${{trigger.payload.transaction}}[i] == input.sql_query.transaction_history[i]) && ${{trigger.payload.transaction}}[size(input.sql_query.transaction_history)] == input.sql_query.query"
      oneoff: false
      expiration_minutes: 60

AWS resources

Formal can also enforce policies on specific AWS Resources. These policies can be actively used for the SSH or Kubernetes.

AWS object

ValueTypeDescription
accountAccount ObjectAWS account
ecsECS ObjectConfiguration details for ECS resources
ec2EC2 ObjectConfiguration details for EC2 instances
eksEKS ObjectConfiguration details for EKS resources

ECS object

ValueTypeDescription
cluster_nameSTRINGName of the ECS cluster
service_nameSTRINGName of the ECS service
task_idSTRINGID of the ECS task
container_nameSTRINGName of the ECS container

EC2 object

ValueTypeDescription
tags[]STRINGTags of the EC2 instance
instance_idSTRINGIdentifier of the EC2 instance

EKS object

ValueTypeDescription
cluster_ arnSTRINGAmazon Resource Name (ARN) of the EKS cluster
cluster_nameSTRINGName of the EKS cluster

Kubernetes resources

Formal can enforce policies on Kubernetes API requests based on the resource being accessed. The Kubernetes context is available via input.kubernetes.

Kubernetes object

ValueTypeDescription
groupSTRINGAPI group of the resource (e.g. apps). Empty string for core API resources.
group_versionSTRINGAPI version of the resource (e.g. v1).
namespaceSTRINGNamespace of the resource. Empty for cluster-scoped resources.
kindSTRINGKind of the resource (e.g. pods).
nameSTRINGName of the specific resource. Empty for list or collection operations.
subresourceSTRINGSubresource being accessed (e.g. exec).
verbSTRINGKubernetes API verb: get, list, watch, create or the lower-cased HTTP method for non-resource requests (e.g. get for /healthz).

LLM resources

Formal can enforce policies on LLM API sessions. Use session rules to block a connection before it reaches the upstream provider, request rules to inspect and rewrite outgoing request headers, and response rules to evaluate model responses.
Tool calls are part of the model response, so policies that inspect input.llm.tool_calls should use the response rule.

LLM object

ValueTypeDescription
providerSTRINGLLM provider name (e.g. anthropic, openai)
modelSTRINGLLM model name
stop_reasonSTRINGReason the model stopped generating
input_tokensINTNumber of input tokens
output_tokensINTNumber of output tokens
tool_calls[]Tool Call ObjectTool/function calls made by the model
provider_session_idSTRINGProvider’s session identifier

Tool call object

ValueTypeDescription
nameSTRINGName of the tool/function called
idSTRINGUnique identifier for the call
inputObjectArguments passed to the tool

Example: Rewrite request headers

The following policy adds request headers before the LLM request is sent to the upstream provider. Header values must be arrays of strings. Set a header to an empty array to remove it.
package formal.v2

import future.keywords.if

rewritten_headers := object.union(input.http.headers, {
  "anthropic-allowed-org-ids": ["aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"],
})

request := {
  "action": "rewrite",
  "headers": rewritten_headers,
} if {
  input.resource.technology == "llm"
}

Example: Block specific tool calls

The following policy blocks any LLM response that includes a Bash tool call with a specific command:
package formal.v2

import future.keywords.if
import future.keywords.in

response := {"action": "block", "type": "block_with_formal_message"} if {
  some tool_call in input.llm.tool_calls
  tool_call.name == "Bash"
  tool_call.input.command == "echo hi"
}

MCP resources

Formal can enforce policies on MCP tool calls. The MCP context is available via input.mcp at the request and response stages when the request is a tool call.

MCP object

ValueTypeDescription
tool_nameSTRINGName of the MCP tool being called (e.g. read_file, delete_file)
tool_paramsObjectParameters passed to the tool

Example: Block a specific tool

package formal.v2

import future.keywords.if

default request := {"action": "allow"}

request := {"action": "block", "type": "block_with_formal_message"} if {
  input.mcp.tool_name == "list_pull_requests"
}

Device

Formal can also enforce policies on specific device attributes.
This feature is only available for devices using the Formal Desktop App.

Device info object

ValueTypeDescription
hardwareHardware Info ObjectHardware information of the device
softwareSoftware Info ObjectSoftware information of the device

Hardware info object

ValueTypeDescription
model_nameSTRINGModel name of the device
model_identifierSTRINGModel identifier of the device
model_numberSTRINGModel number of the device
system_firmware_versionSTRINGSystem firmware version of the device
os_loader_versionSTRINGOS loader version of the device
serial_numberSTRINGSerial number of the device
hardware_uuidSTRINGHardware UUID of the device
provisioning_udidSTRINGProvisioning UDID of the device
activation_lock_statusSTRINGActivation lock status of the device

Software info object

ValueTypeDescription
system_versionSTRINGSystem version of the device
kernel_versionSTRINGKernel version of the device
boot_volumeSTRINGBoot volume of the device
boot_modeSTRINGBoot mode of the device
computer_nameSTRINGComputer name of the device
user_nameSTRINGUser name of the device
secure_virtual_memorySTRINGSecure virtual memory of the device
system_integrity_protectionSTRINGSystem integrity protection of the device
time_since_bootSTRINGTime since boot of the device

AI agents

Formal tracks connections that originate from AI coding agents running through the Formal Desktop App. When an agent is detected, input.agent is populated with context about that agent.
input.agent is only populated for connections made via the Formal Desktop App. It is empty for direct connections.

Agent object

ValueTypeDescription
typeSTRINGThe agent type (e.g. claude-code, cursor, codex_cli_rs).
providerSTRINGThe LLM provider used by the agent (e.g. anthropic, openai).
provider_session_idSTRINGThe LLM provider’s session ID for the current conversation.
versionSTRINGThe version of the agent.
yolo_modeBOOLEANtrue if the agent was launched with the --dangerously-skip-permissions flag. This flag is specific to Claude Code and bypasses its interactive permission prompts, allowing it to execute tool calls without user confirmation.

Example: block Claude Code in YOLO mode

Use input.agent.yolo_mode to block autonomous agents from accessing sensitive resources without per-action approval:
package formal.v2

import future.keywords.if

default session := {"action": "allow"}

session := {"action": "block", "type": "block_with_formal_message"} if {
    input.agent.yolo_mode == true
}

Policy Input Retention

Formal can optionally retain these inputs for policy backtesting where you can test policies on historical data.

Extending Policies with External Data

You can extend policies with custom data fetched by Policy Data Loaders. The data is accessible via the data object using the loader’s configured key. Example:
# If your Policy Data Loader has key "approved_users"
data.approved_users.user_ids
For more information, see Policy Data Loaders.

Legacy Stage Names

Prior to Connector v1.31.19, the Rego rule names for the request and response stages were pre_request and post_request. These legacy names still work and existing policies do not need to be updated. To migrate, rename pre_request to request and post_request to response in your policy code. Different policies can use different naming conventions.