Retry the release attach, and stop signatures outliving their files - #32
Merged
Conversation
`gh release upload` sends each file in turn and gives up on the first rejection with part of the set already attached. A single HTTP 502 from api.github.com did exactly that to pyvider-rpcplugin v0.5.0: PyPI had the package, while the release page kept the sdist and every `.sigstore.json` and lost the wheel and the SBOM -- so it carried signatures for two files it did not have. A signature beside no artifact is worse than an empty release: it reads as something published and verified that is merely hard to find. The attach is retried with backoff now. Uploading is idempotent under `--clobber`, so the whole set is simply resent, and the job fails with nothing half-done that a reader would mistake for complete. The repair path gains the same retry, and drops an SBOM signature whose SBOM is gone. Repair deliberately does not rebuild one -- today's dependency closure is not the release's -- so the signature has nothing left to sign, and absent is the honest state. `sign-and-upload` now checks out, for the attach script only, with no credentials persisted. It was deliberately checkout-free so that nothing fetched from a registry runs beside the signing identity; a script from the repository under a credential-less checkout does not reintroduce that. Fixed first in pyvider-rpcplugin (#18); this is the same change, since the workflow is duplicated across these repositories and every copy can lose part of a release to one 502. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dhi1SLuFiEseRhH9iLMv8Q
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
gh release uploadsends each file in turn and gives up on the first rejection, with part of the set already attached. A single HTTP 502 fromapi.github.comdid exactly that topyvider-rpcpluginv0.5.0:PyPI had the package. The release page kept the sdist and every
.sigstore.json, while losing the wheel and the SBOM — so it carried signatures for two files it did not have. That is worse than an empty release: a.sigstore.jsonbeside no artifact reads as something published and verified that is merely hard to find.This workflow is duplicated across the provide-io Python repositories, so every copy can lose part of a release the same way. Fixed first in pyvider-rpcplugin#18; this is the identical change.
What changes
The attach is retried with backoff. Uploading is idempotent under
--clobber, so the whole set is resent rather than reconstructed piecemeal. Uploading each file in its own command would still leave a partial set when the retries ran out; this way the release either gets everything, or the job fails with nothing half-done.The repair path gains the same retry, and drops an orphaned SBOM signature. Repair deliberately does not rebuild an SBOM — today's dependency closure is not the release's, and an SBOM confidently wrong about what shipped is the failure this ecosystem has already had once. That reasoning is unchanged. But a partially-failed run leaves a signature with nothing to sign, and absent is the honest state. A release holding both is left alone.
sign-and-uploadnow checks out, for the attach script only, withpersist-credentials: false. It was deliberately checkout-free so nothing fetched from a registry runs beside the signing identity; a script from this repository under a credential-less checkout does not reintroduce that, and the comment says so.Both scripts live in
scripts/, not inline in the YAML.Verified
The fix ran against a real broken release:
pyvider-rpcpluginv0.5.0 had its wheel restored (sha256 byte-identical to PyPI) and its orphaned SBOM signature removed, leaving eight assets each of which is a real file with its own signature.🤖 Generated with Claude Code
https://claude.ai/code/session_01Dhi1SLuFiEseRhH9iLMv8Q