Skip to main content
This tutorial assumes that you arere familiar with the basics of Polar, facts, and policy tests.If you are not, check out the Introduction to Polar and Testing with Polar pages.
With the Oso Cloud developer tools installed, you can set up a local development workflow for your authorization code. By eliminating dependencies on remote services, tighter feedback loops emerge that helps detect issues more quickly. This workflow helps achieve that loop.
  1. Make a change to your policy
  2. Validate the policy syntax
  3. Add policy tests
  4. Run the policy tests against the Oso Dev Server
  5. Push the updated policy to the Oso Dev Server
  6. Test application code against the updated policy
We’ll illustrate the workflow with a simple example for developers who use Visual Studio Code.

Initial policy

To start with this workflow, you can use the policy below.
policy.polar
actor User {}

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

  "view" if "member";
}

test "example test" {
  setup {
    has_role(User{"alice"}, "member", Organization{"org1"});
  }

  assert allow(User{"alice"}, "view", Organization{"org1"});
}
This policy defines a single actor, User, and a single resource, Organization. The policy states that a User has the view permission on an Organization if they have the member role on that Organization.Open the policy in an editor. With VS Code, it will look like this:
Polar policy in VS Code
Note the “Run Test” link over the test definition in line 10. Click “Run Test” to see the result in the editor window.
Initial test passing in VS Code
The three dots under the name of the rule indicates the test passed. To continue the workflow, add another resource to the policy.

Make a change to the policy

An Organization contains one or more Projects. Add a Project resource to the policy so you can model its authorization logic.
policy.polar
actor User {}

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

  "view" if "member";
}

resource Project {
  roles = ["member"];
  permissions = ["view"];
  relations = {
    organization: Organization
  };

  "member" if "member" on "organization";

  "view" if "member";
}

test "example test" {
  setup {
    has_role(User{"alice"}, "member", Organization{"org1"});
  }

  assert allow(User{"alice"}, "view", Organization{"org1"});
}
The policy now defines a Project resource. It states that a User can inherit the member role on a Project from its parent Organization. Next, you will validate the policy syntax.

Validate the policy syntax

From VS Code

Syntax errors are indicated in the VSCode editor. For example, if you omit a trailing semi-colon, you’ll see something like this:
Syntax error in VS Code editor
The filename is red in the tab and the word relations on line 13 is underlined in red. If you hover over relations, you can see a description of the issue.
Syntax error in VS Code editor with explanation
Once the trailing semi-colon is added, the VS Code editor window removes the red line.
Fixed syntax in VS Code

Using oso-cloud validate

You can also use the oso-cloud validate CLI command to validate the syntax from the command line.
 oso-cloud validate policy.polar
Policy failed validation with 1 errors:

