Skip to content

Dashboard: "new release available" badge linking to the GitHub release (#224)#225

Merged
VijitSingh97 merged 2 commits into
mainfrom
feat/224-update-badge
Jun 12, 2026
Merged

Dashboard: "new release available" badge linking to the GitHub release (#224)#225
VijitSingh97 merged 2 commits into
mainfrom
feat/224-update-badge

Conversation

@VijitSingh97

Copy link
Copy Markdown
Collaborator

Closes #224. A small, notify-only callout: a header badge that links to a newer GitHub release. Exactly what was asked — an extra badge on top, "New release vX.Y.Z available", clickable, no self-updating.

What it does

When dashboard.check_for_updates is enabled, the dashboard periodically asks GitHub for the latest release and — if it's newer than the running version (#58's PITHEAD_VERSION) — shows a badge next to the version badge:

New release v1.4.0 available ↗ → links to …/releases/tag/v1.4.0 (new tab)

It never updates anything; you upgrade with ./pithead upgrade on your own terms (the one-click upgrade is the separate #59).

Privacy (the important bit)

A dashboard→GitHub check is a new outbound egress, so per the #160 policy:

  • Off by default (dashboard.check_for_updates: false) — the appliance never contacts GitHub unbidden.
  • When on, the check is routed over the bridge Tor SOCKS (reuses XVB_TOR_PROXY, same pattern as the XvB fetch Dashboard: route XvB stats through Tor + gate behind XVB_ENABLED (IP↔wallet leak) #163), so enabling it can't reveal the host IP to GitHub.
  • Cached (hourly), and fails silently offline / Tor-only (no error, no badge).
  • Listed in docs/privacy.md's egress table + documented in docs/configuration.md.

Implementation

  • service/update_checker.pyparse_semver + compute_update (pure), GitHubReleaseClient (Tor fetch, fail-silent), UpdateChecker (hourly throttle; keeps the last result through a transient blip so the badge doesn't flicker).
  • data_service runs it in the existing poll loop (gated on the flag, throttled, asyncio.to_thread) → latest_data["update"]; build_state surfaces state.update; components.mjs renders the UpdateBadge in the Header.
  • Config: dashboard.check_for_updates (default false) → DASHBOARD_CHECK_UPDATES via pithead + compose; describe_change names GitHub/Tor.

Tests + validation

  • 17 dashboard tests (SemVer parse, compute_update ordering, client fail-silent paths, throttle, build_state surfacing) — update_checker.py 100% covered; 5 shell tests (default-off render, opt-in propagation, describe_change).
  • Verified end-to-end in a real browser: the badge reads "New release v1.4.0 available ↗", links to the release, opens in a new tab, accent styling.
  • Full suite green; dashboard coverage 94%; lint clean.

Independent of #223 (the #44 pull-install) — they touch adjacent code but separate concerns; this branch is off main and stands alone.

🤖 Generated with Claude Code

#224)

A notify-only callout: when dashboard.check_for_updates is enabled, the dashboard
periodically asks GitHub for the latest release and, if it's newer than the running
version, shows a header badge next to the version badge — "New release vX.Y.Z
available ↗" — linking to that release. It never updates anything (the one-click
upgrade is the separate #59); you upgrade with ./pithead upgrade on your own terms.

Privacy: OFF by default, so the appliance never contacts GitHub unbidden. When on,
the check is routed over the bridge Tor SOCKS (reusing XVB_TOR_PROXY, like the XvB
fetch #163) so it can't reveal the host IP to GitHub; it's cached hourly and fails
silently offline. Added to docs/privacy.md's egress table per the #160 policy.

- service/update_checker.py: parse_semver + compute_update (pure), GitHubReleaseClient
  (Tor fetch, fail-silent), UpdateChecker (hourly throttle, keeps last result on a blip).
- data_service runs the check in its poll loop (gated, throttled, asyncio.to_thread) ->
  latest_data["update"]; build_state surfaces state.update; components.mjs renders an
  UpdateBadge (accent, opens the release in a new tab) in the Header.
- config: dashboard.check_for_updates (default false) -> DASHBOARD_CHECK_UPDATES via
  pithead + compose; describe_change names GitHub/Tor; config.advanced.example.json.

Tests: 17 dashboard tests (semver/compute_update/client fail-silent/throttle + the
build_state surfacing) — update_checker.py 100% covered; 5 shell tests (render default-off
+ opt-in propagation + describe_change). Verified the badge end to end in a real browser:
"New release v1.4.0 available ↗" links to the release, new tab, accent styling. Full suite
green; coverage 94%; lint clean.

Closes #224.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s audit (#224)

Per maintainer steer: since the new-release check is routed over Tor (socks5h, so
neither the host IP nor a DNS lookup reaches GitHub — GitHub only ever sees a Tor
exit), there's no privacy leak, so make it the default. dashboard.check_for_updates
flips to default true; set it false to opt out. config.py / pithead / compose /
config example / docs / tests updated accordingly.

Stack-wide egress audit (the rest of the stack), reconciled into docs/privacy.md +
a comment on the #160 epic:
- No new RUNTIME clearnet leaks. The only on-by-default clearnet runtime egress
  remains #165 (p2pool outbound peers) and #166 (XvB donation mining), both already
  tracked for v1.1 (the Tor flip needs orphan/reject benchmarking — not easy).
- monerod/Tari DNS stay closed/sinkholed (#161/#162); monerod RPC-to-remote is
  clearnet only in the opt-in monero.mode:remote path; pithead makes no egress.
- Documented the one gap the audit found: the GHCR image pull #44 introduced
  (release installs pull pithead-* from ghcr.io) — an inherent build/setup egress,
  now in privacy.md's build/setup table alongside the github/getmonero downloads.

Tests: the shell render test now asserts default-on + the opt-out (false) path; the
describe_change + update_checker (Tor-routing, fail-silent) tests are unchanged.
Full suite green; coverage 94%; lint + compose clean.

Closes #224.
@VijitSingh97

Copy link
Copy Markdown
Collaborator Author

Update (follow-up commit): flipped to default-on + a stack-wide egress audit.

CI 12/12 green.

@VijitSingh97
VijitSingh97 merged commit cd635fd into main Jun 12, 2026
12 checks passed
@VijitSingh97
VijitSingh97 deleted the feat/224-update-badge branch June 12, 2026 05:25
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.

Dashboard: "new release available" badge linking to the GitHub release (notify-only, no upgrade)

1 participant