fix: 修改接口联调问题 --story=135517916 - #836
Conversation
There was a problem hiding this comment.
Code Review 总结
本 PR 主要新增了批量删除模板接口、模板/任务列表的标签过滤功能、标签列表的 include_children 参数,并清理了旧的 sdk_label 相关 API 资源。文档和 api-resources.yml 已同步更新。
主要问题:
⚠️ get_task_list未对远程调用结果做成功判断即访问嵌套字段,可能导致 500⚠️ get_template_list中id和label同时传入时id__in会被覆盖- ✨
BatchDeleteTemplateSerializer缺少max_length限制 - ✨
batch_delete_template错误信息建议使用ugettext_lazy
整体代码结构清晰,权限配置合理(apigw default backend + appVerifiedRequired),文档同步完整。
| client = TaskComponentClient(space_id=space_id) | ||
| result = client.task_list(data=data) | ||
| label_ids = [] | ||
| for item in result["data"]["results"]: |
There was a problem hiding this comment.
result["data"]["results"],未检查 result.get("result") 是否为 True。若 client.task_list 返回错误响应(如下游超时),会触发 KeyError 导致 500。建议加 if not result.get("result"): return result 提前返回。
| template_ids_subquery = TemplateLabelRelation.objects.filter(label_id__in=label_ids).values_list( | ||
| "template_id", flat=True | ||
| ) | ||
| filter_kwargs["id__in"] = Subquery(template_ids_subquery) |
There was a problem hiding this comment.
id 和 label 参数时,两者都会设置 filter_kwargs["id__in"],后处理的会覆盖前者。建议对 id 筛选和 label 筛选使用不同的 queryset filter 策略(如分开 .filter() 调用),或检测冲突取交集。
|
|
||
|
|
||
| class BatchDeleteTemplateSerializer(serializers.Serializer): | ||
| template_ids = serializers.ListField(help_text=_("模板ID列表"), required=True, child=serializers.IntegerField()) |
There was a problem hiding this comment.
✨ template_ids 缺少 max_length 限制,恶意调用方可传入超大列表导致 DB 压力。建议参考项目中 task_id_list 的做法,添加 max_length=50(或合理上限)。
| failed_data["root_template_info"] = dict(sub_root_map) | ||
|
|
||
| if failed_data: | ||
| return {"result": False, "data": failed_data, "code": err_code.VALIDATION_ERROR.code, "message": "模板被引用,无法删除"} |
There was a problem hiding this comment.
✨ 硬编码中文错误信息 "模板被引用,无法删除" 建议使用 ugettext_lazy("模板被引用,无法删除") 保持国际化一致性。
| trigger_ids = Trigger.objects.filter(template_id__in=template_ids).values_list("id", flat=True) | ||
| Trigger.objects.batch_delete_by_ids(space_id=space_id, trigger_ids=list(trigger_ids)) | ||
| TemplateLabelRelation.objects.filter(template_id__in=template_ids).delete() | ||
| except Exception as e: |
There was a problem hiding this comment.
Exception 并直接返回 str(e) 可能泄露内部实现细节(如 DB 表名、SQL 片段)。建议添加日志记录完整异常栈,对外只返回通用错误提示。
There was a problem hiding this comment.
Code Review 总结(增量)
本次增量审查针对新推送的提交。之前报告的部分问题已修复,但 get_task_list 中的条件判断逻辑出现了新的严重 bug。
已解决的问题:
- ✅
get_template_list中id和label同时传入时id__in覆盖问题已通过链式.filter()解决 - ✅
batch_delete_template错误信息已使用ugettext_lazy
新发现问题:
- 🚨
get_task_list中if not result.get("result")条件反转,导致成功时跳过标签富化、失败时访问不存在的字段触发 500 ⚠️ get_label_ids_by_names新增space_id过滤后遗漏默认标签(space_id=-1)- ✨
BatchDeleteTemplateSerializer.template_ids仍缺少max_length限制
|
|
||
| client = TaskComponentClient(space_id=space_id) | ||
| result = client.task_list(data=data) | ||
| if not result.get("result"): |
There was a problem hiding this comment.
🚨 条件反转:if not result.get("result") 表示调用失败时才进入标签富化逻辑,成功时反而跳过。应改为 if result.get("result")。当前逻辑在失败响应上访问 result["data"]["results"] 会触发 KeyError 导致 500。
| for keyword in labels: | ||
| q_objects |= Q(name__icontains=keyword) | ||
| label_ids = list(Label.objects.filter(q_objects).values_list("id", flat=True)) | ||
| label_ids = list(Label.objects.filter(q_objects, space_id=space_id).values_list("id", flat=True)) |
There was a problem hiding this comment.
space_id=space_id 过滤后,默认标签(space_id=-1)将无法被匹配到。参考 label/views.py:52 的做法,建议改为 space_id__in=[-1, space_id],与项目中其他标签查询的语义保持一致。
There was a problem hiding this comment.
✅ 此问题已在最新提交 b481b06 中解决,现在使用 space_id__in=[-1, space_id] 过滤。
|
|
||
|
|
||
| class BatchDeleteTemplateSerializer(serializers.Serializer): | ||
| template_ids = serializers.ListField(help_text=_("模板ID列表"), required=True, child=serializers.IntegerField()) |
There was a problem hiding this comment.
✨ template_ids 仍缺少 max_length 限制,恶意调用方可传入超大列表导致 DB 压力。建议添加 max_length=50(或合理上限)。
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #836 +/- ##
===========================================
- Coverage 83.83% 83.60% -0.24%
===========================================
Files 323 324 +1
Lines 20617 20722 +105
===========================================
+ Hits 17285 17324 +39
- Misses 3332 3398 +66 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Code Review 总结(增量)
本次针对最新提交 4d3b922 的增量审查。
已解决的问题:
- ✅
get_task_list中if not result.get("result")条件反转 bug 已修复为if result.get("result")
仍未解决的问题(已在先前评论中指出,不重复报告):
get_label_ids_by_names使用space_id=space_id遗漏默认标签(space_id=-1)BatchDeleteTemplateSerializer.template_ids缺少max_length限制
新发现问题:
⚠️ bkflow/interface/task/view.py:70:与apigw/views/get_task_list.py相同的问题——未检查result.get("result")即访问result["data"]["results"]。apigw侧已在本 PR 中修复(加了if result.get("result"):保护),建议此处也做相同处理,避免下游超时时 KeyError 导致 500。
整体来看,本次提交正确修复了关键的条件反转 bug,标签富化逻辑现在可以正常工作。
| query_params = request.query_params.copy() | ||
| labels = request.query_params.get("label", "") | ||
| label_ids = Label.get_label_ids_by_names(labels) | ||
| label_ids = Label.get_label_ids_by_names(labels, space_id) |
There was a problem hiding this comment.
result["data"]["results"] 未做成功判断。apigw/views/get_task_list.py 已在本 PR 中修复(加了 if result.get("result"): 保护),建议此处也做相同处理,避免下游超时时 KeyError 导致 500。
| with transaction.atomic(): | ||
| Template.objects.filter(space_id=space_id, id__in=template_ids, is_deleted=False).update(is_deleted=True) | ||
| clear_result = clear_scope_webhooks([str(tid) for tid in template_ids]) | ||
| if not clear_result["result"]: | ||
| message = clear_result["message"] | ||
| raise Exception(message) | ||
| trigger_ids = Trigger.objects.filter(template_id__in=template_ids).values_list("id", flat=True) | ||
| Trigger.objects.batch_delete_by_ids(space_id=space_id, trigger_ids=list(trigger_ids)) | ||
| TemplateLabelRelation.objects.filter(template_id__in=template_ids).delete() |
There was a problem hiding this comment.
template_ids 未校验归属空间:只有 Template 软删带了 space_id 过滤,clear_scope_webhooks、Trigger 删除、TemplateLabelRelation.delete() 都只按 template_id 过滤。空间 A 的 app 传入空间 B 的 template_ids 时,B 的模板删不掉,但它的 Webhook / 周期触发器 / 标签关联会被删,接口仍返回 result: True(实测 Template 更新 0 行、标签关联删除 1 行)。上面引用检查里的 Template.objects.filter(id__in=all_needed_template_ids) 同样缺空间过滤,会带出其它空间的模板名。
建议先收敛出本空间的 id 再执行清理:
valid_ids = set(Template.objects.filter(space_id=space_id, id__in=template_ids, is_deleted=False).values_list("id", flat=True))
if set(template_ids) - valid_ids:
return {"result": False, "code": err_code.VALIDATION_ERROR.code, "message": _("模板不存在或不属于当前空间")}There was a problem hiding this comment.
✅ 此问题已在最新提交 b481b06 中解决。现在先收敛 valid_ids(校验归属空间),后续所有操作(DecisionTable、Trigger、TemplateLabelRelation、clear_scope_webhooks)均基于 valid_ids 执行,不再存在跨空间误操作风险。
| for keyword in labels: | ||
| q_objects |= Q(name__icontains=keyword) | ||
| label_ids = list(Label.objects.filter(q_objects).values_list("id", flat=True)) | ||
| label_ids = list(Label.objects.filter(q_objects, space_id=space_id).values_list("id", flat=True)) |
There was a problem hiding this comment.
space_id=space_id 会排除默认标签(space_id=-1),但列表侧用的是 space_id__in=[-1, space_id](get_label_list.py:30、label/views.py:52)——默认标签列表里可见,按名字却筛不到。叠加本 PR 把空结果改成 filter(id__in=[]),按默认标签筛选模板会从「返回全部」变成「返回空列表」。
建议:Label.objects.filter(q_objects, space_id__in=[-1, space_id])
There was a problem hiding this comment.
Code Review 总结(增量)
本次针对最新提交 b481b06 的增量审查。
已解决的问题:
- ✅
get_label_ids_by_names中space_id过滤已修复为space_id__in=[-1, space_id],默认标签现在可被正确匹配 - ✅
batch_delete_template跨空间安全问题已修复:新增valid_ids归属校验,所有子操作均使用valid_ids+space_id过滤
新发现问题:
- 🚨
bkflow/label/models.py:177—s.strip缺少括号,应为s.strip()。方法引用恒为 truthy,导致空字符串不会被过滤,后续会以空串构建Q(name__icontains="")匹配所有标签
仍未解决的问题(已在先前评论中指出,不重复报告):
interface/task/view.py:70未做result.get("result")成功判断batch_delete_template中raise Exception(message)可能泄露内部信息BatchDeleteTemplateSerializer.template_ids缺少max_length限制
| def get_label_ids_by_names(names, space_id): | ||
| """通过标签名称列表获取对应的标签ID列表""" | ||
| labels = [s.strip() for s in re.split(r"[,\s]+", names) if s.strip()] | ||
| labels = [s.strip() for s in re.split(r"[,\s]+", names) if s.strip] |
There was a problem hiding this comment.
🚨 s.strip 缺少括号,应为 s.strip()。方法引用(bound method)恒为 truthy,不会过滤掉空字符串,导致空串进入 Q(name__icontains="") 匹配所有标签——标签筛选将完全失效。
There was a problem hiding this comment.
✅ 此问题已在最新提交 4da513d 中解决,s.strip 已修正为 s.strip()。
There was a problem hiding this comment.
Code Review 总结(增量)
本次针对最新提交 4da513d 的增量审查。
已解决的问题:
- ✅
bkflow/label/models.py:177—s.strip缺少括号的 bug 已修复为s.strip(),标签过滤功能现在可以正确工作
仍未解决的问题(已在先前评论中指出,不重复报告):
interface/task/view.py:70未做result.get("result")成功判断即访问嵌套字段BatchDeleteTemplateSerializer.template_ids缺少max_length限制batch_delete_template中raise Exception(message)可能泄露内部信息
本次无新发现问题。 最新提交精准修复了先前报告的 Critical 级别 bug,代码变更正确且最小化。
No description provided.