Skip to content

Commit e69799c

Browse files
committed
fix: source CSAF justification and comment from the status-setting assessment
1 parent eb5f280 commit e69799c

1 file changed

Lines changed: 16 additions & 12 deletions

File tree

backend/application/vex/services/csaf_generator_vulnerability.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from typing import Optional
22

3-
from application.core.models import Observation
4-
from application.core.queries.observation import get_current_observation_log
3+
from application.core.models import Observation, Observation_Log
54
from application.vex.services.csaf_generator_helpers import (
65
get_product_or_relationship_id,
76
get_vulnerability_ecosystem,
@@ -124,16 +123,21 @@ def set_flag_or_threat(vulnerability: CSAFVulnerability, observation: Observatio
124123
vex_status = map_status(observation.current_status)
125124
if vex_status == CSAF_Status.CSAF_STATUS_NOT_AFFECTED:
126125
product_or_relationship_id = get_product_or_relationship_id(observation)
127-
# get_current_observation_log (unlike get_current_modifying_observation_log) excludes empty log
128-
# entries, e.g. the ones created when a rego rule is removed. Those have an empty
129-
# vex_justification and comment and would otherwise shadow the real assessment, leaving the
130-
# product in known_not_affected without any impact statement (CSAF mandatory test 6.1.27.9).
131-
observation_log = get_current_observation_log(observation)
126+
# Use the observation log that set the current status, i.e. the assessment. The generic
127+
# "current"/"modifying" observation log helpers are unreliable here: automated log entries
128+
# (for example "Removed product rego rule ...") carry no status but still pass those filters
129+
# (empty vex_remediations is stored inconsistently as "" or NULL) and would then provide a
130+
# misleading justification and comment. Filtering on the current status skips those entries.
131+
assessment_log = (
132+
Observation_Log.objects.filter(observation=observation, status=observation.current_status)
133+
.order_by("-created")
134+
.first()
135+
)
132136

133-
# Prefer the observation's authoritative current justification, fall back to the log.
137+
# Prefer the observation's authoritative current justification, fall back to the assessment.
134138
justification = observation.current_vex_justification
135-
if not justification and observation_log:
136-
justification = observation_log.vex_justification
139+
if not justification and assessment_log:
140+
justification = assessment_log.vex_justification
137141
csaf_label = map_vex_justification_to_csaf_openvex_justification(justification)
138142
if csaf_label:
139143
found = False
@@ -153,9 +157,9 @@ def set_flag_or_threat(vulnerability: CSAFVulnerability, observation: Observatio
153157
# Surface the assessment comment as a free-text impact threat whenever it exists, so the human
154158
# explanation is kept alongside the machine-readable flag. With neither a flag nor a comment
155159
# the product has no impact statement and validation fails, which is intended.
156-
if observation_log and observation_log.comment:
160+
if assessment_log and assessment_log.comment:
157161
category = "impact"
158-
details = observation_log.comment
162+
details = assessment_log.comment
159163
found = False
160164
for threat in vulnerability.threats:
161165
if threat.category == category and threat.details == details:

0 commit comments

Comments
 (0)