Files
ARTEX-chixuweihu/report/report.go
T
Autumn-27andClaude Opus 4.8 0ef8561411 chore: ARTEX 初始化
ARTEX — AI 自主渗透测试系统(Go 后端 + Next.js 前端,单二进制内嵌)。

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-26 04:27:45 -04:00

98 lines
2.4 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
Severity string
Summary string
PoC string
}
func parseFinding(n *db.Node) findingView {
var p struct {
VulnClass string `json:"vulnclass"`
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.Severity, p.Summary, p.Evidence.PoC}
}
var sevRank = map[string]int{"high": 0, "medium": 1, "low": 2, "": 3}
// 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.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
}