fix: двухшаговый API Sandbox (uploadScanFile -> createScanTask) для совместимости с токеном
This commit is contained in:
1 parent
35a750ca1c
commit
f193b3f553
2 files changed
+73
-36
No files matched your search
+4
-7
@@ -49,8 +49,10 @@ pt_sandbox:
|
|||||||
# Отключать проверку SSL-сертификата (для самоподписанных сертификатов)
|
# Отключать проверку SSL-сертификата (для самоподписанных сертификатов)
|
||||||
verify_ssl: true
|
verify_ssl: true
|
||||||
|
|
||||||
# Endpoint для загрузки и запуска проверки файла
|
# Endpoint для загрузки файла во временное хранилище
|
||||||
upload_endpoint: "/api/v1/scan/checkFile"
|
upload_endpoint: "/api/v1/storage/uploadScanFile"
|
||||||
|
# Endpoint для запуска проверки загруженного файла
|
||||||
|
scan_endpoint: "/api/v1/analysis/createScanTask"
|
||||||
|
|
||||||
# Заголовок и значение для авторизации в Sandbox
|
# Заголовок и значение для авторизации в Sandbox
|
||||||
auth_header: "X-API-Key"
|
auth_header: "X-API-Key"
|
||||||
@@ -59,11 +61,6 @@ pt_sandbox:
|
|||||||
# Формат multipart-поля с файлом
|
# Формат multipart-поля с файлом
|
||||||
file_field_name: "file"
|
file_field_name: "file"
|
||||||
|
|
||||||
# Дополнительные поля, передаваемые с файлом (опционально)
|
|
||||||
extra_fields:
|
|
||||||
# Например: source: "gitflic"
|
|
||||||
source: "gitflic"
|
|
||||||
|
|
||||||
# Таймауты (секунды)
|
# Таймауты (секунды)
|
||||||
timeout_connect: 30
|
timeout_connect: 30
|
||||||
timeout_read: 300 # 5 минут на передачу большого файла
|
timeout_read: 300 # 5 минут на передачу большого файла
|
||||||
|
|||||||
@@ -355,11 +355,11 @@ class PTSandboxClient:
|
|||||||
def __init__(self, cfg: dict):
|
def __init__(self, cfg: dict):
|
||||||
sb_cfg = cfg["pt_sandbox"]
|
sb_cfg = cfg["pt_sandbox"]
|
||||||
self.base_url = sb_cfg["base_url"].rstrip("/")
|
self.base_url = sb_cfg["base_url"].rstrip("/")
|
||||||
self.upload_endpoint = sb_cfg.get("upload_endpoint", "/api/v1/scan/checkFile")
|
self.upload_endpoint = sb_cfg.get("upload_endpoint", "/api/v1/storage/uploadScanFile")
|
||||||
|
self.scan_endpoint = sb_cfg.get("scan_endpoint", "/api/v1/analysis/createScanTask")
|
||||||
self.auth_header = sb_cfg.get("auth_header", "X-API-Key")
|
self.auth_header = sb_cfg.get("auth_header", "X-API-Key")
|
||||||
self.api_key = sb_cfg.get("api_key", "")
|
self.api_key = sb_cfg.get("api_key", "")
|
||||||
self.file_field_name = sb_cfg.get("file_field_name", "file")
|
self.file_field_name = sb_cfg.get("file_field_name", "file")
|
||||||
self.extra_fields = sb_cfg.get("extra_fields", {})
|
|
||||||
self.timeout_connect = sb_cfg.get("timeout_connect", 30)
|
self.timeout_connect = sb_cfg.get("timeout_connect", 30)
|
||||||
self.timeout_read = sb_cfg.get("timeout_read", 300)
|
self.timeout_read = sb_cfg.get("timeout_read", 300)
|
||||||
self.verify_ssl = sb_cfg.get("verify_ssl", True)
|
self.verify_ssl = sb_cfg.get("verify_ssl", True)
|
||||||
@@ -378,54 +378,94 @@ class PTSandboxClient:
|
|||||||
self._session.mount("https://", InsecureSslAdapter())
|
self._session.mount("https://", InsecureSslAdapter())
|
||||||
logger.warning("Проверка SSL-сертификата отключена для PT Sandbox")
|
logger.warning("Проверка SSL-сертификата отключена для PT Sandbox")
|
||||||
|
|
||||||
|
def _request(self, method: str, url: str, **kwargs) -> requests.Response:
|
||||||
|
"""Выполнить HTTP-запрос к API PT Sandbox."""
|
||||||
|
try:
|
||||||
|
resp = self._session.request(method, url, **kwargs)
|
||||||
|
if resp.status_code == 401:
|
||||||
|
logger.error("Sandbox 401: неверный или неактивный токен доступа")
|
||||||
|
return resp
|
||||||
|
resp.raise_for_status()
|
||||||
|
return resp
|
||||||
|
except requests.exceptions.RequestException as exc:
|
||||||
|
logger.error("Ошибка запроса Sandbox %s: %s", url, exc)
|
||||||
|
raise
|
||||||
|
|
||||||
def upload_file(self, file_path: Path) -> Optional[str]:
|
def upload_file(self, file_path: Path) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
Отправить файл в PT Sandbox на анализ (одним запросом — загрузка + запуск проверки).
|
Двухшаговый流程: загрузить файл в Sandbox, затем запустить проверку.
|
||||||
Возвращает ID задачи (scan_id) или None при ошибке.
|
Возвращает scan_id или None при ошибке.
|
||||||
"""
|
"""
|
||||||
params = {
|
# Шаг 1: загрузка файла
|
||||||
"file_name": file_path.name,
|
upload_url = f"{self.base_url}{self.upload_endpoint}"
|
||||||
"async_result": "true",
|
logger.info("Шаг 1/2: загрузка файла %s в Sandbox", file_path.name)
|
||||||
}
|
|
||||||
url = f"{self.base_url}{self.upload_endpoint}"
|
|
||||||
logger.info("Отправка файла в Sandbox: %s (%d bytes)",
|
|
||||||
file_path.name, file_path.stat().st_size)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(file_path, "rb") as fh:
|
with open(file_path, "rb") as fh:
|
||||||
files = {self.file_field_name: (file_path.name, fh)}
|
files = {self.file_field_name: (file_path.name, fh)}
|
||||||
fields = dict(self.extra_fields)
|
|
||||||
|
|
||||||
resp = self._session.post(
|
resp = self._session.post(
|
||||||
url, params=params, files=files, data=fields,
|
upload_url, files=files,
|
||||||
timeout=(self.timeout_connect, self.timeout_read),
|
timeout=(self.timeout_connect, self.timeout_read),
|
||||||
verify=self.verify_ssl,
|
verify=self.verify_ssl,
|
||||||
)
|
)
|
||||||
|
|
||||||
if resp.status_code in (200, 201, 202):
|
if resp.status_code not in (200, 201, 202):
|
||||||
result = resp.json()
|
logger.error("Sandbox ошибка загрузки: %s: %s",
|
||||||
data = result.get("data", {})
|
|
||||||
scan_id = data.get("scan_id") or result.get("task_id") or result.get("id")
|
|
||||||
logger.info("Файл %s принят Sandbox. scan_id=%s",
|
|
||||||
file_path.name, scan_id)
|
|
||||||
return str(scan_id) if scan_id else None
|
|
||||||
else:
|
|
||||||
logger.error("Sandbox вернул %s: %s",
|
|
||||||
resp.status_code, resp.text[:500])
|
resp.status_code, resp.text[:500])
|
||||||
return None
|
return None
|
||||||
|
|
||||||
except requests.exceptions.Timeout:
|
upload_data = resp.json().get("data", {})
|
||||||
logger.error("Тайм-аут при отправке файла %s в Sandbox",
|
file_uri = upload_data.get("file_uri")
|
||||||
file_path.name)
|
if not file_uri:
|
||||||
return None
|
logger.error("Sandbox: не получен file_uri в ответе на загрузку")
|
||||||
except requests.exceptions.RequestException as exc:
|
return None
|
||||||
logger.error("Ошибка отправки файла %s в Sandbox: %s",
|
logger.debug("Файл загружен, file_uri=%s", file_uri)
|
||||||
|
|
||||||
|
except requests.RequestException as exc:
|
||||||
|
logger.error("Ошибка загрузки файла %s в Sandbox: %s",
|
||||||
file_path.name, exc)
|
file_path.name, exc)
|
||||||
return None
|
return None
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
logger.error("Ошибка чтения файла %s: %s", file_path.name, exc)
|
logger.error("Ошибка чтения файла %s: %s", file_path.name, exc)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# Шаг 2: запуск проверки
|
||||||
|
scan_url = f"{self.base_url}{self.scan_endpoint}"
|
||||||
|
logger.info("Шаг 2/2: запуск проверки файла %s", file_path.name)
|
||||||
|
|
||||||
|
try:
|
||||||
|
body = {
|
||||||
|
"file_uri": file_uri,
|
||||||
|
"file_name": file_path.name,
|
||||||
|
"async_result": True,
|
||||||
|
"short_result": True,
|
||||||
|
}
|
||||||
|
resp = self._session.post(
|
||||||
|
scan_url, json=body,
|
||||||
|
timeout=(self.timeout_connect, self.timeout_read),
|
||||||
|
verify=self.verify_ssl,
|
||||||
|
)
|
||||||
|
|
||||||
|
if resp.status_code not in (200, 201, 202):
|
||||||
|
logger.error("Sandbox ошибка запуска проверки: %s: %s",
|
||||||
|
resp.status_code, resp.text[:500])
|
||||||
|
return None
|
||||||
|
|
||||||
|
scan_data = resp.json().get("data", {})
|
||||||
|
scan_id = scan_data.get("scan_id") or scan_data.get("id")
|
||||||
|
if scan_id:
|
||||||
|
logger.info("Файл %s принят Sandbox. scan_id=%s",
|
||||||
|
file_path.name, scan_id)
|
||||||
|
return str(scan_id)
|
||||||
|
|
||||||
|
logger.error("Sandbox: не получен scan_id в ответе")
|
||||||
|
return None
|
||||||
|
|
||||||
|
except requests.RequestException as exc:
|
||||||
|
logger.error("Ошибка запуска проверки %s в Sandbox: %s",
|
||||||
|
file_path.name, exc)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────
|
||||||
# Вспомогательные функции
|
# Вспомогательные функции
|
||||||
|
|||||||
Reference in new issue
Block a user