v0.5.0: TrueNAS alert when an update is available
Raises a real alert in the TrueNAS UI bell -- not a log line nobody reads. On by default, checked once a day. install.sh --no-update-alerts turns it off. It does not nag --------------- A release whose CHANGELOG contains only a "### Docs" section changed no code and raises nothing. Anything else raises INFO; a "### Security" section raises WARNING. The CHANGELOG's own section headings are the signal, and a security fix anywhere in the range escalates the whole span -- a docs-only release sitting on top of a security fix still reports as security rather than hiding it. Why an AlertSource and not midclt ---------------------------------- TrueNAS cannot raise an alert from the CLI. midclt exposes only alert.dismiss, alert.list, alert.list_categories, alert.list_policies and alert.restore -- alert CREATION is internal to middlewared, and none of its ~60 one-shot classes is generic enough to reuse. Registering an AlertSource is the only way. It is also the least invasive thing this patch does. The providers and nested modules both APPEND CODE TO STOCK middleware files; the alert source ADDS ONE FILE and modifies none. It is the native mechanism -- the same one every built-in TrueNAS alert uses -- and TrueNAS polls it itself, so there is no cron job and no systemd timer. - Fail-safe: every error path returns None; it cannot take middlewared down. - Read-only: `git ls-remote` plus an HTTPS fetch of the CHANGELOG. It never writes to .git, so it cannot leave root-owned objects behind the way a `git fetch` from middlewared (running as root) would. - Removed by uninstall.sh (mw_patch.revert_all). - It only tells you; it never updates anything. Verified against the real repo and remote, with middlewared stubbed: on v0.4.1, only a README-only v0.4.2 available -> NO ALERT on v0.4.0, v0.4.1 fixed real bugs -> INFO on v0.3.2, v0.3.3 was the password fix -> SECURITY / WARNING 139 tests, ruff and shellcheck -S style clean.
This commit is contained in:
@@ -21,6 +21,8 @@ from release_notes import ( # noqa: E402
|
||||
extract_notes,
|
||||
normalise,
|
||||
script_versions,
|
||||
significance,
|
||||
version_tuple,
|
||||
)
|
||||
|
||||
REPO = os.path.join(os.path.dirname(__file__), "..")
|
||||
@@ -120,3 +122,81 @@ class TestCheckCatchesMistakes:
|
||||
def test_reports_a_missing_changelog_section(self):
|
||||
problems = check("v9.9.9", REPO)
|
||||
assert any("no section" in p for p in problems)
|
||||
|
||||
|
||||
class TestSignificance:
|
||||
"""Drives the TrueNAS update alert: what is worth bothering a human about.
|
||||
|
||||
The rule: a release whose CHANGELOG only has a "### Docs" section changed no
|
||||
code, and nobody should get an alert because a README was reworded.
|
||||
"""
|
||||
|
||||
TEXT = """\
|
||||
# Changelog
|
||||
|
||||
## v0.4.2 — 2026-07-13
|
||||
|
||||
### Docs
|
||||
|
||||
- reworded the README
|
||||
|
||||
## v0.4.1 — 2026-07-13
|
||||
|
||||
### Fixed
|
||||
|
||||
- a real bug
|
||||
|
||||
## v0.4.0 — 2026-07-13
|
||||
|
||||
### Added
|
||||
|
||||
- a feature
|
||||
|
||||
## v0.3.3 — 2026-07-13
|
||||
|
||||
### Security
|
||||
|
||||
- keep a password out of argv
|
||||
|
||||
## v0.3.2 — 2026-07-13
|
||||
|
||||
### Fixed
|
||||
|
||||
- something
|
||||
"""
|
||||
|
||||
def test_docs_only_release_does_not_alert(self):
|
||||
level, versions, _ = significance(self.TEXT, "0.4.1", "0.4.2")
|
||||
assert level == "docs"
|
||||
assert versions == ["0.4.2"]
|
||||
|
||||
def test_a_real_fix_alerts(self):
|
||||
level, _v, _h = significance(self.TEXT, "0.4.0", "0.4.1")
|
||||
assert level == "notable"
|
||||
|
||||
def test_security_in_range_escalates(self):
|
||||
level, _v, _h = significance(self.TEXT, "0.3.2", "0.3.3")
|
||||
assert level == "security"
|
||||
|
||||
def test_security_wins_even_when_the_newest_release_is_docs_only(self):
|
||||
# A docs-only v0.4.2 sitting on top of a security-fixing v0.3.3 must still
|
||||
# be reported as security — classify the whole span, not just the tip.
|
||||
level, versions, _ = significance(self.TEXT, "0.3.2", "0.4.2")
|
||||
assert level == "security"
|
||||
assert set(versions) == {"0.3.3", "0.4.0", "0.4.1", "0.4.2"}
|
||||
|
||||
def test_same_version_is_never_notable(self):
|
||||
level, versions, _ = significance(self.TEXT, "0.4.2", "0.4.2")
|
||||
assert level == "docs"
|
||||
assert versions == []
|
||||
|
||||
def test_range_is_exclusive_of_current_inclusive_of_latest(self):
|
||||
_l, versions, _h = significance(self.TEXT, "0.4.0", "0.4.2")
|
||||
assert "0.4.0" not in versions
|
||||
assert "0.4.2" in versions
|
||||
|
||||
def test_version_tuple_orders_correctly(self):
|
||||
assert version_tuple("v0.10.0") > version_tuple("v0.9.9")
|
||||
assert version_tuple("0.4.2") > version_tuple("0.4.1")
|
||||
# Pre-release suffixes are dropped, not ranked above the release.
|
||||
assert version_tuple("v0.5.0-rc1") == version_tuple("v0.5.0")
|
||||
|
||||
Reference in New Issue
Block a user