feat: вкладка «Безопасность» — коды УБИ, автоподбор угроз (программа/ИИ), сравнение, новый UI

- угрозы ФСТЭК теперь с кодами: «УБИ.001 Угроза …» (парсинг кода из БДУ, 227 шт)
- threat_rules.py — логика программы: по характеристикам объекта (тип ИС/АСУ/ИТКС,
  интернет да/нет, нарушитель внутр./внешн.) фильтрует перечень по ключевым словам
- verify.py: suggest_threats_ai — ИИ предлагает актуальные угрозы по описанию объекта
- вкладка перестроена: компактная 2-колоночная раскладка, панель действий сверху:
  «⬇️ Загрузить угрозы ФСТЭК» | «⚙️ Подобрать (программа)» | «🤖 Подобрать (ИИ)» |
  «⚖️ Сравнить» | «🤖 Проверить безопасность через ИИ»
- окно выбора из словаря: 720x680 + поле поиска (фильтр по тексту, важно для 227 угроз)
- сравнение программа↔ИИ: окно с двумя списками, совпавшие подсвечены зелёным
This commit is contained in:
2026-08-04 17:44:54 +04:00
parent b6f595fd32
commit 7158a90b76
5 changed files with 676 additions and 348 deletions
+28 -15
View File
@@ -49,29 +49,42 @@ def _fetch(url, timeout=30):
return None
def _normalize_ubi(code):
"""«УБИ. 001» / «УБИ.001» → «УБИ.001» (без пробела после точки)."""
m = re.search(r'(УБИ\.?)\s*([\d.]+)', code or '', re.I)
if m:
return f"{m.group(1).replace('.', '').upper()}.{m.group(2)}"
return (code or '').strip()
def _parse_threats(html):
"""Извлекает названия угроз из HTML-таблицы БДУ.
"""Извлекает пары (код УБИ, название) из HTML-таблицы БДУ.
Строки вида: <tr>...<td>УБИ. 001</td><td>Угроза ...</td>...</tr>
Возвращает список названий (без кода).
Возвращает список строк: «УБИ.001 Угроза ...» (код + название).
"""
names = []
items = []
if not html:
return names
return items
for row in re.findall(r'<tr[^>]*>(.*?)</tr>', html, re.S):
cells = re.findall(r'<t[dh][^>]*>(.*?)</t[dh]>', row, re.S)
cleaned = [re.sub(r'<[^>]+>', '', c).strip() for c in cells]
# формат: [код, название, ...] — берём ячейку, которая не похожа на код УБИ
for cell in cleaned:
if not cell:
continue
if re.fullmatch(r'УБИ\.?\s*[\d.]+', cell):
continue
if cell in ('', 'Идентификатор', 'Наименование', 'Дата', 'Уровень опасности'):
continue
names.append(cell)
break
return names
if not cleaned:
continue
# первая ячейка — код (УБИ.001), вторая — название
code = _normalize_ubi(cleaned[0]) if cleaned else ''
name = ''
for cell in cleaned[1:]:
if cell and cell not in ('', 'Идентификатор', 'Наименование', 'Дата', 'Уровень опасности'):
name = cell
break
if not name:
continue
if code.startswith('УБИ.'):
items.append(f"{code} {name}")
else:
items.append(name)
return items
def download_fstec_threats(dict_dir=None, max_pages=8, page_size=100):