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://docs/ matches hc://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 / |
// Match any .pdf file in documents (not subdirectories)
{
"engine": "Glob",
"statements": [
{ "object": "hc://documents/*.pdf" }
]
}
// Match email addresses from a domain
{
"engine": "Glob",
"statements": [
{ "subject": "*@example.com" }
]
}
// Match API version endpoints
{
"engine": "Glob",
"statements": [
{ "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 RFC3339 format |
$resource_tenant() | The tenant ID of the resource being accessed |
$resource_owner() | The owner of the resource (if available in context) |
$action_type() | Higher-level categorization of the action (read/write/admin) |
$resource_path() | Path component of the resource being accessed |
$resource_type() | Type of resource being accessed |
$is_admin() | Returns "true" if the user has admin role, otherwise "false" |
{
"name": "Owner access policy",
"description": "Allow access only to resources owned by the current user",
"invert": false,
"deny": false,
"engine": "Fixed",
"statements": [
{
"subject": "$current_user()",
"owner": "$resource_owner()",
"action": "read"
}
]
}