fix(agent): list_assets 按任务范围过滤,修复任务间资产互串 (#59)

list_assets 此前把任务 id 写死为 0、裸查整个共享资产库,模型又无从写出
范围过滤条件,于是把别的任务的资产(尤其 IP)当成本任务目标,测试方向
被带偏。

- 新增 QueryDSLInScope / GetByIDsInScope:只返回落在【本任务及直接关联
  任务】task_scope 内的资产,按归属匹配而非字面值(根域范围含其全部子域/
  服务/接口,网段范围含段内主机及服务);越权 id 静默丢弃
- 新增 scopeTargetCTE(纯 scope 归属判定,不含 anchor/tested);whereBuilder
  加占位符偏移,$1 留给 taskID
- 修复 IP 直连主机(http://1.2.3.4/api)无法被网段范围命中的盲区:谓词加
  OR ts.net >>= try_inet(a.domain)
- 非任务上下文(Auto/pentest, taskID<=0)无范围可依,回退全库
- QueryDSL/CountDSL 原样未动,UI 的「测试资产」视图(按生产者过滤)不受影响
This commit is contained in:
Autumn-27 committed 2026-09-12 03:25:47 -04:00
1 parent 16e87b48c2
commit 4ccb8f4ff2
5 files changed
+267 -7

No files matched your search

+5 -5
View File
@@ -456,10 +456,10 @@ func (t *ToolSet) listUntestedAssets() actool.CoreTool {
func (t *ToolSet) listAssets() actool.CoreTool {
return readTool(
"list_assets",
"查询资产库:DSL 表达式搜索,或按 id/ids 直取;支持分页。\n"+
"查询资产库:DSL 表达式搜索,或按 id/ids 直取;支持分页。只返回【本任务及直接关联任务】测试范围内的资产。\n"+
"DSL:field=value 模糊(ILIKE) | field==value 精确 | field!=value 排除 | 数字字段支持 > >= < <= | 裸词=全文模糊;AND/OR 组合(AND 优先级高),可用括号分组。资产类型用独立 type 参数,不写进 DSL。\n"+
"未传 id/ids 时 dsl 必须非空(不允许无条件全量查询)。\n"+
"可用字段:domain(根/子/服务域名)、root_domain、ip、url、page_title、icp、service_name、app_name、method(如 GET/POST)、service_type(http|other)、record_type(如 A/CNAME)、technology(数组,=模糊 ==精确)、port/status_code/company_id/task_id(整数)。\n"+
"可用字段:domain(根/子/服务域名)、root_domain、ip、url、page_title、icp、service_name、app_name、method(如 GET/POST)、service_type(http|other)、record_type(如 A/CNAME)、technology(数组,=模糊 ==精确)、port/status_code/company_id(整数)。\n"+
"示例:status_code>=400 AND technology=shiro ;(port==80 OR port==443) AND technology=nginx",
obj(map[string]any{
"dsl": str(`DSL 查询表达式(语法/字段见工具描述)。未传 id/ids 时必须非空。`),
@@ -490,11 +490,11 @@ func (t *ToolSet) listAssets() actool.CoreTool {
var err error
switch {
case a.ID > 0:
assets, err = t.as.GetByIDs([]int64{a.ID})
assets, err = t.as.GetByIDsInScope(t.taskID, []int64{a.ID})
case len(a.IDs) > 0:
assets, err = t.as.GetByIDs(a.IDs)
assets, err = t.as.GetByIDsInScope(t.taskID, a.IDs)
case a.DSL != "":
assets, err = t.as.QueryDSL(a.DSL, a.Type, 0, a.Limit, a.Offset)
assets, err = t.as.QueryDSLInScope(a.DSL, a.Type, t.taskID, a.Limit, a.Offset)
default:
return actool.Errorf("未传 id/ids 时 dsl 不能为空:不允许无条件查询全部资产,请提供查询条件"), nil
}