Getting Started
Install
After wheels are published:
pip install pybetterleaks
For production Docker images, prefer binary-only installs:
pip install --only-binary=:all: pybetterleaks
Local Repository Build
Build the native bridge locally:
uv sync --all-extras --dev
uv run python scripts/build_native.py
Then run a scan:
uv run python - <<'PY'
from pybetterleaks import betterleaks_version, scan_text
print("Betterleaks:", betterleaks_version())
result = scan_text(
"AGE-SECRET-KEY-"
+ "1QPZRY9X8GF2TVDW0S3JN54KHCE6MUA7LQPZRY9X8GF2TVDW0S3JN54KHCE"
)
for finding in result.findings:
print(f"{finding.rule_id}: {finding.secret}")
PY
Expected output:
Betterleaks: v1.6.1
age-secret-key: REDACTED
The example secret is synthetic.
Typed Config
from pybetterleaks import BetterleaksConfig, Rule, scan_text
config = BetterleaksConfig(
rules=[
Rule(
id="internal-token",
description="Internal service token",
regex=r"INTERNAL_[A-Z0-9]{16}",
keywords=["INTERNAL_"],
)
]
)
result = scan_text("INTERNAL_0123456789ABCDEF", config=config)
Use config_path=".betterleaks.toml" when you already have a TOML config file.
Do not pass both config and config_path.
Directory Scans
from pybetterleaks import scan_dir
result = scan_dir(".", config_path=".betterleaks.toml")
if result.ok:
for finding in result.findings:
print(f"{finding.file}:{finding.line} {finding.rule_id}")
else:
for error in result.errors:
print(f"{error.code}: {error.message}")
Git Worktree Scans
from pybetterleaks import SUPPORTED_GIT_SCOPES, scan_git
print(SUPPORTED_GIT_SCOPES)
result = scan_git(".", scope="worktree", config_path=".betterleaks.toml")
for finding in result.findings:
print(f"{finding.file}:{finding.line} {finding.rule_id}")
scan_git currently supports local worktree scans only. It validates that the
target is inside a Git worktree, skips .git metadata, and does not invoke the
Git executable. History, staged-only, and diff scans are planned for a later
v0.3 slice.
Async Scans
import asyncio
from pybetterleaks import scan_git_async
async def main() -> None:
result = await scan_git_async(".", timeout_seconds=10)
print(result.ok, len(result.findings))
asyncio.run(main())
The async API uses an executor under the hood. When the Python task is cancelled, PyBetterleaks sends a cancellation request to the Go bridge for the active scan request id.
Docker
FROM python:3.12-slim
RUN pip install --only-binary=:all: pybetterleaks
COPY . /app
WORKDIR /app
CMD ["python", "scan.py"]
No go install, no Betterleaks CLI, and no install-time native binary download.
Build The Docs
uv run --group docs mkdocs serve
The published HTML site is built by GitHub Actions from the Markdown files in
docs/.