Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a new playground to the docs #1184

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
19 changes: 19 additions & 0 deletions doc/source/_static/css/custom.css
Original file line number Diff line number Diff line change
@@ -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;
}
15 changes: 14 additions & 1 deletion doc/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand Down
1 change: 1 addition & 0 deletions doc/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Using and Extending Bandit
blacklists/index
formatters/index
faq
playground

Contributing
============
Expand Down
128 changes: 128 additions & 0 deletions doc/source/playground.py
Original file line number Diff line number Diff line change
@@ -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 = """
<div id="issue-{issue_no}">
<div class="issue-block {issue_class}">
<b>[{test_id}:{test_name}]</b> {test_text}<br>
<b>Severity: </b>{severity}<br>
<b>Confidence: </b>{confidence}<br>
<b>CWE: </b><a href="{cwe_link}" target="_blank">{cwe}</a><br>
<b>More info: </b><a href="{url}" target="_blank">{url}</a><br>
<b>Location: </b>&lt;stdin&gt;:{line_number}:{col_offset}<br>
</div>
</div>
"""

MESSAGE_BLOCK = """
<div id="no-issues">
<div class="issue-block">
<b>{message}</b><br>
</div>
</div>
"""

output_element = document.getElementById("output")


def run_analysis(code):
issue_metrics = metrics.Metrics()
scores = []
skipped = []
filename = "<stdin>"

# 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
38 changes: 38 additions & 0 deletions doc/source/playground.rst
Original file line number Diff line number Diff line change
@@ -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

<script type="py-editor" id="editor">
import ssl

# Correct
context = ssl.create_default_context()

# Incorrect: unverified context
context = ssl._create_unverified_context()
</script>

.. py-script::
:file: playground.py

.. raw:: html

<div id="output"></div>