diff --git a/doc/requirements.txt b/doc/requirements.txt index 0d2074715..c8f46ece5 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -4,3 +4,7 @@ sphinx>=4.0.0 # BSD sphinx-rtd-theme>=0.3.0 sphinx-copybutton + +# FIXME: remove index url once offical sphinx-pyscript 0.2.0 +--extra-index-url https://test.pypi.org/simple/ +sphinx-pyscript-temp == 0.2.0 diff --git a/doc/source/_static/css/custom.css b/doc/source/_static/css/custom.css new file mode 100644 index 000000000..2ae8ea689 --- /dev/null +++ b/doc/source/_static/css/custom.css @@ -0,0 +1,19 @@ +.issue-block { + border: 1px solid LightGray; + padding-left: .5em; + padding-top: .5em; + padding-bottom: .5em; + margin-bottom: .5em; +} + +.issue-sev-high { + background-color: Pink; +} + +.issue-sev-medium { + background-color: NavajoWhite; +} + +.issue-sev-low { + background-color: LightCyan; +} diff --git a/doc/source/conf.py b/doc/source/conf.py index f2a991c11..5e893c488 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -14,6 +14,7 @@ "sphinx.ext.coverage", "sphinx.ext.viewcode", "sphinx_copybutton", + "sphinx_pyscript_temp", # FIXME: replace with sphinx_pyscript ] # autodoc generation is a bit aggressive and a nuisance when doing heavy @@ -63,8 +64,20 @@ # Sphinx are currently 'default' and 'sphinxdoc'. # html_theme_path = ["."] html_theme = "sphinx_rtd_theme" -# html_static_path = ['static'] +# These folders are copied to the documentation's HTML output +html_static_path = ["_static"] +# These paths are either relative to html_static_path +# or fully qualified paths (eg. https://...) +html_css_files = [ + "css/custom.css", + # FIXME: setting priority here overrides the outdated pyscript css + ("https://pyscript.net/releases/2024.9.2/core.css", {"priority": 500}), +] html_theme_options = {} +html_js_files = [ + # FIXME: setting priority here overrides the outdated pyscript js + ("https://pyscript.net/releases/2024.9.2/core.js", {"type": "module", "priority": 500}), +] # Output file base name for HTML help builder. htmlhelp_basename = f"{project}doc" diff --git a/doc/source/index.rst b/doc/source/index.rst index fbf3e205e..77e627d8b 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -17,6 +17,7 @@ Using and Extending Bandit blacklists/index formatters/index faq + playground Contributing ============ diff --git a/doc/source/playground.py b/doc/source/playground.py new file mode 100644 index 000000000..1637a65a0 --- /dev/null +++ b/doc/source/playground.py @@ -0,0 +1,128 @@ +import io +import logging +import tokenize + +from bandit.core import config +from bandit.core import docs_utils +from bandit.core import manager +from bandit.core import meta_ast +from bandit.core import metrics +from bandit.core import node_visitor +from bandit.core import test_set +from pyscript import document + + +# Disable noisy output from Bandit getting rendered to page +logging.basicConfig(level=logging.ERROR) + +ISSUE_BLOCK = """ +
+
+ [{test_id}:{test_name}] {test_text}
+ Severity: {severity}
+ Confidence: {confidence}
+ CWE: {cwe}
+ More info: {url}
+ Location: <stdin>:{line_number}:{col_offset}
+
+
+""" + +MESSAGE_BLOCK = """ +
+
+ {message}
+
+
+""" + +output_element = document.getElementById("output") + + +def run_analysis(code): + issue_metrics = metrics.Metrics() + scores = [] + skipped = [] + filename = "" + + # Clear previous output + output_element.innerHTML = "" + + try: + fobj = io.BytesIO(code) + issue_metrics.begin(filename) + data = fobj.read() + lines = data.splitlines() + issue_metrics.count_locs(lines) + nosec_lines = {} + + try: + fobj.seek(0) + tokens = tokenize.tokenize(fobj.readline) + for toktype, tokval, (lineno, _), _, _ in tokens: + if toktype == tokenize.COMMENT: + nosec_lines[lineno] = manager._parse_nosec_comment(tokval) + except tokenize.TokenError: + pass + + visitor = node_visitor.BanditNodeVisitor( + filename, + fobj, + metaast=meta_ast.BanditMetaAst(), + testset=test_set.BanditTestSet( + config.BanditConfig(), + profile={ + "include": [], + "exclude": ["B613"], # FIXME: issue #1182 + }, + ), + debug=False, + nosec_lines=nosec_lines, + metrics=issue_metrics, + ) + score = visitor.process(code) + scores.append(score) + issue_metrics.count_issues([score]) + + for index, issue in enumerate(visitor.tester.results): + url = docs_utils.get_url(issue.test_id) + output_element.innerHTML += ISSUE_BLOCK.format( + issue_no=index, + issue_class=f"issue-sev-{issue.severity.lower()}", + test_name=issue.test, + test_id=issue.test_id, + test_text=issue.text, + severity=issue.severity.capitalize(), + confidence=issue.confidence.capitalize(), + cwe=str(issue.cwe), + cwe_link=issue.cwe.link(), + url=url, + line_number=issue.lineno, + col_offset=issue.col_offset, + ) + + if not visitor.tester.results: + output_element.innerHTML += MESSAGE_BLOCK.format( + message="No issues identified." + ) + except SyntaxError: + output_element.innerHTML += MESSAGE_BLOCK.format( + message="Syntax error parsing code." + ) + except Exception: + output_element.innerHTML += MESSAGE_BLOCK.format( + message="Exception scanning code." + ) + + issue_metrics.aggregate() + + +def handle_event(event): + run_analysis(event.code.encode()) + + # prevent default execution + return False + + +editor = document.getElementById("editor") +editor.handleEvent = handle_event diff --git a/doc/source/playground.rst b/doc/source/playground.rst new file mode 100644 index 000000000..1669035d4 --- /dev/null +++ b/doc/source/playground.rst @@ -0,0 +1,38 @@ +Playground +========== + +Welcome to the Bandit Playground! This interactive web page allows you to +experience the power of Bandit, a leading Static Application Security Testing +(SAST) tool designed to help identify security issues in Python code. Bandit +scans your code for potential vulnerabilities and provides detailed insights +to help improve the overall security of your application. Whether you’re a +security professional or a developer looking to secure your codebase, this +playground offers a hands-on way to experiment with Bandit’s capabilities +in real-time. Simply paste your Python code into the editor, run the scan, +and explore the results instantly! + +.. py-config:: + + splashscreen: + autoclose: true + packages: + - bandit + +.. raw:: html + + + +.. py-script:: + :file: playground.py + +.. raw:: html + +