diff --git a/poetry.lock b/poetry.lock index 9d4fb31e02..def2321b2a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2530,14 +2530,14 @@ files = [ [[package]] name = "markdown" -version = "3.8.2" +version = "3.9" description = "Python implementation of John Gruber's Markdown." optional = false python-versions = ">=3.9" -groups = ["docs"] +groups = ["main", "docs"] files = [ - {file = "markdown-3.8.2-py3-none-any.whl", hash = "sha256:5c83764dbd4e00bdd94d85a19b8d55ccca20fe35b2e678a1422b380324dd5f24"}, - {file = "markdown-3.8.2.tar.gz", hash = "sha256:247b9a70dd12e27f67431ce62523e675b866d254f900c4fe75ce3dda62237c45"}, + {file = "markdown-3.9-py3-none-any.whl", hash = "sha256:9f4d91ed810864ea88a6f32c07ba8bee1346c0cc1f6b1f9f6c822f2a9667d280"}, + {file = "markdown-3.9.tar.gz", hash = "sha256:d2900fe1782bd33bdbbd56859defef70c2e78fc46668f8eb9df3128138f2cb6a"}, ] [package.dependencies] @@ -5891,4 +5891,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">3.9.1,<3.13" -content-hash = "aea38b0311bfabac00d4bf9ee5d2fa0a7f3e32dd2ee5c5d27eb54c69a80b35e9" +content-hash = "285ee6b8c630e9908b8b05ced6be1cb67385d5f83af2b6175430a7ccdb9606a4" diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 5d873f663b..c5797f961d 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -11,6 +11,7 @@ All notable changes to the **Prowler SDK** are documented in this file. ### Changed - Update AWS Neptune service metadata to new format [(#8494)](https://github.com/prowler-cloud/prowler/pull/8494) - Update AWS Config service metadata to new format [(#8641)](https://github.com/prowler-cloud/prowler/pull/8641) +- HTML output now properly renders markdown syntax in Risk and Recommendation fields [(#8727)](https://github.com/prowler-cloud/prowler/pull/8727) ### Fixed diff --git a/prowler/lib/outputs/html/html.py b/prowler/lib/outputs/html/html.py index c35d2826d1..903c9d7b91 100644 --- a/prowler/lib/outputs/html/html.py +++ b/prowler/lib/outputs/html/html.py @@ -1,7 +1,8 @@ -import html import sys from io import TextIOWrapper +import markdown + from prowler.config.config import ( html_logo_url, prowler_version, @@ -15,6 +16,42 @@ from prowler.providers.common.provider import Provider class HTML(Output): + @staticmethod + def process_markdown(text: str) -> str: + """ + Process markdown syntax in text and convert to HTML using the markdown library. + + Args: + text (str): Text containing markdown syntax + + Returns: + str: HTML with markdown syntax converted + """ + if not text: + return text + + # Initialize markdown converter with safe mode to prevent XSS + md = markdown.Markdown(extensions=["nl2br"]) + + # Convert markdown to HTML + html_content = md.convert(text) + + # Strip outer
tags if present, as we're embedding in existing HTML + # Handle single paragraph case + if ( + html_content.startswith("
") + and html_content.endswith("
") + and html_content.count("") == 1 + ): + html_content = html_content[3:-4] + # Handle multiple paragraphs case - replace
and
with" in html_content and "
" in html_content: + html_content = html_content.replace("\n", "
\n
\n")
+ html_content = html_content.replace("
", "") + html_content = html_content.replace("
", "") + + return html_content + def transform(self, findings: list[Finding]) -> None: """Transforms the findings into the HTML format. @@ -47,8 +84,8 @@ class HTML(Output):{html.escape(finding.metadata.Risk)}
{html.escape(finding.metadata.Remediation.Recommendation.Text)}
{HTML.process_markdown(finding.metadata.Risk)}
{HTML.process_markdown(finding.metadata.Remediation.Recommendation.Text)}
{parse_html_string(unroll_dict(finding.compliance, separator=": "))}
text"""
+ test_text = "Use the `ls` command to list files and `cd` to change directories"
+ result = HTML.process_markdown(test_text)
+ expected = "Use the ls command to list files and cd to change directories"
+ assert result == expected
+
+ def test_process_markdown_line_breaks(self):
+ """Test that line breaks are converted to code elements.monitored aliases" in output_data
+ assert "