From 52b4ee6f1ac97d592f9fbbf066b6be25522f7318 Mon Sep 17 00:00:00 2001 From: LocoAgent Date: Wed, 5 Aug 2026 14:14:06 +0400 Subject: [PATCH] =?UTF-8?q?=D0=A3=D0=B3=D1=80=D0=BE=D0=B7=D1=8B:=20=D1=81?= =?UTF-8?q?=D0=BF=D0=B8=D1=81=D0=BE=D0=BA=20=D1=81=D0=BE=D1=80=D1=82=D0=B8?= =?UTF-8?q?=D1=80=D1=83=D0=B5=D1=82=D1=81=D1=8F=20=D0=BF=D0=BE=20=D0=B2?= =?UTF-8?q?=D0=BE=D0=B7=D1=80=D0=B0=D1=81=D1=82=D0=B0=D0=BD=D0=B8=D1=8E=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=B4=D0=B0=20=D0=A3=D0=91=D0=98=20(=D0=A3=D0=91?= =?UTF-8?q?=D0=98.001=20=E2=86=92=20=D0=A3=D0=91=D0=98.211)=20=D0=B2=D0=BE?= =?UTF-8?q?=20=D0=B2=D1=81=D0=B5=D1=85=20=D0=BC=D0=B5=D1=81=D1=82=D0=B0?= =?UTF-8?q?=D1=85=20=E2=80=94=20=D0=BF=D0=BE=D0=B4=D0=B1=D0=BE=D1=80=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B3=D1=80=D0=B0=D0=BC=D0=BC=D0=BE=D0=B9,?= =?UTF-8?q?=20=D0=98=D0=98,=20=D0=B0=D0=B2=D1=82=D0=BE=D0=B7=D0=B0=D0=BF?= =?UTF-8?q?=D0=BE=D0=BB=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5,=20=D0=B8=D0=BC?= =?UTF-8?q?=D0=BF=D0=BE=D1=80=D1=82,=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BD=D0=B5=D0=B4=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D0=B0=D1=8E=D1=89=D0=B8=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dokogen/threat_rules.py | 24 +++++++++++++++++++++--- dokogen/ui.py | 39 +++++++++++++++++++++++++++++---------- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/dokogen/threat_rules.py b/dokogen/threat_rules.py index b1561dd..5eb929f 100644 --- a/dokogen/threat_rules.py +++ b/dokogen/threat_rules.py @@ -11,6 +11,24 @@ import os import json +import re + + +def _ubi_num(text): + """Код УБИ из строки → int: «УБИ.069 Название» → 69. None, если кода нет.""" + m = re.search(r'уби\.?\s*(\d+)', str(text), re.IGNORECASE) + return int(m.group(1)) if m else None + + +def sort_threats_by_ubi(items): + """Сортировка угроз по возрастанию кода УБИ (УБИ.001, УБИ.002, …). + + Строки без кода УБИ уходят в конец (по алфавиту). + """ + def _key(t): + n = _ubi_num(t) + return (0, n) if n is not None else (1, str(t).lower()) + return sorted(items, key=_key) def load_threats(dict_dir=None): @@ -244,9 +262,9 @@ def suggest_threats_program(isys, threats=None, limit=None): sc = sum(1 for kw in pos if kw in tl) scored.append((sc, t)) - # Сортируем по релевантности (сначала — с наибольшим совпадением) - scored.sort(key=lambda x: -x[0]) - result = [t for sc, t in scored if sc > 0] + # Сортируем по возрастанию кода УБИ (УБИ.001 → УБИ.211…) + scored = [t for sc, t in scored if sc > 0] + result = sort_threats_by_ubi(scored) if limit and len(result) > limit: result = result[:limit] diff --git a/dokogen/ui.py b/dokogen/ui.py index 8779e94..3e1a166 100644 --- a/dokogen/ui.py +++ b/dokogen/ui.py @@ -1908,9 +1908,12 @@ class DokoGenApp: w.set(val) elif isinstance(w, tk.Listbox): w.delete(0, tk.END) - for line in str(val).split('\n'): - if line.strip(): - w.insert(tk.END, line.strip()) + lines = [ln.strip() for ln in str(val).split('\n') if ln.strip()] + if model_field == 'threats': + from .threat_rules import sort_threats_by_ubi + lines = sort_threats_by_ubi(lines) + for line in lines: + w.insert(tk.END, line) elif isinstance(w, tk.Text): w.delete('1.0', tk.END) w.insert('1.0', val) @@ -2873,9 +2876,12 @@ class DokoGenApp: if key in fill and hasattr(self, attr): lb = getattr(self, attr) lb.delete(0, tk.END) - for line in fill[key].split('\n'): - if line.strip(): - lb.insert(tk.END, line.strip()) + lines = [ln.strip() for ln in fill[key].split('\n') if ln.strip()] + if key == 'threats': + from .threat_rules import sort_threats_by_ubi + lines = sort_threats_by_ubi(lines) + for line in lines: + lb.insert(tk.END, line) self._collect_is() # сохранить в модель filled = ', '.join({ @@ -2911,7 +2917,8 @@ class DokoGenApp: return lb = self.is_threats_listbox lb.delete(0, tk.END) - for t in threats: + from .threat_rules import sort_threats_by_ubi + for t in sort_threats_by_ubi(threats): lb.insert(tk.END, t) self._collect_is() # сохранить в модель — галочки в словаре будут стоять self.log(f"⚙️ Угрозы подобраны программой: {len(threats)} шт.") @@ -3286,6 +3293,12 @@ class DokoGenApp: existing.add(key) added += 1 if added: + # сортируем по возрастанию кода УБИ + from .threat_rules import sort_threats_by_ubi + items = [str(lb.get(i)) for i in range(lb.size())] + lb.delete(0, tk.END) + for t in sort_threats_by_ubi(items): + lb.insert(tk.END, t) self._collect_is() self.log(f"➕ Добавлено недостающих угроз (по словарю): {added}") else: @@ -3462,15 +3475,21 @@ class DokoGenApp: e = entries.get(key) return e.get('1.0', 'end-1c').strip() if e else '' - def _fill_listbox(lb, text): + def _fill_listbox(lb, text, sort_ubi=False): if not lb: return lb.delete(0, tk.END) import re as _re3 + lines = [] for line in _re3.split(r'[\n,;]+', text or ''): line = line.strip().lstrip('•-–— ') if line: - lb.insert(tk.END, line) + lines.append(line) + if sort_ubi: + from .threat_rules import sort_threats_by_ubi + lines = sort_threats_by_ubi(lines) + for line in lines: + lb.insert(tk.END, line) try: if _wanted('attacker_category'): @@ -3480,7 +3499,7 @@ class DokoGenApp: exact = next((v for v in values if v.lower() == val.lower()), None) self.is_attacker_category_combo.set(exact or val) if _wanted('threats'): - _fill_listbox(getattr(self, 'is_threats_listbox', None), _text('threats')) + _fill_listbox(getattr(self, 'is_threats_listbox', None), _text('threats'), sort_ubi=True) if _wanted('incidents'): _fill_listbox(getattr(self, 'is_incidents_listbox', None), _text('incidents')) if _wanted('criteria_values'):