diff --git a/.github/workflows/python-static.yml b/.github/workflows/python-static.yml
index 5c0ac32..ae18d08 100644
--- a/.github/workflows/python-static.yml
+++ b/.github/workflows/python-static.yml
@@ -25,4 +25,4 @@ jobs:
python -m pip install --upgrade pip tox
- name: Test with tox
run: |
- tox -e ${{ matrix.check }} || true
+ tox -e ${{ matrix.check }}
diff --git a/pyproject.toml b/pyproject.toml
index f0eb063..34eb58e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -59,4 +59,4 @@ python = ["3.14", "3.13", "3.12", "3.11"]
[tool.black]
target-version = ["py311", "py312", "py313"]
-extend-exclude ='(python2_file_willnotwork|dunderexec_with_parsing_error).py'
+extend-exclude ='(python2_file_willnotwork|dunderexec_with_parsing_error).py|validationfiles|suppression|spytestdir'
diff --git a/src/codeaudit/__about__.py b/src/codeaudit/__about__.py
index afbebcb..829f225 100644
--- a/src/codeaudit/__about__.py
+++ b/src/codeaudit/__about__.py
@@ -1,4 +1,4 @@
-# SPDX-FileCopyrightText: 2025-present Maikel Mardjan
+# SPDX-FileCopyrightText: 2025-present Maikel Mardjan
#
# SPDX-License-Identifier: GPL-3.0-or-later
__version__ = "1.6.2"
diff --git a/src/codeaudit/__init__.py b/src/codeaudit/__init__.py
index 8439191..c27c1ea 100644
--- a/src/codeaudit/__init__.py
+++ b/src/codeaudit/__init__.py
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2025-present Maikel Mardjan - https://nocomplexity.com/
#
# SPDX-License-Identifier: GPL-3.0-or-later
-from . __about__ import __version__
\ No newline at end of file
+from .__about__ import __version__
diff --git a/src/codeaudit/altairplots.py b/src/codeaudit/altairplots.py
index e254bdf..e0d8939 100644
--- a/src/codeaudit/altairplots.py
+++ b/src/codeaudit/altairplots.py
@@ -12,12 +12,12 @@
Altair Plotting functions for Python Code Audit (aka codeaudit)
"""
-import altair as alt
-import pandas as pd
-
from collections import Counter
from pathlib import Path
+import altair as alt
+import pandas as pd
+
def module_count_barchart(scanresult):
"""Create a bar chart showing module counts by category.
diff --git a/src/codeaudit/api_helpers.py b/src/codeaudit/api_helpers.py
index a9a8271..f29763f 100644
--- a/src/codeaudit/api_helpers.py
+++ b/src/codeaudit/api_helpers.py
@@ -12,18 +12,18 @@
Function to create nice APIs. So API helper functions.
"""
-import pandas as pd
import html
-from codeaudit.security_checks import ast_security_checks
+import pandas as pd
+
+from codeaudit.api_interfaces import get_modules, get_overview
+from codeaudit.checkmodules import get_all_modules
from codeaudit.filehelpfunctions import (
- get_filename_from_path,
collect_python_source_files,
+ get_filename_from_path,
)
-from codeaudit.security_checks import perform_validations
+from codeaudit.security_checks import ast_security_checks, perform_validations
from codeaudit.suppression import filter_sast_results
-from codeaudit.checkmodules import get_all_modules
-from codeaudit.api_interfaces import get_modules, get_overview
from codeaudit.totals import overview_per_file
diff --git a/src/codeaudit/api_interfaces.py b/src/codeaudit/api_interfaces.py
index 13f1e5c..1eda2b2 100644
--- a/src/codeaudit/api_interfaces.py
+++ b/src/codeaudit/api_interfaces.py
@@ -13,38 +13,37 @@
Public API functions for Python Code Audit aka codeaudit on pypi.org
"""
+import datetime
+import json
+import platform
+from collections import Counter
+from pathlib import Path
+
+import altair as alt
+import pandas as pd
+
from codeaudit import __version__
+from codeaudit.checkmodules import (
+ check_module_vulnerability,
+ get_all_modules,
+ get_imported_modules_by_file,
+ get_standard_library_modules,
+)
from codeaudit.filehelpfunctions import (
- get_filename_from_path,
collect_python_source_files,
+ get_filename_from_path,
is_ast_parsable,
)
-from codeaudit.security_checks import perform_validations, ast_security_checks
+from codeaudit.privacy_lint import data_egress_scan
+from codeaudit.pypi_package_scan import get_package_source, get_pypi_download_info
+from codeaudit.security_checks import ast_security_checks, perform_validations
+from codeaudit.suppression import filter_sast_results
from codeaudit.totals import (
- overview_per_file,
get_statistics,
overview_count,
+ overview_per_file,
total_modules,
)
-from codeaudit.checkmodules import (
- get_all_modules,
- get_imported_modules_by_file,
- get_standard_library_modules,
- check_module_vulnerability,
-)
-from codeaudit.pypi_package_scan import get_pypi_download_info, get_package_source
-from codeaudit.suppression import filter_sast_results
-from codeaudit.privacy_lint import data_egress_scan
-
-from pathlib import Path
-import json
-import datetime
-import pandas as pd
-import platform
-from collections import Counter
-
-
-import altair as alt
def version():
diff --git a/src/codeaudit/api_reporting.py b/src/codeaudit/api_reporting.py
index 11e44a6..21386ca 100644
--- a/src/codeaudit/api_reporting.py
+++ b/src/codeaudit/api_reporting.py
@@ -19,9 +19,10 @@
"""
-import pandas as pd
from collections import Counter
+import pandas as pd
+
def total_weaknesses(input_file):
"""Returns the total weaknesses found"""
diff --git a/src/codeaudit/checkmodules.py b/src/codeaudit/checkmodules.py
index 12d0dc3..a2ac4a0 100644
--- a/src/codeaudit/checkmodules.py
+++ b/src/codeaudit/checkmodules.py
@@ -14,8 +14,8 @@
"""
import ast
-import sys
import json
+import sys
import urllib.request
from codeaudit.filehelpfunctions import collect_python_source_files, read_in_source_file
diff --git a/src/codeaudit/codeaudit.py b/src/codeaudit/codeaudit.py
index 54922d9..86a7c9b 100644
--- a/src/codeaudit/codeaudit.py
+++ b/src/codeaudit/codeaudit.py
@@ -13,14 +13,16 @@
CLI functions for codeaudit
"""
-import fire # for working CLI with this PoC-thing (The Google way)
import sys
+
+import fire # for working CLI with this PoC-thing (The Google way)
+
from codeaudit import __version__
from codeaudit.reporting import (
overview_report,
+ report_implemented_tests,
report_module_information,
scan_report,
- report_implemented_tests,
)
codeaudit_ascii_art = r"""
diff --git a/src/codeaudit/codeaudit_dashboard.py b/src/codeaudit/codeaudit_dashboard.py
index cb27bab..f8dfcfb 100644
--- a/src/codeaudit/codeaudit_dashboard.py
+++ b/src/codeaudit/codeaudit_dashboard.py
@@ -10,30 +10,19 @@
You should have received a copy of the GNU General Public License along with this program. If not, see .
-WASM Dashboard version of codeaudit - limited functionality -
+WASM Dashboard version of codeaudit - limited functionality -
"""
-import inspect
-import sys
import asyncio
-
import datetime
+import inspect
import json
+import sys
import panel as pn
-pn.extension('vega')
+pn.extension("vega")
-from codeaudit.api_interfaces import version, get_package_source
-from codeaudit.api_helpers import _codeaudit_directory_scan_wasm
-
-from codeaudit.dashboard_reports import (
- report_sast_results,
- report_used_modules,
- get_info_text,
- get_disclaimer_text,
- create_statistics_overview,
-)
from codeaudit.altairplots import (
ast_nodes_overview,
@@ -45,24 +34,35 @@
weaknesses_overview,
weaknesses_radial_overview,
)
+from codeaudit.api_helpers import _codeaudit_directory_scan_wasm
+from codeaudit.api_interfaces import get_package_source, version
+from codeaudit.dashboard_reports import (
+ create_statistics_overview,
+ get_disclaimer_text,
+ get_info_text,
+ report_sast_results,
+ report_used_modules,
+)
# --- Environment Detection ---
IS_PYODIDE = "pyodide" in sys.modules
async def get_pypi_package_info_wasm(package_name):
- url = f"https://pypi.org/pypi/{package_name}/json"
+ url = f"https://pypi.org/pypi/{package_name}/json"
if IS_PYODIDE:
from pyodide.http import pyfetch
+
try:
- response = await pyfetch(url)
+ response = await pyfetch(url)
if not response.ok:
return False
- return await response.json()
+ return await response.json()
except:
return False
else:
import urllib.request
+
try:
with urllib.request.urlopen(url) as response:
return json.loads(response.read().decode("utf-8"))
@@ -72,21 +72,27 @@ async def get_pypi_package_info_wasm(package_name):
async def get_pypi_download_info_wasm(package_name):
data = await get_pypi_package_info_wasm(package_name)
- if not data or 'info' not in data:
+ if not data or "info" not in data:
return False
- version_str = data.get('info', {}).get('version')
- releases = data.get('releases', {}).get(version_str, [])
+ version_str = data.get("info", {}).get("version")
+ releases = data.get("releases", {}).get(version_str, [])
for file_info in releases:
- if file_info.get('packagetype') == 'sdist' and file_info.get('url').endswith(".tar.gz"):
- return {"download_url": file_info.get('url'), "release": version_str}
+ if file_info.get("packagetype") == "sdist" and file_info.get("url").endswith(
+ ".tar.gz"
+ ):
+ return {"download_url": file_info.get("url"), "release": version_str}
return False
async def get_package_source_wasm(url):
+ import gzip
+ import tarfile
+ import tempfile
+ import zlib
+
from pyodide.http import pyfetch
- import gzip, zlib, tarfile, tempfile
try:
response = await pyfetch(url)
@@ -109,7 +115,7 @@ async def get_package_source_wasm(url):
f.write(content)
with tarfile.open(tar_path, "r:gz") as tar:
- tar.extractall(path=temp_dir, filter='data')
+ tar.extractall(path=temp_dir, filter="data")
return temp_dir, tmpdir_obj
@@ -130,7 +136,7 @@ async def filescan_wasm(input_path, nosec=False):
ca_version_info = version()
now = datetime.datetime.now()
timestamp_str = now.strftime("%Y-%m-%d %H:%M")
- output = ca_version_info | {"generated_on": timestamp_str}
+ output = ca_version_info | {"generated_on": timestamp_str}
pypi_data = await get_pypi_download_info_wasm(input_path)
if pypi_data:
@@ -153,7 +159,7 @@ async def filescan_wasm(input_path, nosec=False):
if decoded_res is None:
return {
"Error": f"Could not download or extract package from {url}. "
- f"This may be due to browser restrictions."
+ f"This may be due to browser restrictions."
}
src_dir, tmp_handle = decoded_res
@@ -165,9 +171,7 @@ async def filescan_wasm(input_path, nosec=False):
}
try:
- scan_output = _codeaudit_directory_scan_wasm(
- src_dir, nosec_flag=nosec
- )
+ scan_output = _codeaudit_directory_scan_wasm(src_dir, nosec_flag=nosec)
output |= scan_output
finally:
if tmp_handle:
@@ -175,9 +179,7 @@ async def filescan_wasm(input_path, nosec=False):
return output
# ---------------------------------------------------------
- return {
- "Error": "Package not found on PyPI.org."
- }
+ return {"Error": "Package not found on PyPI.org."}
# - END of specific HELPERS to do CA things -#
@@ -185,31 +187,33 @@ async def filescan_wasm(input_path, nosec=False):
# --- UI Component Definitions ---
text_input = pn.widgets.TextInput(
- name='Python Package Name',
- placeholder='Enter PyPI package (e.g., requests)...'
+ name="Python Package Name", placeholder="Enter PyPI package (e.g., requests)..."
)
-run_button = pn.widgets.Button(name='Run Scan', button_type='primary')
+run_button = pn.widgets.Button(name="Run Scan", button_type="primary")
status = pn.pane.Markdown("### Ready to scan.")
-result_pane = pn.pane.JSON({}, name='JSON', sizing_mode="stretch_both", depth=-1)
-loading = pn.indicators.LoadingSpinner(value=False, size=60, color='primary', bgcolor='light' , name='Scanning...')
+result_pane = pn.pane.JSON({}, name="JSON", sizing_mode="stretch_both", depth=-1)
+loading = pn.indicators.LoadingSpinner(
+ value=False, size=60, color="primary", bgcolor="light", name="Scanning..."
+)
overview_visuals = create_statistics_overview(result_pane.object)
-tabs =pn.Tabs(
- ('Package Overview', overview_visuals),
- ('Used Modules', overview_visuals),
- ('Complexity Insights', overview_visuals),
- ('Weaknesses Overview', overview_visuals),
- ('Weaknesses per file', overview_visuals),
- ('Weaknesses Details', overview_visuals),
+tabs = pn.Tabs(
+ ("Package Overview", overview_visuals),
+ ("Used Modules", overview_visuals),
+ ("Complexity Insights", overview_visuals),
+ ("Weaknesses Overview", overview_visuals),
+ ("Weaknesses per file", overview_visuals),
+ ("Weaknesses Details", overview_visuals),
dynamic=True,
- sizing_mode="stretch_both"
+ sizing_mode="stretch_both",
)
# --- UI Callback ---
+
async def run_scan(event):
package_name = text_input.value.strip()
@@ -252,7 +256,9 @@ async def run_scan(event):
pn.Column(
pn.Row(
pn.pane.Vega(module_count_barchart(result), show_actions=True),
- pn.pane.Vega(module_distribution_view(result), show_actions=True),
+ pn.pane.Vega(
+ module_distribution_view(result), show_actions=True
+ ),
),
report_used_modules(result),
pn.Spacer(height=60),
@@ -271,9 +277,7 @@ async def run_scan(event):
tabs[3] = (
"Weaknesses Overview",
- pn.Column(
- pn.pane.Vega(weaknesses_overview(result), show_actions=True)
- ),
+ pn.Column(pn.pane.Vega(weaknesses_overview(result), show_actions=True)),
)
tabs[4] = (
@@ -315,23 +319,21 @@ async def run_scan(event):
text_input,
run_button,
loading,
- status,
+ status,
infotext,
- disclaimer_text,
+ disclaimer_text,
sizing_mode="stretch_width",
)
-main_pane = pn.Column(
- tabs, sizing_mode="stretch_both"
-)
+main_pane = pn.Column(tabs, sizing_mode="stretch_both")
app = pn.template.MaterialTemplate(
- header_background="#262626",
+ header_background="#262626",
title="Python Security Code Audit",
sidebar=[ca_sidebar],
- main=[main_pane]
+ main=[main_pane],
)
app.servable()
diff --git a/src/codeaudit/dashboard_reports.py b/src/codeaudit/dashboard_reports.py
index aa778a3..e3777d4 100644
--- a/src/codeaudit/dashboard_reports.py
+++ b/src/codeaudit/dashboard_reports.py
@@ -12,6 +12,7 @@
API functions: Used for dashboard reporting (Panel / WASM) and notebooks, or to build custom reports.
"""
+# import panel as pn
SAST_REPORT_CSS = """