fix: Fable audit — auth Bearer + cap DELAY + fail-next + setparam try (v0.3.0)
This commit is contained in:
@@ -18,8 +18,8 @@ import config.loader as _cfg # для чтения/записи модульн
|
||||
bp = Blueprint("mock", __name__, url_prefix="/api/v1/svc/_mock")
|
||||
|
||||
# Токен для защиты _mock/* эндпоинтов (из env, опционально).
|
||||
# Если не задан — эндпоинты открыты (dev/локально).
|
||||
# Если задан — требуется заголовок X-Mock-Auth: <токен>.
|
||||
# Дублирует глобальную проверку в app.py, но оставлен для обратной совместимости
|
||||
# и ясности — _mock/* исторически имели отдельную защиту.
|
||||
_MOCK_TOKEN = os.getenv("MOCK_AUTH_TOKEN", "")
|
||||
|
||||
|
||||
@@ -29,7 +29,10 @@ def _check_mock_auth():
|
||||
|
||||
Вызывается Flask перед КАЖДЫМ обработчиком в этом blueprint'е.
|
||||
Если токен не задан в env — пропускаем всех (dev-режим).
|
||||
Если задан — требуем совпадения с заголовком."""
|
||||
Если задан — требуем совпадения с заголовком.
|
||||
|
||||
Примечание: app.before_request уже проверяет Authorization: Bearer;
|
||||
этот хук — дополнительная защита для _mock/* эндпоинтов."""
|
||||
if _MOCK_TOKEN and request.headers.get("X-Mock-Auth") != _MOCK_TOKEN:
|
||||
abort(403)
|
||||
|
||||
@@ -100,6 +103,11 @@ def mock_services():
|
||||
return jsonify({"count": len(result), "services": result})
|
||||
|
||||
|
||||
# Максимальная задержка — защита от блокировки /health (1 воркер).
|
||||
# При DELAY > healthcheck timeout платформа рестартит под.
|
||||
_MAX_DELAY = 5.0
|
||||
|
||||
|
||||
@bp.route("/delay/<string:seconds>", methods=["POST"])
|
||||
def mock_set_delay(seconds):
|
||||
"""POST /api/v1/svc/_mock/delay/{s} — изменить задержку операции.
|
||||
@@ -108,11 +116,35 @@ def mock_set_delay(seconds):
|
||||
Полезно в тестах: установить delay=0 для мгновенных операций,
|
||||
или delay=5 чтобы проверить таймауты поллинга.
|
||||
|
||||
ВАЖНО: меняет модульную переменную config.loader.DELAY, которую читает
|
||||
routes/run.py при каждом вызове /run.
|
||||
⛔ Максимум {max_delay}с — защита от блокировки /health (1 воркер).
|
||||
⛔ Минимум 0с — отрицательные значения запрещены.
|
||||
|
||||
Принимает строку и конвертирует в float — Flask <float:> не матчит
|
||||
целые числа без десятичной точки (0, 2).
|
||||
"""
|
||||
_cfg.DELAY = float(seconds)
|
||||
""".format(max_delay=_MAX_DELAY)
|
||||
try:
|
||||
val = float(seconds)
|
||||
except (ValueError, TypeError):
|
||||
return jsonify({"error": f"invalid delay: {seconds}"}), 400
|
||||
if val < 0:
|
||||
return jsonify({"error": "delay must be >= 0"}), 400
|
||||
if val > _MAX_DELAY:
|
||||
return jsonify({"error": f"delay must be <= {_MAX_DELAY}s (Nubes healthcheck protection)"}), 400
|
||||
_cfg.DELAY = val
|
||||
return jsonify({"delay": _cfg.DELAY})
|
||||
|
||||
|
||||
@bp.route("/fail-next", methods=["POST"])
|
||||
def mock_fail_next():
|
||||
"""POST /api/v1/svc/_mock/fail-next — следующая операция упадёт.
|
||||
|
||||
Устанавливает флаг в MockState. При следующем POST /run:
|
||||
- isSuccessful = False
|
||||
- errorLog = "mock failure (requested by /_mock/fail-next)"
|
||||
- эффект НЕ применяется (состояние инстанса не меняется)
|
||||
|
||||
После использования флаг сбрасывается (one-shot).
|
||||
Позволяет тестировать негативные сценарии.
|
||||
"""
|
||||
mock_state.state.fail_next = True
|
||||
return jsonify({"fail_next": True})
|
||||
|
||||
+13
-1
@@ -54,9 +54,21 @@ def run_operation(uid):
|
||||
if _cfg.DELAY > 0:
|
||||
time.sleep(_cfg.DELAY)
|
||||
|
||||
# Проверка /_mock/fail-next — симуляция падения операции
|
||||
st = mock_state.state
|
||||
if st.fail_next:
|
||||
st.fail_next = False # one-shot: сбросить после использования
|
||||
op["dtFinish"] = _now()
|
||||
op["isSuccessful"] = False
|
||||
op["errorLog"] = "mock failure (requested by /_mock/fail-next)"
|
||||
op["stages"] = [
|
||||
{"stage": "mock_error", "status": "failed", "error": "mock failure"}
|
||||
]
|
||||
return jsonify({"ok": False, "error": op["errorLog"]})
|
||||
|
||||
# Применить эффект операции к состоянию инстанса
|
||||
# (create → running+params, delete → удалить, modify → мерж params, ...)
|
||||
state_machine.apply_effect(uid, mock_state.state, _cfg.SERVICES)
|
||||
state_machine.apply_effect(uid, st, _cfg.SERVICES)
|
||||
|
||||
# Фиксируем время завершения — операция выполнена успешно
|
||||
op["dtFinish"] = _now()
|
||||
|
||||
Reference in New Issue
Block a user