fix(reports): safe-fence markdown PoC export and share fence helpers

This commit is contained in:
Ahmed Allam
2026-07-25 13:09:57 -07:00
committed by Ahmed Allam
parent 97ed7e79a1
commit 21243486e2
10 changed files with 55 additions and 36 deletions
+7 -5
View File
@@ -39,13 +39,14 @@ from strix.interface.tui.live_view import TuiLiveView
from strix.interface.tui.messages import send_user_message_to_agent
from strix.interface.tui.renderers import render_tool_widget
from strix.interface.tui.renderers.agent_message_renderer import AgentMessageRenderer
from strix.interface.tui.renderers.fenced import (
from strix.interface.tui.renderers.user_message_renderer import UserMessageRenderer
from strix.interface.utils import build_tui_stats_text
from strix.report.fenced import (
guess_language_name,
parse_fenced_code,
resolve_lexer,
safe_fence,
)
from strix.interface.tui.renderers.user_message_renderer import UserMessageRenderer
from strix.interface.utils import build_tui_stats_text
from strix.report.state import ReportState, set_global_report_state
from strix.runtime import session_manager
@@ -608,9 +609,10 @@ class VulnerabilityDetailScreen(ModalScreen): # type: ignore[misc]
if vuln.get("poc_script_code"):
poc_language, poc_code = parse_fenced_code(vuln["poc_script_code"])
fence_lang = poc_language or guess_language_name(poc_code)
lines.append(f"```{fence_lang}")
fence = safe_fence(poc_code)
lines.append(f"{fence}{fence_lang}")
lines.append(poc_code)
lines.append("```")
lines.append(fence)
if vuln.get("code_locations"):
lines.extend(["", "## Code Analysis", ""])
-59
View File
@@ -1,59 +0,0 @@
import re
from pygments.lexer import Lexer
from pygments.lexers import PythonLexer, get_lexer_by_name, guess_lexer
from pygments.lexers.special import TextLexer
from pygments.util import ClassNotFound
_FENCE_RE = re.compile(r"^```([^\n`]*)\n(.*?)\n?```$", re.DOTALL)
def parse_fenced_code(raw: str) -> tuple[str | None, str]:
"""Split an optionally fenced code string into ``(language, code)``.
Agent-generated code fields (e.g. ``poc_script_code``) are stored wrapped in
a markdown fence carrying the language, like ``` ```python\n...\n``` ```.
Return the fence's language tag and the inner code, or ``(None, raw)`` when
the value isn't fenced.
"""
match = _FENCE_RE.match(raw.strip())
if not match:
return None, raw
info = match.group(1).strip()
language = info.split()[0] if info else None
return (language or None), match.group(2)
def resolve_lexer(language: str | None, code: str) -> Lexer:
"""Pick a pygments lexer for ``code``.
Prefer the explicit fence ``language`` when it names a known lexer, otherwise
auto-detect from the source. Fall back to Python when detection is
inconclusive, since legacy (unfenced) PoC scripts are Python.
"""
if language:
try:
return get_lexer_by_name(language)
except ClassNotFound:
pass
try:
lexer = guess_lexer(code)
except ClassNotFound:
return PythonLexer()
# ``guess_lexer`` returns the plain-text lexer when it can't detect anything.
if isinstance(lexer, TextLexer):
return PythonLexer()
return lexer
def guess_language_name(code: str) -> str:
"""Return a markdown fence tag for ``code``, defaulting to ``python`` when
auto-detection is inconclusive."""
try:
lexer = guess_lexer(code)
except ClassNotFound:
return "python"
if isinstance(lexer, TextLexer) or not lexer.aliases:
return "python"
return str(lexer.aliases[0])
@@ -5,8 +5,9 @@ from pygments.styles import get_style_by_name
from rich.text import Text
from textual.widgets import Static
from strix.report.fenced import parse_fenced_code, resolve_lexer
from .base_renderer import BaseToolRenderer
from .fenced import parse_fenced_code, resolve_lexer
from .registry import register_tool_renderer