entry-claim-audit
Offline static CLI that checks Python packaging entry-point claims against source on disk. It checks [project.scripts] and [project.gui-scripts] targets for a module, symbol, and callability, and checks documented command names. It never executes project code, accesses the network, or reads .env contents. Reports contain rule names, paths, script names and targets, not unrelated file contents.
Requires Python 3.9 or later. Runtime dependencies: none.
Usage
pip install .
entry-claim-audit .
entry-claim-audit /path/to/project --json
entry-claim-audit . --fail-on HIGH
entry-claim-audit . --ignore script-undocumented,script-target-not-callable
entry-claim-audit . --verbose
entry-claim-audit --version
python -m entry_claim_audit .
The path defaults to .. Exit codes: 0 PASS, 2 FAIL, 1 usage/input error. Default failure threshold is MEDIUM; --fail-on HIGH still prints MEDIUM findings but does not fail for them. --ignore RULE,... drops those rules entirely, for example when scripts are documented elsewhere or a data-object target is intentional. --verbose adds verified scripts to human output.
Human output has one SEVERITY rule file:line message line per finding followed by PASS/FAIL. Metadata findings use pyproject.toml:0. JSON contains status, findings (severity, rule, file, line, message) sorted by rule/file/line, and verified_scripts (script, table, target).
For example, mytool = "pkg.cli:main" passes if pkg/cli.py defines def main() and README mentions mytool. Renaming that file without updating the target yields script-target-module-missing and exit 2.
Full rule table
| Rule | Severity | Trigger and report |
|---|---|---|
script-target-malformed |
HIGH | Target has no colon, an empty module/object, internal whitespace, or invalid dotted identifiers. Surrounding whitespace is stripped. Reports script, table and raw target; no further target checks for that script. |
script-target-module-missing |
HIGH | Target module does not resolve to a source file in the supported layouts. Reports script, table and module. |
script-target-symbol-missing |
HIGH | Resolved module lacks the first object segment. Reports script, table, module and missing symbol. |
script-target-attr-missing |
HIGH | First object is a class but the next segment is absent from its directly defined methods. Reports script, table and missing method. Chains beyond that method, or attributes of non-class objects, are unchecked. |
script-target-not-callable |
MEDIUM | First object is a plain data assignment. Functions, async functions, classes, imports, lambdas and call-result assignments pass. Only the first object segment is checked. |
documented-command-missing |
HIGH | First token of a fenced or inline code command equals the project name (case/dash/underscore normalized), but is not an exactly declared script name. Reports doc file:line, token and declared names. Arbitrary other commands are ignored; skipped without a project name. |
script-name-duplicate |
MEDIUM | Same name is declared in both scripts and gui-scripts. |
script-undocumented |
MEDIUM | Script name never occurs as a whole word anywhere in scanned docs, including prose. Skipped when there is neither README.md nor docs markdown. |
Verified targets are not findings. Both script tables receive the same checks. No pyproject.toml, no project table, or no script tables yields PASS with zero findings.
Static interpretation
Modules resolve in this order: src/pkg/mod.py, src/pkg/mod/__init__.py, pkg/mod.py, pkg/mod/__init__.py. Single-segment modules and package __init__.py targets are supported. Namespace parent directories are allowed. The directories tests, .venv, pycache, dist, .git and .egg-info are not module evidence.
Only the resolved module is parsed. Top-level functions, async functions, classes, Name assignment targets (including annotations), and imported names count as symbols. Re-exports count without importing or following them. Direct class methods include __init__. Assignments to lambda/call expressions count as callable or unknown; all other assigned values, including names and attributes, count as data. Definitions nested inside functions or conditional blocks are not collected.
Docs scanned: top-level *.md including README.md, and recursive docs/**/*.md. Command claims come only from fenced code and inline code spans. Undocumented checks use full text. TOML uses stdlib tomllib on Python 3.11+, with a minimal quoted key/value regex fallback for script tables on older Python (and a simple project-name lookup).
Differentiation
- readme-claim-audit audits pip install names against pyproject and docs flags, links, versions and make targets. This checks whether installed commands resolve to modules, symbols and callables; the rules do not overlap.
- api-claim-audit audits symbols promised in docs code examples. This checks symbols promised in packaging metadata, using similar AST machinery with a different promise source; the rules do not overlap.
- dep-claim-audit audits dependency declarations against imports. This audits entry-point declarations against source.
- pip-check, pipdeptree and importlib.metadata checks inspect an installed environment at runtime. This tool is static and offline and works on a repository that has never been installed.
- twine check validates package metadata for upload; it does not resolve entry-point targets to source symbols.
Honest limitations
Static scanning misses dynamic symbols created by importlib, module __getattr__ hooks, exec or eval. An existing symbol still counts even if a failing top-level import prevents actual import. Imported/re-exported names and call-result assignments have unknown runtime callability and pass. Decorators and runtime behavior are not evaluated.
Attribute chains resolve only one class-method step. Further attributes and non-class attributes remain unchecked. setup.cfg and setup.py entry_points are not parsed. The documented-command rule catches only the project's own name, not arbitrary mistyped command names. It examines the first whitespace-separated code token, so shell prompts or wrappers can hide commands. script-undocumented is heuristic: a script documented only outside README/top-level markdown/docs is flagged; use --ignore script-undocumented.
The fallback parser supports simple single-line quoted declarations, not full TOML syntax. Invalid TOML (with tomllib), unreadable files and invalid Python syntax produce input-error exit 1. The tool establishes static evidence, not that a built distribution includes the module or that a command will execute successfully.
Development
PYTHONPATH=src python3 -m unittest discover -s tests -v
python3 -m build
MIT licensed.
Metadata
Release files for entry-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)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| entry_claim_audit-0.1.0.tar.gz | 12.9 kB | Without provenance | Details for entry_claim_audit-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| entry_claim_audit-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for entry_claim_audit-0.1.0-py3-none-any.whl |
Total release size: 22.3 kB
Release files / entry_claim_audit-0.1.0.tar.gz
| Download URL | entry_claim_audit-0.1.0.tar.gz |
|---|---|
| Size | 12.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
27e170ed0aba56c679c7fa4b4035309e78e32861f28268ab16b738f580ee73ec
|
|
BLAKE2b-256 checksum How to use checksums |
c565f66751068c46254614e0b2494da2f827ddae2a01522e7c83efe02ee24e86
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / entry_claim_audit-0.1.0-py3-none-any.whl
| Download URL | entry_claim_audit-0.1.0-py3-none-any.whl |
|---|---|
| Size | 9.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
61ab4e4e48a474d6cd3f8fba19a1edc3b65ab0ad3918e58a994b5ac612d5c869
|
|
BLAKE2b-256 checksum How to use checksums |
1ddfe2cefb7749061a58f9ee3d811700728bf52aa4b5205a1b0bff75d6bb8b12
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Security for entry-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.