Docs

Access rules tests

Write who-can-do-what cases in a YAML file, run them against your live access policies or local drafts with sov rules test, read the results, and fail CI with a JUnit report.

Updated Oct 17, 2026Open in console

A rules test states what must happen — "visitors can't change posts", "only staff publish on the news channel" — and checks it against your access policies exactly as live traffic is checked. Nothing is written. Needs sovaria-cli 0.2.10 or newer.

sov rules init                 # writes sovaria.rules.test.yaml to edit
sov rules test                 # exit 1 if any case fails
sov rules test --drafts policies/ --junit rules.xml

The test file

cases:
  - name: visitors can't change posts
    as: guest
    do: update
    on: posts
    expect: deny

  - name: signed-in users can read posts
    as: user
    do: read
    on: posts
    expect: allow

  - name: only staff publish on the news channel
    as: app:staff
    do: publish
    on: news
    expect: allow

  - name: users manage files in their own folder
    as: user
    do: WRITE
    on: avatars
    expect: allow
    context: {actor: {user_id: "u_123"}, storage: {path: "u_123/me.png", folder: "u_123", in_own_folder: true}}
KeyValue
nameWhat the case checks; shown in the results.
asguest (an anonymous visitor), user (any signed-in app user), app:<role> (an app user with that role), team:<role> (a team member with that role, for example team:VIEWER).
doTables: read, insert, update, delete. Documents: doc:read, doc:write, doc:delete. Storage: storage:read (download a file, checks READ), storage:list (list a bucket, LIST), storage:write (upload, WRITE), storage:delete (DELETE). Realtime: subscribe, publish. Any other value is passed to your policies unchanged.
onThe resource: table, collection, bucket, channel or function name (resource: works too).
expectallow or deny. No matching policy counts as deny — Sovaria denies by default.
contextOptional. Merged into the request context your policies read (ctx.*): give the user an id, a storage path, a channel prefix…

Test changes before you deploy them

--drafts <folder> evaluates the *.spl files in that folder together with your live policies. A file named after a live policy's id (<policy-id>.spl) stands in for that policy; any other file is added as a new one. Up to 50 drafts; a draft that doesn't compile stops the run with 422 and the error.

ALLOW IF ctx.resource.name == "posts" AND ctx.action IN ["SELECT", "sql:select"]

Results

PASS  visitors can't change posts  [guest update posts]
FAIL  signed-in users can read posts  [user read posts]  expected allow, got deny (NO_POLICY_DEFINED)
1 of 2 case(s) failed
  • Exit code 0 when every case passes, 1 when any fails (or the request fails), 2 when the file is invalid.
  • --junit <file> writes a JUnit XML report that CI systems show on the pull request.
  • Each run uses one policy simulation from the plan's monthly allowance.
FreeProUltraTeamEnterprise
Policy simulations per month—3001,0003,00020,000
Something unclear or missing on this page?Tell us