Skip to main content

Filter Language

Most Workshop API methods that begin with List (e.g., ListHosts, ListRules, ListEvents) support filtering results using a standardized filter language.

Overview​

The filter system is:

  • Generic: Works across all API types that support filtering
  • Type-safe: Validates field names and types against the protobuf schema at runtime
  • AIP-160 compliant: Based on Google's AIP-160 filtering standard

Filters are provided as a string in the filter field of List request messages:

message ListHostsRequest {
int32 page_size = 1;
int32 page = 2;
string filter = 3; // Filter expression goes here
string order_by = 4;
}

The fields available for filtering will match those in the type returned in the response message. For example, the ListHostsResponse message looks like this:

message ListHostsResponse {
repeated Host hosts = 1;
optional bool more = 2;
}

The fields available for filtering are those on the Host message:

message Host {
string uuid = 1;
string serial = 2;
string machine_model = 3;
// remaining fields elided for brevity
}

Basic Syntax​

Simple Equality​

hostname = 'example-host'

Comparison Operators​

last_seen_client_mode > 1
last_seen_client_mode >= 1
last_seen_client_mode < 3
last_seen_client_mode <= 3
last_seen_client_mode != 2

String Pattern Matching (Case-Insensitive)​

The : operator performs a case-insensitive pattern match (SQL ILIKE):

hostname:'r%' # Hostnames starting with 'r'
hostname:'%dev%' # Hostnames containing 'dev'

Boolean Logic​

AND Operator​

hostname = 'homer' AND last_seen_client_mode > 1

OR Operator​

hostname = 'homer' OR hostname = 'marge'

NOT Operator​

NOT (hostname = 'homer')

Operator Precedence​

AND has higher precedence than OR. Use parentheses to control evaluation order:

tags_locked = true AND hostname = 'homer' OR hostname = 'marge'
# Evaluates as: (tags_locked = true AND hostname = 'homer') OR (hostname = 'marge')

Special Values​

Boolean Literals​

tags_locked = true
tags_locked = TRUE # Case-insensitive
tags_locked = false
tags_locked = FALSE

NULL Values​

hostname = NULL # Becomes: hostname IS NULL
hostname != NULL # Becomes: hostname IS NOT NULL

Timestamp Fields​

Timestamp fields can be compared using Unix timestamps (seconds since epoch):

rule_sync_time > 946688400 # After 2000-01-01 01:00:00 UTC

Current Time​

Use NOW() to get the current timestamp:

rule_sync_time > NOW() # Rule sync time is in the future

Time Arithmetic​

Use ADD() and SUB() to perform arithmetic on timestamps:

rule_sync_time > SUB(NOW(), 3600) # Within the last hour (3600 seconds)
rule_sync_time > SUB(NOW(), 86400) # Within the last 24 hours
rule_sync_time < ADD(NOW(), 86400) # Within the next 24 hours

These functions take two integer arguments and return the result:

FunctionDescriptionExample
ADD(a, b)Returns a + bADD(NOW(), 3600)
SUB(a, b)Returns a - bSUB(NOW(), 3600)

Both arguments must be numeric values (not field references).

Enum Fields​

Enum fields can be queried by their string identifier or numeric value:

last_seen_client_mode = 'MONITOR' # Using enum identifier
last_seen_client_mode = 1 # Using numeric value

The filter system validates enum identifiers against the protobuf enum definition at runtime.

Repeated Fields​

IN Operator with Repeated Fields​

Check if a value exists within a repeated field:

IN('dev', tags) # Check if 'dev' is in the tags array
IN('prod', tags) # Check if 'prod' is in the tags array

IN Operator with Multiple Values​

Check if a field matches any value in a list:

IN(hostname, 'homer', 'marge', 'bart')
IN(last_seen_client_mode, 1, 2)
IN(last_seen_client_mode, 'LOCKDOWN', 'STANDALONE')

Counting Array Elements​

Use .count to get the number of elements in a repeated field:

tags.count > 0 # Has at least one tag
tags.count = 3 # Has exactly 3 tags
tags.count < 5 # Has fewer than 5 tags

Nested Fields​

For message types that contain nested messages, use dot notation:

host.hostname = 'kvothe'
host.last_seen_client_mode = 'MONITOR'

Example with IN() on nested fields:

IN(host.hostname, 'kvothe', 'bast')

Complex Examples​

Multiple Conditions​

hostname:web% AND tags.count > 0 AND last_seen_client_mode = 'MONITOR'

Combining OR and AND​

(hostname = 'web-1' OR hostname = 'web-2') AND tags_locked = false

Checking for Tagged Production Hosts​

IN('prod', tags) AND hostname:prod-%

Type Safety​

The filter system validates:

  1. Field existence: Referenced fields must exist in the protobuf message
  2. Field types: Argument types must match the field type
  3. Enum values: String enum identifiers must be valid for the enum type
  4. Repeated field operations: .count can only be used on repeated fields

Common Type Errors​

# ERROR: Type mismatch (string vs int64)
hostname = 42

# ERROR: Type mismatch (enum vs float64)
last_seen_client_mode = 3.14

# ERROR: Type mismatch (bool vs int64)
tags_locked = 1

# ERROR: Invalid enum identifier
last_seen_client_mode = 'INVALID_MODE'

# ERROR: .count on non-repeated field
hostname.count > 1

Error Messages​

When a filter fails validation, you'll receive an error describing the problem:

field "MissingField" referenced in filter does not exist or is not exported
type of argument 42 (int64) in filter isn't convertible to type of field "hostname" (StringKind)
argument FLARGLE is not valid for the enum santa.sync.v1.ClientMode

See Also​