PyPI Trusted Publishing Branch Enforcement Boundary
PyPI Trusted Publishing does not validate the ref claim from OIDC tokens against publisher bindings. Publisher bindings define repository, workflow filename, and optionally an environment, but they do not include a branch or ref constraint. When a CI job emits an OIDC token with a branch identifier such as ref: refs/heads/main, PyPI's trust model accepts the token as long as the repository and workflow filename match the binding. If the branch differs—say a token from refs/heads/feature-x is used against a binding intended for main—the upload still succeeds because no branch-level comparison is performed. This creates a scoping gap: maintainers who expect branch-scoped releases may inadvertently publish the same package version from multiple branches using the same repository and workflow filename.
Confirmed facts
- Bindings omit branch/ref fields.
- OIDC tokens carry a
ref claim, but PyPI does not publicly document validation of this claim. - Uploads proceed without branch enforcement when the binding lacks a branch constraint.
- No documented mechanism exists to enforce branch restriction within Trusted Publishing.
- Extending a binding to include a branch constraint is not supported.
Likely explanation
The PyPI trust model was designed around repository and workflow identity, not branch granularity. OIDC token claims are treated as supplementary identity signals, and in the absence of an explicit branch constraint in the binding, they are ignored.
Uncertainty and version assumptions
Absent a public statement from the PyPI team, behavior could shift if PyPI introduces branch-aware bindings. Until such a feature is documented, maintainers should not rely on implicit branch validation.
Practical verification steps
- Navigate to the repository's PyPI settings and inspect the publisher binding; confirm that no branch or ref field is present.
- Trigger a package upload from a CI job targeting a different branch (e.g.,
feature-x) and observe whether PyPI accepts the upload. Compare the ref claim in the emitted OIDC token with the binding. - Review PyPI Trusted Publishing documentation and release notes for any mention of branch validation or future support.
Compensating controls
- Naming environments after branches (e.g.,
production-main, staging-feature-x). - Configuring CI-level branch filtering to ensure OIDC tokens are only emitted for intended branches.
- Using environment protection rules in the CI provider to restrict which branches may trigger uploads.
If you are determining whether your specific CI workflow and branch pattern require additional controls, please specify which CI provider and branch naming convention you use; this detail helps tailor the recommended compensating strategy.