---
title: "Filter Language - Workshop Docs"
description: "Filter Language - Enterprise control plane for Santa. Manage rules, approvals, telemetry, and policies across your macOS fleet."
doc_version: "1"
last_updated: "2026-05-22"
canonical: "https://northpole.security/docs/workshop/filter-language"
---
# 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](https://google.aip.dev/160)

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`](https://buf.build/northpolesec/workshop-api/docs/main:workshop.v1#workshop.v1.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:

Function

Description

Example

`ADD(a, b)`

Returns a + b

`ADD(NOW(), 3600)`

`SUB(a, b)`

Returns a - b

`SUB(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

-   [AIP-160: Filtering](https://google.aip.dev/160) - Google’s API Improvement Proposal for filtering

## Sitemap

- [Home](https://northpole.security/index.md)
- [Workshop](https://northpole.security/workshop.md)
- [Santa](https://northpole.security/santa.md)
- [Features](https://northpole.security/features.md)
- [Cookbook](https://northpole.security/cookbook.md)
- [Docs](https://northpole.security/docs.md)
- [Blog](https://northpole.security/blog.md)
- [Glossary](https://northpole.security/glossary.md)
- [About](https://northpole.security/about.md)
- [Contact](https://northpole.security/contact.md)
