fix(checkers): read real PyPI provenance and authenticate GitHub reads
User description
What
Two checker defects, both verified today against the live registries by a read-only pass before this PR started, and both fixed here:
scripts/release/check_drift.pyread attestation coverage from the wrong PyPI API. It called the legacyhttps://pypi.org/pypi/wave-sdk/<version>/jsonendpoint and checkedurls[].provenance, which PyPI has permanently null on that legacy field. Result: the release-drift check reported wave-sdk 2.2.0 as having no PEP 740 attestation even though attestations are actually published — a healthy state rendered as a false failure.scripts/ga/check_ver_001.py(viascripts/ga/ga_evidence.py) called the GitHub REST API unauthenticated.https://api.github.com/repos/<repo>/tagsand.../releases/tags/<tag>are capped at 60 requests/hour per source IP unauthenticated — a cap CI runners sharing NAT'd IP pools burn through easily. Any non-404 HTTPError (including a 403 rate-limit) was turned into a bareRegistryErrorwith no detail, andga_evidence.pyreported that as exit 2 "could not run" — an absent measurement standing in for a real check, distinct from and worse than a false failure.
Fix
Provenance (drift check): pypi_attestations() now reads the PyPI Simple API (https://pypi.org/simple/wave-sdk/ with Accept: application/vnd.pypi.simple.v1+json), which lists each file's provenance URL, and follows that link to the PyPI Integrity API (https://pypi.org/integrity/wave-sdk/<version>/<filename>/provenance). A 200 response carrying attestation_bundles means provenance is present for that file. A 404 (or a file with no provenance link at all) is treated as genuinely absent — that's a real, meaningful drift finding, not an UnreadableError. Only a real network/parse failure (non-200/404, connection error, bad JSON) still raises UnreadableError → exit 2. Added _files_for_version() with a version-boundary regex so e.g. 2.2.0 never accidentally matches a 2.2.0rc1 file.
GitHub auth (ga-evidence): scripts/ga/ga_common.py gained a _headers_for(url) helper that attaches Authorization: Bearer <token> — sourced from the GITHUB_TOKEN or GH_TOKEN environment variable — only when the request targets api.github.com; it is never sent to pypi.org or any other host (verified by a negative-control unit test). .github/workflows/ga-evidence.yml now passes GITHUB_TOKEN: ${{ github.token }} into the producer step's env — the default, job-scoped, read-only token, already governed by the workflow's existing permissions: contents: read block, no new secret. A genuine 403/429 (rate-limited even with a token, or any other non-404 registry error) still fails loud as a RegistryError with the response body attached for diagnosis — it is never silently downgraded to a detail-free "could not run," and never coerced into looking like a legitimate 404 "absent" result.
Out of scope (operator-only)
The PyPI trusted-publisher environment for wave-sdk is currently null ("unconstrained") — every workflow in this repo, not just release.yml, could in principle publish under that trusted-publisher binding rather than only a scoped release GitHub Environment. That is a PyPI project settings change only the package owner/operator can make (Trusted Publisher management UI), and it is not touched by this PR — noted here per the task brief so it's tracked, not silently left unmentioned.
Tests
Added two new unit-test files, both fully mocked (no real network calls in the suite):
tests/test_check_drift.py— 7 tests covering: attestation present via Simple API + Integrity API (the real regression case), genuinely-absent-is-not-UnreadableError (404 negative control), partial coverage, Simple-API network failure raisingUnreadableError, Integrity-API non-404 error raisingUnreadableErrorwith body detail, no-files-for-version raisingUnreadableError, and the version-boundary regex not false-matching a prerelease.tests/test_ga_common_github_auth.py— 6 tests covering:GITHUB_TOKENattached toapi.github.comrequests,GH_TOKENfallback, the token never sent topypi.org(negative control for credential scoping), no token in env → noAuthorizationheader, a 403 raisingRegistryErrorwith the response body (the core regression guard — never silently swallowed), and 404 still being the normal "absent" case.
$ python -m pytest -q
........................................................................ [ 85%]
............ [100%]
84 passed in 2.22s
$ ruff check
All checks passed!
Real-run receipts
scripts/release/check_drift.py --repo-root . against wave-sdk 2.2.0 on live PyPI + GitHub — now goes green (previously would have reported the attestation line as NONE):
[source] latest git tag : v2.2.0 (version 2.2.0)
[source] pyproject.toml version : 2.2.0
[source] PyPI latest version : 2.2.0
[source] GitHub Release for v2.2.0 : exists
[source] PyPI 2.2.0 attestations : present on all files
RESULT: in sync (tag, pyproject, PyPI, GitHub Release, and attestations all agree)
Exit code: 0
scripts/ga/ga_evidence.py --repo wave-av/sdk-python --package wave-sdk run with a real GitHub token in env (job-scoped gh auth token, injected into the process environment only, never printed) — completes and prints its verdict instead of exit-2'ing:
PASS VER-001: wheel-digest-matches-index=True; wheel-metadata-matches-pypi-version=True; newest-tag-exists=True; newest-tag-has-github-release=True; head-version-matches-published=True; newest-tag-matches-published=True
UNKNOWN SUPPLY-001: provenance-present:wave_sdk-2.2.0-py3-none-any.whl=True; provenance-present:wave_sdk-2.2.0.tar.gz=True; sbom-attached=None; known-vuln-resolution=None
evidence fingerprint: 804778014ea46ff44d9b26e3e8aadadec5ba4978f00e66d0b8816db718b02057
Exit code: 0 (SUPPLY-001 is UNKNOWN, not FAIL or a crash — sbom-attached and known-vuln-resolution are explicitly out of scope for that producer and always report unknown, by design, per its docstring)
Not merging
This PR is left open for review per the task's scope — it is not merged here.
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.
[!NOTE]
Cursor Bugbot is generating a summary for commit 47f65f52379dc952daef27c5a6a5b45e7cc328f0. Configure here.
CodeAnt-AI Description
Correct PyPI provenance checks and authenticate GitHub registry reads
What Changed
- Release-drift checks now verify PyPI attestations through the current Simple and Integrity APIs, correctly identifying present, partial, and genuinely missing provenance.
- Version matching no longer confuses a release with similarly prefixed versions such as release candidates.
- GitHub registry requests use the CI-provided read-only token when available, while keeping credentials off non-GitHub requests.
- GitHub rate-limit and other HTTP failures now include response details; expected 404 responses remain treated as missing resources.
- Added regression tests covering provenance results, version filtering, credential scoping, and registry error handling.
Impact
✅ Accurate PyPI attestation drift results
✅ Fewer GitHub API rate-limit failures in CI
✅ Clearer registry failure diagnostics
💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
@codeant-ai ask: Your question here
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
@codeant-ai ask: Can you suggest a safer alternative to storing this secret?
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
@codeant-ai: Your feedback here
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
@codeant-ai: Do not flag unused imports.
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
@codeant-ai: review
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.