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
.
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
Related Resources
- Rego Style Guide: Package name should match file location
- Regal Docs: test-outside-test-package
- OPA Docs: Bundles
- Styra Docs: Styra DAS
- GitHub: Source Code
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!