Testing & Validating Policies
Run verdict validate to check policy syntax and lint diagnostics, and verdict test to verify access boundaries before publishing. Both commands run directly against your .vd file without needing a running server or live database.
Writing inline policy tests
Section titled “Writing inline policy tests”Place test "name" { ... } blocks directly inside a .vd file to set up temporary fixture facts and verify decisions with assert and assert not:
declare has_role(User, string, Organization);declare has_relation(Document, string, Organization);
allow(user: User, "read", document: Document) if has_relation(document, "organization", org: Organization) and has_role(user, "member", org);
test "organization members can read organization documents" { has_relation(Document:handbook, "organization", Organization:acme); has_role(User:alice, "member", Organization:acme);
assert allow(User:alice, "read", Document:handbook);}Each test block runs in isolation with its own fixture facts. When you publish a policy to Verdict Server, test blocks are excluded from the compiled rules and never enter your live fact store.
verdict test policy.vdTesting boundaries and negative cases
Section titled “Testing boundaries and negative cases”A reliable test suite checks both positive grants and the boundaries where access must be denied:
- Action boundaries: A user granted
"read"is denied"edit". - Unprivileged actors: A user with no matching role or share is denied access.
- Cross-tenant isolation: A member of
Organization:acmeis denied access toOrganization:globexresources. - Resource restrictions: Archiving a document blocks
"edit"even when organization membership grants edit permission.
Suppose your policy derives "read" and "edit" permissions from organization membership, accepts direct has_permission shares, and blocks edits on archived documents (Permissions):
declare has_role(User, string, Organization);declare has_relation(Document, string, Organization);declare has_permission(User, string, Document);declare is_archived(Document);
has_permission(user: User, "read", document: Document) if has_relation(document, "organization", org: Organization) and has_role(user, "member", org);
has_permission(user: User, "edit", document: Document) if has_relation(document, "organization", org: Organization) and has_role(user, "member", org);
allow(user: User, "read", document: Document) if has_permission(user, "read", document);
allow(user: User, "edit", document: Document) if has_permission(user, "edit", document) and not is_archived(document);You can test each boundary in focused test blocks:
test "enforces role, action, and tenant boundaries" { has_relation(Document:handbook, "organization", Organization:acme); has_relation(Document:roadmap, "organization", Organization:globex);
has_role(User:alice, "member", Organization:acme); has_permission(User:bob, "read", Document:handbook);
// Positive grants assert allow(User:alice, "edit", Document:handbook); assert allow(User:bob, "read", Document:handbook);
// Action boundary: read-only collaborator cannot edit assert not allow(User:bob, "edit", Document:handbook);
// Cross-tenant boundary: Acme member cannot read or edit Globex document assert not allow(User:alice, "read", Document:roadmap); assert not allow(User:alice, "edit", Document:roadmap);}
test "archived documents reject edits" { has_relation(Document:handbook, "organization", Organization:acme); has_role(User:alice, "member", Organization:acme); is_archived(Document:handbook);
assert allow(User:alice, "read", Document:handbook); assert not allow(User:alice, "edit", Document:handbook);}assert and assert not can test any predicate in your policy, including intermediate helpers like has_permission(User:alice, "edit", Document:handbook).
Validating policies
Section titled “Validating policies”Run verdict validate to catch syntax errors and lint warnings such as typos in predicate names (undefined-predicate) or accidental arity mismatches (mixed-arity):
verdict validate policy.vdStatic validation checks that your policy is well-formed, while verdict test verifies that your rules enforce the right access boundaries. See Policy Diagnostics for every diagnostic code and remedy.
Configuring warning gates
Section titled “Configuring warning gates”By default, verdict validate exits with code 1 on warnings as well as errors. To print warnings while exiting 0 when no errors are present, pass --allow-warnings:
verdict validate --allow-warnings policy.vdPass --skip-warnings to suppress warning output entirely. See validation settings and the validate CLI reference for per-file directives and flags.
Formatting and CI checks
Section titled “Formatting and CI checks”Run formatting (verdict fmt), validation, and tests together in CI so every policy change is checked before merge:
verdict fmt --check policy.vdverdict validate policy.vdverdict test policy.vdEach command exits 0 on success and 1 on failure. Pass --json to verdict validate and verdict test for structured machine output.
Next steps
Section titled “Next steps”- Look up complete
.vdsyntax, operators, and validation rules in the Language Reference. - Review CLI flags and exit codes in the CLI reference.
- Publish your verified policy in Publishing Policies and synchronize application data in Managing Facts.