The Housecarl policy language is the means of applying policies.
Policies use evaluation engines to determine how pattern matching is performed. Choose the engine based on your matching requirements:
| Engine | Matching Style | Best For | Example Pattern |
|---|---|---|---|
Fixed | Exact string equality | Specific resources | alice matches only alice |
Prefix | String starts-with | Hierarchical paths | hc://domain/<uuid>/docs/ matches hc://domain/<uuid>/docs/readme |
RegEx | Regular expressions | Complex patterns | user-[0-9]+ matches user-123 |
Glob | Shell-style wildcards | File-like paths | *.txt matches report.txt |
The Glob engine provides shell-style wildcard matching, similar to file system globs:
| Wildcard | Matches | Does NOT Match |
|---|---|---|
* | Zero or more characters (excluding /) | Path separators |
? | Exactly one character (excluding /) | Empty or / |
Complete deployable policy examples using Glob patterns:
# Match any .pdf file in documents (not subdirectories)
name = "documents-pdf-read"
description = "Allow reading PDF files in the documents folder"
engine = "Glob"
invert = false
deny = false
[[statements]]
action = "read"
object = "hc://domain/550e8400-e29b-41d4-a716-446655440000/documents/*.pdf"
# Match email addresses from a domain
name = "example-domain-users"
description = "Allow users with @example.com emails"
engine = "Glob"
invert = false
deny = false
[[statements]]
subject = "*@example.com"
action = "read"
object = "hc://domain/550e8400-e29b-41d4-a716-446655440000/shared/*"
# Match API version endpoints
name = "api-users-access"
description = "Allow access to any API version user endpoints"
engine = "Glob"
invert = false
deny = false
[[statements]]
action = "read"
object = "/api/v?/users/*"
The * and ? wildcards do not match the path separator /. This provides security and predictable hierarchical matching:
| Pattern | Text | Result |
|---|---|---|
* | file.txt | Match |
* | path/file.txt | No match |
*/file | path/file | Match |
a/*/c | a/b/c | Match |
a/*/c | a/b/d/c | No match |
This behavior follows POSIX fnmatch(3) FNM_PATHNAME semantics and prevents patterns from accidentally matching across directory boundaries.
* and ? wildcards[a-z], alternation a|b, or complex patterns| Macro | Description |
|---|---|
$current_user() | The current authenticated user/subject making the request |
$requestors_tenant() | The tenant ID from which the request originates |
$current_time() | Current UTC time in milliseconds since epoch |
$resource_tenant() | The tenant ID of the resource being accessed |
$resource_path() | Path component of the resource being accessed |
$resource_type() | Type of resource being accessed |
name = "Tenant isolation policy"
description = "Allow users to access resources only within their own tenant"
engine = "Fixed"
invert = false
deny = false
[[statements]]
subject = "$current_user()"
action = "read"
object = "hc://domain/550e8400-e29b-41d4-a716-446655440000/$resource_path()"