526 lines
23 KiB
Python
526 lines
23 KiB
Python
"""A complete report context, filled by hand.
|
|
|
|
Every section the template can draw appears here at least once, with the content of the design
|
|
sample in ``sample_report_template/``. It is what the tests render, and what to compare a real
|
|
context against once one is built from a scan: whatever the sample shows, the template supports.
|
|
|
|
Written out rather than generated so that it stays readable as a specification of the shape. When a
|
|
section gains a field, this file is where it is seen first.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
SCAN_ID = "3f7a1c9e-8b42-4d61-9c05-27ae1f6b3d80"
|
|
|
|
|
|
def _fact(label: str, value: str, *, gap: bool = False, kind: str | None = None) -> dict[str, Any]:
|
|
"""One label/value row, optionally opening a gap above itself."""
|
|
return {"label": label, "value": value, "gap": gap, "kind": kind}
|
|
|
|
|
|
def _row(
|
|
label: str,
|
|
value: str,
|
|
*,
|
|
aside: bool = False,
|
|
kind: str | None = None,
|
|
token: str | None = None,
|
|
) -> dict[str, Any]:
|
|
"""One row of a card.
|
|
|
|
Args:
|
|
label: What the row is called.
|
|
value: What it says.
|
|
aside: Tints the row, for the one that argues rather than states.
|
|
kind: ``severity`` to colour it, ``mono`` for anything a reader might
|
|
have to type or compare character by character.
|
|
token: A VEX justification or similar, set as the token it is and placed
|
|
before the prose that explains it.
|
|
"""
|
|
return {"label": label, "value": value, "aside": aside, "kind": kind, "token": token}
|
|
|
|
|
|
def _mono(value: str) -> dict[str, Any]:
|
|
"""A grid cell set in the monospace face."""
|
|
return {"value": value, "kind": "mono"}
|
|
|
|
|
|
def _sev(value: str) -> dict[str, Any]:
|
|
"""A grid cell carrying a severity's colour."""
|
|
return {"value": value, "kind": "severity"}
|
|
|
|
|
|
def _bar(label: str, count: int, parts: list[tuple[str, float]], *, mono: bool = False) -> dict[str, Any]:
|
|
"""One distribution row: a label, its count, and the severity segments of its bar.
|
|
|
|
``mono`` sets the label in the monospace face, for the rows labelled by a package rather than by
|
|
a sentence.
|
|
"""
|
|
return {
|
|
"label": label,
|
|
"count": count,
|
|
"mono": mono,
|
|
"parts": [{"severity": severity, "share": share} for severity, share in parts],
|
|
}
|
|
|
|
|
|
def _cover() -> dict[str, Any]:
|
|
"""The first page: who it is about, and the one table that answers "how bad"."""
|
|
return {
|
|
"scan_id": SCAN_ID,
|
|
"subject": "SampleRepository v2.4.0",
|
|
"footer_date": "16 September 2026",
|
|
"logo": "cc_logo.png",
|
|
"title": "SAST/SCA Report",
|
|
"identity": [
|
|
_fact("Scan Identifier", SCAN_ID, kind="mono"),
|
|
_fact("Report ID", "b64d05f2-1ac7-4e9a-8f13-6d20c9b47e55", kind="mono"),
|
|
_fact("Artifact ID", "e1c8a730-5f96-42bb-b0d4-9a7351ec2f18", kind="mono"),
|
|
_fact("Technology", "SAST, SCA"),
|
|
_fact("Project", "SampleRepository", gap=True),
|
|
_fact("Version", "v2.4.0 (commit 9f3c2ab1d4e7)"),
|
|
_fact("Report Created", "Wednesday, September 16, 2026"),
|
|
_fact("Manufacturer", "Firma XY welche den Code besitzt"),
|
|
],
|
|
"severity_ledger": {
|
|
"title": "True issues by severity",
|
|
"rows": [
|
|
{"label": "Critical severity issues", "count": 3},
|
|
{"label": "High severity issues", "count": 73},
|
|
{"label": "Medium severity issues", "count": 28},
|
|
{"label": "Low severity issues", "count": 11},
|
|
{"label": "Total true issues", "count": 115, "total": True},
|
|
],
|
|
},
|
|
}
|
|
|
|
|
|
def _scan() -> dict[str, Any]:
|
|
"""What the pipeline did, stage by stage, and what each stage was configured with."""
|
|
return {
|
|
"title": "CipherCell Scan Information",
|
|
"overview": [
|
|
_fact("Scan started at", "Wednesday, September 16, 2026 05:43:14 (UTC)"),
|
|
_fact("Scan duration", "07:30:38"),
|
|
_fact("Scan completed at", "Wednesday, September 16, 2026 13:13:52 (UTC)"),
|
|
_fact(
|
|
"Pipeline Steps",
|
|
"Preanalysis, SAST, SBOM Dependency Tracking, SBOM Reachability, AI FP Detection, AI Ranking",
|
|
),
|
|
_fact("Errors Detected", "None (2 warnings, see SBOM Reachability)"),
|
|
],
|
|
"stages": [
|
|
{
|
|
"title": "Pre-Analysis Settings",
|
|
"rows": [
|
|
_fact("Selected Tools", "Propylon v0.9.4"),
|
|
_fact("Profile", "deterministic"),
|
|
_fact("Errors Detected", "None"),
|
|
],
|
|
},
|
|
{
|
|
"title": "SAST Settings",
|
|
"rows": [
|
|
_fact("Selected Tools", "ruff v0.14.4, bandit v1.8.6, cppcheck v2.18.0, semgrep v1.145.0"),
|
|
_fact("Language Coverage", "C (cppcheck, semgrep), Python (ruff, bandit, semgrep)"),
|
|
_fact("Rule Profile", "security — ruleset ciphercell-sec-2026.03, sha256 8f2b41c6…d97a"),
|
|
_fact("Deduplication Method", "Deterministic"),
|
|
_fact("Created Artifacts", "sast_combined.sarif", kind="mono"),
|
|
_fact("Errors Detected", "None"),
|
|
],
|
|
},
|
|
{
|
|
"title": "SBOM Dependency Tracking Settings",
|
|
"rows": [
|
|
_fact("Selected Tools", "syft v1.33.0, cdxgen v11.10.0, deptrace v0.7.2"),
|
|
_fact("Profile", "Standard SBOM"),
|
|
_fact("SBOM Format", "CycloneDX 1.6"),
|
|
_fact("Advisory Sources", "NVD, OSV.dev, GitHub Advisory Database, Sonatype OSS Index"),
|
|
_fact("Created Artifacts", "sbom.cdx.json, sbom.vdr.json", kind="mono"),
|
|
_fact("Errors Detected", "None"),
|
|
],
|
|
},
|
|
{
|
|
"title": "SBOM Reachability",
|
|
"rows": [
|
|
_fact("Selected Tools", "CodeQL v2.24.1, Joern v4.0.312"),
|
|
_fact("Profile", "Default Taint Analysis"),
|
|
_fact("Created Artifacts", "sbom_annotated.vdr.json", kind="mono"),
|
|
_fact("Errors Detected", "2 warnings"),
|
|
],
|
|
"table": {
|
|
"columns": ["ID", "Stage", "Warning"],
|
|
"rows": [
|
|
{
|
|
"cells": [
|
|
"W-01",
|
|
"Joern, JavaScript",
|
|
"2 of 148 entry points could not be resolved (dynamic require() in "
|
|
"server/plugins/loader.js:41). The 6 findings depending on these entry points "
|
|
"were escalated and are reported conservatively as true issues.",
|
|
]
|
|
},
|
|
{
|
|
"cells": [
|
|
"W-02",
|
|
"CodeQL, C",
|
|
"Database build skipped for vendored sources under third_party/; excluded by "
|
|
"scan scope, no reachability verdict is claimed for those paths.",
|
|
]
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
"title": "AI FP Detection",
|
|
"rows": [
|
|
_fact("Selected Tools", "Polygraph v1.6.2"),
|
|
_fact("Profile", "static and escalation agent"),
|
|
_fact("AI Model", "Qwen3-32B, digest sha256:4ab1…c70f"),
|
|
_fact("Inference", "On-premise, CipherCell inference cluster"),
|
|
_fact("Reasoning Effort", "Default (classification), Default (escalation)"),
|
|
_fact("Response Cache", "Enabled"),
|
|
_fact("Context Enrichment", "Static (50 lines before, 50 lines after)"),
|
|
_fact("Errors Detected", "None"),
|
|
],
|
|
},
|
|
{
|
|
"title": "Ranking",
|
|
"rows": [
|
|
_fact("Selected Tools", "Prism v0.4.1"),
|
|
_fact("Effort", "Standard"),
|
|
_fact("Context Size", "Minimal"),
|
|
_fact("Errors Detected", "None"),
|
|
],
|
|
},
|
|
],
|
|
}
|
|
|
|
|
|
def _project() -> dict[str, Any]:
|
|
"""What was scanned, and what it is written in."""
|
|
return {
|
|
"title": "Project Information",
|
|
"overview": [
|
|
_fact("Project", "SampleRepository"),
|
|
_fact("Version", "v2.4.0 (commit 9f3c2ab1d4e7)"),
|
|
_fact("Analysed lines of code", "184,920"),
|
|
],
|
|
"languages": {
|
|
"title": "Languages",
|
|
"rows": [
|
|
{"label": "C", "share": "40.2 %"},
|
|
{"label": "Python", "share": "39.6 %"},
|
|
{"label": "JavaScript", "share": "20.2 %"},
|
|
{"label": "Total", "share": "100.0 %", "total": True},
|
|
],
|
|
},
|
|
}
|
|
|
|
|
|
def _summary() -> dict[str, Any]:
|
|
"""The counts, and where they concentrate."""
|
|
return {
|
|
"title": "Summary",
|
|
"overview": [
|
|
_fact("Raw findings", "210"),
|
|
_fact("Filtered", "95 (82 SAST, 13 SCA)"),
|
|
_fact("True issues", "115 (86 SAST, 29 SCA)"),
|
|
_fact("Distinct issue types (true)", "8 SAST CWEs, 12 affected components"),
|
|
],
|
|
"distributions": [
|
|
{
|
|
"title": "True SAST issues by CWE (86)",
|
|
"rows": [
|
|
_bar("CWE-22: Improper Limitation of a Pathname to a Restricted Directory", 3, [("High", 6)]),
|
|
_bar(
|
|
"CWE-78: Improper Neutralization of Special Elements used in an OS Command",
|
|
2,
|
|
[("Critical", 4)],
|
|
),
|
|
_bar("CWE-327: Use of a Broken or Risky Cryptographic Algorithm", 3, [("Medium", 6)]),
|
|
_bar("CWE-674: Uncontrolled Recursion", 50, [("High", 84), ("Medium", 16)]),
|
|
_bar(
|
|
"CWE-770: Allocation of Resources Without Limits or Throttling",
|
|
10,
|
|
[("High", 14), ("Medium", 6)],
|
|
),
|
|
_bar("CWE-798: Use of Hard-coded Credentials", 4, [("High", 5), ("Medium", 3)]),
|
|
_bar("CWE-918: Server-Side Request Forgery", 2, [("High", 4)]),
|
|
_bar("CWE-1333: Inefficient Regular Expression Complexity", 12, [("Medium", 5), ("Low", 19)]),
|
|
],
|
|
"legend": {
|
|
"entries": [
|
|
{"severity": "Low", "label": "Low (9)"},
|
|
{"severity": "Medium", "label": "Medium (20)"},
|
|
{"severity": "High", "label": "High (55)"},
|
|
{"severity": "Critical", "label": "Critical (2)"},
|
|
],
|
|
"caveat": "bar length is proportional to the issue count (100 % = 50).",
|
|
},
|
|
},
|
|
{
|
|
"title": "Most affected components, true SCA issues (top 4 of 12)",
|
|
"rows": [
|
|
_bar("next@16.3.2", 4, [("Critical", 25), ("High", 50), ("Medium", 25)], mono=True),
|
|
_bar("glibc@2.36-9+deb12u7", 3, [("High", 75)], mono=True),
|
|
_bar("nanoid@3.3.14", 2, [("Medium", 50)], mono=True),
|
|
_bar("lodash@4.17.21", 2, [("High", 25), ("Medium", 25)], mono=True),
|
|
],
|
|
"legend": {
|
|
"entries": [
|
|
{"severity": "Low", "label": "Low"},
|
|
{"severity": "Medium", "label": "Medium"},
|
|
{"severity": "High", "label": "High"},
|
|
{"severity": "Critical", "label": "Critical"},
|
|
],
|
|
"caveat": "11 of 29 true SCA issues shown; 100 % = 4.",
|
|
},
|
|
},
|
|
],
|
|
}
|
|
|
|
|
|
def _critical() -> dict[str, Any]:
|
|
"""The handful worth reading first, whichever half of the pipeline found them."""
|
|
return {
|
|
"title": "Most Critical Vulnerabilities",
|
|
"table": {
|
|
"columns": ["Type", "Severity", "CVE/CWE", "Affected File / Component", "Description"],
|
|
"rows": [
|
|
{
|
|
"cells": [
|
|
"SAST",
|
|
_sev("Critical"),
|
|
"CWE-78",
|
|
_mono("src/tools/exporter.py:57"),
|
|
"User-controlled argument passed to subprocess.run(…, shell=True).",
|
|
]
|
|
},
|
|
{
|
|
"cells": [
|
|
"SCA",
|
|
_sev("Critical"),
|
|
"GHSA-2xp9-vwfh-vxw4",
|
|
_mono("next@16.3.2"),
|
|
"Heap buffer overflow in libheif, reached through sharp during AVIF image "
|
|
"optimization; allows unauthenticated remote code execution.",
|
|
]
|
|
},
|
|
{
|
|
"cells": [
|
|
"SAST",
|
|
_sev("High"),
|
|
"CWE-22",
|
|
_mono("src/storage/paths.py:114"),
|
|
"Non-literal path component passed to os.path.join().",
|
|
]
|
|
},
|
|
],
|
|
},
|
|
}
|
|
|
|
|
|
def _sast_section() -> dict[str, Any]:
|
|
"""The SAST findings: what was kept, and what was set aside and why."""
|
|
return {
|
|
"title": "SAST Vulnerabilities",
|
|
"groups": [
|
|
{
|
|
"title": "True Issues by CWEs",
|
|
"cards": [
|
|
{
|
|
"title": "CWE-22: Improper Limitation of a Pathname to a Restricted Directory (3 issues)",
|
|
"rows": [
|
|
_row("Severity", "High", kind="severity"),
|
|
_row(
|
|
"Description",
|
|
"A path component that is not a string literal is passed to a file system API. "
|
|
"Where the component originates from a request parameter, an attacker can "
|
|
"traverse outside the intended directory.",
|
|
),
|
|
],
|
|
},
|
|
{
|
|
"title": "CWE-22 #1 — sast-9f3c2ab-0001",
|
|
"rows": [
|
|
_row("Location", "src/storage/paths.py:114", kind="mono"),
|
|
_row(
|
|
"Description",
|
|
"Non-literal path component passed to os.path.join(). The value originates "
|
|
'from request.args["file"] and is not normalised before use.',
|
|
),
|
|
_row("Reported By", "bandit v1.8.6 (B108), semgrep v1.145.0"),
|
|
_row(
|
|
"Reachability",
|
|
"Reachable — taint path from entry point api/upload.py:31 (upload_handler), "
|
|
"4 hops (Joern)",
|
|
),
|
|
_row("Evidence", "Deterministic, no LLM escalation"),
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"title": "Filtered Issues by CWEs",
|
|
"note": (
|
|
"The following findings were reported by the scanners but assessed as not exploitable in "
|
|
"this artifact. Each entry carries the filtering reason together with the VEX justification "
|
|
"that is written to sbom_annotated.vdr.json. Filtered issues are not counted in the "
|
|
"severity summary."
|
|
),
|
|
"cards": [
|
|
{
|
|
"title": "CWE-1333 #1 — sast-9f3c2ab-0113",
|
|
"rows": [
|
|
_row("Location", "server/lib/llm.js:68", kind="mono"),
|
|
_row(
|
|
"Description", "Backtracking regular expression in the log line parser parseLogLine()."
|
|
),
|
|
_row("Reported By", "semgrep v1.145.0"),
|
|
_row(
|
|
"Filtering Reason",
|
|
"no call path from any of the 148 resolved entry points to parseLogLine(); the "
|
|
"only caller is the debug CLI, which is excluded from the production build. "
|
|
"Deterministic (Joern), no LLM escalation. Decided 2026-09-16 by Polygraph "
|
|
"v1.6.2.",
|
|
aside=True,
|
|
token="code_not_reachable",
|
|
),
|
|
],
|
|
},
|
|
],
|
|
"table": {
|
|
"title": "Filtered SAST issues by CWE (82)",
|
|
"columns": ["CWE", "Filtered", "Dominant VEX justification"],
|
|
"rows": [
|
|
{"cells": ["CWE-674: Uncontrolled Recursion", "41", _mono("protected_by_mitigating_control")]},
|
|
{
|
|
"cells": [
|
|
"CWE-1333: Inefficient Regular Expression Complexity",
|
|
"18",
|
|
_mono("code_not_reachable"),
|
|
]
|
|
},
|
|
{
|
|
"cells": [
|
|
"CWE-327: Use of a Broken or Risky Cryptographic Algorithm",
|
|
"9",
|
|
"code_not_reachable",
|
|
]
|
|
},
|
|
{"cells": ["CWE-798: Use of Hard-coded Credentials", "8", _mono("code_not_present")]},
|
|
{"cells": ["Total", "82", ""], "total": True},
|
|
],
|
|
},
|
|
},
|
|
],
|
|
}
|
|
|
|
|
|
def _sca_section() -> dict[str, Any]:
|
|
"""The dependency findings, in the same two halves."""
|
|
return {
|
|
"title": "SBOM / SCA Vulnerabilities",
|
|
"new_page": True,
|
|
"groups": [
|
|
{
|
|
"title": "True Issues by CVEs",
|
|
"cards": [
|
|
{
|
|
"title": "GHSA-2xp9-vwfh-vxw4",
|
|
"rows": [
|
|
_row("Affected component", "next@16.3.2 (via sharp → libheif@1.23.1)", kind="mono"),
|
|
_row("CVE", "None assigned"),
|
|
_row("Severity", "Critical", kind="severity"),
|
|
_row(
|
|
"Description",
|
|
"A heap buffer overflow in the libheif library used by sharp, which Next.js uses "
|
|
"for image optimization, can lead to remote code execution when AVIF files are "
|
|
"optimized.",
|
|
),
|
|
_row("CVSS", "9.5 / 10 (CVSS v4.0) — CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H"),
|
|
_row("Impact", "Confidentiality (High), Integrity (High), Availability (High)"),
|
|
_row("Fixed in", "next 16.3.3 / 15.5.24", kind="mono"),
|
|
_row(
|
|
"Reachability",
|
|
"Reachable — AVIF output is enabled in next.config.js:22 "
|
|
"(images.formats contains image/avif)",
|
|
),
|
|
_row("Known for", "22 days (advisory published 2026-08-25)"),
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"title": "Filtered Issues by CVEs",
|
|
"note": (
|
|
"Vulnerabilities present in the SBOM whose vulnerable code path is not exploitable in this "
|
|
"artifact. The filtering reason is carried into sbom.vdr.json as a CycloneDX VEX statement."
|
|
),
|
|
"cards": [
|
|
{
|
|
"title": "CVE-2026-75604 (GHSA-p293-qw3h-jr36)",
|
|
"rows": [
|
|
_row("Affected component", "next@16.3.2", kind="mono"),
|
|
_row("Reported Severity", "Critical", kind="severity"),
|
|
_row(
|
|
"Description",
|
|
"Path traversal (CWE-22) in Next.js applications served from a Windows "
|
|
"filesystem, leading to unauthenticated remote code execution.",
|
|
),
|
|
_row("CVSS", "9.0 / 10 (CVSS v3.1) — CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H"),
|
|
_row("Fixed in", "next 16.3.3 / 15.5.24", kind="mono"),
|
|
_row(
|
|
"Filtering Reason",
|
|
"the vulnerable code path only executes on a Windows filesystem. The deployment "
|
|
"target of this artifact is linux/amd64 (base image debian:12-slim, see "
|
|
"sbom.cdx.json). Deterministic, no LLM escalation.",
|
|
aside=True,
|
|
token="requires_environment",
|
|
),
|
|
_row("Known for", "22 days (advisory published 2026-08-25)"),
|
|
],
|
|
},
|
|
],
|
|
"table": {
|
|
"title": "Filtered SCA issues by justification (13)",
|
|
"columns": ["VEX justification", "Filtered", "Typical case in this artifact"],
|
|
"rows": [
|
|
{
|
|
"cells": [
|
|
_mono("code_not_reachable"),
|
|
"7",
|
|
"Development-scoped dependencies and unused packages",
|
|
]
|
|
},
|
|
{"cells": [_mono("requires_environment"), "3", "Windows-only or macOS-only code paths"]},
|
|
{
|
|
"cells": [
|
|
_mono("requires_configuration"),
|
|
"2",
|
|
"Feature flags not enabled in the shipped config",
|
|
]
|
|
},
|
|
{"cells": [_mono("code_not_present"), "1", "Vulnerable function removed by the tree shaker"]},
|
|
{"cells": ["Total", "13", ""], "total": True},
|
|
],
|
|
},
|
|
},
|
|
],
|
|
}
|
|
|
|
|
|
def sample_context() -> dict[str, Any]:
|
|
"""A complete context, covering every section the template can draw."""
|
|
return {
|
|
"cover": _cover(),
|
|
"scan": _scan(),
|
|
"project": _project(),
|
|
"summary": _summary(),
|
|
"critical": _critical(),
|
|
"sections": [_sast_section(), _sca_section()],
|
|
}
|