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
+43 -22
View File
@@ -130,44 +130,48 @@ def create_operation():
Также заполняет kind и action операции из конфига сервиса — они нужны
state_machine.apply_effect() чтобы понять что делать при run.
"""
body = request.get_json(silent=True) or {}
body = request.get_json(silent=True)
if not isinstance(body, dict):
return jsonify({"error": "request body must be a JSON object"}), 400
instance_uid = body.get("instanceUid")
operation = body.get("operation", "")
svc_op_id = body.get("svcOperationId")
# Валидация: instanceUid обязателен
if not instance_uid:
if not isinstance(instance_uid, str) or not instance_uid:
return jsonify({"error": "instanceUid is required"}), 400
if not isinstance(operation, str) or not operation:
return jsonify({"error": "operation must be a non-empty string"}), 400
# Проверка что инстанс существует
inst = state.get_instance(instance_uid)
if not inst:
return jsonify({"error": "instance not found"}), 404
# Если svcOperationId не передан — найти по имени операции
# (например app-autotest при create не знает ID, передаёт только "create")
svc_id = inst.get("serviceId")
svc_def = SERVICES.get(svc_id, {})
service_operations = svc_def.get("operations", [])
# При create app-autotest может передать только имя операции.
if svc_op_id is None:
svc_id = inst.get("serviceId")
svc_def = SERVICES.get(svc_id, {})
for op in svc_def.get("operations", []):
for op in service_operations:
if op["operation"] == operation:
svc_op_id = op["svcOperationId"]
break
elif not isinstance(svc_op_id, int) or isinstance(svc_op_id, bool):
return jsonify({"error": "svcOperationId must be an integer"}), 400
# Если и после поиска не нашли — операция не поддерживается сервисом
if svc_op_id is None:
# ID должен принадлежать именно сервису инстанса, не только глобальному индексу.
target_op = next(
(op for op in service_operations if op["svcOperationId"] == svc_op_id),
None,
)
if target_op is None:
return jsonify({"error": f"operation '{operation}' not found for service"}), 404
# Определить kind и action операции из конфига
# (один проход — поиск по svcOperationId, не по имени)
svc_def = OPS_INDEX.get(svc_op_id, {})
kind = "instance"
action = operation
for op in svc_def.get("operations", []):
if op["svcOperationId"] == svc_op_id:
kind = op.get("kind", "instance")
action = op.get("action", operation)
break
kind = target_op.get("kind", "instance")
action = target_op.get("action", operation)
# Создать операцию в MockState (dtFinish=None — ещё не выполнена)
op_uid = state.create_operation(instance_uid, svc_op_id, operation, kind, action)
@@ -228,7 +232,10 @@ def set_operation_param():
Значения сохраняются в mock_state.op_params[opUid][paramId] = value.
При apply_effect (modify) значения мержатся в state.params инстанса.
"""
body = request.get_json(silent=True) or {}
body = request.get_json(silent=True)
if not isinstance(body, dict):
return jsonify({"error": "request body must be a JSON object"}), 400
op_uid = body.get("instanceOperationUid")
param_id = body.get("svcOperationCfsParamId")
value = body.get("paramValue", "")
@@ -241,9 +248,23 @@ def set_operation_param():
if not isinstance(param_id, int) or isinstance(param_id, bool):
return jsonify({"error": "svcOperationCfsParamId must be an integer"}), 400
# Проверка что операция существует
if not state.get_operation(op_uid):
# Проверка что операция существует и ещё не завершена.
op = state.get_operation(op_uid)
if not op:
return jsonify({"error": "operation not found"}), 404
if op.get("dtFinish") is not None:
return jsonify({"error": "operation already completed"}), 409
if not isinstance(value, str):
return jsonify({"error": "paramValue must be a string"}), 400
inst = state.get_instance(op.get("instanceUid"))
if not inst:
return jsonify({"error": "instance not found"}), 404
svc_def = SERVICES.get(inst.get("serviceId"), {})
valid_param_ids = svc_def.get("cfsParamsByOp", {}).get(op.get("svcOperationId"), [])
if param_id not in valid_param_ids:
return jsonify({"error": "parameter not found for operation"}), 400
# Сохранить параметр (param_id — int, value — str)
state.set_param(op_uid, param_id, value)