fix(releases-proxy): switch to asset API endpoint + add observability#14
Merged
Merged
Conversation
The releases.hal0.dev/{stable,nightly,dev}.json proxy was silently
falling through to the static `_placeholder: true` backstop despite
v0.1.0-alpha.1 shipping a real `stable.json` asset. Two changes:
1. **Switch asset fetch from `browser_download_url` to `asset.url`**
with `Accept: application/octet-stream`. Both end up at
`objects.githubusercontent.com`, but the api.github.com asset
endpoint is the documented direct-download path and is slightly
more reliable for cross-origin redirect handling from CF Workers.
2. **Add observability.** Every failure branch (list fetch threw,
list non-2xx, list parse, asset fetch threw, asset non-2xx, no
release with the named asset) now:
- emits a `console.warn` with a stable reason tag, visible in
`wrangler tail` and the CF Pages logs UI
- propagates a `x-hal0-proxy-failed: <reason>` response header
on the fallthrough static-placeholder response
The second piece is the meaningful change. Previously, an external
`curl https://releases.hal0.dev/stable.json` could not distinguish
"middleware never deployed" from "middleware deployed and failed".
Both produced byte-identical responses (the static placeholder body
with `_headers`-derived cache-control). With this PR, the header
tells you which code path executed and why it bailed — no Cloudflare
account access required to diagnose the next regression.
Returns nothing else changed: success path still sets the same
content-type / CORS / cache-control / x-hal0-source / x-hal0-channel
headers, and non-channel paths still take the original /releases/*
rewrite.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Deploying hal0-web with
|
| Latest commit: |
e6d302b
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://be61482c.hal0-web.pages.dev |
| Branch Preview URL: | https://fix-releases-proxy-observabi.hal0-web.pages.dev |
4 tasks
thinmintdev
added a commit
that referenced
this pull request
May 22, 2026
…OKEN (#15) PR #14's observability change confirmed the failure mode: $ curl -sSI https://releases.hal0.dev/stable.json | grep x-hal0 x-hal0-proxy-failed: gh-list-403 The very first upstream call — the releases list on api.github.com — gets a 403 from inside CF Pages Functions. Cloudflare's outbound IP pool is shared across every CF customer, so the anonymous 60/hr/IP limit is permanently exhausted long before our request arrives. Authenticated requests get 5000/hr per token, comfortably above any realistic load on releases.hal0.dev. Changes: - New `authHeaders(token)` helper attaches `Authorization: Bearer` when env.GITHUB_TOKEN is present; falls back to anonymous when not set (so this PR is a no-op until the secret lands in CF). - Both fetches (releases list + asset download) use the helper. - `PagesFunctionContext` type now includes `env: { GITHUB_TOKEN? }` and the proxy function takes the token as a parameter. - `gh-list-<status>` reason gets a `-auth` / `-anon` suffix so the `x-hal0-proxy-failed` header tells us whether the secret is wired. The token only needs public-repo read scope — a fine-grained PAT restricted to Hal0ai/hal0 with `Contents: Read` is the minimum. Classic tokens with no scopes also work (they get 5000/hr for public-repo reads). Pre-merge requirement: set `GITHUB_TOKEN` in CF Pages env (production + preview) before merging, or the fix is a no-op and stable.json keeps serving the placeholder. Co-authored-by: Claude Opus 4.7 (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.
Summary
releases.hal0.dev/stable.jsonis silently returning the static_placeholder: truebackstop despiteHal0ai/hal0@v0.1.0-alpha.1shipping a realstable.jsonasset. Two changes to fix + diagnose.Background
After PR #10 merged, manual verification showed:
Upstream is healthy —
api.github.com/repos/Hal0ai/hal0/releasesreturnsv0.1.0-alpha.1with thestable.jsonasset attached. So the proxy is failing somewhere insideproxyChannelManifest()and returningnull, falling through to the static placeholder.The problem: with the original code, we cannot tell from the outside whether the new middleware ever deployed vs. deployed-and-failed. Both produce byte-identical responses, because the static-placeholder response's
cache-control: public, max-age=60, must-revalidateactually comes frompublic/_headers(not the proxy code), so even that header doesn't disambiguate.What changed
1. Asset fetch via
api.github.comasset endpointSwitch from
asset.browser_download_urltoasset.urlwithAccept: application/octet-stream. Both ultimately land onobjects.githubusercontent.comfor the bytes, but theapi.github.comasset endpoint is the documented direct-download path and is slightly more predictable for CF Workers' cross-origin redirect handling.2. Observability on every failure branch
Each bailout point now:
console.warntagx-hal0-proxy-failedheader valuegh-list-threw:<err>gh-list-<status>gh-list-parse:<err>gh-asset-threw:<err>:<tag>gh-asset-<status>:<tag>no-asset:<channel>.json:<count>releasesThe
console.warncalls show up inwrangler tailand the CF Pages logs UI. Thex-hal0-proxy-failedresponse header is visible to anycurl -I, so the next time this regresses we can diagnose without Cloudflare account access:Out of scope
GITHUB_TOKENto raise the 60/hr rate limit. If the logs surface that this is the actual failure mode, follow-up PR can add the secret to CF Pages env. Not done here because we don't know it's the issue yet.@cloudflare/workers-typesstill not added. The localPagesFunctionContexttype stays the same.releases.hal0.dev does not exist yetcomment inHal0ai/hal0:.github/workflows/release.ymllines 13–15 — different repo, separate PR.Test plan
Vercel Preview,Cloudflare Pages,Vercel Agent Review)curl -sSI https://releases.hal0.dev/stable.json | grep x-hal0shows eitherx-hal0-source: github-release/v0.1.0-alpha.1(fix worked) or a specificx-hal0-proxy-failed: <reason>(fix didn't work but we now know exactly why)v0.1.0-alpha.1manifest with non-zerodigest_sha256, not_placeholder: true🤖 Generated with Claude Code