Test your Policy Code

Testing your policy

This guide will show you how to write and run test cases for your Polar policy.

Prerequisites

💡

You can skip this section if you've completed the quickstart.

Install the oso-cloud command line tool


$ curl -L https://cloud.osohq.com/install.sh | bash

Create an Oso Cloud API key for your environment.

How to add and run a test

To start, assume that you have the following policy saved at PATH_TO_POLICY:


actor User {}
resource Organization {
permissions = ["read"];
roles = ["owner"];
"read" if "owner";
}
resource Repository {
permissions = ["push"];
roles = ["maintainer"];
relations = { parent: Organization };
"maintainer" if "owner" on "parent";
"push" if "maintainer";
}

A simple test for your policy would be to check that a user can only read organizations they own.

This would look like:


test "owners can read organizations" {
setup {
has_role(User{"bob"}, "owner", Organization{"acme"});
}
assert allow(User{"bob"}, "read", Organization{"acme"});
assert_not allow(User{"bob"}, "read", Organization{"bigco"});
}

If you add this to your policy and run


oso-cloud test PATH_TO_POLICY

Oso will:

  • assume that you've written a single fact to Oso: that the user Bob has the "owner" role on Acme
  • check that Bob can "read" Acme
  • check that Bob cannot "read" Bigco

If either of those checks are false (Bob cannot read Acme or he can read Bigco) then the tests have failed.

We'll use this example to walk through the components of a test in more detail.

Anatomy of a test

Polar tests live in the same file as your policy.

There are four keywords used to define a test: test, setup, assert, and assert_not.

test

A test's name must be unique, as it is used to report the results of a test run.

Example:


test "owners can read organizations" {
# ...
}

setup

Inside the test block, you can have one optional setup block, where you declare the facts that your test case depends on. All the facts in a setup block must have literal arguments (no variables).

Each fact in a setup block is validated just like in an client Oso client tell call.

Example:


test "owners can read organizations" {
setup {
has_role(User{"bob"}, "owner", Organization{"acme"});
}
# ...
}

assert and assert_not

A test block needs at least one assert or assert_not statement (we'll refer to both of these as "assertions").

These statements assert that a rule implication is true or false, respectively. Just like the facts in a setup block, rule implications in assertions must have literal arguments.

To assert that a user is authorized to perform a particular action, you can write an assertion against the built-in allow rule.

assert allow(User{"bob"}, "read", Organization{"acme"});

You can write assertions against any rule, not just allow.

Example:


test "owners can read organizations" {
# ...
assert allow(User{"bob"}, "read", Organization{"acme"});
assert_not allow(User{"bob"}, "read", Organization{"bigco"});
}

Running tests

You can run tests via the Oso Cloud CLI test command:


oso-cloud test PATH_TO_POLICY

💡

Note that running tests will not save your policy or setup facts, nor will it use any of the facts that you may have written to your environment.

The test command is ephemeral, so that you can run tests as part of a development loop without affecting your environment. If you want to save your policy, you'll need to explicitly call the oso-cloud policy PATH_TO_POLICY command.

Putting it all together

We already have a basic test asserting that Bob can only read organizations he owns:


test "owners can read organizations" {
setup {
has_role(User{"bob"}, "owner", Organization{"acme"});
}
assert allow(User{"bob"}, "read", Organization{"acme"});
assert_not allow(User{"bob"}, "read", Organization{"bigco"});
}

We can also test that, as an owner of Acme, Bob can push to any of Acme's repository, since owners inherit the "maintainer" role on all of their organization's repositories.

We'll re-use the setup block from our first test, but we'll add a fact indicating that Acme has a repository called "Anvils".

In addition to asserting that Bob is can push to the anvils repository, we can also assert that he has inherited that maintainer role.


test "owners are maintainers" {
setup {
has_role(User{"bob"}, "owner", Organization{"acme"});
has_relation(Repository{"anvils"}, "parent", Organization{"acme"});
}
assert allow(User{"bob"}, "push", Repository{"anvils"});
assert has_role(User{"bob"}, "maintainer", Repository{"anvils"});
assert_not allow(User{"bob"}, "push", Repository{"safes"});
assert_not has_role(User{"bob"}, "maintainer", Repository{"safes"});
}

Talk to an Oso Engineer

If you have any questions about this guide, or you are facing challenges while adding tests to your policy, schedule a 1x1 with an Oso engineer. We're happy to help.

Get started with Oso Cloud →