Filter DSL + attribute_path
One filter syntax for triggers, conditions and separation-of-duties rules.
One filter DSL, several use cases
app/core/attribute_path.py is the single source of path resolution and filter evaluation. It drives, among others:
- Workflow definition trigger filters
generate_valueconditional branches- Separation-of-duties (SoD) rule conditions (
condition_a+condition_b) - Rule-based (dynamic)
IGAGroupmembership - Audience and scoping conditions
One mental model — admins learn it once and use it everywhere. In the UI the DSL is the wire format: the default editing surface is picker-based (field + operator + a value picker bound to the real options); the expression editor is the advanced fallback for what a picker cannot express.
resolve_path — four resolution strategies
-
resolve_path("subject.email", subject=ident)— direct ORM column. -
resolve_path("subject.attributes.<key>", subject=ident)— JSONB lookup. -
resolve_path("subject.<key>", subject=ident)— fallback to attributes. -
resolve_path("payload.<dotted>", payload=dict)— dict walk. -
resolve_path("literal:foo")— escape hatch for literals (handy in workflow steps).
Filter DSL — a tree of conditions
{
"all": [
{"path": "subject.department", "op": "eq", "value": "IT"},
{"any": [
{"path": "subject.function", "op": "in",
"value": ["sysadmin", "devops"]},
{"path": "subject.attributes.risk_level", "op": "regex",
"value": "high|critical"}
]}
]
}
all = AND, any = OR. Nest as deep as you need. Leaf conditions are {path, op, value?}.
Operators — what the DSL understands
Equality: eq ne. Membership: in not_in contains includes. Pattern: regex. Existence: exists not_exists. Ordering: gt gte lt lte.
ℹ Good to know
An unknown operator or an unresolvable path makes the filter return False (fail-closed). No exceptions that silently skip rules — you do get a log warning so you can find the typo.
Further reading: