Policies
Policies are YAML, evaluated deterministically and locally.
apiVersion: guard.unveilr.ai/v1alpha1
kind: Policy
metadata:
name: protect-production
spec:
rules:
- id: protect-iam
description: Agents may not perform dangerous IAM changes.
match:
action.provider: aws
action.name: [iam:PassRole, iam:AttachRolePolicy, iam:PutRolePolicy]
effect: deny
Effects
Ordered by increasing restriction:
| Effect | Meaning |
|---|---|
allow | Forward the call |
redact | Forward with matched content removed |
sanitize | Forward with content normalised |
scoped_token | Substitute a narrowed credential |
require_approval | Hold pending a human decision |
step_up | Demand stronger authentication |
deny | Refuse |
Some effects need infrastructure a local binary does not have.
require_approval and step_up need somewhere to route the request and someone
to answer it; scoped_token needs a broker. Locally these degrade rather than
silently passing — see Open source vs Enterprise.
Combination is forbid-overrides
The most restrictive matching effect wins, so adding a policy can never widen access.
That property is worth internalising, because it makes policy composition safe to reason about: you never have to check whether a new rule accidentally unlocked something. It can only ever restrict further.
Unknown effects fail closed
An effect the binary does not recognise is resolved as the most restrictive effect it knows, not ignored.
This matters more than it sounds. A typo — denny for deny — becomes a block,
not a silently skipped rule. And it is what makes it safe for a newer build to
introduce an effect an older one has never heard of: the old build refuses
rather than waving the call through.
Testing
unveilr policy test --server <id> --tool <name> --args '{"path":"/etc/passwd"}'
Deterministic, needs no agent, and is the intended way to develop a policy. There is no model in the decision path, so a test result is the decision you will get in production against the same inputs.
Schema stability
apiVersion: guard.unveilr.ai/v1alpha1. Pre-1.0, and may change before 1.0 —
breaking changes are documented. The v1alpha1 suffix is the honest signal, not
a formality.