# Validating and testing policies

|     |     |
| --- | --- |
|  | This documentation is for<br>a previous<br>version of Cerbos. Choose 0.53.0 from the version picker at the top right or navigate to [https://docs.cerbos.dev](https://docs.cerbos.dev/) for the latest version. |

## Validating policies

You can use the Cerbos compiler to make sure that your policies are valid before pushing them to a production Cerbos instance. We recommend setting up a git hook or a CI step to run the Cerbos compiler before you push any policy changes to production.

```sh
docker run -i -t -v /path/to/policy/dir:/policies ghcr.io/cerbos/cerbos:0.35.1 compile /policies
```

## Testing policies

You can write optional tests for policies and run them as part of the compilation stage to make sure that the policies do exactly what you expect.

Tests are defined using the familiar YAML format as well. A test file must have `_test` suffix in the name and one of the following file extensions: `yaml`, `yml`, or `json`. For example, `album_test.yml`, `album_test.yaml` or `album_test.json`.

### Test suite definition

```yaml
---
name: AlbumObjectTestSuite (1)
description: Tests for verifying the album:object resource policy (2)
options:
  now: "2022-08-02T15:00:00Z" (3)
  lenientScopeSearch: true (4)
  globals: (5)
    my_global_var: foo
principals: (6)
  alicia:
    id: aliciaID
    roles:
      - user
  bradley:
    id: bradleyID
    roles:
      - user
resources: (7)
  alicia_album:
    id: XX125
    kind: album:object
    policyVersion: default
    attr:
      owner: aliciaID
      public: false
      flagged: false
  bradley_album:
    id: XX250
    kind: album:object
    policyVersion: staging
    attr:
      owner: bradleyID
      public: false
      flagged: false
auxData: (8)
  validJWT:
    jwt:
      iss: my.domain
      aud: ["x", "y"]
      myField: value
tests: (9)
  - name: Accessing an album (10)
    options:
      now: "2022-08-03T15:00:00Z" (11)
      lenientScopeSearch: false (12)
      globals: (13)
        my_global_var: bar
    input: (14)
      principals: (15)
        - alicia
        - bradley
      resources: (16)
        - alicia_album
        - bradley_album
      actions: (17)
        - view
        - delete
      auxData: validJWT (18)
    expected: (19)
      - principal: alicia (20)
        resource: alicia_album (21)
        actions: (22)
          view: EFFECT_ALLOW
          delete: EFFECT_ALLOW
      - principal: bradley
        resource: bradley_album
        actions:
          view: EFFECT_ALLOW
          delete: EFFECT_ALLOW
```

### Sharing test fixtures

It is possible to share principals, resources and auxData blocks between test suites stored in the same directory. Create a `testdata` directory in the directory containing your test suite files, then define shared resources, principals and auxData in `testdata/resources.yml`, `testdata/principals.yml`, `testdata/auxdata.yml` respectively (`yaml` and `json` extensions are also supported).

```
tests
├── album_object_test.yaml
├── gallery_object_test.yaml
├── slideshow_object_test.yaml
└── testdata
   ├── auxdata.yaml
   ├── principals.yaml
   └── resources.yaml
```

An example of `testdata/principals.yml`

```yaml
---
principals:
  john:
    id: johnID
    roles:
      - user
      - moderator
```

An example of `testdata/resources.yml`

```yaml
---
resources:
  alicia_album:
    id: XX125
    kind: "album:object"
    attr:
      owner: aliciaID
      public: false
      flagged: false
```

An example of `testdata/auxdata.yml`

```yaml
---
auxData:
  validJWT:
    jwt:
      iss: my.domain
      aud: ["x", "y"]
      myField: value
```

|  | [YAML anchors and overrides](https://www.educative.io/blog/advanced-yaml-syntax-cheatsheet#anchors) are a great way to reduce repetition and reuse definitions in test cases.

For example, the following definitions are equivalent:

| Without anchors and overrides | With anchors and overrides |
| --- | --- |
| ```yaml<br>resources:<br>  alicias_album1:<br>    id: "XX125"<br>    kind: "album:object"<br>    attr:<br>      owner: "alicia"<br>      public: false<br>      flagged: false<br>  alicias_album2:<br>    id: "XX525"<br>    kind: "album:object"<br>    attr:<br>      owner: "alicia"<br>      public: false<br>      flagged: false<br>  alicias_album3:<br>    id: "XX925"<br>    kind: "album:object"<br>    attr:<br>      owner: "alicia"<br>      public: false<br>      flagged: false<br>```<br>yamlCopied! | ```yaml<br>resources:<br>  alicias_album1:<br>    id: "XX125"<br>    kind: "album:object"<br>    attr: &alicia_album_attr<br>      owner: "alicia"<br>      public: false<br>      flagged: false<br>  alicias_album2:<br>    id: "XX525"<br>    kind: "album:object"<br>    attr:<br>      <<: *alicia_album_attr<br>  alicias_album3:<br>    id: "XX925"<br>    kind: "album:object"<br>    attr:<br>      <<: *alicia_album_attr<br>```<br>yamlCopied! |

### Running tests

The `compile` command automatically discovers test files in the policy repository.

```sh
docker run -i -t \
    -v /path/to/policy/dir:/policies \
    ghcr.io/cerbos/cerbos:0.35.1 compile /policies
```

The output format can be controlled using the `--output` flag, which accepts the values `tree` (default), `list` and `json`. The `--color` flag controls the coloring of the output. To produce machine readable output from the tests, pass `--output=json --color=never` to the command.

By default, all discovered tests are run. Use the `--skip-tests` flag to skip all tests or use the `--run` flag to run a set of tests that match a regular expression.

Example: Running only tests that contain 'Delete' in the name

```sh
docker run -i -t \
    -v /path/to/policy/dir:/policies \
    ghcr.io/cerbos/cerbos:0.35.1 compile --run=Delete /policies
```

You can mark entire suites or individual tests in a suite with `skip: true` to skip them during test runs.

Example: Skipping a test

```yaml
---
name: AlbumObjectTestSuite
description: Tests for verifying the album:object resource policy
tests:
  - name: View private album
    skip: true
    skipReason: "Policy under review"
    input:
      principals: ["alicia"]
      resources: ["alicia_private_album"]
      actions: ["view"]
    expected:
      - principal: alicia
        resource: alicia_private_album
        actions:
          view: EFFECT_ALLOW
```

## Validating and testing policies in CI environments

Because Cerbos artefacts are distributed as self-contained containers and binaries, you should be able to easily integrate Cerbos into any CI environment. Simply configure your workflow to execute the commands described in the sections above using either the Cerbos container (you may need to configure mount points to suit your repo structure) or the binary.

### GitHub Actions

- [cerbos-setup-action](https://github.com/cerbos/cerbos-setup-action): Install `cerbos` and `cerbosctl` binaries into your workflow tools cache

- [cerbos-compile-action](https://github.com/cerbos/cerbos-compile-action): Compile and (optionally) test Cerbos policies

Example workflow

```yaml
---
name: PR Check
on:
  pull_request:
    branches:
      - main
jobs:
  cerbosCheck:
    name: Check Cerbos policies
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

- name: Setup Cerbos
        uses: cerbos/cerbos-setup-action@v1
        with:
          version: latest

- name: Compile and test policies
        uses: cerbos/cerbos-compile-action@v1
        with:
          policyDir: policies
```

### GitLab CI

Example pipeline

```yaml
---
stages:
  - prepare
  - compile

download-cerbos:
  stage: prepare
  script:
    - curl https://github.com/cerbos/cerbos/releases/download/v0.35.1/cerbos_0.35.1_Linux_x86_64.tar.gz -L --output /tmp/cerbos.tar.gz
    - tar -xf /tmp/cerbos.tar.gz -C ./
    - chmod +x ./cerbos
  artifacts:
    paths:
      - cerbos

compile-job:
  stage: compile
  dependencies: ["download-cerbos"]
  script:
    - ./cerbos compile ./policies
```

### Dagger

The [Dagger](https://dagger.io/) Cerbos module can be installed by running `dagger install github.com/cerbos/dagger-cerbos`. This module provides a `compile` function for compiling and testing Cerbos policy repositories and a `server` service for starting a Cerbos server.

```yaml
# Compile and run tests on a policy repository
dagger -m github.com/cerbos/dagger-cerbos call compile --policy-dir=./cerbos

# Start a Cerbos server with the default disk driver
dagger -m github.com/cerbos/dagger-cerbos call server --policy-dir=./cerbos up

# Start a Cerbos server instance configured to use an in-memory SQLite policy repository
dagger -m github.com/cerbos/dagger-cerbos call server --config=storage.driver=sqlite3,storage.sqlite3.dsn=:memory:,server.adminAPI.enabled=true up

# View usage information
dagger -m github.com/cerbos/dagger-cerbos call compile --help
dagger -m github.com/cerbos/dagger-cerbos call server --help
```
