Documentation
¶
Overview ¶
Package report generates an engagement's report from stored data and seals it with a SHA-256 (chain-of-custody). No LLM is in the report path: every format is a pure, deterministic function of the stored findings. PDF is rendered by the maroto renderer; HTML/DOCX are assembled into a format-agnostic ReportDocument here and handed to a DocRenderer.
Index ¶
- Constants
- func ValidType(t string) bool
- type Options
- type Service
- func (s *Service) Generate(ctx context.Context, tenantID, engagementID shared.ID) ([]byte, string, error)
- func (s *Service) RegisterFormat(format string, r ports.DocRenderer)
- func (s *Service) Render(ctx context.Context, tenantID, engagementID shared.ID, opts Options) (data []byte, contentType, sha string, err error)
- func (s *Service) SetJudgments(r judgmentReader)
Constants ¶
const ( SectionEngagement = "engagement" // engagement summary (client, dates, prepared-by) SectionScope = "scope" // scope statement + authorization window SectionMethodology = "methodology" // what was performed + standards + ordering SectionSummary = "summary" // executive summary (narrative posture) SectionRemediation = "remediation" // retest / remediation status (retest reports) SectionRisk = "risk" // risk overview (severity + priority breakdown) SectionTop = "top" // top findings to remediate first SectionFindings = "findings" // full findings table SectionDetails = "details" // per-finding detail SectionScan = "scan" // scan & SBOM insight SectionEvidence = "evidence" // evidence & chain of custody SectionExhibits = "exhibits" // inline evidence images (captured screenshots) )
Section keys the report builder can select/order. The canonical order below is also the default when a request names no sections. The leading sections (engagement → scope → methodology → summary → risk → top) make the output a client-ready deliverable, not just a findings dump.
const ( TypeSCA = "sca" // dependency / SCA report (the default, current behavior) TypeExternal = "external" // external / perimeter assessment TypeInternal = "internal" // internal network assessment TypeRetest = "retest" // remediation verification (retest) report )
Report types frame the deliverable: each picks a title, an executive-summary posture line, a methodology narrative, and a default section set. The underlying finding data is identical – only the framing + selection differ, so nothing is invented. TypeRetest additionally surfaces real retest verdicts in a Remediation Status section.
const ( FormatHTML = "html" FormatDOCX = "docx" )
Format identifiers for the document renderers (PDF has its own typed path).
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Options ¶
type Options struct {
Format string // html | docx
Type string // sca | external | internal | retest; empty = sca
Statuses []string // include only findings in these statuses; empty = all
Sections []string // include only these section keys; empty = the type's default set
Title string // override the report title; empty = the type's default / engagement name
}
Options customizes a built report (the "report builder"). Zero value = the full report in every section, no status filter. It only narrows/relabels stored data; it never adds anything not derived from the engagement.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service builds engagement reports in multiple formats.
func NewService ¶
func NewService(e ports.EngagementRepository, f ports.FindingRepository, retests ports.RetestRepository, evidence ports.ReportEvidenceProvider, r ports.ReportRenderer, insight ports.ReportInsightProvider, clock ports.Clock, version string) *Service
NewService wires the report service. insight/retests/evidence may each be nil – the report then omits the corresponding sections (scan-level executive sections, the retest remediation status, and the evidence image exhibits respectively).
func (*Service) Generate ¶
func (s *Service) Generate(ctx context.Context, tenantID, engagementID shared.ID) ([]byte, string, error)
Generate renders the engagement's PDF report from stored data and returns the PDF bytes plus the lowercase hex SHA-256 of those bytes (the integrity seal). l.findings is promotable-gated by load(), so an unproven finding never reaches the PDF.
func (*Service) RegisterFormat ¶
func (s *Service) RegisterFormat(format string, r ports.DocRenderer)
RegisterFormat registers a DocRenderer for a format key (e.g. "html", "docx"). Wired in the composition root, once per format, before the server starts serving (it mutates the renderer map and is not safe to call concurrently with Render).
func (*Service) Render ¶
func (s *Service) Render(ctx context.Context, tenantID, engagementID shared.ID, opts Options) (data []byte, contentType, sha string, err error)
Render builds a customized report in opts.Format (html|docx) from stored data and returns the bytes, MIME content-type, and the hex SHA-256 seal. The document is assembled deterministically here; the DocRenderer only formats it (no business logic, no LLM). Filename/Content-Disposition is the adapter's concern.
func (*Service) SetJudgments ¶
func (s *Service) SetJudgments(r judgmentReader)
SetJudgments wires the optional reader that projects accepted risk-narrative + correlation judgments into the report insight. nil leaves those sections empty.