More Concise Policy Tests with “iff” and wildcards

We’re excited to announce new policy test features that let you validate multiple permissions in a single assert statement!

Oso Cloud policy tests are unit tests for your authorization code. You can define initial conditions and assert authorization results right in your policy code. This lets you confirm that your logic yields the expected results before you deploy changes to your authorization code.

In a (very) simple RBAC policy, that might look something like this:

actor User {}

resource Organization {
  roles = ["member"];
  permissions = ["view"];

  # Members can view organizations
  "view" if "member";
}

test "Organization permissions" {
  setup {
    # Alice is a member of the "acme" Organization
    has_role(User{"alice"}, "member", Organization{"acme"});
  }

  # Alice can view the "Acme" organization, but not edit
  assert has_permission(User{"alice"}, "view", Organization{"acme"});
  assert_not has_permission(User{"alice"}, "edit", Organization{"acme"});
}


In smaller policies, it doesn’t take much test code to validate the different authorization paths. But as you add resources, roles, and relations, you need more assertions to make sure everything’s doing what you intend. Let’s add a couple roles and permissions to the policy and see what happens.

actor User {}

resource Organization {
  roles = ["member", "admin", "owner"];
  permissions = ["view", "edit", "delete"];

  # Members can view organizations
  "view" if "member";

  # Admins can edit organizations
  "edit" if "admin";

  # Owners can delete organizations
  "delete" if "owner";

  # Admins can do everything members can do
  "member" if "admin";

  # Owners can do everything admins can do
  "admin" if "owner";
}


With just two more roles and two more permissions, you have to test 9 conditions to make sure all the role/permission combinations work.

test "Organization permissions" {
  setup {
    # Alice is a member of the "acme" Organization
    has_role(User{"alice"}, "member", Organization{"acme"});
    has_role(User{"bob"}, "admin", Organization{"acme"});
    has_role(User{"charlotte"}, "owner", Organization{"acme"});
  }

  # Alice can view the "Acme" organization, but not edit or delete
  assert has_permission(User{"alice"}, "view", Organization{"acme"});
  assert_not has_permission(User{"alice"}, "edit", Organization{"acme"});
  assert_not has_permission(User{"alice"}, "delete", Organization{"acme"});

  # Bob can view or edit the "Acme" organization, but not delete
  assert has_permission(User{"bob"}, "view", Organization{"acme"});
  assert has_permission(User{"bob"}, "edit", Organization{"acme"});
  assert_not has_permission(User{"bob"}, "delete", Organization{"acme"});

  # Charlotte can view, edit, and delete the "Acme" organization
  assert has_permission(User{"charlotte"}, "view", Organization{"acme"});
  assert has_permission(User{"charlotte"}, "edit", Organization{"acme"});
  assert has_permission(User{"charlotte"}, "delete", Organization{"acme"});
}


You can see how this can get unwieldy as you add new assert statements to your tests.

Testing permissions in bulk

To help you keep your tests concise as your policy grows, we’ve introduced two new capabilities:

  1. Variables in assert statements
  2. The iff operator

These let you write a single assertion that tests multiple permissions. Let’s look at some examples:

Instead of writing 3 individual assert statements to confirm that alice can only read the organization, we can instead write this single statement:

  assert has_permission(User{"alice"}, action: String, Organization{"acme"}) iff action in ["view"];


This simultaneously validates that alice has the view permission and that alice doesn’t have the edit or delete permissions.

You can even use wildcards as variables. Suppose you have a global admin role that should always have every permission, including permissions that don’t exist today but that you may add in the future. You can test that with a wildcard:

assert allow(User{"superadmin"}, _action: String, Organization{"acme"});


This will confirm that the superadmin user will always have permission to perform any action on the acme repository.

The VSCode extension and web editor will now offer a quickfix to update the permissions in the iff clause. So if you add a role or change a permission, you can update any affected test with a single click.

Start simplifying your tests

With assert variables and the iff operator, you can make your tests easier to read and maintain. For more details and examples, check out our policy testing docs. If you have questions or ideas about how we can make policy tests even better, come talk with us on Slack! We’re always up for a policy testing conversation.

Want us to remind you?
We'll email you before the event with a friendly reminder.

Write your first policy