Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 15 additions & 0 deletions src/main/java/org/dependencytrack/model/Policy.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,13 @@ public enum FetchGroup {
@Element(column = "TAG_ID")
private Set<Tag> tags;

/**
* If true, the policy will only match projects that do not have any of the specified tags.
*/
@Persistent
@Column(name = "INVERT_TAG_MATCH", defaultValue = "false")
private boolean invertTagMatch;

/**
* The unique identifier of the object.
*/
Expand Down Expand Up @@ -226,6 +233,14 @@ public void setTags(Set<Tag> tags) {
this.tags = tags;
}

public boolean isInvertTagMatch() {
return invertTagMatch;
}

public void setInvertTagMatch(boolean invertTagMatch) {
this.invertTagMatch = invertTagMatch;
}

public UUID getUuid() {
return uuid;
}
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/org/dependencytrack/policy/PolicyEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ private boolean isPolicyAssignedToProjectTag(Policy policy, Project project) {
break;
}
}
return flag;

return policy.isInvertTagMatch() != flag;
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ public Response updatePolicy(Policy jsonPolicy) {
policy.setViolationState(jsonPolicy.getViolationState());
policy.setIncludeChildren(jsonPolicy.isIncludeChildren());
policy.setOnlyLatestProjectVersion(jsonPolicy.isOnlyLatestProjectVersion());
policy.setInvertTagMatch(jsonPolicy.isInvertTagMatch());
policy = qm.persist(policy);
return Response.ok(policy).build();
} else {
Expand Down
51 changes: 51 additions & 0 deletions src/test/java/org/dependencytrack/policy/PolicyEngineTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,57 @@ void noTagMatchPolicyLimitedToTag() {
Assertions.assertEquals(0, violations.size());
}

@Test
void hasTagMatchPolicyWithExcludedTag() {
Policy policy = qm.createPolicy("Test Policy", Operator.ANY, ViolationState.INFO);
policy.setInvertTagMatch(true);
qm.createPolicyCondition(policy, Subject.SEVERITY, PolicyCondition.Operator.IS, Severity.CRITICAL.name());
Tag commonTag = qm.createTag("Tag 1");
qm.bind(policy, List.of(commonTag));
Project project = qm.createProject("My Project", null, "1", List.of(commonTag), null, null, true, false);
Component component = new Component();
component.setName("Test Component");
component.setVersion("1.0");
component.setProject(project);
Vulnerability vulnerability = new Vulnerability();
vulnerability.setVulnId("12345");
vulnerability.setSource(Vulnerability.Source.INTERNAL);
vulnerability.setSeverity(Severity.CRITICAL);
qm.persist(project);
qm.persist(component);
qm.persist(vulnerability);
qm.persist(policy);
qm.addVulnerability(vulnerability, component, AnalyzerIdentity.INTERNAL_ANALYZER);
PolicyEngine policyEngine = new PolicyEngine();
List<PolicyViolation> violations = policyEngine.evaluate(List.of(component));
Assertions.assertEquals(0, violations.size());
}

@Test
void noTagMatchPolicyWithExcludedTag() {
Policy policy = qm.createPolicy("Test Policy", Operator.ANY, ViolationState.INFO);
policy.setInvertTagMatch(true);
qm.createPolicyCondition(policy, Subject.SEVERITY, PolicyCondition.Operator.IS, Severity.CRITICAL.name());
qm.bind(policy, List.of(qm.createTag("Tag 1")));
Project project = qm.createProject("My Project", null, "1", List.of(qm.createTag("Tag 2")), null, null, true, false);
Component component = new Component();
component.setName("Test Component");
component.setVersion("1.0");
component.setProject(project);
Vulnerability vulnerability = new Vulnerability();
vulnerability.setVulnId("12345");
vulnerability.setSource(Vulnerability.Source.INTERNAL);
vulnerability.setSeverity(Severity.CRITICAL);
qm.persist(project);
qm.persist(component);
qm.persist(vulnerability);
qm.addVulnerability(vulnerability, component, AnalyzerIdentity.INTERNAL_ANALYZER);
PolicyEngine policyEngine = new PolicyEngine();
List<PolicyViolation> violations = policyEngine.evaluate(List.of(component));
Assertions.assertEquals(1, violations.size());
}


@Test
void hasPolicyAssignedToParentProject() {
Policy policy = qm.createPolicy("Test Policy", Operator.ANY, ViolationState.INFO);
Expand Down
Loading