ConcurrencyGuard (cguard)
Deterministic AST + Runtime Concurrency & Idempotency Verifier for Python FastAPI, SQLAlchemy, and Celery Backends.
⚡ Why ConcurrencyGuard?
Modern async Python services frequently suffer from silent concurrency bugs, double-spend race conditions, lost updates, and duplicate background tasks. Traditional linters only check syntax and type hints, while external LLM tools hallucinate or miss non-local control flow races.
ConcurrencyGuard (cguard) solves this with a 100% deterministic pipeline:
- Pure AST Static Scanning: Catches race patterns, missing idempotency keys, N+1 queries, uniqueness races, and unsafe Celery retry tasks.
- Runtime
asyncio.BarrierExploit Engine: Proves race conditions empirically by synchronizing concurrent coroutines to hit endpoints at the exact same microsecond. - Deterministic
LibCSTAuto-Patcher: Safely rewrites code to apply database row locks (.with_for_update()), inject FastAPIIdempotency-Keyheaders, and wrap transactions inIntegrityErrorguards. - Automated GitHub PR Reporter: Emits rich Markdown comments with exploit proofs and diff previews for pull requests.
📋 Rule Catalog
| Rule ID | Name | Target / Trigger Condition | Automated Fix |
|---|---|---|---|
CG-001 |
Unlocked Read-Modify-Write Race | Async route reads database state with select(), mutates an attribute, and calls commit() without .with_for_update() locking. |
Appends .with_for_update() row-level locks via LibCST. |
CG-002 |
Missing Idempotency Guard | Async @app.post or @router.post route mutates state without an idempotency_key parameter. |
Injects idempotency_key: str = Header(..., alias="Idempotency-Key") into route parameters. |
CG-003 |
Async Loop N+1 Query Explode | db.execute(...) or session.execute(...) call located directly inside a for or async for loop body. |
Flags query explosion; suggests batching or eager loading (joinedload/selectinload). |
CG-004 |
Check-Then-Act Uniqueness Race | Async route checks existence with select(), calls add(), and commits without catching sqlalchemy.exc.IntegrityError. |
Wraps commit statements in try...except IntegrityError with session rollback. |
CG-005 |
Non-Idempotent Celery Retry Task | Celery task (@app.task, @shared_task) with autoretry_for or max_retries executes mutations (.add(), .commit(), .post()) without acks_late=True or an idempotency lock. |
Recommends acks_late=True and distributed deduplication lock before side-effects. |
🚀 Installation
# Clone and install in virtual environment
git clone https://github.com/AyushkhatiDev/concurrency-guard.git
cd concurrency-guard
python -m venv .venv
source .venv/bin/activate
pip install -e .
To install with development and testing dependencies:
pip install -e ".[dev]"
🛠️ CLI Usage
1. cguard scan — Static AST Analysis
Scan files or entire directories for concurrency vulnerabilities:
# Scan a single file
cguard scan examples/vulnerable_wallet.py
# Scan an entire codebase
cguard scan src/
2. cguard verify — Runtime asyncio.Barrier Verification
Simulate high-concurrency traffic using synchronized barrier workers to prove whether an invariant holds or breaks under load:
cguard verify examples/vulnerable_wallet.py --workers 20
Sample exploit proof output:
❌ CONCURRENCY INVARIANT VIOLATED (RACE PROVEN)
Target File: examples/vulnerable_wallet.py
Target Endpoint: POST /wallet/withdraw
Concurrent Barrier Workers: 20
Initial Wallet Balance: $50
Successful Withdrawals ($50 each): 20
Final Resulting Balance: $-950
INVARIANT VIOLATION PROVEN:
Multiple concurrent withdrawals succeeded against a $50 balance due to an unlocked
Read-Modify-Write race condition (CG-001).
3. cguard fix — Deterministic LibCST Auto-Patcher
Inspect and apply deterministic code patches:
# Preview auto-fixes (dry-run)
cguard fix examples/vulnerable_wallet.py
# Apply specific rule fix
cguard fix examples/vulnerable_wallet.py --rule CG-001 --write
# Apply all available auto-fixes directly to disk
cguard fix examples/vulnerable_wallet.py --write
4. cguard report — GitHub Pull Request Markdown Reporter
Generate comprehensive Markdown summaries for CI/CD:
# Print report to stdout
cguard report examples/vulnerable_wallet.py
# Write report to markdown file for GitHub Actions PR comment
cguard report examples/vulnerable_wallet.py --output pr_report.md
🤖 GitHub Action Integration
Add ConcurrencyGuard to your pull request workflows:
name: Concurrency Guard CI
on:
pull_request:
branches: [main]
jobs:
concurrency-audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run ConcurrencyGuard Action
uses: AyushkhatiDev/concurrency-guard@main
with:
path: "app"
report-file: "app/main.py"
output: "pr-report.md"
- name: Post PR Comment
if: failure() || success()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
if (fs.existsSync('pr-report.md')) {
const body = fs.readFileSync('pr-report.md', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
});
}
🧪 Testing
ConcurrencyGuard is thoroughly tested with unit tests and runtime stress verifications:
# Run test suite
pytest -v
# Run lint and type checking
ruff check .
mypy src/
📄 License
MIT License. See LICENSE for details.
Metadata
Release files for concurrency-guard 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| concurrency_guard-0.1.0.tar.gz | 31.1 kB | Without provenance | Details for concurrency_guard-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| concurrency_guard-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for concurrency_guard-0.1.0-py3-none-any.whl |
Total release size: 57.1 kB
Release files / concurrency_guard-0.1.0.tar.gz
| Download URL | concurrency_guard-0.1.0.tar.gz |
|---|---|
| Size | 31.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
940ad64b2fc83164fd73ed0433eee96fbda13d4cbe8955d1cee547de2654462e
|
|
BLAKE2b-256 checksum How to use checksums |
96ea0a6a1710b8ffd0cc9568e67a56bfa3182e81ad265dc0fbed47ca26bfead3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.8
|
Release files / concurrency_guard-0.1.0-py3-none-any.whl
| Download URL | concurrency_guard-0.1.0-py3-none-any.whl |
|---|---|
| Size | 25.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d6904159ed58878f440a3abb7965bcdc825b2d071e1a4abd5993432abff925c5
|
|
BLAKE2b-256 checksum How to use checksums |
f543281bf96c5f4743d97c8aa2eedad9cbfb409d9e3812667b6067c9abe5aa2b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.8
|
Security for concurrency-guard 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.