Skip to content

feat: tell the operator when a newer release exists - #263

Merged
GeiserX merged 1 commit into
mainfrom
feat/tell-the-operator-they-are-behind
Aug 6, 2026
Merged

feat: tell the operator when a newer release exists#263
GeiserX merged 1 commit into
mainfrom
feat/tell-the-operator-they-are-behind

Conversation

@GeiserX

@GeiserX GeiserX commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Closes CashPilot-w0ss. Your own fleet is the evidence: 33 releases behind, and no surface said so.

What was actually missing

Half the machinery already existed — version.skewed() compares this build against each worker. What was missing is a reference point outside the deployment: nothing in the application had any idea what the newest published release was.

Once a day, one unauthenticated GET to the public releases endpoint. A dismissible banner when there's something newer.

Three constraints, and they're the whole design

  • Silent when unknown. Offline, firewalled, disabled, never-run, or a dev build all produce known: false, and unknown renders nothing — no error, no spinner, and above all no reassuring "up to date" it never earned. Every failure mode inside refresh() lands on the same answer, which is what makes it safe on an air-gapped install.
  • Never auto-updates. This deploys containers and holds credentials. It tells you; you decide.
  • Answerable. CASHPILOT_UPDATE_CHECK=off makes no connection at all — not "fetch and discard", which is precisely what an operator disabling it would assume it doesn't do. Tested by asserting the HTTP client is never even constructed.

Dismissible per version: dismiss v1.20.1 and it stays gone until v1.20.2 exists, so it can't become wallpaper.

Two existing tests failed, and both were right to

The scheduler test pins the exact job set and a uniform misfire_grace_time. I'd used 3600 for a daily job. I conformed to 300 rather than carve out an exception to a convention a test enforces uniformly — a missed daily check simply happens tomorrow.

test_no_telemetry_or_phone_home_code_exists fired on the word "telemetry" in my module's docstring — in a sentence saying it sends none.

That's worth more than a reword. A check that can't tell a denial from an admission gets worked around by rephrasing, and then it protects nothing. It now strips comments and docstrings but keeps string literals, so a telemetry endpoint URL or a posthog import is still caught.

Proved by control rather than asserted — dropping this into app/:

import posthog
TELEMETRY_URL = "https://example.invalid/collect"

fails it on both needles.

What it sends

Nothing about you. No request body, no identifier, and your version is not reported upstream. GitHub learns that an IP asked what the latest release is. Documented in docs/configuration.md alongside the opt-out.

Verification

Five controls on the feature, all failing as required: reporting up-to-date when unreachable; comparing series as strings (1.9 vs 1.10 — live, this project passed its tenth minor); fetching despite the off switch; trusting a non-version tag; re-fetching after every failure.

3688 tests pass, coverage 95.54%.

@GeiserX

GeiserX commented Aug 6, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@GeiserX, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 32 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 439cb9f1-c5b7-44f4-9435-35fddd1389a5

📥 Commits

Reviewing files that changed from the base of the PR and between b4ed415 and 192dd16.

📒 Files selected for processing (9)
  • app/main.py
  • app/static/css/style.css
  • app/static/js/app.js
  • app/templates/base.html
  • app/update_check.py
  • docs/configuration.md
  • tests/test_beads_batch_68.py
  • tests/test_main_routes.py
  • tests/test_secure_defaults.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

A live fleet sat 33 releases behind and nothing anywhere said so. Half
the machinery was already here -- version.skewed() compares this build
against each worker -- but nothing knew what the newest PUBLISHED release
was, so there was no reference point outside the deployment.

Once a day, one unauthenticated GET to the public releases endpoint; a
dismissible banner when there is something newer.

THREE CONSTRAINTS, and they are what separate this from an unwelcome
feature:

* SILENT WHEN UNKNOWN. Offline, firewalled, disabled, never-run, or a dev
  build all produce known=false, and unknown renders NOTHING -- no error,
  no spinner, and above all no reassuring "up to date" it never earned.
  Every failure mode inside refresh() lands on the same answer.
* NEVER AUTO-UPDATES. This deploys containers and holds credentials.
* ANSWERABLE. CASHPILOT_UPDATE_CHECK=off makes no connection at all --
  not "fetch and discard", which is what an operator disabling it would
  reasonably assume it does NOT do.

Dismissible per version, so dismissing 1.20.1 leaves it gone until
1.20.2 exists and it cannot become wallpaper.

TWO EXISTING TESTS FAILED, and both were right to:

* The scheduler test pins the exact job set and a uniform
  misfire_grace_time. I had used 3600 for a daily job; conformed to 300
  rather than carving out an exception to a convention a test enforces
  uniformly. A missed daily check simply happens tomorrow.
* test_no_telemetry_or_phone_home_code_exists fired on the WORD
  "telemetry" in my module's docstring -- in a sentence saying it sends
  none. A check that cannot tell a denial from an admission gets worked
  around by rewording, and then it protects nothing. It now strips
  comments and docstrings but KEEPS string literals, so a telemetry
  endpoint URL or a posthog import is still caught. Proved by control,
  not asserted: dropping a module with `import posthog` and a
  TELEMETRY_URL string into app/ fails it on both needles.

Five controls on the feature itself: reporting up-to-date when
unreachable, comparing series as strings (1.9 vs 1.10 -- live, this
project has passed its tenth minor), fetching despite the off switch,
trusting a non-version tag, and re-fetching after every failure.

Closes CashPilot-w0ss
@GeiserX
GeiserX force-pushed the feat/tell-the-operator-they-are-behind branch from de0a3e8 to 192dd16 Compare August 6, 2026 13:39
@codecov

codecov Bot commented Aug 6, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.21429% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 95.49%. Comparing base (b4ed415) to head (192dd16).

Files with missing lines Patch % Lines
app/main.py 80.00% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #263      +/-   ##
==========================================
+ Coverage   95.47%   95.49%   +0.02%     
==========================================
  Files          47       48       +1     
  Lines        6294     6350      +56     
==========================================
+ Hits         6009     6064      +55     
- Misses        285      286       +1     
Files with missing lines Coverage Δ
app/update_check.py 100.00% <100.00%> (ø)
app/main.py 97.76% <80.00%> (-0.06%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@GeiserX
GeiserX merged commit 0ddd64d into main Aug 6, 2026
10 checks passed
@GeiserX
GeiserX deleted the feat/tell-the-operator-they-are-behind branch August 6, 2026 13:49
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.

1 participant