Policy failed validation due to parser error: did not expect to find the token 'relations' at line 13, column 3 of file policy.polar:
	013:   relations = {
	      ^
Once you’ve fixed the problem, oso-cloud validate passes.
 oso-cloud validate policy.polar
Policy validated successfully.

Add policy tests

Next, you will add tests to confirm that the authorization logic for Projects is correct. The initial policy has a test that validates the Organization role logic.
test "example test" {
  setup {
    has_role(User{"alice"}, "member", Organization{"org1"});
  }

  assert allow(User{"alice"}, "view", Organization{"org1"});
}
Now that the Project resource is added, you can add tests to confirm the Project authorization logic. You can create new tests or extend the existing one. For simplicity, we’ll extend the existing test.
test "example test" {
  setup {
    # Project "project1" belongs to Organization "org1"
    has_relation(Project{"project1"}, "organization", Organization{"org1"});
    # User "alice" has the "member" role on Organization "org1"
    has_role(User{"alice"}, "member", Organization{"org1"});
    # User "bob" has the "member" role on Project "project1"
    has_role(User{"bob"}, "member", Project{"project1"});
  }

  # Alice can view the "org1" Organization
  assert allow(User{"alice"}, "view", Organization{"org1"});
  # Alice can view the "project1" Project via inheritance from the "org1" Organization
  assert allow(User{"alice"}, "view", Project{"project1"});

  # Bob can not view the "org1" Organization
  assert_not allow(User{"bob"}, "view", Organization{"org1"});
  # Bob can view the "project1" Project via direct assignment
  assert allow(User{"bob"}, "view", Project{"project1"});

  # Charlie can view neither the "org1" Organization nor the "project1" Project
  assert_not allow(User{"charlie"}, "view", Organization{"org1"});
  assert_not allow(User{"charlie"}, "view", Project{"project1"});
}
Now the test covers the positive and negative cases of all authorization paths for the two resources.

Run the policy tests against the Oso Dev Server

Next, you will run the policy tests against the Oso Development Server running on your local machine.

Start the Oso Dev Server

First, make sure the Oso Dev Server is running. The filename is standalone and you can start it from wherever you saved it.
 ~/.local/bin/standalone
Server is in test mode, use token 'e_0123456789_12345_osotesttoken01xiIn'
The server runs in the foreground and listens on port 8080. On startup, the dev server writes the API key to stdout. You can interact with it from the oso-cloud CLI by setting the OSO_URL and OSO_AUTH environment variables as follows:
 export OSO_URL='http://localhost:3000'
 export OSO_AUTH='e_0123456789_12345_osotesttoken01xiIn'
You can either export the environment variables to set them for the session or prepend them to each oso-cloud command.

Run the policy tests

Run the policy tests against the Oso Dev Server by issuing the oso-cloud test command:
❯ oso-cloud test policy.polar
Loading policy from files:
policy.polar

Ran 1 test:
example test: 6/6 PASS
PASS
If your policy is split into multiple .polar files, you must pass all of them to oso-cloud test.
Once the tests pass, you can push the updated policy to the Oso Dev Server and test your application code against it.

Push the updated policy to the Oso Dev Server

Push the updated policy to the local binary with the oso-cloud policy command:
If your policy is split into multiple .polar files, you must push each .polar file to the Oso Dev Server on any update.
 oso-cloud policy policy.polar
Loading policy from files:
policy.polar

Policy successfully loaded.

Verify the policy (optional)

You can verify that the correct policy is loaded by issuing the oso-cloud policy command without an argument.
 oso-cloud policy
The currently loaded policy will be written to stdout.
You can also start the Oso Dev Server with a list of policy files and the --watch-for-changes flag to instruct it to automatically reload your policy files and rerun tests any time they change. See the docs for more details.
Now you are ready to test your application locally against the updated policy.

Test application code against the Oso Dev Server

Local integration tests and functional tests should run against the local Oso Dev Server after you’ve updated the policy.

Clear old fact data

To ensure that the Oso Dev Server is in a known state before running local integration tests, you can delete all existing facts by either:
  • Issuing the oso-cloud clear command from the command line
  • Invoking the clear_data API endpoint at the Oso Dev Server
Make sure that you run these commands against your local Oso Dev Server instance and not the live Oso Cloud environment.

Re-seed initial state

After deleting old facts from the Oso Dev Server, you can re-seed it with any initial facts that are not recreated by your integration tests. For example, if you have a role table that contains pre-seeded roles, you should add facts for those roles to the Oso Dev Server before starting your tests. If your tests add new roles, you should not pre-seed the Oso Dev Server with facts for those roles. Instead, you should let your application code do that as part of the tests.
Your integration tests should cover all of your code paths, including those that add facts to Oso Cloud. If you preseed facts that are added by your tests, the tests will not identify bugs in code adding those facts.However, if the testing database has an initial state, you should add facts to the Oso Dev Server to mirror the database’s initial state. Otherwise tests that rely on a consistent initial state will fail
We recommend defining the initial state in a script that issues oso-cloud tell commands to the Oso Dev Server for all facts that need to be present before the integration test suite runs.

Initialize the SDK against the Oso Dev Server

To use the Oso Dev Server from your code, you instantiate the client in your application with the dev server’s URL. Refer to the your SDK’s documentation for details. For example, you’d initialize the Node.js client like this:
const { Oso } = require("oso-cloud");

const oso = new Oso(
  "http://localhost:8080",
  "e_0123456789_12345_osotesttoken01xiIn",
);

Conclusion

With the Oso Cloud developer tools, you can build a local development workflow to iterate quickly on authorization code. That workflow follows these steps.
  1. Make a change to your policy
  2. Validate the policy syntax
  3. Add policy tests
  4. Run the policy tests against the Oso Dev Server
  5. Push the updated policy to the Oso Dev Server
  6. Test application code against the updated policy
Once you’ve validated your changes locally and are ready to commit, you’re ready to start moving your code to production. Read the CI/CD doc to learn how to set up a deployment pipeline that works with Oso Cloud.