Skip to content

Commit

Permalink
Include sprint information in rescoring proposal
Browse files Browse the repository at this point in the history
  • Loading branch information
8R0WNI3 committed Apr 25, 2024
1 parent 0731ac2 commit c10cef8
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 0 deletions.
2 changes: 2 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,8 @@ def handle_exception(req, resp, ex, params, ws=None):
component_descriptor_lookup=component_descriptor_lookup,
namespace_callback=namespace_callback,
kubernetes_api_callback=kubernetes_api_callback,
sprints_repo_callback=sprints_repo_callback,
sprints_relpath_callback=sprints_relpath_callback,
),
)

Expand Down
85 changes: 85 additions & 0 deletions rescore.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import collections.abc
import dataclasses
import datetime
import enum
import logging
import typing
Expand All @@ -23,9 +24,11 @@
import deliverydb.model as dm
import deliverydb.util as du
import k8s.backlog
import k8s.model
import k8s.util
import middleware.auth
import util
import yp


logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -81,6 +84,8 @@ class RescoringProposal:
severity: Severity
matching_rules: list[str]
applicable_rescorings: tuple[dso.model.ArtefactMetadata, ...] # "..." for dacite.from_dict
discovery_date: str
sprint: yp.Sprint | None


def _find_cve_rescoring_rule_set(
Expand Down Expand Up @@ -424,11 +429,35 @@ def filesystem_paths_for_finding(
})


def sprint_for_finding(
finding: dm.ArtefactMetaData,
severity: gcm.Severity | None,
max_processing_days: gcm.MaxProcessingTimesDays | None,
sprints: list[yp.Sprint],
) -> yp.Sprint | None:
if not severity or not max_processing_days or not sprints:
return None

max_days = max_processing_days.for_severity(severity=severity)
date = finding.discovery_date + datetime.timedelta(days=max_days)

for sprint in sorted(sprints, key=lambda sprint: sprint.end_date):
if sprint.end_date.date() > date:
break
else:
logger.warning(f'could not determine target sprint for {finding=} with {severity=}')
return None

return sprint


def _iter_rescoring_proposals(
artefact_metadata: list[dm.ArtefactMetaData],
rescorings: tuple[dso.model.ArtefactMetadata],
rescoring_rules: tuple[dso.cvss.RescoringRule] | None,
categorisation: dso.cvss.CveCategorisation | None,
max_processing_days: gcm.MaxProcessingTimesDays | None=None,
sprints: list[yp.Sprint]=[],
) -> collections.abc.Generator[RescoringProposal, None, None]:
seen_ids = set()

Expand Down Expand Up @@ -458,6 +487,22 @@ def _iter_rescoring_proposals(
rescorings=rescorings,
)

if current_rescorings:
current_severity = gcm.Severity[current_rescorings[0].data.severity]
elif am.type != dso.model.Datatype.STRUCTURE_INFO:
# structure info does not have any severity but is just retrieved to evaluate
# whether a scan exists for the given artefacts (if no finding is found)
current_severity = gcm.Severity[am.data.get('severity')]
else:
current_severity = None

sprint = sprint_for_finding(
finding=am,
severity=current_severity,
max_processing_days=max_processing_days,
sprints=sprints,
)

if (
am.type == dso.model.Datatype.VULNERABILITY and
am.data.get('id').get('source') == dso.model.Datasource.BDBA
Expand Down Expand Up @@ -519,6 +564,8 @@ def _iter_rescoring_proposals(
)
] if rescoring_rules and categorisation else ['original-severity'],
'applicable_rescorings': current_rescorings,
'discovery_date': am.discovery_date.isoformat(),
'sprint': sprint,
},
)

Expand Down Expand Up @@ -566,6 +613,8 @@ def _iter_rescoring_proposals(
'severity': severity,
'matching_rules': ['original-severity'],
'applicable_rescorings': current_rescorings,
'discovery_date': am.discovery_date.isoformat(),
'sprint': sprint,
},
)

Expand Down Expand Up @@ -692,12 +741,16 @@ def __init__(
component_descriptor_lookup: cnudie.retrieve.ComponentDescriptorLookupById,
namespace_callback,
kubernetes_api_callback,
sprints_repo_callback,
sprints_relpath_callback,
):
self.cve_rescoring_rule_set_lookup = cve_rescoring_rule_set_lookup
self.default_rule_set_callback = default_rule_set_callback
self.component_descriptor_lookup = component_descriptor_lookup
self.namespace_callback = namespace_callback
self.kubernetes_api_callback = kubernetes_api_callback
self.sprints_repo_callback = sprints_repo_callback
self.sprints_relpath_callback = sprints_relpath_callback

def on_post(self, req: falcon.Request, resp: falcon.Response):
'''
Expand Down Expand Up @@ -891,11 +944,43 @@ def on_get(self, req: falcon.Request, resp: falcon.Response):
type_filter=type_filter,
)

scan_configs = tuple(k8s.util.iter_scan_configurations(
namespace=self.namespace_callback(),
kubernetes_api=self.kubernetes_api_callback(),
))

# only if there is one scan config we can assume for sure that this config should be used
if len(scan_configs) != 1:
max_processing_days = None
sprints = []
else:
scan_config = scan_configs[0]
issue_replicator_config = config.deserialise_issue_replicator_config(
spec_config=scan_config.config,
)
if issue_replicator_config:
max_processing_days = issue_replicator_config.max_processing_days
else:
max_processing_days = gcm.MaxProcessingTimesDays()

if (
(repo := self.sprints_repo_callback())
and (relpath := self.sprints_relpath_callback())
):
sprints = yp._sprints(
repo=repo,
sprints_file_relpath=relpath,
)
else:
sprints = []

rescoring_proposals = _iter_rescoring_proposals(
artefact_metadata=artefact_metadata,
rescorings=rescorings,
rescoring_rules=cve_rescoring_rule_set.rules if cve_rescoring_rule_set else None,
categorisation=categorisation,
max_processing_days=max_processing_days,
sprints=sprints,
)

resp.media = tuple(rescoring_proposals)
Expand Down

0 comments on commit c10cef8

Please sign in to comment.