Detect silent failures and unexpected runtime side effects during development and CI.
Project description
SilentGuard
pip install silentguard— detect silent failures and unexpected runtime side effects during local development and CI.
The Problem
Developers often catch exceptions too broadly, suppress failures unintentionally, or trigger hidden side effects — global state mutation, file I/O, network calls, subprocess execution, environment changes. These issues are hard to spot in tests and code review.
SilentGuard surfaces these behaviours with clear, actionable runtime reports.
Quick Start
pip install silentguard
As a Decorator
from silentguard import guard
@guard()
def process_data():
try:
result = risky_operation()
except Exception:
pass # SilentGuard flags this
os.environ["API_KEY"] = "secret" # flagged
As a Context Manager
from silentguard import guard
with guard(report_format="markdown", output_path="report.md") as session:
do_something_risky()
print(f"Detected {len(session.events)} events")
CLI — Run Under Instrumentation
# Run a script with full instrumentation
silentguard guard my_script.py
# Run a module
silentguard guard my_package.module
# Hide LOW-confidence noise
silentguard guard my_script.py --min-confidence medium
# Lower overhead (disable trace hook)
silentguard guard my_script.py --no-trace
CLI — Static Audit
# Scan a file
silentguard audit app.py
# Scan a directory
silentguard audit src/
# Output as HTML
silentguard audit src/ --format html --output audit.html
CLI — Run Tests
# Run pytest with SilentGuard
silentguard test
# With pytest args
silentguard test -- -x -v tests/
# With report format
silentguard test --format markdown --output test_report.md
# Reduce noise and fail CI on actionable findings
silentguard test --min-confidence medium --fail-on high
pytest Integration
# Directly with pytest (plugin auto-discovered)
pytest --silentguard
# With format options
pytest --silentguard --sg-format=html --sg-output=report.html
What It Detects
| Category | Detection Method | Confidence |
|---|---|---|
| Suppressed exceptions | sys.monitoring (3.12+) or sys.settrace fallback (3.11) |
HIGH for broad except Exception, MEDIUM for specific types, skips control-flow (StopIteration, etc.) |
| File I/O | sys.addaudithook — open events |
HIGH for writes, MEDIUM for reads |
| Network calls | sys.addaudithook — socket.connect, socket.getaddrinfo |
HIGH |
| Subprocess execution | sys.addaudithook — subprocess.Popen, os.system |
HIGH |
| Env variable mutation | sys.addaudithook — os.putenv, os.unsetenv |
HIGH |
| Thread spawning | sys.addaudithook — _thread.start_new_thread |
MEDIUM |
| Global state mutation | AST analysis — global statements |
MEDIUM (audit only) |
Static Audit (AST-based)
The audit command performs additional best-effort checks:
- Bare
except:clauses - Broad
except Exception:with silent bodies (pass/...) - Calls to
exec(),eval(),os.system(),subprocess.* globalstatements indicating module state mutation- Imports of networking modules (
socket,requests, etc.)
Output Formats
| Format | Use Case |
|---|---|
terminal |
Interactive development (default, Rich-powered) |
markdown |
Issue trackers, PR comments, postmortems |
html |
Self-contained single-file reports for sharing |
sarif |
GitHub Code Scanning / CI pipelines |
Project Configuration
SilentGuard auto-discovers a .silentguardrc file by walking up from the
current working directory. This lets a project tune noise levels and ignore
known-benign patterns without changing application code.
[runtime]
detect_asyncio = true
[allow]
files = ["*.log", "*/.pytest_cache/*"]
network_hosts = ["localhost"]
[filters]
min_confidence = "medium"
ignore_file_patterns = ["*/vendor/*"]
ignore_function_patterns = ["legacy_*"]
[categories]
disabled_events = ["thread_spawn"]
disabled_scan = ["bare_except"]
CLI flags override config values when you need a one-off run:
silentguard guard app.py --min-confidence high
silentguard audit src/ --min-confidence medium
silentguard test --min-confidence medium --fail-on high
CI / Code Scanning
# Emit SARIF for GitHub Code Scanning or other CI integrations
silentguard ci src/ --output silentguard.sarif --fail-on high
The repository also includes a GitHub Actions workflow in
.github/workflows/silentguard.yml that runs both static audit and pytest
instrumentation and uploads SARIF results.
Configuration
All detection categories can be toggled:
from silentguard import guard
@guard(
detect_suppressed_exceptions=True, # default: True
detect_file_io=False, # disable file I/O detection
detect_network=True,
detect_subprocess=True,
detect_env_mutation=True,
detect_threading=True,
report_format="markdown",
output_path="report.md",
allowed_file_patterns=[".log", "/tmp/"], # ignore these paths
allowed_network_hosts=["localhost"], # ignore these hosts
)
def my_function():
...
Runtime reports automatically drop SilentGuard internals and stdlib/importlib-only frames from stack summaries so common interpreter noise does not dominate output.
Architecture
silentguard/
├── __init__.py # Public API
├── __version__.py # Version metadata
├── core.py # GuardSession + SourceScanner
├── decorators.py # @guard() decorator / context manager
├── hooks.py # sys.addaudithook + sys.settrace management
├── reporter.py # Terminal / Markdown / HTML formatters
├── cli.py # Click CLI
├── pytest_plugin.py # pytest plugin (auto-discovered)
└── utils.py # Shared data structures and helpers
Limitations & Known Issues
By Design
- Best-effort diagnostics, not a formal verifier. SilentGuard uses runtime heuristics. It will miss some issues and may flag intentional behaviour.
- Confidence levels are heuristic. A HIGH confidence event is not certain to be a bug — it means the structural pattern is commonly problematic.
sys.addaudithookis permanent. Once installed, CPython audit hooks cannot be removed for the lifetime of the process. SilentGuard minimises impact with a fast no-op guard when inactive.- Tracing adds overhead. On Python 3.11, suppressed-exception detection uses
sys.settrace; on 3.12+, SilentGuard usessys.monitoringfast-path where available and falls back tosys.settrace.
Overhead Benchmarks (pyperf)
Measured on Python 3.13 (Windows laptop), workload: 1000 pure-Python function calls (benchmarks/workload.py), with and without instrumentation.
- Baseline (no instrumentation): ~3.97 ms
- SilentGuard with
sys.monitoring: ~6.48 ms (about 1.6x baseline) - SilentGuard forced
sys.settrace: ~418.97 ms (about 105x baseline)
For this workload, sys.monitoring is roughly 65x faster than sys.settrace (418.97 / 6.48).
Detection Limits
- Suppressed exceptions: Cannot distinguish between intentional handling (e.g.
try: d[k] except KeyError: default) and genuine suppression. Mitigated by confidence levels. - Global state mutation at runtime: Not detected beyond environment variables. The AST scanner catches
globalstatements but cannot track arbitrary attribute mutations. - Asyncio side effects: Limited to thread-spawning detection. Full coroutine-level instrumentation is out of scope for v1.
- Indirect network calls: Calls through C extensions or FFI that bypass Python's socket layer are invisible to audit hooks.
- File I/O noise: Python's own import machinery triggers
openevents. SilentGuard filters.pyc/.pyo/.sofiles and its own internals, but some noise may remain.
Platform & Version
- Requires Python 3.11+.
sys.addaudithookis available since Python 3.8.sys.settracebehaviour may vary between CPython versions; not supported on alternative interpreters (PyPy, GraalPy).
Development
# Clone and install in editable mode
git clone https://github.com/your-org/silentguard.git
cd silentguard
pip install -e ".[dev]"
# Run tests
pytest
# Run with SilentGuard's own plugin
pytest --silentguard
# Type checking
mypy src/
# Linting
ruff check src/ tests/
# Benchmarks
pip install pyperf
python benchmarks/pyperf_silentguard.py
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file silentguard-0.1.0.tar.gz.
File metadata
- Download URL: silentguard-0.1.0.tar.gz
- Upload date:
- Size: 63.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
87a2aa3a48880c566ff5ceea7c534fc610e3bc5f26f7beec79b071edfc16f0fe
|
|
| MD5 |
b2434a00d57e91f72f372274f445ddbb
|
|
| BLAKE2b-256 |
26a7e5e3bc7c30568e85daac95c9eb7bd16c04e4aee567bd2ddaab741b04b2e4
|
File details
Details for the file silentguard-0.1.0-py3-none-any.whl.
File metadata
- Download URL: silentguard-0.1.0-py3-none-any.whl
- Upload date:
- Size: 31.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
abb69e7a0760e888637edfb01e950016eb38e706c1128d6db38b122c6ad7048b
|
|
| MD5 |
8cd8d8d5ddf422556c89631f53e0da40
|
|
| BLAKE2b-256 |
6542ae8e28bf0373922cb16b146c9d047937824376dcbd46b2e843f82016b19a
|