Skip to main content

directory-package-mismatch

Summary: Directory structure should mirror package

Category: Idiomatic

Automatically fixable: Yes

Rationale

Quickly finding the package you're looking for in a policy repository is made much easier when package paths are mirrored in the directory structure of your project. Meaning that if the name of your package is permissions.users.claims, it should reside in a file under the permissions/users/claims directory. Note however that any number of files can contribute to the same package! The permissions/users/claims directory may thus contain several policy files that all declare package permissions.users.claims.

Example

An example of directory structure for a project following this convention might look like this:

# Directory structure                   # Package path
.
├── README.md
└── bundle
└── authorization
├── main.rego # authorization
└── rbac
├── data.json # authorization.rbac
├── roles
│   └── roles.rego # authorization.rbac.roles
│   └── roles_test.rego # authorization.rbac.roles_test
└── users
├── customers.rego # authorization.rbac.users
├── customers_test.rego # authorization.rbac.users_test
├── internal.rego # authorization.rbac.users
└── internal_test.rego # authorization.rbac.users_test

Tests

Astute observers may notice that the test files in the example above are placed in the same directory as the policies they test. This may seem to contradict the test-outside-test-package rule, which says that any test package should have a _test suffix in its package path. However, putting tests next to the file they target arguably makes it easier to find, and is a common practice in the OPA community. This rule therefore by default ignores the _test suffix when determining whether the package path matches the directory structure.

This behavior can be changed by setting the exclude-test-suffix configuration option to false, in which case package paths with a _test suffix also will be required to reside in a directory with a _test suffix. Notably, this directory structure is used (and enforced) by Styra DAS and projects that integrate with it.

Setting the exclude-test-suffix option to false means the example from above would now look like this:

# Directory structure                   # Package path
.
├── README.md
└── bundle
└── authorization
├── main.rego # authorization
└── rbac
├── data.json # authorization.rbac
├── roles
│   └── roles.rego # authorization.rbac.roles
├── roles_test
│   └── roles_test.rego # authorization.rbac.roles_test
├── users
│   ├── customers.rego # authorization.rbac.users
│   └── internal.rego # authorization.rbac.users
└── users_test
├── customers_test.rego # authorization.rbac.users_test
└── internal_test.rego # authorization.rbac.users_test

Whichever way you choose is up to you. Consistency is key!

Bundles

While directory structure doesn't matter to OPA when parsing policies, directories parsed as bundles will read data (data.json or data.yaml) files and insert the data in the data document tree based on the directory structure relative to the bundle root. Having policies structured in the same manner provides a uniform experience, and makes it easier to understand where both policies and data come from.

Editor Support

Editors integrating Regal's language server will automatically display suggestions for idiomatic package paths based on the directory structure in which a policy resides. The image below demonstrates a new policy being created inside an authorization/rbac/roles directory, and the editor (via Regal) suggesting the package path authorization.rbac.roles.

Package path auto-completion in VS Code

In addition, empty files will be be 'formatted' to have the correct package based on the directory structure. Newly created Rego files are treated in much the same way. When a new file is created, the server will send a series of edits back to set the content. If exclude-test-suffix is set to false, the file will also be moved if required to the _test directory for that package.

Configuration Options

This linter rule provides the following configuration options:

rules:
idiomatic:
directory-package-mismatch:
# one of "error", "warning", "ignore"
level: error
# exclude _test suffixes from package paths before comparing
# them to directory structure paths. when set to false, a
# package like authz.policy_test would need to be placed in
# an authz/policy_test directory, and if set to true (default)
# would be expected to be in authz/policy
exclude-test-suffix: true

Community

If you think you've found a problem with this rule or its documentation, would like to suggest improvements, new rules, or just talk about Regal in general, please join us in the #regal channel in the Styra Community Slack!