Testing + Policy Iteration

Polar: Testing and Policy Iteration

In this guide, we'll cover using Polar's test to build, iterate, and troubleshoot your policies.

This tutorial assumes you have gone over Polar: Introduction.

Policy tests

Polar includes a built-in feature that lets you write unit tests for your policy.

Let's start with the following policy in your Rules editor (opens in a new tab).


actor User {}
resource Organization {}
# Members can view organizations
has_permission(user: User, "view", organization: Organization) if
has_role(user, "member", organization);
test "Polar testing and iteration" {
setup {
has_role(User{"alice"}, "member", Organization{"acme"});
}
assert has_permission(User{"alice"}, "view", Organization{"acme"});
assert_not has_permission(User{"alice"}, "edit", Organization{"acme"});
}

This policy includes tests inside a test block, ensuring that this logic behaves as we expect when dealing with authorization requests.

While you can read a detailed account of the feature in the Polar reference, the basic structure is:

  • test lets you define a scope for a single unit test
  • setup provides authorization data for the lifetime of the test
  • The remainder of the block declares whether conditions should be true (assert) or false (assert_not)

The tests above ensure that admins receive the edit privilege while members do not.

Once you have the test in your policy, press Run tests in the rules editor, which produces a window letting your know all of the tests passed.

allow vs. has_permission

Though the examples above uses has_permission as the predicate in the tests, it is more conventional to use the allow predicate.

For example:


test "Polar allow" {
setup {
has_role(User{"alice"}, "member", Organization{"acme"});
}
assert allow(User{"alice"}, "view", Organization{"acme"});
}

This works because Oso treats allow as a special rule––if you do not define your own allow rule, Polar uses it as an alias for has_permission.

Polar does this so that when your client's make authorization decisions, they can query the allow rule. This way you can also choose to customize the default behavior of authorization requests.

For more details on this interaction, see Default & custom allow rules.

When to use test

Polar's builtin test feature has many uses:

  • Provide unit tests to run in your CI + CD pipeline.
  • Verify your policy's behavior without worrying about authorization data.
  • Iterate on and troubleshoot your policies. For example, you can write and run tests countless times before deploying policy changes to an environment.
  • Explain and demonstrate potentially complex rule interactions in your policy.

test best practices

  • Ensure each actor and resource you define in your policy are present in tests, especially if they have complex interactions.
  • Avoid exhaustively testing all possible combinations of elements. While it can seem appealing, exhaustive tests are difficult to read, reason about, and maintain.
  • Trim tests before deploying. For example, if you used test for debugging, not all tests you wrote need to make it to the environment.