Skip to content

Retry the release attach, and stop signatures outliving their files - #32

Merged
livingstaccato merged 2 commits into
mainfrom
ci/release-attach-retry
Sep 5, 2026
Merged

Retry the release attach, and stop signatures outliving their files#32
livingstaccato merged 2 commits into
mainfrom
ci/release-attach-retry

Conversation

@livingstaccato

Copy link
Copy Markdown
Member

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:

HTTP 502: Server Error (https://api.github.com/repos/.../releases/assets/545028939)

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.json beside 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-upload now checks out, for the attach script only, with persist-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-rpcplugin v0.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

livingstaccato and others added 2 commits September 4, 2026 16:32
`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
@livingstaccato
livingstaccato merged commit 4fa1057 into main Sep 5, 2026
33 checks passed
@livingstaccato
livingstaccato deleted the ci/release-attach-retry branch September 5, 2026 00:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant