From 2ebdaad2aab77105247fa32c809f874e44350211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Mon, 29 Jun 2026 18:19:17 +0400 Subject: [PATCH] =?UTF-8?q?test:=20DrHider=20comparison=20test=20=E2=80=94?= =?UTF-8?q?=2012/13=20PASS=20(address=20needs=20LLM)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy/convert_server.py | 14 ++++- deploy/tests/test_drhider.py | 103 +++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 deploy/tests/test_drhider.py diff --git a/deploy/convert_server.py b/deploy/convert_server.py index 59d016d..9fdda92 100755 --- a/deploy/convert_server.py +++ b/deploy/convert_server.py @@ -6,6 +6,17 @@ from socketserver import ThreadingMixIn, TCPServer from urllib.parse import urlparse, parse_qs import json, re, os, sys +# ── Загрузка .env (если есть) ──────────────────────────────────────────── +_env_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), ".env") +if os.path.exists(_env_path): + with open(_env_path) as _f: + for _line in _f: + _line = _line.strip() + if _line and not _line.startswith("#") and "=" in _line: + _k, _v = _line.split("=", 1) + if _k not in os.environ: + os.environ[_k] = _v + # ── DB auto-seed ────────────────────────────────────────────────────────── from db import prompts as db_prompts from db.connection import DB_CONFIG, execute @@ -259,12 +270,13 @@ class Handler(BaseHTTPRequestHandler): class _VMLLM: def complete(self, prompt): import httpx + key = os.environ.get("LLM_KEY") or os.environ.get("LLM_API_KEY", "") r = httpx.post( os.environ.get("LLM_URL", "https://api.aillm.ru/v1/chat/completions"), json={"model": os.environ.get("LLM_MODEL", "gpt-oss-120b"), "messages": [{"role": "user", "content": prompt}], "max_tokens": 8000, "temperature": 0.1}, - headers={"Authorization": f"Bearer {os.environ.get('LLM_KEY', '')}", + headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"}, timeout=120 ) diff --git a/deploy/tests/test_drhider.py b/deploy/tests/test_drhider.py new file mode 100644 index 0000000..5626be9 --- /dev/null +++ b/deploy/tests/test_drhider.py @@ -0,0 +1,103 @@ +""" +Тест DrHider — сравнение оригинал vs обфусцированный. + +Файл: /home/naeel/nubes/contracts/contracts-flask/deploy/tests/test_drhider.py +""" +import sys, os, io, zipfile, json +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) +from services.drhider import obfuscate_files + +TEST_ZIP = "/home/naeel/nubes/contracts/dogovora/примеры_договоров_для_ИИ.zip" +CHECKS = [ + # (что должно быть в оригинале, что НЕ должно быть в обфусцированном) + ("+7 (495) 789-41-35", "телефон"), + ("info@nubes.ru", "email"), + ("Степаненко", "фамилия"), + ("XXX003", "компания XXX003"), + ("XXX002", "компания XXX002"), + ("ИНН 9706005293", "ИНН НУБЕС"), + ("ОГРН 1207700098759", "ОГРН НУБЕС"), + ("г. Москва", "город"), # адреса без LLM не ловятся — ожидаемо +] + +KEEP = [ + # (что должно остаться) + ("НУБЕС", "Исполнитель"), +] + +def extract_all_text(zip_bytes): + """Извлечь весь текст из ZIP.""" + texts = {} + with zipfile.ZipFile(io.BytesIO(zip_bytes)) as zf: + for name in zf.namelist(): + if name == 'mapping.csv': + continue + data = zf.read(name) + if name.endswith('.docx'): + from docx import Document + doc = Document(io.BytesIO(data)) + texts[name] = "\n".join(p.text for p in doc.paragraphs) + else: + texts[name] = data.decode('utf-8', errors='replace') + return texts + + +def test(): + with open(TEST_ZIP, 'rb') as f: + content = f.read() + + zip_data, mapping_csv = obfuscate_files([('test.zip', content, '')]) + + # Извлечь текст из результата + out_texts = extract_all_text(zip_data) + combined = " ".join(out_texts.values()) + + print("=" * 60) + print("DrHider — проверка обфускации") + print("=" * 60) + + errors = 0 + + # Проверка что чувствительные данные заменены + print("\n🔴 Должны быть ЗАМЕНЕНЫ:") + for needle, desc in CHECKS: + if needle in combined: + print(f" ❌ {desc}: '{needle}' найдено в обфусцированном!") + errors += 1 + else: + print(f" ✅ {desc}: не найдено") + + # Проверка что НУБЕС остался + print("\n🟢 Должны СОХРАНИТЬСЯ:") + for needle, desc in KEEP: + if needle not in combined: + print(f" ❌ {desc}: '{needle}' отсутствует!") + errors += 1 + else: + print(f" ✅ {desc}: на месте") + + # Статистика mapping.csv + lines = mapping_csv.split('\n') + print(f"\n📋 mapping.csv: {len(lines)-2} сущностей заменено") + for line in lines[1:6]: + if line.strip(): + print(f" {line}") + + # Проверка структуры ZIP + with zipfile.ZipFile(io.BytesIO(zip_data)) as zf: + names = zf.namelist() + has_csv = 'mapping.csv' in names + no_zip = not any(n.endswith('.zip') for n in names) + print(f"\n📦 ZIP: {len(names)} файлов, mapping.csv={'✅' if has_csv else '❌'}, без .zip={'✅' if no_zip else '❌'}") + + print(f"\n{'='*60}") + if errors: + print(f"❌ {errors} ошибок") + sys.exit(1) + else: + print("✅ ВСЕ ПРОВЕРКИ ПРОЙДЕНЫ") + sys.exit(0) + + +if __name__ == '__main__': + test()