Support Common Expression Language (CEL) in policy conditions
Current Behavior
Policy evaluation today is based on conditions that are evaluated one-by-one, for every component.
Evaluations of conditions do not have a shared context. This means that for certain types of conditions, it is not possible to chain them in a conjunctive way. This is most noticeable for policies that target vulnerability details.
For example, given the policy operator ALL, and the following policy conditions:
- CWE
CONTAINS_ANY666 - Severity
ISHIGH
Policy violations will be will be raised, if:
- Any vulnerability affecting the component has the CWE
666, and - Any vulnerability affecting the component has the severity
HIGH
Whereas in reality, users may want to only receive a violation when the component is affected by a vulnerability that both has the CWE 666, and a HIGH severity.
Proposed Behavior
Instead of introducing a shared context for policy conditions, or complex abstractions and UI elements for such cases, I propose to support expressions instead.
And instead of embedding scripting languages and having to deal with all the security implications that come with that, I propose to use languages that are purpose-built for this kind of thing. A popular choice appears to be the Common Expression Language (CEL). Java bindings are available.
The basic idea would be to define an object model that is passed as input to the CEL evaluator. Users would then be able to provide their conditions as CEL expressions. The policy mentioned above may be implemented like so:
vulnerabilities.exists(v, 666 in v.cwes && (v.severity == "HIGH" || v.severity == "CRITICAL"))
(See macros)
Note
We should not reuse the existing model classes (org.dependencytrack.model) as inputs, as they hold internal fields and may cause unintended side effects, like database interactions, due to them being bound to the ORM. CEL inputs should be clearly defined and limited to useful fields, so that users know what they can expect as input.
Another option we could consider is integration with Open Policy Agent. While CEL can be embedded as library, OPA would be an external application that users need to run. Evaluating conditions will thus also involve network calls, causing a noticeable performance hit.
Supporting an expression language will make the policy engine much more flexible, extensible, and more useful.
Checklist
- [X] I have read and understand the contributing guidelines
- [X] I have checked the existing issues for whether this enhancement was already requested
There may be more areas where support for expressions can be helpful. For example the automated analysis of findings and policy violations (similar to dtapac, which uses OPA).
CEL is increasingly gaining industry traction, with Kubernetes now supporting it natively.
Would not CEL be useful in other places as well?
- Component search
- Vulnerability search (does not yet exist, but should... having a quarter million vulns known to DT and only being able to filter by vulnerability ID is, ummm, less than optimal).
Theoretically yes, but practically it can't be used for those areas.
You can think of CEL expressions as mini programs that run in their own isolated context. You can provide inputs to it, and get an output. CEL is great to perform evaluations on data you already have.
What we'd need for the various search interfaces we have, is something like Jira's JQL, which we can translate to SQL (or JDOQL) behind the scenes. This would require us to define our own grammar, and special care needs to be taken to prevent SQL / JDOQL injections. After all, there's a reason we're not allowing users to run queries directly on the database.
Perhaps there is an even simpler solution, but so far I have failed to find a turnkey general purpose query language.
Note, for the frontend part we can embed monaco, which is the same editor that powers VS Code.
Seems like there are easy ways to plug in custom syntax highlighting, themes, and auto-complete providers.
Error reporting including appropriate editor markers are also straightforward to set up: