Skip to content

Commit 584ee9d

Browse files
committed
refine polivy violation table
Signed-off-by: tdruez <tdruez@aboutcode.org>
1 parent 158df92 commit 584ee9d

4 files changed

Lines changed: 82 additions & 11 deletions

File tree

policy/rules.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class BaseRule:
1515
rule_type = None
1616
label = None
1717
description = None
18+
severity = "warning"
1819
default_threshold = 0
1920
parameters_schema = {}
2021

@@ -53,6 +54,7 @@ def get_package_filter(self):
5354
class UsagePolicyErrorRule(PackageBaseRule):
5455
rule_type = "usage_policy_error"
5556
label = "Usage Policy Error"
57+
severity = "error"
5658
description = (
5759
"Detects packages assigned a usage policy with a compliance alert level of 'error'."
5860
)
@@ -71,6 +73,7 @@ class UsagePolicyWarningRule(PackageBaseRule):
7173
class LicensePolicyErrorRule(PackageBaseRule):
7274
rule_type = "license_policy_error"
7375
label = "License Policy Error"
76+
severity = "error"
7477
description = (
7578
"Detects packages whose licenses are assigned a usage policy"
7679
" with a compliance alert level of 'error'."
@@ -100,6 +103,7 @@ class LicenseCoverageGapRule(PackageBaseRule):
100103
class VulnerabilityDetectedRule(BaseRule):
101104
rule_type = "vulnerability_detected"
102105
label = "Vulnerability Detected"
106+
severity = "error"
103107
description = "Detects packages with at least one known vulnerability (non-null risk score)."
104108
parameters_schema = {
105109
"min_risk_score": "Minimum risk score (0.0-10.0). Default: any vulnerability.",

product_portfolio/models.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
from dje.validators import validate_url_segment
5959
from dje.validators import validate_version
6060
from policy.models import AbstractPolicyViolation
61+
from policy.rules import RULE_REGISTRY
6162
from vulnerabilities.fetch import fetch_for_packages
6263
from vulnerabilities.models import AffectedByVulnerabilityMixin
6364
from vulnerabilities.models import AffectedByVulnerabilityRelationship
@@ -1956,14 +1957,15 @@ def __str__(self):
19561957

19571958
@property
19581959
def rule_label(self):
1959-
from policy.rules import RULE_REGISTRY
1960-
19611960
handler = RULE_REGISTRY.get(self.rule_type)
19621961
return handler.label if handler else self.rule_type
19631962

19641963
@property
19651964
def rule_description(self):
1966-
from policy.rules import RULE_REGISTRY
1967-
19681965
handler = RULE_REGISTRY.get(self.rule_type)
19691966
return handler.description if handler else ""
1967+
1968+
@property
1969+
def rule_severity(self):
1970+
handler = RULE_REGISTRY.get(self.rule_type)
1971+
return handler.severity if handler else "warning"

product_portfolio/templates/product_portfolio/compliance/compliance_panels.html

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,39 +6,90 @@
66
<div class="col-12">
77
<div class="border rounded-3 p-3">
88
<div class="d-flex justify-content-between align-items-center mb-3">
9-
<h3 class="fs-6 fw-medium mb-0">{% trans "Policy violations" %}</h3>
9+
<div class="d-flex align-items-center gap-2">
10+
<h3 class="fs-6 fw-medium mb-0">{% trans "Policy violations" %}</h3>
11+
<button type="button"
12+
id="rules-overview-btn"
13+
class="btn btn-link p-0 text-body-tertiary lh-1"
14+
aria-label="{% trans 'View active rules' %}">
15+
<i class="fas fa-circle-info small"></i>
16+
</button>
17+
</div>
1018
<span class="badge bg-danger-subtle text-danger-emphasis">
1119
{{ policy_violation_count }} {% trans "active" %}
1220
</span>
1321
</div>
14-
<table class="table table-sm mb-0">
22+
<table class="table table-sm align-middle mb-0">
1523
<thead>
1624
<tr>
1725
<th class="fw-medium">{% trans "Rule" %}</th>
1826
<th class="fw-medium">{% trans "Description" %}</th>
19-
<th class="fw-medium">{% trans "Objects in violation" %}</th>
20-
<th class="fw-medium">{% trans "Detected" %}</th>
27+
<th class="fw-medium text-end">{% trans "In violation" %}</th>
28+
<th class="fw-medium text-end">{% trans "Detected" %}</th>
2129
</tr>
2230
</thead>
2331
<tbody>
2432
{% for violation in policy_violations %}
2533
<tr>
26-
<td>{{ violation.rule_label }}</td>
34+
<td class="text-nowrap">
35+
{% if violation.rule_severity == "error" %}
36+
<span class="badge bg-danger-subtle text-danger-emphasis">{{ violation.rule_label }}</span>
37+
{% else %}
38+
<span class="badge bg-warning-subtle text-warning-emphasis">{{ violation.rule_label }}</span>
39+
{% endif %}
40+
</td>
2741
<td class="text-body-secondary small">{{ violation.rule_description }}</td>
28-
<td>
42+
<td class="text-end">
2943
<a href="{{ product_url }}?inventory-policy_rule={{ violation.rule_type }}#inventory"
3044
class="text-decoration-none">
3145
{{ violation.violation_count }}
3246
</a>
3347
</td>
34-
<td class="text-body-tertiary small">{{ violation.detected_date|date:"N j, Y" }}</td>
48+
<td class="text-end text-body-tertiary small text-nowrap">{{ violation.detected_date|date:"N j, Y" }}</td>
3549
</tr>
3650
{% endfor %}
3751
</tbody>
3852
</table>
3953
</div>
4054
</div>
4155
</div>
56+
57+
{# Hidden popover content -- not data-bs-toggle so the global init doesn't conflict #}
58+
<div id="rules-overview-content" class="d-none">
59+
{% for rule in all_rules %}
60+
<div class="d-flex align-items-center justify-content-between {% if not forloop.last %}mb-2{% endif %}">
61+
<span class="small me-3">{{ rule.label }}</span>
62+
{% if not rule.is_active %}
63+
<span class="badge text-bg-secondary">{% trans "Disabled" %}</span>
64+
{% elif rule.is_violated %}
65+
{% if rule.severity == "error" %}
66+
<span class="badge bg-danger-subtle text-danger-emphasis">{% trans "Triggered" %}</span>
67+
{% else %}
68+
<span class="badge bg-warning-subtle text-warning-emphasis">{% trans "Triggered" %}</span>
69+
{% endif %}
70+
{% else %}
71+
<span class="badge bg-success-subtle text-success-emphasis">{% trans "OK" %}</span>
72+
{% endif %}
73+
</div>
74+
{% endfor %}
75+
</div>
76+
<script>
77+
(function () {
78+
const btn = document.getElementById("rules-overview-btn");
79+
const content = document.getElementById("rules-overview-content");
80+
const popover = new bootstrap.Popover(btn, {
81+
html: true,
82+
container: "body",
83+
placement: "right",
84+
trigger: "click",
85+
title: "{% trans 'Active rules' %}",
86+
content: content.innerHTML,
87+
});
88+
document.addEventListener("click", function (event) {
89+
if (!btn.contains(event.target)) popover.hide();
90+
});
91+
})();
92+
</script>
4293
{% endif %}
4394

4495
<div class="row g-4 mb-4">

product_portfolio/views.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@
143143
from product_portfolio.models import ScanCodeProject
144144
from product_portfolio.tasks import improve_packages_from_purldb_task
145145
from product_portfolio.tasks import pull_project_data_from_scancodeio_task
146+
from policy.engine import get_effective_config
147+
from policy.rules import RULE_REGISTRY
146148
from vulnerabilities.forms import VulnerabilityAnalysisForm
147149
from vulnerabilities.models import AffectedByVulnerabilityMixin
148150
from vulnerabilities.models import Vulnerability
@@ -2849,9 +2851,21 @@ def get_license_compliance_context(licenses, distribution_limit=10):
28492851
@staticmethod
28502852
def get_policy_compliance_context(product):
28512853
policy_violations = product.policy_violations.filter(resolved=False).order_by("rule_type")
2854+
violated_rule_types = {violation.rule_type for violation in policy_violations}
2855+
all_rules = [
2856+
{
2857+
"label": handler.label,
2858+
"rule_type": rule_type,
2859+
"severity": handler.severity,
2860+
"is_active": get_effective_config(rule_type, product.dataspace)["is_active"],
2861+
"is_violated": rule_type in violated_rule_types,
2862+
}
2863+
for rule_type, handler in RULE_REGISTRY.items()
2864+
]
28522865
return {
28532866
"policy_violations": policy_violations,
28542867
"policy_violation_count": policy_violations.count(),
2868+
"all_rules": all_rules,
28552869
}
28562870

28572871
@staticmethod

0 commit comments

Comments
 (0)