mirror of
https://github.com/RuoJi6/ARTEX.git
synced 2026-11-14 14:13:50 +08:00
feat(findings): consolidate duplicate reports into expandable cases
This commit is contained in:
1 parent
a91b27feb7
commit
24d4726aee
29 files changed
+3051
-63
No files matched your search
@@ -16,6 +16,8 @@ import (
|
||||
// UnlockSkill unlocks a named skill's MCPs — hosts call it to rebuild the unlock set
|
||||
// from history on a resumed session (design doc C2).
|
||||
type DeferredInfo struct {
|
||||
CaseGuidance string // independent of optional traffic binding
|
||||
|
||||
FindingGuidance string // derived from the final permitted tools, including DB overrides
|
||||
Deferred []string // all MCP tool names (schema withheld)
|
||||
GlobalNames []string // MCP names to list in the system-prompt block
|
||||
@@ -61,6 +63,7 @@ func AugmentTools(ctx context.Context, agentKey string, base []actool.CoreTool)
|
||||
out = ToolResolve(ctx, agentKey, out)
|
||||
}
|
||||
out, def.FindingGuidance = findingWorkflowTools(agentKey, out)
|
||||
out, def.CaseGuidance = findingCaseWorkflow(agentKey, out)
|
||||
for i, t := range out {
|
||||
out[i] = guardPanic(t)
|
||||
}
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ import (
|
||||
// skill loads. Returns a single plain segment + boundary 0 when there is no global
|
||||
// block to add.
|
||||
func deferredSystem(sysText string, def DeferredInfo) (system []string, boundary int) {
|
||||
sysText += def.FindingGuidance
|
||||
sysText += def.FindingGuidance + def.CaseGuidance
|
||||
block := actool.RenderDeferredToolsBlock(def.GlobalNames)
|
||||
if block == "" {
|
||||
return []string{sysText}, 0
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package agent
|
||||
|
||||
import actool "github.com/Autumn-27/norma/tool"
|
||||
|
||||
// This guidance is appended to the runtime prompt, including editable old prompts.
|
||||
// Never reintroduce unbound tools or recreate a deleted Reporter.
|
||||
func findingCaseWorkflow(key string, tools []actool.CoreTool) ([]actool.CoreTool, string) {
|
||||
if key != "reporter" {
|
||||
return tools, ""
|
||||
}
|
||||
has := map[string]bool{}
|
||||
for _, t := range tools {
|
||||
has[t.Name()] = true
|
||||
}
|
||||
if !has["search_finding_duplicates"] || !has["merge_finding_records"] || !has["get_finding_case"] || !has["update_finding_case_report"] {
|
||||
return tools, ""
|
||||
}
|
||||
return tools, `
|
||||
|
||||
【同一漏洞的多次上报整理】保留本次独立报告,不覆盖其他原报告。默认报告完成即停止的旧指引在此扩展:先保存本次报告,然后 search_finding_duplicates(finding_id=独立记录ID) 分页读取同任务候选摘要,按需 get_finding_record 查看证据。仅凭漏洞类型/标题相似或高中低等级不能归并;须核对目标、接口、参数、权限边界、根因及实际验证证据。明确同一缺陷时 merge_finding_records(task_id,finding_ids,title,reason),不确定时 suggest_finding_merge 留待人工确认,不能强行归并。不重复上报、不删除记录、不重新探测目标。人工选择整理时只能判断所选记录,不能加入未选记录(既有组成员可作为报告上下文)。
|
||||
归并成功或已有case_id时,get_finding_case 记录实际version,分页读取全部成员,按需get_finding_record、get_finding_traffic读取原报告、PoC及已保存流量。update_finding_case_report保存完整统一报告和基于已验证影响的severity及severity_reason;不能直接取成员最高等级。集中给出前置条件、完整执行顺序、输入输出如何衔接、可运行的完整脚本及命令,不把必要步骤分散到原报告;缺失条件、未验证步骤如实标明。版本冲突重新读取材料并生成,不能仅换version重试。各成员仍有独立报告、评级和证据。没有明确重复则保留独立记录。工具被关闭时不绕过配置。`
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
actool "github.com/Autumn-27/norma/tool"
|
||||
)
|
||||
|
||||
func TestFindingCaseGuidanceRespectsToolsAndTrafficSwitch(t *testing.T) {
|
||||
tools := []actool.CoreTool{}
|
||||
for _, name := range []string{"search_finding_duplicates", "merge_finding_records", "get_finding_case", "update_finding_case_report"} {
|
||||
tools = append(tools, writeTool(name, name, obj(nil), func(context.Context, json.RawMessage) (actool.Result, error) { return actool.Text("ok"), nil }))
|
||||
}
|
||||
_, guide := findingCaseWorkflow("reporter", tools)
|
||||
if !strings.Contains(guide, "不能直接取成员最高等级") || !strings.Contains(guide, "独立报告") {
|
||||
t.Fatal("missing preservation rules")
|
||||
}
|
||||
if _, guide := findingCaseWorkflow("worker", tools); guide != "" {
|
||||
t.Fatal("worker changed")
|
||||
}
|
||||
if _, guide := findingCaseWorkflow("reporter", tools[:2]); guide != "" {
|
||||
t.Fatal("unbound tools reintroduced")
|
||||
}
|
||||
system, _ := deferredSystem("CUSTOM PROMPT", DeferredInfo{CaseGuidance: guide})
|
||||
if !strings.HasPrefix(system[0], "CUSTOM PROMPT") || !strings.Contains(system[0], guide) {
|
||||
t.Fatal("custom prompt lost")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user