Authenticate the latest-release lookup - #4
Merged
Conversation
Resolving "latest" calls the GitHub API unauthenticated, and that is
capped at 60 requests an hour PER IP ADDRESS. CI runners share addresses,
GitHub-hosted macOS runners heavily so, and the result is a 403 several
times an hour:
curl: (56) The requested URL returned error: 403
failed to resolve latest release for aviorstudio/gdam
That failed installs intermittently for every repository using
gdam-actions, and it blocked a release three times in a row this morning
before the cause was clear -- which is the second half of this change.
The token is optional and the unauthenticated path is untouched: someone
installing by hand from their own address is nowhere near the limit.
GDAM_GITHUB_TOKEN is checked first so a caller can point this at a
different token, then GITHUB_TOKEN and GH_TOKEN, which CI and the gh CLI
already set.
It reaches curl through a config on STDIN rather than as -H on the
command line, because arguments are visible in the process list to every
other user on the machine and this script runs on shared boxes as well as
in CI.
The error message now names the rate limit when no token was used. It
previously said only that the release could not be resolved, which reads
as "there is no release" and sends you to the wrong repository -- the
limit was the actual cause every time it fired.
--retry covers the transient half: 429 and 5xx are retried, and a 403
from the rate limiter is not, so an exhausted quota still fails fast
rather than sleeping through three attempts.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
5000/hour is a personal access token. A workflow's GITHUB_TOKEN gets 1000/hour PER REPOSITORY, which is the number that matters here because CI is where this fires. Both are a large improvement on 60/hour shared across every repository on a runner address, and the denominator is the real change -- but the code and the error message should not state a figure nobody will observe. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
nicodes
added a commit
to aviorstudio/gdam-actions
that referenced
this pull request
Aug 1, 2026
The install script can now use a token for the API call that resolves "latest" (aviorstudio/gdam#4). It is not in the environment by default in Actions, so it has to be handed over -- this does that, defaulting to the workflow's own token so no consumer has to change anything. The unauthenticated API allows 60 requests an hour PER IP ADDRESS, and runners share addresses. macOS runners share them heavily enough that the lookup returned 403 several times an hour, which failed installs intermittently across all sixteen repositories using this action and blocked this repo's own release three times. Authenticated, the limit is scoped to the token: 1000/hour per repository, against one lookup per run. Passed as GDAM_GITHUB_TOKEN rather than GITHUB_TOKEN so the script gets exactly what the caller chose, instead of quietly inheriting whatever the job happened to have in GITHUB_TOKEN. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
scripts/install_cli.shresolveslatestwith an unauthenticated GitHub API call:That is capped at 60 requests an hour per IP address. CI runners share addresses — GitHub-hosted macOS runners heavily so — and the result is:
Why this matters now
It fails intermittently for every repository using
gdam-actions/installwith the defaultversion: latest— 16 of them. It blocked thegdam-actionsrelease three times in a row, with successes interleaved, which is what made it read as flake rather than as a rate limit.It also predates this work: there's a matching
install (macos-latest)failure ingdam-actionsCI history from before any of it.The change
Send a token when one is available.
GDAM_GITHUB_TOKENfirst, so a caller can point this at a different token than whateverGITHUB_TOKENholds; thenGITHUB_TOKENandGH_TOKEN, which CI and theghCLI already set.What that buys, stated accurately: 1,000/hour per repository for a workflow's
GITHUB_TOKEN(5,000/hour for a personal access token). The denominator is the real fix — one repository's runs stop competing with every other repository that happens to share a runner address. Each workflow run makes exactly onelatestlookup, so the headroom is ~1000×.The unauthenticated path is untouched. Installing by hand from your own address is nowhere near 60/hour, so no token is required and nothing about that case changes.
The token goes to curl via a config on stdin, not
-Hon the command line — arguments are visible in the process list to every other user on the machine, and this script runs on shared boxes as well as in CI.The error message now names the cause. It previously said only that the release could not be resolved, which reads as "there is no release" and sends you to the wrong repository. The limit was the actual cause every time it fired.
--retry 3covers the transient half. 429 and 5xx are retried; a 403 from the rate limiter is not, so an exhausted quota still fails fast rather than sleeping through three attempts.Verified
All four paths, end to end against the real API:
gdam 0.0.7gdam 0.0.7— unchangedVERSION=0.0.6gdam 0.0.6, never touches the APIAnd that the header is genuinely applied, rather than both paths merely happening to succeed:
sh -nandshellcheck -s shclean. (One pre-existing SC2016 at line 176 — the literal$HOMEin the "rerun with INSTALL_DIR=…" advice — is correct as-is and untouched.)Needed alongside this
This makes the script able to authenticate; it doesn't make CI pass on its own.
GITHUB_TOKENis not in the environment by default in Actions.gdam-actions/installwill take atokeninput defaulting to${{ github.token }}, so consumers get it for free without changing anything.