How pycqa/bandit works
1. Bandit is a Python security linter packaged as a library plus CLI. Its core runtime is the bandit package, and the primary execution path starts from bandit/__main__.py or bandit/cli/main.py when invoked as a command-line tool.
2. The main scan pipeline is: load configuration, discover test plugins, walk Python source files, build an AST, run security checks against AST nodes, collect issues, then format/report results. This is the central data flow that an architecture diagram should show.
3. bandit/core is the engine layer. It contains the AST traversal and orchestration pieces (manager, node_visitor, tester, context, issue, metrics, config, extension_loader). This layer owns file scanning, plugin invocation, issue aggregation, and run metadata.
4. The AST-based analysis boundary is important: Bandit reads Python source, parses it into AST, and evaluates nodes rather than executing code. meta_ast.py and node_visitor.py support this traversal, while context.py carries node-specific information into tests.
5. Security rules live mostly in bandit/plugins. These are the pluggable detectors for patterns like shell injection, SQL injection, hardcoded secrets, unsafe deserialization, insecure SSL/TLS, template/XSS issues, and unsafe model downloads. Each plugin is a focused rule module that emits findings when it matches an AST pattern.
6. bandit/blacklists provides a second rule mechanism for banned calls and imports. These are more table-driven checks, complementing the plugin system with explicit forbidden APIs and modules.
7. bandit/cli is the user-facing command layer. It handles argument parsing, baseline comparison, and config generation. The baseline feature is an architectural boundary for suppressing previously accepted findings so that only new issues are reported.
8. Reporting is separated into bandit/formatters. The same issue set can be rendered as screen text, plain text, JSON, YAML, CSV, XML, HTML, or SARIF. This formatter layer is the output boundary and is important for integrations with CI, code scanning tools, and human review.
9. The repository includes a large examples/ corpus and tests/ suite that validate detection behavior. The examples act as fixture-like inputs for many vulnerability patterns, while unit and functional tests cover CLI behavior, engine logic, and formatter output.
10. Packaging and distribution are handled through standard Python tooling: setup.py, setup.cfg, requirements.txt, and tox/pre-commit configs. The repo is released to PyPI and also built into a container image via GitHub Actions, which makes Bandit usable both as an installed CLI and as a Dockerized scanner.
11. Documentation is a first-class subsystem under doc/, built with Sphinx and published to Read the Docs. The docs mirror the internal architecture: configuration, blacklists, plugins, formatters, and CI/CD usage.
12. For an architecture diagram, the key boundaries are: source files in, AST analysis in the middle, plugins/blacklists as rule providers, formatter outputs on the other side, and CLI/config/baseline as orchestration around the engine. The external surfaces are Python source repositories, CI pipelines, PyPI, Read the Docs, and the published container image.
Main entry points: manager.py Manager · main.py CLI · tester.py Tester · __init__.py Plugins
Components 21
Runtime
Python package and CLI entrypoints
- Entrypoints · CLI and module entrypoints into Bandit
bandit/__main__.py - CLI · Argument parsing, baseline handling, and config generation
bandit/cli/main.py - Baseline · Compares against saved findings to suppress accepted issues
bandit/cli/baseline.py - Config gen · Generates starter configuration for scans
bandit/cli/config_generator.py
Engine
Core AST scan orchestration and analysis
- Manager · Coordinates file discovery, scanning, and result collection
bandit/core/manager.py - Config · Loads and normalizes scan configuration
bandit/core/config.py - Loader · Discovers and loads test plugins
bandit/core/extension_loader.py - AST parse · Parses Python source into AST form for analysis
bandit/core/meta_ast.py - Visitor · Walks AST nodes and dispatches checks
bandit/core/node_visitor.py - Tester · Executes registered checks against nodes
bandit/core/tester.py - Context · Carries node-specific data into checks
bandit/core/context.py - Issue · Represents a security finding and its metadata
bandit/core/issue.py - Metrics · Collects scan counts and run metadata
bandit/core/metrics.py
Rules
Pluggable security detectors and blacklist checks
- Plugins · Focused AST detectors for security patterns
bandit/plugins/__init__.py - Blacklists · Table-driven checks for forbidden imports and calls
bandit/blacklists/__init__.py
Reporting
Formatter and output layers
- Formatters · Render findings for humans and tool integrations
bandit/formatters/__init__.py
Support
Docs, examples, tests, and packaging
- Examples · Representative vulnerable and safe code samples
examples/__init__.py - Tests · Unit and functional coverage for CLI, engine, and formatters
tests/__init__.py - Docs · Sphinx docs for usage, rules, and integrations
doc/source/index.rst - Packaging · Build, publish, and repository tooling for distribution
setup.py - Container image · Published Docker image for scanner execution
docker/Dockerfile
Connections 26
- Entrypoints → CLI: invokes · Module and console entrypoints hand off to the CLI
- CLI → Config: loads · CLI loads runtime configuration for a scan
- CLI → Baseline: applies · Baseline comparison suppresses previously accepted issues
- CLI → Config gen: generates · CLI can emit a starter configuration file
- CLI → Manager: starts scan · CLI delegates scan execution to the engine
- Manager → Loader: discovers · Manager loads available plugin rules
- Manager → AST parse: parses · Source files are converted into ASTs
- Manager → Visitor: walks · Manager drives AST traversal over files
- Visitor → Tester: dispatches · Visitor sends each node to registered tests
- Tester → Context: builds · Tests receive node-local context objects
- Tester → Plugins: runs · Plugin detectors evaluate AST patterns
- Tester → Blacklists: checks · Blacklist rules flag forbidden calls and imports
- Plugins → Issue: emits · Matching rules create findings
- Blacklists → Issue: emits · Forbidden API matches become findings
- Manager → Metrics: records · Scan progress and run metadata are tracked
- Manager → Issue: collects · Manager aggregates findings from all checks
- Issue → Formatters: renders · Findings are formatted for each output target
- Formatters → Tests: verified by · Formatter behavior is covered by unit tests
- Manager → Tests: verified by · Engine behavior is covered by functional and unit tests
- Plugins → Examples: exercised by · Example corpus supplies representative detector inputs
- Blacklists → Docs: documented in · Blacklist rules are described in the docs
- Plugins → Docs: documented in · Plugin rules are documented in Sphinx pages
- Formatters → Docs: documented in · Output formats are documented for users and integrations
- Packaging → Container image: builds · Release tooling produces a container image
- Packaging → Docs: publishes · Docs are built and published through project tooling
- Packaging → Tests: guards · CI and test tooling validate packaging and release paths