Repository navigation
fix(release): upload release assets by id so a spent API quota stops reading as "release not found" - #344
Merged
Conversation
Contributor
Vulnetix config planManager
0 to create, 1 to update, 0 to delete, 0 unchanged |
…reading as "release not found" The provenance and publish-tea jobs failed together on v4.24.8, v4.24.32 and v4.24.34 with "release not found" from `gh release upload <tag>`, minutes after the release was published, on different runners; a re-run of the failed jobs passed. The release was never missing, a draft or immutable. gh (since cli/cli#13723) looks a release up by tag over REST and as a draft over GraphQL at once, and when both fail it prefers to report "release not found". With PACKAGES_TOKEN's REST quota spent, the REST lookup is refused with 403/429 and the GraphQL lookup, which has its own quota, correctly finds no draft, so a published release reads as missing. That token is a personal token whose 5,000 requests an hour are shared with everything else using it; at 16:08:18 on the day of v4.24.32 the quota was at 0 (see #342), and the provenance upload failed at 16:16:10. - scripts/release-asset-upload.sh uploads to a release by id (the caller's, or resolved over GraphQL), replaces an existing asset of the same name, waits a spent quota out until its reset (65 minutes at most), honours Retry-After for a secondary limit, retries 404/5xx a few times, and names the HTTP status of every failure. - The release job asks GraphQL whether the release exists, uploads by id, and outputs release_id; the provenance workflow takes it as an optional input (belai's call still works by tag) and runs the script from its own commit (job_workflow_sha), so a caller in another repository runs it too. - The slsa-provenance artifact is uploaded before the release asset, so a failed release upload no longer loses the hand-off. - publish-tea needs provenance to succeed, and accepts a skipped update-packages only for a release older than the newest. Before, a provenance failure skipped canary and update-packages, and publish-tea still ran: it would have put v4.24.34 in the transparency log, which cannot be unpublished, without its bundle and with Homebrew, Scoop and the flake left on v4.24.33.
0x73746F66
force-pushed
the
fix/release-upload-quota
branch
from
November 13, 2026 20:56
3c0698e to
c15a9e8
Compare
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.
Why
On v4.24.8, v4.24.32 and v4.24.34,
provenanceandpublish-teafailed in the same run. Both died atgh release upload <tag>withrelease not found, minutes after the release was published and on different runners. Re-running the failed jobs passed. For v4.24.34, this left Homebrew, Scoop and the flake on v4.24.33, becausecanaryneedsprovenance.The release was never missing:
immutable: false).The cause is how gh handles a rate-limit error:
FetchReleaselooks a release up two ways at once: by tag over REST, and as a draft over GraphQL.release not found(pkg/cmd/release/shared/fetch.go).PACKAGES_TOKENis a personal token, and its 5,000 REST requests an hour are shared with everything else that uses it.The timing matches. On the day v4.24.32 was released, the quota was at 0 at 16:08:18 (#342), and the provenance upload failed at 16:16:10. While this fix was being prepared, the same token had 0 REST requests left but 4,997 GraphQL requests left.
This was not GitHub's eventual consistency. The uploads ran 60 to 100 s after the release was created in passing runs and in failing runs alike, and
publish-teafailed seven minutes after creation.What changes
scripts/release-asset-upload.shuploads to a release by its id. The id comes from the caller, or is resolved over GraphQL. The script:Retry-Afteron a secondary limit;releasejob:gh release view;release_id.slsa-provenance.yml:release_idinput, so belai's existing call still works by tag;job_workflow_shaOIDC claim);slsa-provenanceartifact before the release asset (withoverwrite: true), so a failed release upload no longer loses the hand-off;publish-tea:provenanceto succeed;update-packagesonly when the release is not the newest. Previously, a provenance failure skippedcanaryandupdate-packages, andpublish-tearan anyway. That could permanently publish a TEA release without its bundle, while the package managers were never updated.continue-on-erroron the bundle download.docs/PUBLISHING.mddescribes the new behaviour.Checks
actionlint 1.7.12 with shellcheck 0.10.0:
release.yml: the same 6 pre-existing info/warning notes as on main;slsa-provenance.ymlis clean;gh actions-lock --ignore-local-actions --verify-localreports all 12 workflows covered (actions/checkout@v7added forslsa-provenance.yml).The script was run offline against scripted responses. Each case behaved as expected:
Retry-After