Files
ARTEX-chixuweihu/server/finding_cases_export.go
T

125 lines
3.9 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 server
import (
"fmt"
"strings"
"github.com/Autumn-27/artex/db"
)
type findingCaseExportPlan struct {
cases map[int64]*db.FindingCase
membership map[int64]int64
selected map[int64]bool
}
// Expand selection to complete cases before the evidence store freezes snapshots.
func (s *Server) prepareFindingCaseExport(fs []*db.DBFinding) ([]*db.DBFinding, *findingCaseExportPlan, error) {
plan := &findingCaseExportPlan{cases: map[int64]*db.FindingCase{}, membership: map[int64]int64{}, selected: map[int64]bool{}}
expanded := append([]*db.DBFinding{}, fs...)
seen := map[int64]bool{}
for _, f := range fs {
seen[f.ID] = true
plan.selected[f.ID] = true
}
for _, f := range fs {
cid, err := s.m.pg.FindingCaseID(f.ID)
if err != nil {
return nil, nil, err
}
if cid == 0 {
continue
}
if _, ok := plan.cases[cid]; ok {
continue
}
c, err := s.m.pg.GetFindingCase(cid)
if err != nil {
return nil, nil, err
}
if c == nil || !c.Active {
continue
}
plan.cases[cid] = c
members, _, err := s.m.pg.FindingCaseMembers(cid, 1, 1000000)
if err != nil {
return nil, nil, err
}
for _, m := range members {
plan.membership[m.ID] = cid
if !seen[m.ID] {
seen[m.ID] = true
expanded = append(expanded, m)
}
}
}
return expanded, plan, nil
}
// Composites are built AFTER staging real records, so their traffic attachments
// remain private frozen export copies, not aliases to live or deleted evidence.
func (s *Server) consolidateFindingCaseExport(fs []*db.DBFinding, plan *findingCaseExportPlan, includeOriginals bool) ([]*db.DBFinding, error) {
out := []*db.DBFinding{}
emitted := map[int64]bool{}
for _, f := range fs {
cid := plan.membership[f.ID]
if cid == 0 {
if plan.selected[f.ID] {
out = append(out, f)
}
continue
}
if !emitted[cid] {
emitted[cid] = true
c := plan.cases[cid]
latest, err := s.m.pg.GetFindingCase(cid)
if err != nil {
return nil, err
}
stale := latest == nil || latest.Version != c.Version || c.ReportVersion != c.Version
title := c.Title
sev := c.Severity
if sev == "" {
sev = "unassessed"
}
composite := &db.DBFinding{ID: f.ID, ExportCaseID: c.ID, TaskID: c.TaskID, TaskDescription: f.TaskDescription, Name: title, VulnClass: "归并漏洞", Severity: sev, Status: f.Status, CreatedAt: c.CreatedAt, Report: c.Report, EvidenceVersion: c.Version, ReportEvidenceVersion: c.ReportVersion}
assets := map[int64]bool{}
var refs []string
var evidence strings.Builder
for _, member := range fs {
if plan.membership[member.ID] != cid {
continue
}
composite.ExportMemberIDs = append(composite.ExportMemberIDs, member.ID)
for _, aid := range member.AssetIDs {
if !assets[aid] {
assets[aid] = true
composite.AssetIDs = append(composite.AssetIDs, aid)
}
}
refs = append(refs, fmt.Sprintf("#%d [%s] %s", member.ID, member.Severity, member.Name))
fmt.Fprintf(&evidence, "原始上报 #%d:%s\n%s\n\n", member.ID, member.Summary, member.Evidence)
if member.Report != "" {
fmt.Fprintf(&evidence, "原始报告 #%d:\n%s\n\n", member.ID, member.Report)
}
for _, b := range member.TrafficBindings {
b.Note = fmt.Sprintf("来自上报 #%d;%s", member.ID, b.Note)
composite.TrafficBindings = append(composite.TrafficBindings, b)
}
}
composite.Summary = fmt.Sprintf("漏洞文件夹 #%d;原始记录:%s。统一评级依据:%s", cid, strings.Join(refs, ";"), c.SeverityReason)
composite.TrafficCount = len(composite.TrafficBindings)
if stale || c.Report == "" {
composite.Report = "**统一报告尚未生成或已过期,以下提供全部原始证据,不能视为完整复现已验证。**\n\n" + c.Report
composite.Evidence = evidence.String()
composite.ReportEvidenceVersion = -1
}
out = append(out, composite)
}
if includeOriginals {
out = append(out, f)
}
}
return out, nil
}