Skip to main content

locking-claim-audit

Offline audit of documented cross-process exclusion promises against Python source.

Version 0.1.0. Requires Python 3.9 or newer; runtime dependencies: standard library only. The auditor reads Markdown and parses Python ASTs. It never executes target code, uses the network, or reads .env contents. Symlinked files and directories are skipped.

Usage

python3 -m pip install .
locking-claim-audit /path/to/project
python3 -m locking_claim_audit /path/to/project --json
locking-claim-audit . --ignore 'vendor/*' --ignore 'generated/*' --verbose
locking-claim-audit . --fail-on HIGH
locking-claim-audit --version

The console entry point calls locking_claim_audit.__main__:main. The optional path defaults to the current directory. --ignore is repeatable; patterns use case-sensitive glob matching against relative paths with / separators. --verbose adds the complete analysis to text output. --json emits one JSON object with findings, verified_claims, claims, production_evidence, test_only_evidence, and source_errors. Findings contain rule, severity, family, claims, and evidence. Each claim includes path, line, and sentence; evidence includes path, line, and kind. Evidence is deduplicated by path, line, and kind. Paths and results have deterministic traversal order.

Exit 0 means no findings reached the selected threshold; exit 2 means at least one did. Exit 1 means invalid usage, unreadable input, or a source parse failure. The default threshold is MEDIUM. --fail-on HIGH retains MEDIUM findings in output but does not fail for them. A project with no extracted claims passes, regardless of detected mechanisms. Each family is evaluated independently.

Rules

Rule identifiers are fenced to keep the documentation self-audit neutral:

L1 documented-locked-claim-false
L2 documented-locked-claim-false-test-only
N1 documented-nolock-claim-false
N2 documented-nolock-claim-false-test-only
Rule Severity Condition
L1 HIGH Positive family present, no production or test-only evidence
L2 MEDIUM Positive family present, evidence exists only in tests or fixtures
N1 HIGH Negative family present, production evidence exists
N2 MEDIUM Negative family present, evidence exists only in tests or fixtures

Each finding aggregates all claim sentences for its family. N1 includes every production evidence item; L2 and N2 include every test-only item. If there is no production Python source, each documented family gets one HIGH finding under L1 or N1, with {"kind": "no-source"} evidence. This takes precedence over test-only evidence. Positive claims with production evidence are verified; negative claims with zero evidence anywhere are verified. Contradictory families can produce two findings, for example when neither has production source.

Claim extraction

Only root README.md and docs/**/*.md are considered. Backtick and tilde fenced blocks are excluded; inline code spans remain prose. Sentences are lowercased, n't becomes not, hyphens become spaces, and whitespace is collapsed. Wrapped prose is supported. Exact phrases with word boundaries are required; optional inserted words are never inferred.

These are the complete normalized phrases, listed once per family:

locked:
file locking
uses locking
uses a lock
uses locks
locking support
supports locking
safe for concurrent runs
safe to run concurrently
concurrent safe
prevents concurrent runs
prevents concurrent access
serializes concurrent access
serialises concurrent access
uses a lock file
creates a lock file
protected by a lock
guarded by a lock
acquires a lock

nolock:
no locking
does not lock
does not use locking
does not use a lock
without locking
no lock file
no lock
not safe for concurrent runs
not safe to run concurrently
do not run concurrently
must not run concurrently

Negation is asymmetric: a sentence containing no, not, never, or without suppresses the positive family, while listed negative phrases still count. Negative phrases are matched first and their spans masked before positive matching to avoid overlap. The following examples illustrate the boundary:

"does not use a lock" -> nolock only
"doesn't lock" -> nolock via contraction normalization
"file-locking" -> locked
"concurrent-safe" -> locked
"never locked" -> no claim
"does not claim to use locking" -> no claim
"lock" -> no claim
"lock file" -> no claim

Evidence

Production source consists of .py files outside tests/, fixtures/, docs/, and examples/, excluding test_*.py and *_test.py. Test directories, fixture directories, and test filename patterns are collected separately. Python files under documentation and examples are excluded altogether. Ignore patterns apply to both documentation and source. Files named .env or starting with .env. are never read, including when they have a source-like suffix.

