fix: harden Polygon operation validation
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user