DependencyTrack / dependency-track

Dependency-Track is an intelligent Component Analysis platform that allows organizations to identify and reduce risk in the software supply chain.
https://dependencytrack.org/
Apache License 2.0
2.72k stars 580 forks source link

Support Common Expression Language (CEL) in policy conditions #2673

Open nscuro opened 1 year ago

nscuro commented 1 year ago

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:

Policy violations will be will be raised, if:

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

nscuro commented 1 year ago

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).

nscuro commented 1 year ago

CEL is increasingly gaining industry traction, with Kubernetes now supporting it natively.

msymons commented 1 year ago

Would not CEL be useful in other places as well?

nscuro commented 1 year ago

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.

nscuro commented 1 year ago

Note, for the frontend part we can embed monaco, which is the same editor that powers VS Code.

image

Seems like there are easy ways to plug in custom syntax highlighting, themes, and auto-complete providers.

nscuro commented 1 year ago

Error reporting including appropriate editor markers are also straightforward to set up:

image