Files
rengine/reports/sections/executive_summary/section.py
T
Yogesh OjhaandClaude Opus 5 724ebd42bb feat(reports): a section declares its role, its order and what it asks at generate time
Choosing what a report contains required editing a template. That is the wrong
place for a decision made per report, and the scan launch flow already
established the alternative: a saved configuration seeds the run, the run may
depart from it, and the saved configuration is never touched.

Three declarations put sections on the same footing as stages. SectionRole
separates the content a reader asked for from the furniture around it, so a
picker can offer twenty-one choices and include the cover, the contents and the
reference matter without being asked. Section.order fixes the reading order,
which until now was however the directories happened to sort — the executive
summary came after attack paths because "a" precedes "e". Section.launch_fields
names the settings worth surfacing when the report is generated rather than
only in the builder, mirroring Stage.launch_fields; the findings section
declares its severities, its detail depth, its roll-up and its asset cap.

The estimate had to become honest for any of this to be worth showing. It
counted every finding in the scan whatever the section filtered to, so dropping
three severities moved nothing. It now counts through the same severity filter
the section applies and prices each tier separately, from the real per-severity
issue counts rather than an assumed split: 28 pages against 26 rendered for a
full template, 10 against 9 for critical and high alone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AW5pitnosX8LEFEYxH8gFS
2026-09-06 17:14:01 +05:30

100 lines
3.5 KiB
Python

from __future__ import annotations
from reports.base import RenderContext, Section
from reports.config import SectionConfig, flag, paragraph
from shared.definitions.reports import SectionGroup
from shared.definitions.surface import SURFACE_LABELS, SURFACE_ORDER, SurfaceDimension
from shared.definitions.vulnerabilities import SEVERITY_LABELS, SEVERITY_ORDER, Severity
class ExecutiveSummaryConfig(SectionConfig):
show_score: bool = flag(
True,
title="Show posture score",
description="The dial and what deducted from it.",
)
show_kpis: bool = flag(True, title="Show surface figures")
show_severity: bool = flag(True, title="Show severity distribution")
show_deductions: bool = flag(True, title="Explain the score")
preamble: str = paragraph(
"", title="Opening note", description="Markdown printed before the narrative."
)
class ExecutiveSummarySection(Section):
name = "executive_summary"
title = "Executive summary"
description = "The narrative, the posture score and the figures behind both."
group = SectionGroup.SUMMARY.value
order = 10
config_model = ExecutiveSummaryConfig
def build(self, ctx: RenderContext, cfg: ExecutiveSummaryConfig) -> dict:
brief = ctx.brief
severity = [
{
"severity": key,
"label": SEVERITY_LABELS[key],
"count": brief.severity.get(key, 0),
}
for key in SEVERITY_ORDER
if key != Severity.UNKNOWN.value
]
assessed = any(
c["covered"]
for c in brief.coverage
if c["dimension"] == SurfaceDimension.VULNERABILITIES.value
)
kpis = [
{
"dimension": key,
"label": SURFACE_LABELS[key],
"value": f"{ctx.data.coverage[key].count:,}"
if ctx.data.coverage[key].covered
else "Not scanned",
"note": _note(ctx, key),
"dash": not ctx.data.coverage[key].covered,
}
for key in SURFACE_ORDER
]
return {
"narrative": ctx.narrator.executive_summary(brief),
"preamble": cfg.preamble,
"posture": brief.posture if cfg.show_score else None,
"score_arc": _arc(ctx, brief.posture.score),
"deductions": brief.posture.deductions[:5] if cfg.show_deductions else [],
"kpis": kpis if cfg.show_kpis else [],
"severity": severity if cfg.show_severity and assessed else [],
"assessed": assessed,
"headline": brief.headline,
"actionable": brief.actionable,
"kev": brief.kev_count,
"ai": ctx.narrator.ai_used and getattr(ctx.narrator, "used_model", False),
"disclose": ctx.spec.narrative.disclose_ai,
}
_GOOD, _FAIR = 80, 60
def _arc(ctx: RenderContext, score: int) -> str:
if score >= _GOOD:
return ctx.hue(1)
if score >= _FAIR:
return ctx.sev("medium")
return ctx.sev("critical")
def _note(ctx: RenderContext, dimension: str) -> str:
entry = ctx.data.coverage[dimension]
if not entry.covered:
return "no run produced this"
if entry.previous is None:
return ""
delta = entry.count - entry.previous
if delta > 0:
return f"{delta:,} more than the previous run"
if delta < 0:
return f"{abs(delta):,} fewer than the previous run"
return "unchanged"