fix: harden Polygon operation validation

This commit is contained in:
Repinoid
2026-10-25 14:07:13 +03:00
parent 3df89ec9e7
commit e3a031ce50
18 changed files with 803 additions and 346 deletions
+23 -26
View File
@@ -49,11 +49,16 @@ def _build_spec():
"""Собрать OpenAPI 3.1.0 спецификацию.
Включает:
- Все 17 эндпоинтов (REST API + _mock)
- Bearer-авторизацию
- REST API и служебные _mock endpoints
- Условную авторизацию _mock/* через X-Mock-Auth
- Схемы: Service, Instance, Operation, CfsParam, Stage
- Примеры запросов и ответов
"""
stand_descriptions = "\n".join(
f"- **{stand_id}** — {len(stand['SERVICES'])} сервисов"
for stand_id, stand in _cfg.STANDS.items()
)
return {
"openapi": "3.1.0",
"info": {
@@ -65,10 +70,8 @@ def _build_spec():
"операции, параметры, валидацию — но работает **без реальной инфраструктуры**, "
"в памяти, с мгновенным откликом.\n\n"
"### Стенды\n"
"**3 изолированных стенда** — переключайте в выпадающем списке серверов выше:\n"
"- **dev** — 37 сервисов (разработка)\n"
"- **test** — 37 сервисов (тестирование)\n"
"- **prod** — 35 сервисов (продуктив)\n"
f"**{len(_cfg.STANDS)} изолированных стенда** — переключайте в выпадающем списке серверов выше:\n"
f"{stand_descriptions}\n"
"У каждого стенда **свои инстансы, свои операции, своё состояние**.\n\n"
"### Особенности\n"
"- Все операции синхронные (настраиваемая задержка через `/_mock/delay`)\n"
@@ -78,8 +81,8 @@ def _build_spec():
"- Симуляция ошибок через `/_mock/fail-next`\n\n"
"### Авторизация\n"
"- Основные эндпоинты — без авторизации\n"
"- `_mock/*` — заголовок `X-Mock-Auth: test-token-123` "
"(настроен через `MOCK_AUTH_TOKEN`)"
"- `_mock/*` требуют заголовок `X-Mock-Auth`, только если на сервере "
"задан `MOCK_AUTH_TOKEN`"
),
"contact": {
"name": "Nubes Platform",
@@ -101,7 +104,7 @@ def _build_spec():
"type": "apiKey",
"in": "header",
"name": "X-Mock-Auth",
"description": "Токен для _mock/* эндпоинтов (по умолчанию: test-token-123)",
"description": "Нужен для _mock/* только если MOCK_AUTH_TOKEN задан на сервере.",
},
},
"schemas": {
@@ -170,7 +173,7 @@ def _build_spec():
"serviceId": {"type": "integer"},
"displayName": {"type": "string"},
"descr": {"type": "string"},
"status": {"type": "string", "description": "creating | running | modifying | deleting | suspended"},
"status": {"type": "string", "description": "creating | running | suspended"},
"explainedStatus": {"type": "string"},
"svc": {"type": "string"},
"dtCreate": {"type": "string", "format": "date-time"},
@@ -209,20 +212,14 @@ def _build_spec():
"svcOperationCfsParamId": {"type": "integer", "description": "ID параметра"},
"svcOperationCfsParam": {"type": "string", "description": "Название параметра"},
"dataType": {"type": "string", "description": "string | integer | map | map-fixed | boolean"},
"dataDescriptor": {"type": "string", "description": "JSON-описание подполей (для map-типов)"},
"dataDescriptor": {"type": "object", "description": "Описание подполей (для map-типов)"},
"isRequired": {"type": "boolean"},
"isModifiable": {"type": "boolean"},
"defaultValue": {"type": "string"},
"paramValue": {"type": "string", "description": "Текущее значение (если задано)"},
"valueList": {
"type": "array",
"items": {
"type": "object",
"properties": {
"value": {"type": "string"},
"label": {"type": "string"},
},
},
"items": {"type": "string"},
},
},
},
@@ -249,7 +246,7 @@ def _build_spec():
"instanceUid": {"type": "string", "format": "uuid"},
"svcOperationId": {"type": "integer"},
"operation": {"type": "string"},
"kind": {"type": "string", "description": "instance | access"},
"kind": {"type": "string", "description": "instance | subresource"},
"action": {"type": "string", "description": "create | modify | delete | …"},
"dtStart": {"type": ["string", "null"], "format": "date-time"},
"dtFinish": {"type": ["string", "null"], "format": "date-time"},
@@ -406,8 +403,8 @@ def _build_paths():
{
"name": "pageSize",
"in": "query",
"schema": {"type": "integer", "default": 200},
"description": "Размер страницы (значения > 200 обрезаются до 200)",
"schema": {"type": "integer", "default": 200, "minimum": 1, "maximum": 200},
"description": "Размер страницы (значения ограничиваются диапазоном 1…200)",
},
{
"name": "page",
@@ -720,7 +717,7 @@ def _build_paths():
"summary": "Сброс состояния",
"description": "Удаляет **все** инстансы, операции и параметры. Используется в тестах для изоляции.",
"operationId": "mockReset",
"security": [{"mockAuth": []}],
"security": [{"mockAuth": []}, {}],
"responses": {
"200": {
"description": "Состояние сброшено",
@@ -735,7 +732,7 @@ def _build_paths():
"summary": "Дамп состояния",
"description": "Возвращает все инстансы и операции для отладки.",
"operationId": "mockState",
"security": [{"mockAuth": []}],
"security": [{"mockAuth": []}, {}],
"responses": {
"200": {
"description": "Текущее состояние",
@@ -750,7 +747,7 @@ def _build_paths():
"summary": "Список загруженных сервисов",
"description": "Возвращает все загруженные сервисы с количеством операций и параметров.",
"operationId": "mockServices",
"security": [{"mockAuth": []}],
"security": [{"mockAuth": []}, {}],
"responses": {
"200": {
"description": "Список сервисов",
@@ -768,7 +765,7 @@ def _build_paths():
"Минимум: 0, максимум: 5 (защита /health)."
),
"operationId": "mockSetDelay",
"security": [{"mockAuth": []}],
"security": [{"mockAuth": []}, {}],
"parameters": [
{
"name": "seconds",
@@ -799,7 +796,7 @@ def _build_paths():
"Позволяет тестировать негативные сценарии."
),
"operationId": "mockFailNext",
"security": [{"mockAuth": []}],
"security": [{"mockAuth": []}, {}],
"responses": {
"200": {
"description": "Флаг установлен",