The Housecarl policy language is the means of applying policies.
Evaluation Engines
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 |
Glob Engine
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 / |
Glob Examples
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/*"
Path Separator Behavior
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.
When to Use Glob vs Other Engines
- Use Glob when you want file-path-like matching with
*and?wildcards - Use Prefix when you only need starts-with matching (faster, simpler)
- Use RegEx when you need character classes
[a-z], alternationa|b, or complex patterns - Use Fixed when you need exact equality matching
Elements
Macros
- Macros are dynamic values that can be referenced in policy statements and are evaluated at request time.
- They provide a powerful way to create flexible and contextual policies.
List of Available Macros
| 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 |
Example Usage
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()"