Variables and matching
Variables let a single rule apply across any user or resource in your domain. In .vd, a variable is a logical placeholder: when the same variable name appears in multiple places in a rule, every occurrence must match the exact same value.
Matching concrete checks and open queries
Section titled “Matching concrete checks and open queries”Variables can appear in both rule definitions and evaluation goals:
allow(user: User, "read", document: Document) if same_organization(user, document);- Concrete check (
allow(User:alice, "read", Document:handbook)): Supplies concrete values for every position. Verdict bindsusertoUser:aliceanddocumenttoDocument:handbook, then evaluatessame_organization(User:alice, Document:handbook). - Open query (
allow(User:alice, "read", doc: Document)): Leaves one or more positions as variables. Verdict finds everyDocumentidentity that satisfies the rule forUser:aliceand returns those bindings.
If a variable appears in a rule head without appearing in the body, it acts as a wildcard for concrete checks (and triggers an unconstrained-head-variable warning by default):
// Grants admins any action on any resource during a concrete check,// but leaves "action" and "resource" unconstrained for open queriesallow(actor: User, action, resource) if is_admin(actor);
Joining facts on shared variables
Section titled “Joining facts on shared variables”Rules often need to inspect an intermediate entity that was not passed in the check, such as the organization a document belongs to. Repeating a variable across conditions joins those facts on the same entity:
same_organization(user: User, document: Document) if belongs_to(document, organization: Organization) and member(user, organization);Because organization appears in both conditions, belongs_to and member must match the same Organization identity. If the two conditions used different variable names (doc_org and user_org), the rule would succeed whenever the document belonged to some organization and the user belonged to any organization.
Equality and comparison operators
Section titled “Equality and comparison operators”Repeating a variable name is the most concise way to require two positions to match. You can also bind or compare values explicitly with =:
is_read(action: string) if action = "read";
allow(user: User, action: string, document: Document) if same_organization(user, document) and is_read(action);- Equality (
=): Unifies its two sides. If both sides already have values,=checks that they match; if one side is an unbound variable,=binds it to the other side’s value. - Inequality and ordering (
!=,<,<=,>,>=): Filter values that have already been bound by the check, a positive fact, or=. They cannot generate a value for an unbound variable. See the Language Reference for complete operator rules.
Restricting matches with type qualifiers
Section titled “Restricting matches with type qualifiers”An unqualified variable like resource can match any identity or scalar value. Adding a : Type qualifier narrows what the variable can match:
| Syntax | Matches |
|---|---|
User:alice | Concrete identity of type User with ID "alice" |
user: User | Variable user restricted to User identities |
action: string | Variable action restricted to scalar string values |
You only need to qualify a variable once in a rule (usually in the head or where it first appears in the body); that constraint applies to every use of the variable in the rule. See Values and identities for how typed identities and scalar values differ.
Next steps
Section titled “Next steps”- Combine requirements,
orbranches, and helper predicates in Combining conditions. - Read and compare entity properties with Attribute access.
- Look up complete binding rules in the Language Reference.