Files
ARTEX-chixuweihu/report/report.go
T
Autumn-27 ff3d41ea35 feat: 漏洞新增 severity=critical(严重) 与 name(漏洞名称)字段
severity 严重级:
- report_finding 工具 severity 说明改为 critical|high|medium|low
- DB 排序 CASE、report 报告 sevRank、FindingStats 增加 critical
- 前端 Severity 类型、status.ts 新增 rose 色调(实心高强调,视觉高于高危)、
  发现页严重度筛选/统计卡、任务发现 Tab 排序、dashboard 汇总均加入严重

name 漏洞名称:
- findings 表加 name 列(schema + ALTER TABLE ADD COLUMN IF NOT EXISTS 补旧库)
- report_finding 工具新增 name 入参(非必填),写入 node payload 与独立 findings 行
- DBFinding/AddFinding/AddStandaloneFinding、FindingDTO、findingPayload、report 全链路透传
- 发现列表页与任务发现 Tab 展示 name,为空时回退 vulnclass;vulnclass 移到展开详情「类型」
- report 报告标题优先 name,回退 vulnclass

无 CHECK 约束,旧库仅需补 name 列;critical/name 均向后兼容。
db 测试补充 critical 排序/统计与 name 往返断言。
2026-08-18 11:21:08 -04:00

100 lines
2.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package report renders a deliverable Markdown report from the exploration
// graph: confirmed findings (with severity/evidence) (docs §15 P5).
package report
import (
"encoding/json"
"fmt"
"sort"
"strings"
"time"
"github.com/Autumn-27/artex/db"
)
// Input bundles what the report needs.
type Input struct {
Title string
Goal string
GeneratedAt time.Time
AssetCounts map[string]int
Findings []*db.Node
}
type findingView struct {
VulnClass string
Name string
Severity string
Summary string
PoC string
}
func parseFinding(n *db.Node) findingView {
var p struct {
VulnClass string `json:"vulnclass"`
Name string `json:"name"`
Severity string `json:"severity"`
Summary string `json:"summary"`
Evidence struct {
PoC string `json:"poc"`
} `json:"evidence"`
}
_ = json.Unmarshal(n.Payload, &p)
return findingView{p.VulnClass, p.Name, p.Severity, p.Summary, p.Evidence.PoC}
}
var sevRank = map[string]int{"critical": 0, "high": 1, "medium": 2, "low": 3, "": 4}
// Markdown renders the report.
func Markdown(in Input) string {
var b strings.Builder
fmt.Fprintf(&b, "# 渗透测试报告 — %s\n\n", nz(in.Title, "未命名任务"))
fmt.Fprintf(&b, "- **任务目标**:%s\n", nz(in.Goal, "(未指定)"))
fmt.Fprintf(&b, "- **生成时间**:%s\n\n", in.GeneratedAt.Format("2006-01-02 15:04:05"))
// summary
fmt.Fprintf(&b, "## 摘要\n\n")
fmt.Fprintf(&b, "- 确认发现:**%d** 个\n", len(in.Findings))
fmt.Fprintf(&b, "- 资产:")
var types []string
for t := range in.AssetCounts {
types = append(types, t)
}
sort.Strings(types)
for i, t := range types {
if i > 0 {
b.WriteString("、")
}
fmt.Fprintf(&b, "%s %d", t, in.AssetCounts[t])
}
b.WriteString("\n\n")
// findings
fmt.Fprintf(&b, "## 发现\n\n")
if len(in.Findings) == 0 {
b.WriteString("_本次未确认漏洞。_\n\n")
} else {
fs := make([]findingView, 0, len(in.Findings))
for _, n := range in.Findings {
fs = append(fs, parseFinding(n))
}
sort.SliceStable(fs, func(i, j int) bool { return sevRank[fs[i].Severity] < sevRank[fs[j].Severity] })
for i, f := range fs {
fmt.Fprintf(&b, "### %d. [%s] %s\n\n", i+1, strings.ToUpper(nz(f.Severity, "info")), nz(f.Name, nz(f.VulnClass, "未分类")))
fmt.Fprintf(&b, "%s\n\n", nz(f.Summary, ""))
if f.PoC != "" {
fmt.Fprintf(&b, "**PoC / 证据:**\n\n```\n%s\n```\n\n", f.PoC)
}
}
}
return b.String()
}
func nz(s, d string) string {
if strings.TrimSpace(s) == "" {
return d
}
return s
}