Skip to content

Fress v1.0.3

Choose a tag to compare

@github-actions github-actions released this 18 Oct 13:27
· 46 commits to main since this release
5d8630e

Fress v1.0.3 — the never-unreached release

This release closes, at the root, the error some users saw on the download button: "No download was started: the download sources could not be reached. Retry, or open the app for its official options."

What was wrong

Every catalog lookup (GitHub Releases, the F-Droid index, vendor manifests) was a single unauthenticated HTTP request. Three independent roots turned ordinary network weather into that failure:

  1. One dropped packet failed the whole lookup. A DNS hiccup, a connection reset, or a slow handshake — routine on throttled or censored networks — was never retried.
  2. The GitHub rate-limit window could be exhausted by browsing. Unauthenticated GitHub allows 60 requests/hour per IP, and every lookup spent 2–3 of them even when nothing had changed. Once drained, every lookup failed until the window reset.
  3. A failed lookup forgot everything the app already knew. Even a repository resolved successfully minutes earlier failed again from scratch.

What changed (native layer, api_resilience)

  • Transient failures are retried — up to four attempts with jittered exponential backoff; a server-sent Retry-After is honored (capped at 15 s). Deterministic answers (404, refusals, broken bodies) fail exactly once, as they should.
  • GitHub quota is conserved — every answer is cached with its ETag; repeat lookups revalidate with If-None-Match and a 304 costs no rate-limit budget. Steady-state browsing of an unchanged catalog spends almost no quota.
  • Stale-while-error — if every fresh attempt fails, the last known answer (up to 7 days old, refreshed by every successful revalidation) is served instead of an error: a slightly old release list still names real, downloadable files, and a working download beats an error toast.
  • Vendor manifests share the retry contract — a KDE mirror or Tor manifest behind one lost packet no longer fails the whole official-resolver chain.

Security posture

Unchanged. The resilience layer never constructs URLs, chooses hosts, or sees credentials; URL admission, redirect rules and the public-address-only resolver are exactly as audited. The cache stores only public API response bodies, atomically written, and can never become a new way for a lookup to fail.

Quality

  • 22 new tests over real loopback HTTP pin every serving path (fresh 200, quota-free 304 with on-the-wire If-None-Match proof, 5xx retries to success, exactly-once 404/403/redirect refusals, stale-serve through a rate-limited window, ancient-entry refusal).
  • cargo test 272 passed / 0 failed · clippy -D warnings clean · fmt clean · 12/12 CI checks green · validate:versions 8 fields agree on 1.0.3.

Full changelog: https://github.com/WasewaseX/Fress/blob/main/CHANGELOG.md