Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
import org.dependencytrack.notification.proto.v1.ComponentVulnAnalysisCompleteSubject;
import org.dependencytrack.notification.proto.v1.NewVulnerabilitySubject;
import org.dependencytrack.notification.proto.v1.NewVulnerableDependencySubject;
import org.dependencytrack.notification.proto.v1.Policy;
import org.dependencytrack.notification.proto.v1.PolicyCondition;
import org.dependencytrack.notification.proto.v1.PolicyViolation;
import org.dependencytrack.notification.proto.v1.PolicyViolationSubject;
import org.dependencytrack.notification.proto.v1.Project;
import org.dependencytrack.notification.proto.v1.Vulnerability;
import org.dependencytrack.notification.proto.v1.VulnerabilityAnalysisDecisionChangeSubject;
Expand All @@ -31,6 +35,7 @@
import org.dependencytrack.persistence.jdbi.mapping.NotificationSubjectNewVulnerabilityRowMapper;
import org.dependencytrack.persistence.jdbi.mapping.NotificationSubjectProjectAuditChangeRowMapper;
import org.dependencytrack.persistence.jdbi.mapping.NotificationVulnerabilityRowMapper;
import org.dependencytrack.persistence.jdbi.mapping.RowMapperUtil;
import org.dependencytrack.persistence.jdbi.query.GetProjectAuditChangeNotificationSubjectQuery;
import org.jdbi.v3.sqlobject.SqlObject;
import org.jdbi.v3.sqlobject.config.RegisterRowMapper;
Expand Down Expand Up @@ -553,4 +558,99 @@ SELECT ARRAY_AGG(DISTINCT t."NAME")
""")
List<Project> getProjects(@Bind Collection<UUID> projectUuids);

default List<PolicyViolationSubject> getForNewPolicyViolations(Collection<Long> violationIds) {
if (violationIds.isEmpty()) {
return List.of();
}

Comment thread
nscuro marked this conversation as resolved.
final var componentRowMapper = new NotificationComponentRowMapper();
final var projectRowMapper = new NotificationProjectRowMapper();

return getHandle()
.createQuery("""
SELECT pv."UUID" AS "violationUuid"
, pv."TYPE" AS "violationType"
, pv."TIMESTAMP" AS "violationTimestamp"
, pc."UUID" AS "conditionUuid"
, pc."SUBJECT" AS "conditionSubject"
, pc."OPERATOR" AS "conditionOperator"
, pc."VALUE" AS "conditionValue"
, po."UUID" AS "policyUuid"
, po."NAME" AS "policyName"
, po."VIOLATIONSTATE" AS "policyViolationState"
, va."SUPPRESSED" AS "analysisSuppressed"
, va."STATE" AS "analysisState"
, c."UUID" AS "componentUuid"
, c."GROUP" AS "componentGroup"
, c."NAME" AS "componentName"
, c."VERSION" AS "componentVersion"
, c."PURL" AS "componentPurl"
, c."MD5" AS "componentMd5"
, c."SHA1" AS "componentSha1"
, c."SHA_256" AS "componentSha256"
, c."SHA_512" AS "componentSha512"
, p."UUID" AS "projectUuid"
, p."NAME" AS "projectName"
, p."VERSION" AS "projectVersion"
, p."DESCRIPTION" AS "projectDescription"
, p."PURL" AS "projectPurl"
, (p."INACTIVE_SINCE" IS NULL) AS "isActive"
, (
SELECT ARRAY_AGG(DISTINCT t."NAME")
FROM "TAG" AS t
INNER JOIN "PROJECTS_TAGS" AS pt
ON pt."TAG_ID" = t."ID"
WHERE pt."PROJECT_ID" = p."ID"
) AS "projectTags"
FROM UNNEST(:violationIds) AS req(violation_id)
INNER JOIN "POLICYVIOLATION" AS pv
ON pv."ID" = req.violation_id
INNER JOIN "POLICYCONDITION" AS pc
ON pc."ID" = pv."POLICYCONDITION_ID"
INNER JOIN "POLICY" AS po
ON po."ID" = pc."POLICY_ID"
INNER JOIN "COMPONENT" AS c
ON c."ID" = pv."COMPONENT_ID"
INNER JOIN "PROJECT" AS p
ON p."ID" = pv."PROJECT_ID"
LEFT JOIN "VIOLATIONANALYSIS" AS va
ON va."POLICYVIOLATION_ID" = pv."ID"
WHERE va."SUPPRESSED" IS DISTINCT FROM TRUE
AND va."STATE" IS DISTINCT FROM 'APPROVED'
""")
.bindArray("violationIds", Long.class, violationIds)
.map((rs, ctx) -> {
final Component component = componentRowMapper.map(rs, ctx);
final Project project = projectRowMapper.map(rs, ctx);

final Policy policy = Policy.newBuilder()
.setUuid(rs.getString("policyUuid"))
.setName(rs.getString("policyName"))
.setViolationState(rs.getString("policyViolationState"))
.build();

final PolicyCondition condition = PolicyCondition.newBuilder()
.setUuid(rs.getString("conditionUuid"))
.setSubject(rs.getString("conditionSubject"))
.setOperator(rs.getString("conditionOperator"))
.setValue(rs.getString("conditionValue"))
.setPolicy(policy)
.build();

final PolicyViolation violation = PolicyViolation.newBuilder()
.setUuid(rs.getString("violationUuid"))
.setType(rs.getString("violationType"))
.setTimestamp(RowMapperUtil.nullableTimestamp(rs, "violationTimestamp"))
.setCondition(condition)
.build();

return PolicyViolationSubject.newBuilder()
.setProject(project)
.setComponent(component)
.setPolicyViolation(violation)
.build();
})
.list();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@
import org.dependencytrack.policy.cel.CelPolicyEngine;
import org.dependencytrack.proto.internal.workflow.v1.EvalProjectPoliciesArg;
import org.jspecify.annotations.Nullable;
import org.slf4j.MDC;

import java.util.UUID;

import static org.dependencytrack.common.MdcKeys.MDC_PROJECT_UUID;

/**
* @since 5.7.0
*/
Expand All @@ -46,7 +49,10 @@ public EvalProjectPoliciesActivity(CelPolicyEngine policyEngine) {
throw new TerminalApplicationFailureException("No argument provided");
}

policyEngine.evaluateProject(UUID.fromString(argument.getProjectUuid()));
try (var ignored = MDC.putCloseable(MDC_PROJECT_UUID, argument.getProjectUuid())) {
policyEngine.evaluateProject(UUID.fromString(argument.getProjectUuid()));
}

return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import io.github.nscuro.versatile.VersException;
import jakarta.annotation.Nullable;
import org.dependencytrack.model.RepositoryType;
import org.dependencytrack.persistence.QueryManager;
import org.dependencytrack.policy.cel.persistence.CelPolicyDao;
import org.dependencytrack.proto.policy.v1.Component;
import org.dependencytrack.proto.policy.v1.License;
import org.dependencytrack.proto.policy.v1.Project;
Expand Down Expand Up @@ -65,6 +65,7 @@
import static org.apache.commons.lang3.StringUtils.substringAfter;
import static org.dependencytrack.persistence.jdbi.JdbiAttributes.ATTRIBUTE_QUERY_NAME;
import static org.dependencytrack.persistence.jdbi.JdbiFactory.openJdbiHandle;
import static org.dependencytrack.persistence.jdbi.JdbiFactory.withJdbiHandle;
import static org.dependencytrack.policy.cel.definition.CelPolicyTypes.TYPE_COMPONENT;
import static org.dependencytrack.policy.cel.definition.CelPolicyTypes.TYPE_PROJECT;
import static org.dependencytrack.policy.cel.definition.CelPolicyTypes.TYPE_VERSION_DISTANCE;
Expand Down Expand Up @@ -248,11 +249,8 @@ private static boolean matchesVersionDistance(Component component, String compar
""".formatted(FUNC_COMPARE_VERSION_DISTANCE, component, component.getUuid(), component.getVersion(), component.getLatestVersion()), e);
return false;
}
final boolean isDirectDependency;
try (final var qm = new QueryManager();
final var celQm = new CelPolicyQueryManager(qm)) {
isDirectDependency = celQm.isDirectDependency(component);
}
final boolean isDirectDependency = withJdbiHandle(handle ->
new CelPolicyDao(handle).isDirectDependency(component));
return isDirectDependency && org.dependencytrack.model.VersionDistance.evaluate(value, comparatorComputed, versionDistance);
}

Expand Down Expand Up @@ -686,7 +684,7 @@ private static boolean isExclusiveDependencyOf(final Component leafComponent, fi
// If the component is a direct dependency of the project,
// it can no longer be a dependency exclusively introduced
// through another component.
if (isDirectDependency(jdbiHandle, leafComponent)) {
if (new CelPolicyDao(jdbiHandle).isDirectDependency(leafComponent)) {
return false;
}

Expand Down Expand Up @@ -1087,25 +1085,4 @@ private static <T> boolean containsExactly(final List<T> lhs, final List<T> rhs)
return Objects.equals(lhs, rhs);
}

private static boolean isDirectDependency(final Handle jdbiHandle, final Component component) {
final Query query = jdbiHandle.createQuery("""
SELECT
1
FROM
"COMPONENT" AS "C"
INNER JOIN
"PROJECT" AS "P" ON "P"."ID" = "C"."PROJECT_ID"
WHERE
"C"."UUID" = :leafComponentUuid
AND "P"."DIRECT_DEPENDENCIES" @> JSONB_BUILD_ARRAY(JSONB_BUILD_OBJECT('uuid', :leafComponentUuid))
""");

return query
.define(ATTRIBUTE_QUERY_NAME, "%s#isDirectDependency".formatted(CelCommonPolicyLibrary.class.getSimpleName()))
.bind("leafComponentUuid", UUID.fromString(component.getUuid()))
.mapTo(Boolean.class)
.findOne()
.orElse(false);
}

}
Loading
Loading