tagtruth
Your PyPI package says 1.36.1. The Git tag says 1.36.0.
Real case: google-adk==1.36.0
exists on PyPI, but there is no GitHub release or tag for v1.36.0 —
releases/tag/v1.36.0
returns 404 and git ls-remote --tags shows only v1.36.1. Worse, the v1.36.1
tag points at a commit whose version.py still says __version__ = "1.36.0"
while the PyPI 1.36.1 sdist says 1.36.1. The tag doesn't even match the code
that shipped.
tagtruth checks that a package's published PyPI versions actually correspond to tags in its GitHub repo — the release-integrity question nobody's CI asks.
Part of the release-integrity series: readmeta (did your README render?), wheeltruth (did your wheel ship complete?), tagtruth (does the tag match the release?).
Quickstart
pip install tagtruth
tagtruth check --package google-adk --repo google/adk-python
version expected tag found tag sdist verdict
------- ------------- --------- ----- -------
1.36.1 v1.36.1 v1.36.1 - OK
1.36.0 v1.36.0/1.36.0 - - MISSING_TAG
checked 2 versions, 1 mismatch(es): 1.36.0 (MISSING_TAG)
Exit codes: 0 clean, 1 mismatches found, 2 errors (fetch failures, bad args).
Options:
tagtruth check --package <pypi-name> --repo <owner/repo> \
[--limit 10 | --all] \ # how many of the newest versions to check
[--deep] \ # also download each sdist, compare PKG-INFO Version
[--map 1.36.0=v1.36] \ # expected tag name for a version (repeatable)
[--ignore 1.0rc1] \ # skip a version (repeatable)
[--config path.toml] \ # TOML file with [tool.tagtruth] (default: ./pyproject.toml)
[--format json] # machine-readable output
--deep additionally verifies that each version's sdist actually claims the
version PyPI lists, and that the tag name agrees with the sdist:
version expected tag found tag sdist verdict
1.36.1 v1.36.1 v1.36.1 1.36.1 OK
New verdicts under --deep: SDIST_MISMATCH (PyPI says X, sdist says Y),
TAG_SDIST_MISMATCH (tag name disagrees with the sdist).
Config: killing false positives
Many projects intentionally skip tags or name them differently. Without a
mapping file, tagtruth drowns in false positives — so mapping is a first-class
feature, not an afterthought. Put this in your pyproject.toml:
[tool.tagtruth]
ignore = ["0.0.0-nightly", "1.0.0rc1"]
map = { "1.36.0" = "v1.36", "2.0" = "release-2.0" }
CLI flags --map and --ignore do the same thing ad hoc and override the
file per key.
CI snippet
- name: Check release/tag integrity
run: |
pip install tagtruth
tagtruth check --package my-pkg --repo myorg/myrepo --all
Add it as a post-release job: if a release ever ships without its tag, the pipeline fails loudly instead of rotting silently.
How it works
- PyPI versions:
https://pypi.org/pypi/<name>/json(releaseskeys, sdist URLs). - GitHub tags:
https://api.github.com/repos/<owner>/<repo>/tags(paginated). - Expected tag for version
XisvXorX, unless--map/mapsays otherwise. --deepdownloads each sdist (capped at 100 MB) and readsPKG-INFO'sVersion:field from the zip/tarball.
Zero dependencies, Python 3.9+. Unauthenticated GitHub API calls are fine for occasional checks (60 req/hour); the deep sdist check is structured so a future version can also compare the tag's commit content.
Limitations
- Tag-name comparison is syntactic: it can't tell you the tag points at the wrong commit (the second half of the adk story). That's the next check on the roadmap.
- Version ordering is best-effort without PEP 440 (no dependency means no
packaging); exotic schemes may sort oddly — use--alland eyeball it.
Metadata
Release files for tagtruth 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 | |
|---|---|---|---|---|
| tagtruth-0.1.0.tar.gz | 17.8 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tagtruth-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 31.8 kB
Release files / tagtruth-0.1.0.tar.gz
| Download URL | tagtruth-0.1.0.tar.gz |
|---|---|
| Size | 17.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4de9121634560157e947e8d6ce64495db61dd0335bbc3b9b03217f105dbea74f
|
|
BLAKE2b-256 checksum How to use checksums |
0652854c4547113f2ac5db9fffa7abf2aa28fb13d6998501e700ad1d8412687d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / tagtruth-0.1.0-py3-none-any.whl
| Download URL | tagtruth-0.1.0-py3-none-any.whl |
|---|---|
| Size | 14.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f7f8362ffbb1e186956959c273e039d32ad4b37f1ed3cdad6da6034731e4ea3b
|
|
BLAKE2b-256 checksum How to use checksums |
9ea7ed806a89f5519f7caf7b5c4f387208ce90249cc408aa29a87b726fb192e8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Security for tagtruth 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.