Skip to content

Serve release downloads from R2 instead of GitHub for IPv6 hosts - #207

Merged
admdly merged 4 commits into
mainfrom
claude/ipv6-auto-update-failures-195f03
Aug 30, 2026
Merged

Serve release downloads from R2 instead of GitHub for IPv6 hosts#207
admdly merged 4 commits into
mainfrom
claude/ipv6-auto-update-failures-195f03

Conversation

@admdly

@admdly admdly commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Summary

github.com and api.github.com have no AAAA record, so IPv6-only hosts (no NAT64) can check /versions/v1/latest for an update but can never download it. FOSSBilling/FOSSBilling now mirrors every release archive to R2 under download.fossbilling.org, which is IPv6-reachable.

  • getReleases() now looks up each release's R2 mirror and prefers its download_url and digest over the GitHub asset.
  • digest is read from R2 custom metadata set by CI from the exact uploaded file, rather than recomputed here.
  • Releases without a mirror (published before this existed, or on a failed R2 lookup) fall back to the GitHub asset, unchanged from current behavior.
  • stats/v1 skips the R2 lookup entirely since it never reads download_url/digest.
  • The preview branch endpoint already returns a download.fossbilling.org URL and needed no change.

Fixes FOSSBilling/FOSSBilling#2479.

github.com and api.github.com have no AAAA record, so IPv6-only hosts
(no NAT64) can check /versions/v1/latest for an update but can never
download it. FOSSBilling/FOSSBilling now mirrors every release archive
to R2 under download.fossbilling.org, which is IPv6-reachable.

getReleases() now looks up each release's R2 mirror and prefers its
download_url and digest (the digest is R2 custom metadata set by CI
from the exact uploaded file, so it's read rather than recomputed).
Releases without a mirror - published before this existed, or on a
failed R2 lookup - fall back to the GitHub asset as before.

Fixes FOSSBilling/FOSSBilling#2479
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 30, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
api 09b394f Commit Preview URL

Branch Preview URL
Aug 30 2026, 07:15 PM

@admdly admdly self-assigned this Aug 30, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 4 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/services/versions/v1/index.ts
Comment thread src/services/versions/v1/r2.ts
Comment thread src/services/stats/v1/index.ts Outdated
Comment thread test/services/versions/v1/index.test.ts Outdated
Comment thread src/services/versions/v1/index.ts
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 1 file (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread test/services/versions/v1/index.test.ts
- getReleases now requires downloadBucket instead of it being optional.
  stats/v1 was passing undefined, and since it writes to the exact same
  RELEASE_CACHE_KEY the versions service reads, a stats-triggered cache
  refresh could overwrite that shared cache with GitHub-only download
  URLs for up to 24h - silently undoing the R2 preference for IPv6-only
  hosts until something refreshed it again. stats/v1 now threads
  c.env.DOWNLOAD_BUCKET through so every writer resolves R2 consistently.
- Fixed a test assertion left out of sync with a manually-edited mock
  digest (61 vs 64 hex chars) from the previous review round.
- Updated the versions/v1 README: download_url/digest now documented as
  R2-preferred with a GitHub fallback, and DOWNLOAD_BUCKET is listed as
  a required binding.
@admdly

admdly commented Aug 30, 2026

Copy link
Copy Markdown
Contributor Author

Addressed cubic's findings in 7edd9ff:

  • stats/v1 cache-poisoning (P1) — real bug, fixed. getReleases writes to the same RELEASE_CACHE_KEY the versions service reads, so a stats-triggered refresh with no R2 bucket could overwrite that shared cache with GitHub-only URLs for up to 24h. downloadBucket is now a required param, and stats/v1 threads c.env.DOWNLOAD_BUCKET through instead of skipping the lookup.
  • Test assertion mismatch (P2) — fixed; the digest assertion was out of sync with the mock value from the previous review round's manual edit.
  • Stale README (P3) — updated: download_url/digest now documented as R2-preferred with a GitHub fallback, DOWNLOAD_BUCKET listed as a required binding.

Two items I'm not changing:

  • Update.php allowlist (P1) — already handled client-side. FOSSBilling/FOSSBilling's Update.php already has https://download.fossbilling.org/releases/ in allowedDownloadPrefixes (confirmed on main), so this isn't blocking.
  • getReleaseR2Object always returning null for now (P1) — expected, not a bug in this repo. The matching "Upload Release Archive to R2" step in FOSSBilling/FOSSBilling's create-release.yml is a separate change landing in that repo; until it ships, releases just fall back to the GitHub asset URL as before, which is the intended degrade-safe behavior.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 4 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread src/services/stats/v1/index.ts
Comment thread src/services/versions/v1/README.md Outdated
- The GET / example in the versions README keyed its sample release as
  0.5.0, which (per the fallback note added last commit) would predate
  R2 mirroring and show a GitHub URL - contradicting the R2 download_url
  shown right next to it. Swapped the example to 0.6.0.
- Added a regression test for the stats/v1 cache-poisoning fix: seeds
  DOWNLOAD_BUCKET, forces /stats/v1/data through a fresh release fetch,
  and asserts the shared gh-fossbilling-releases cache it writes carries
  the R2 download_url/digest rather than the GitHub asset. Confirmed it
  fails against the pre-fix code (undefined bucket) before restoring the
  real fix.
@admdly

admdly commented Aug 30, 2026

Copy link
Copy Markdown
Contributor Author

Addressed both findings from the latest round in 09b394f:

  • README example inconsistency (P3) — fixed. Swapped the GET / example from 0.5.0 to 0.6.0 so it's consistent with the fallback note (a pre-mirroring release wouldn't actually show an R2 URL).
  • Missing regression test for the cache-poisoning fix (P2) — added test/services/stats/v1/index.test.ts's new "Shared release cache" test: it seeds DOWNLOAD_BUCKET, forces /stats/v1/data through a fresh fetch, and asserts the shared gh-fossbilling-releases cache entry it writes carries the R2 download_url/digest. Verified it actually catches the regression by reverting the fix locally and confirming the test fails, then restored the fix.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 2 files (changes from recent commits).

Requires human review: Auto-approval blocked by 1 unresolved issue from previous reviews.

Re-trigger cubic

@admdly
admdly merged commit 9a9259f into main Aug 30, 2026
9 checks passed
@admdly
admdly deleted the claude/ipv6-auto-update-failures-195f03 branch August 30, 2026 19:22
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.

Ensure compatibility with IPv6 only enviroments

1 participant