Evidence kind Static mechanism
os-lock-call Calls to fcntl.flock, fcntl.lockf, or msvcrt.locking
library-import Imports from filelock, portalocker, fasteners, or flufl.lock, including submodules and names
lock-constructor Dotted names ending in FileLock, or portalocker.Lock, fasteners.InterProcessLock, flufl.lock.Lock
exclusive-create os.open with both literal flag names O_CREAT and O_EXCL in its arguments
lock-file-path open, io.open, os.open, or Path open/write methods with a string argument containing .lock
lock-directory-path os.mkdir or os.makedirs with a string argument containing .lock

Honest limitations

This is a heuristic existence check, not a proof of mutual exclusion or correct coverage. Dead code counts. A mechanism guarding only a small part of a program counts. An import of one of the named third-party libraries is sufficient, even if unused. Constructor suffix matching can also produce false positives.

Per-file import aliases are tracked. A bare flock or lockf call is accepted only with an import from fcntl or of that module; a bare locking call requires an import from msvcrt or of that module. Qualified spellings are recognized statically without requiring an import. Alias tracking does not model scope, rebinding, execution order, or dynamic imports. Flags held only in a variable are not resolved: the required flag names must appear in the call arguments. Computed path values and arbitrary object types are not inferred.

threading.Lock, multiprocessing.Lock, and asyncio.Lock do not qualify under this tool's deliberately restricted mechanism model. A bare Lock() call, a lock variable, a string mentioning a mechanism, and comments do not count. Neither a LockTimeout name alone nor releasing/checking an existing object is sufficient. An acquire() call on an arbitrary variable is insufficient. Shell commands invoking flock(1) are not parsed. Native extensions, non-Python implementations, semantic correctness, lock lifetime, and platform behavior are outside scope. Exact-phrase extraction can miss paraphrases and Markdown edge cases; this is not a complete Markdown parser. Sentence boundaries use punctuation and paragraph breaks, so abbreviations can split a sentence.

Differentiation

Neighbour Distinction
concurrency-claim-audit Parallelism inside one run; this tool checks exclusion between separate processes
thread-safety-claim-audit In-process synchronization rather than OS or filesystem exclusion
atomic-claim-audit Crash safety of one write rather than mutual exclusion
Bandit / Ruff Source issues rather than documentation promises
filelock / portalocker / fasteners documentation Explains primitives rather than comparing project documentation to source

Development and packaging

PYTHONPATH=src python3 -m unittest discover -s tests -v
python3 -m pip install build
python3 -m build
python3 tests/smoke.py
python3 -m venv /tmp/locking-audit-venv
/tmp/locking-audit-venv/bin/python3 -m pip install dist/locking_claim_audit-0.1.0-py3-none-any.whl
/tmp/locking-audit-venv/bin/locking-claim-audit tests/fixtures/good/locked --json
PYTHONPATH=src python3 -m locking_claim_audit . --json

The build produces a wheel and an sdist in dist/. If isolated build dependencies are unavailable offline, install the build backend beforehand and use python3 -m build --no-isolation. MANIFEST.in includes the unittest suite and fixture trees in the sdist. Fixtures cover positive and negative contracts, contradictions, and test-only evidence. The tool's own README yields zero claims.

MIT licensed; see LICENSE.

Metadata

Release files for locking-claim-audit 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for locking-claim-audit 0.1.0
File Size Uploaded Provenance Actions
locking_claim_audit-0.1.0.tar.gz 17.6 kB Without provenance Details for locking_claim_audit-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for locking-claim-audit 0.1.0
File Interpreter ABI Platform Actions
locking_claim_audit-0.1.0-py3-none-any.whl Python 3 none any Details for locking_claim_audit-0.1.0-py3-none-any.whl

Total release size: 27.9 kB

Release files / locking_claim_audit-0.1.0.tar.gz

Download URL locking_claim_audit-0.1.0.tar.gz
Size 17.6 kB
Tags Source
SHA-256 checksum
How to use checksums
89b4e46cc815191773a60b7cce47ae126b6ed58077c3f662b5f67ca0cedbec03
BLAKE2b-256 checksum
How to use checksums
b9a10db19aec024ebb0dfdf865f51f142bf2a9c0ab2808e2aeae58bf232724a8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release files / locking_claim_audit-0.1.0-py3-none-any.whl

Download URL locking_claim_audit-0.1.0-py3-none-any.whl
Size 10.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2765ebfb3b560cc19cd6382d1950b9fab1740b9c143587e9f566403dcc396aee
BLAKE2b-256 checksum
How to use checksums
89e0515cecf1d2be50762e2bf42ee73c88ac349a60bc7a5366fb9f7dfceeffe2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Security for locking-claim-audit 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.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page