Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for CEL policy conditions #316

Merged
merged 47 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
f98e600
Initial commit of CEL policy work
nscuro Sep 6, 2023
e0d35d0
Add a few custom CEL functions
nscuro Sep 6, 2023
9d735c5
Make policies work with legacy way of reporting violations
nscuro Sep 7, 2023
6703e62
Implement `is_dependency_of` CEL function
nscuro Sep 7, 2023
fe0a3ed
Support vuln aliases in CEL policies
nscuro Sep 7, 2023
fee1f46
Few minor adjustments
nscuro Sep 8, 2023
b95d72a
Return CEL errors in API response
nscuro Sep 11, 2023
2f6c2e3
Fix some vulnerability fields not being fetched for policies
nscuro Sep 12, 2023
07c42fa
Bump `versatile` to `0.3.0`
nscuro Sep 12, 2023
8634563
Use AST visitor to determine which fields are accessed for any given …
nscuro Sep 12, 2023
086f70a
Cleanup
nscuro Sep 14, 2023
e956ca4
Cleanup
nscuro Sep 15, 2023
d2c4841
WIP: Loading of required fields; Project policy evaluation
nscuro Sep 17, 2023
26c1a4b
Improve violation reconciliation for projects
nscuro Sep 17, 2023
5f56384
Add test with bloated BOM to debug performance bottlenecks
nscuro Sep 18, 2023
2016e0e
Disable DataNucleus L1 cache for policy reconciliation
nscuro Sep 18, 2023
40e9218
Add field mapping tests
nscuro Sep 18, 2023
1994988
Handle implicit policy script requirements for custom functions
nscuro Sep 18, 2023
3ec5f3b
Minor readability and code documentation improvements
nscuro Sep 18, 2023
489d1c5
Fetch data for policy violation notifications in a single query
nscuro Sep 18, 2023
68d54a9
Perform violation reconciliation using direct JDBC access
nscuro Sep 19, 2023
eb8c458
Include strings library in CEL policy environment
nscuro Sep 19, 2023
3d1a436
Cleanup; Support project properties, tags, and vulnerability aliases
nscuro Sep 20, 2023
e1f3419
Add test to verify that all fields can be loaded
nscuro Sep 20, 2023
499e97d
Add remaining fields to `testWithAllFields`
nscuro Sep 21, 2023
047d5a5
Add test for vuln severity evaluation
nscuro Sep 21, 2023
e824c5c
Remove un-implemented `depends_on` function; Add proper logging for c…
nscuro Sep 21, 2023
7978c1e
Handle invalid scripts and script runtime failures
nscuro Sep 21, 2023
2f37004
Add `escapeQuotes` for CEL script builders
nscuro Sep 21, 2023
ff9d52f
Add tests for some legacy conditions
nscuro Sep 21, 2023
706922c
More tests for `CelPolicyEngine`
nscuro Sep 22, 2023
0452d00
Add more tests; Implement script cache bypass for REST API interactions
nscuro Sep 22, 2023
b1c4b0a
Add tests for hash policy (#326)
mehab Sep 25, 2023
9487edb
Add version cel policy script builder (#324)
VithikaS Sep 25, 2023
f012cfa
Fix new UNIQUE constraint breaking existing behavior
nscuro Sep 25, 2023
4310a80
Add feature flag for CEL policy engine
nscuro Sep 25, 2023
ae9f067
Add `UpgradeItem` to update type of `"POLICYCONDITION"."VALUE"` to `T…
nscuro Sep 25, 2023
5a5dcf7
Handle policy evaluation for individual components
nscuro Sep 25, 2023
88ad93e
added unit tests for cwe cel policy
mehab Sep 25, 2023
d6eb71b
Add license condition test (#332)
VithikaS Sep 26, 2023
0f4c0a8
Fix projection mapping for `Double` / `BigDecimal` fields
nscuro Sep 26, 2023
8f36c64
support wildcard
Sep 26, 2023
0c47b4f
Merge pull request #333 from DependencyTrack/edge-cases-for-coordiate…
nscuro Sep 26, 2023
94eb8fc
Add `buf` config and workflow
nscuro Sep 26, 2023
1d78e4b
Change Proto package from `hyades` to `dependencytrack`
nscuro Sep 26, 2023
2b035e4
Fix failing tests due to Proto package change
nscuro Sep 27, 2023
39664d5
Un-ignore `cyclonedx.proto` from breaking changes check
nscuro Sep 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/buf.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Buf

on:
pull_request:
branches: [ "main" ]

permissions: { }

jobs:
buf:
name: Buf
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout Repository
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # tag=v4.1.0
- name: Setup buf
uses: bufbuild/buf-setup-action@eb60cd0de4f14f1f57cf346916b8cd69a9e7ed0b # tag=v1.26.1
with:
github_token: ${{ github.token }}
- name: Lint Protobuf
uses: bufbuild/buf-lint-action@bd48f53224baaaf0fc55de9a913e7680ca6dbea4 # tag=v1.0.3
with:
input: src/main/proto
- name: Detect Breaking Changes
uses: bufbuild/buf-breaking-action@a074e988ee34efcd4927079e79c611f428354c01 # tag=v1.1.3
with:
input: src/main/proto
against: https://github.com/${{ github.repository }}.git#branch=main,subdir=src/main/proto
13 changes: 13 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
<frontend.version>4.7.1</frontend.version>
<lib.alpine.version>${project.parent.version}</lib.alpine.version>
<lib.awaitility.version>4.2.0</lib.awaitility.version>
<lib.cel-tools.version>0.3.21</lib.cel-tools.version>
<lib.cpe-parser.version>2.0.2</lib.cpe-parser.version>
<lib.cvss-calculator.version>1.4.1</lib.cvss-calculator.version>
<lib.owasp-rr-calculator.version>1.0.1</lib.owasp-rr-calculator.version>
Expand All @@ -102,6 +103,7 @@
<lib.testcontainers.version>1.18.3</lib.testcontainers.version>
<lib.resilience4j.version>2.0.1</lib.resilience4j.version>
<lib.snappy-java.version>1.1.10.1</lib.snappy-java.version>
<lib.versatile.version>0.3.0</lib.versatile.version>
<lib.woodstox.version>6.4.0</lib.woodstox.version>
<lib.junit-params.version>1.1.1</lib.junit-params.version>
<lib.log4j-over-slf4j.version>2.0.9</lib.log4j-over-slf4j.version>
Expand Down Expand Up @@ -193,6 +195,12 @@
</exclusion>
</exclusions>
</dependency>
<!-- Common Expression Language (CEL) -->
<dependency>
<groupId>org.projectnessie.cel</groupId>
<artifactId>cel-tools</artifactId>
<version>${lib.cel-tools.version}</version>
</dependency>
<!-- CVSS Calculator -->
<dependency>
<groupId>us.springett</groupId>
Expand Down Expand Up @@ -326,6 +334,11 @@
<artifactId>woodstox-core</artifactId>
<version>${lib.woodstox.version}</version>
</dependency>
<dependency>
<groupId>io.github.nscuro</groupId>
<artifactId>versatile</artifactId>
<version>${lib.versatile.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/org/dependencytrack/common/ConfigKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ public enum ConfigKey implements Config.Key {
BOM_UPLOAD_PROCESSING_TRX_FLUSH_THRESHOLD("bom.upload.processing.trx.flush.threshold", "10000"),
WORKFLOW_RETENTION_DURATION("workflow.retention.duration", "P3D"),
WORKFLOW_STEP_TIMEOUT_DURATION("workflow.step.timeout.duration", "PT1H"),
TMP_DELAY_BOM_PROCESSED_NOTIFICATION("tmp.delay.bom.processed.notification", "false");
TMP_DELAY_BOM_PROCESSED_NOTIFICATION("tmp.delay.bom.processed.notification", "false"),
CEL_POLICY_ENGINE_ENABLED("cel.policy.engine.enabled", "false");

private final String propertyName;
private final Object defaultValue;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/dependencytrack/model/Policy.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public enum ViolationState {
@Column(name = "VIOLATIONSTATE", allowsNull = "false")
@NotBlank
@Size(min = 1, max = 255)
@Pattern(regexp = RegexSequence.Definition.PRINTABLE_CHARS, message = "The operator may only contain printable characters")
@Pattern(regexp = RegexSequence.Definition.PRINTABLE_CHARS, message = "The violation state may only contain printable characters")
private ViolationState violationState;

/**
Expand Down
53 changes: 39 additions & 14 deletions src/main/java/org/dependencytrack/model/PolicyCondition.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,21 +63,28 @@ public enum Operator {
}

public enum Subject {
AGE,
AGE(PolicyViolation.Type.OPERATIONAL),
//ANALYZER,
//BOM,
COORDINATES,
CPE,
COORDINATES(PolicyViolation.Type.OPERATIONAL),
CPE(PolicyViolation.Type.OPERATIONAL),
//INHERITED_RISK_SCORE,
LICENSE,
LICENSE_GROUP,
PACKAGE_URL,
SEVERITY,
SWID_TAGID,
VERSION,
COMPONENT_HASH,
CWE,
VULNERABILITY_ID
EXPRESSION(null),
LICENSE(PolicyViolation.Type.LICENSE),
LICENSE_GROUP(PolicyViolation.Type.LICENSE),
PACKAGE_URL(PolicyViolation.Type.OPERATIONAL),
SEVERITY(PolicyViolation.Type.SECURITY),
SWID_TAGID(PolicyViolation.Type.OPERATIONAL),
VERSION(PolicyViolation.Type.OPERATIONAL),
COMPONENT_HASH(PolicyViolation.Type.OPERATIONAL),
CWE(PolicyViolation.Type.SECURITY),
VULNERABILITY_ID(PolicyViolation.Type.SECURITY);

private final PolicyViolation.Type violationType;

Subject(final PolicyViolation.Type violationType) {
this.violationType = violationType;
}
}

@PrimaryKey
Expand All @@ -104,12 +111,18 @@ public enum Subject {
private Subject subject;

@Persistent
@Column(name = "VALUE", allowsNull = "false")
@Column(name = "VALUE", allowsNull = "false", jdbcType = "CLOB")
@NotBlank
@Size(min = 1, max = 255)
@Size(min = 1)
@Pattern(regexp = RegexSequence.Definition.PRINTABLE_CHARS, message = "The value may only contain printable characters")
private String value;

@Persistent
@Column(name = "VIOLATIONTYPE", allowsNull = "true")
@Size(min = 1, max = 255)
@Pattern(regexp = RegexSequence.Definition.PRINTABLE_CHARS, message = "The violation type may only contain printable characters")
private PolicyViolation.Type violationType;

/**
* The unique identifier of the object.
*/
Expand Down Expand Up @@ -159,6 +172,18 @@ public void setValue(String value) {
this.value = value;
}

public PolicyViolation.Type getViolationType() {
if (subject != null && subject.violationType != null) {
return subject.violationType;
}

return violationType;
}

public void setViolationType(PolicyViolation.Type violationType) {
this.violationType = violationType;
}

public UUID getUuid() {
return uuid;
}
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/org/dependencytrack/model/PolicyViolation.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@
@PersistenceCapable
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
// TODO: Add @Unique composite constraint on the fields component, policyCondition, and type.
// The legacy PolicyEngine erroneously allows for duplicates on those fields, but CelPolicyEngine
// will never produce such duplicates. Until we remove the legacy engine, we can't add this constraint.
public class PolicyViolation implements Serializable {

public enum Type {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ private String getBySource(final Vulnerability.Source source) {
case NVD -> getCveId();
case OSSINDEX -> getSonatypeId();
case OSV -> getOsvId();
case SNYK -> getSnykId();
case VULNDB -> getVulnDbId();
default -> null;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ private Bom create(final List<Component>components, final List<ServiceComponent>
bom.setComponents(cycloneComponents);
bom.setServices(cycloneServices);
bom.setVulnerabilities(cycloneVulnerabilities);
if (components != null) {
if (cycloneComponents != null) {
bom.setDependencies(ModelConverter.generateDependencies(project, components));
}
return bom;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,26 @@ public Policy createPolicy(String name, Policy.Operator operator, Policy.Violati
*/
public PolicyCondition createPolicyCondition(final Policy policy, final PolicyCondition.Subject subject,
final PolicyCondition.Operator operator, final String value) {
return createPolicyCondition(policy, subject, operator, value, null);
}

/**
* Creates a policy condition for the specified Project.
* @return the created PolicyCondition object
*/
public PolicyCondition createPolicyCondition(final Policy policy, final PolicyCondition.Subject subject,
final PolicyCondition.Operator operator, final String value,
final PolicyViolation.Type violationType) {
final PolicyCondition pc = new PolicyCondition();
pc.setPolicy(policy);
pc.setSubject(subject);
pc.setOperator(operator);
if (subject == PolicyCondition.Subject.EXPRESSION) {
pc.setOperator(PolicyCondition.Operator.MATCHES);
} else {
pc.setOperator(operator);
}
pc.setValue(value);
pc.setViolationType(violationType);
return persist(pc);
}

Expand All @@ -200,8 +215,13 @@ public PolicyCondition createPolicyCondition(final Policy policy, final PolicyCo
public PolicyCondition updatePolicyCondition(final PolicyCondition policyCondition) {
final PolicyCondition pc = getObjectByUuid(PolicyCondition.class, policyCondition.getUuid());
pc.setSubject(policyCondition.getSubject());
pc.setOperator(policyCondition.getOperator());
if (policyCondition.getSubject() == PolicyCondition.Subject.EXPRESSION) {
pc.setOperator(PolicyCondition.Operator.MATCHES);
} else {
pc.setOperator(policyCondition.getOperator());
}
pc.setValue(policyCondition.getValue());
pc.setViolationType(policyCondition.getViolationType());
return persist(pc);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,12 @@ public PolicyCondition createPolicyCondition(final Policy policy, final PolicyCo
return getPolicyQueryManager().createPolicyCondition(policy, subject, operator, value);
}

public PolicyCondition createPolicyCondition(final Policy policy, final PolicyCondition.Subject subject,
final PolicyCondition.Operator operator, final String value,
final PolicyViolation.Type violationType) {
return getPolicyQueryManager().createPolicyCondition(policy, subject, operator, value, violationType);
}

public PolicyCondition updatePolicyCondition(final PolicyCondition policyCondition) {
return getPolicyQueryManager().updatePolicyCondition(policyCondition);
}
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/org/dependencytrack/policy/PolicyEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ public PolicyViolation.Type determineViolationType(final PolicyCondition.Subject
case AGE, COORDINATES, PACKAGE_URL, CPE, SWID_TAGID, COMPONENT_HASH, VERSION ->
PolicyViolation.Type.OPERATIONAL;
case LICENSE, LICENSE_GROUP -> PolicyViolation.Type.LICENSE;
// Just here to satisfy the switch exhaustiveness. Conditions with subject EXPRESSION
// will never yield any violations, because there's no evaluator supporting it.
case EXPRESSION -> null;
};
}

Expand Down
Loading
Loading