Skip to content

fix(plugin-manager): surface plugin update validation failures instead of reporting up-to-date#2666

Open
elibosley wants to merge 3 commits into
masterfrom
fix/plugin-update-validation-visible
Open

fix(plugin-manager): surface plugin update validation failures instead of reporting up-to-date#2666
elibosley wants to merge 3 commits into
masterfrom
fix/plugin-update-validation-visible

Conversation

@elibosley

@elibosley elibosley commented Jun 18, 2026

Copy link
Copy Markdown
Member

Summary

When a plugin update is available, the pre_plugin_checks hook validates it by re-downloading the update's files and verifying their SHA256/MD5. On any validation failure it silently reverted the cached .plg to the installed version, and plugin check still exited successfully — so the Plugins page showed "up-to-date" and the available update vanished with no error.

The failure is most visible when the root filesystem is full: the (often large) .txz can't be downloaded for the hash check, validation fails, and the update silently disappears. This was diagnosed on a live server where a stale 1.2 GB /tmp/unRAIDServer.zip filled the rootfs — every plugin update check reported "up-to-date" with no indication that validation was failing for lack of space.

Root cause

In check flow:

  1. plugin check downloads the new .plg, then runs pre_plugin_checks.
  2. The hook validates the update — scripts/plugin validate re-downloads the txz and checks its hash.
  3. On failure it returns false (download/IO/network error and bad-hash are indistinguishable), and the hook reverts the cached .plg to the installed one.
  4. plugin check prints the reverted (old) version and exits done(0). The version comparison in ShowPlugins.php sees them equal → renders up-to-date.

The failure reason was swallowed twice (PluginHelpers discards it; the hook reverts silently).

Change

  • pre-hooks/pre_plugin_checks — capture the validation reason (via scripts/plugin validate, which prints plugin: <reason> and exits non-zero) and, on failure, write a /tmp/plugins/<name>.invalid marker recording the available version + reason. Clears the marker when validation passes or no newer version exists. The existing revert behavior is unchanged (we still don't offer an unvalidated update).
  • post-hooks/post_plugin_checks — clear the marker after a successful install/update.
  • include/ShowPlugins.php — when the marker is present and a newer version exists, render an "Update validation failed" status (with the reason as a tooltip) and the available version, ranked with updates — instead of the silent "up-to-date".

Additive and contained: success / no-update paths are unchanged except for marker cleanup. OS (unRAIDServer) updates are excluded, matching the existing hook guard.

Testing

  • php -l clean on all three files.
  • Unit-tested the reason extraction (handles download failure: File I/O error, bad hash value, zero-length file) and the marker-driven status/version/rank rendering.

Notes

A natural follow-up (not in this PR) is to also raise a notification and/or proactively warn on low rootfs free space, since "disk full" is the most common trigger.

Summary by CodeRabbit

  • New Features

    • Plugin update validation failures now surface as warning tooltips, including the rejected version details.
  • Improvements

    • When an update fails validation, the previously working plugin version is automatically restored.
    • Validation failure warnings are deprioritized in the plugin list (ranking set to reflect the warning).
    • Any prior validation-failure indicators are cleared after successful installs/updates.

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@elibosley, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 53 minutes and 10 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

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 credits.

🚦 How do rate limits work?

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

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, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a6e4ab9f-0c9d-47a7-844e-1a2389c07c20

📥 Commits

Reviewing files that changed from the base of the PR and between c5dc579 and 665b5ff.

📒 Files selected for processing (3)
  • emhttp/plugins/dynamix.plugin.manager/include/ShowPlugins.php
  • emhttp/plugins/dynamix.plugin.manager/post-hooks/post_plugin_checks
  • emhttp/plugins/dynamix.plugin.manager/pre-hooks/pre_plugin_checks

Walkthrough

A plugin update validation failure is now persisted as a .invalid JSON marker file under /tmp/plugins/. The pre-hook validates updates via subprocess, writes the marker with candidate version and classified failure reason on failure (restoring the original plugin), and clears it on success. The plugin listing UI reads the marker to display a versioned "Update validation failed" warning ranked alongside available updates. The post-hook deletes the marker after successful installs/updates.

Changes

Plugin Update Validation Failure Marker

Layer / File(s) Summary
Pre-hook: validation subprocess, failure classification, and marker lifecycle
emhttp/plugins/dynamix.plugin.manager/pre-hooks/pre_plugin_checks
Replaces inline plugin('validate') with subprocess scripts/plugin validate invocation using exit codes; on failure parses the reason, classifies it into integrity/diskspace/download categories, writes a JSON .invalid marker with candidate version and classified summary, and restores original plugin files; on success or when no newer version exists, deletes any stale marker.
UI: display validation failure warning
emhttp/plugins/dynamix.plugin.manager/include/ShowPlugins.php
Reads the .invalid marker for non-OS plugins, parses its JSON, appends candidate version to displayed version and sets status to "Update validation failed" warning tooltip when the candidate is newer; deletes the marker otherwise; maps the validation-failed status to rank 0 so it sorts alongside available updates.
Post-hook: clear marker after successful install/update
emhttp/plugins/dynamix.plugin.manager/post-hooks/post_plugin_checks
After a successful install or update completes without error, deletes the per-plugin /tmp/plugins/<name>.invalid marker file to clear persisted validation-failure state.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A marker of .invalid rests in /tmp/'s care,
When validation stumbles, the old plugin stays there!
The UI warns loudly with rank set to zero,
Success clears the marker—our cleanup hero.
Hop hop—the updates shine true once again! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the main change: surfacing plugin update validation failures instead of hiding them as up-to-date status.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/plugin-update-validation-visible

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

@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown

🔧 PR Test Plugin Available

A test plugin has been generated for this PR that includes the modified files.

Version: 2026.06.19.1437
Build: View Workflow Run

📥 Installation Instructions:

Install via Unraid Web UI:

  1. Go to Plugins → Install Plugin
  2. Copy and paste this URL:
https://preview.dl.unraid.net/pr-plugins/pr-2666/webgui-pr-2666.plg
  1. Click Install

Alternative: Direct Download

⚠️ Important Notes:

  • Testing only: This plugin is for testing PR changes
  • Backup included: Original files are automatically backed up
  • Easy removal: Files are restored when plugin is removed
  • Conflicts: Remove this plugin before installing production updates
  • Post-merge behavior: This preview stays available after merge until preview storage expires or it is manually cleaned up

📝 Modified Files:

Click to expand file list
emhttp/plugins/dynamix.plugin.manager/include/ShowPlugins.php
emhttp/plugins/dynamix.plugin.manager/post-hooks/post_plugin_checks
emhttp/plugins/dynamix.plugin.manager/pre-hooks/pre_plugin_checks

🔄 To Remove:

Navigate to Plugins → Installed Plugins and remove webgui-pr-2666, or run:

plugin remove webgui-pr-2666

🤖 This comment is automatically generated and will be updated with each new push to this PR.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@emhttp/plugins/dynamix.plugin.manager/include/ShowPlugins.php`:
- Line 201: The validation-failure status label on line 201 uses a translated
string via _('Update validation failed'), but line 209 appears to match against
a hardcoded English phrase "Update validation failed" for ranking purposes. In
non-English locales this hardcoded string won't match the translated output,
causing incorrect ranking. Instead of matching against the translated label
text, use a locale-independent identifier or flag variable to track when the
validation-failure status is set, and use that identifier in the ranking logic
at line 209 rather than comparing against the hardcoded English string.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: cced1315-9ea5-41c1-9e84-ac7cc7cc5b71

📥 Commits

Reviewing files that changed from the base of the PR and between cc6a800 and b333432.

📒 Files selected for processing (3)
  • emhttp/plugins/dynamix.plugin.manager/include/ShowPlugins.php
  • emhttp/plugins/dynamix.plugin.manager/post-hooks/post_plugin_checks
  • emhttp/plugins/dynamix.plugin.manager/pre-hooks/pre_plugin_checks

Comment thread emhttp/plugins/dynamix.plugin.manager/include/ShowPlugins.php Outdated
…d of reporting up-to-date

When a plugin update is available, pre_plugin_checks validates it by
re-downloading the update's files and verifying their SHA256/MD5. On any
failure it reverted the cached .plg to the installed version and the check
returned success, so the Plugins page showed "up-to-date" — hiding the
available update entirely.

This is most visible when the root filesystem is full: the (often large) txz
can't be downloaded for the hash check, validation fails, and the update
silently disappears with no error shown to the user.

Record the available version and failure reason in a marker file and render an
"Update validation failed" state (with the reason as a tooltip) in the Plugins
page instead of the silent revert. The marker is cleared once validation
passes or the plugin is updated/installed.
… remediation)

Classify the validation failure in pre_plugin_checks instead of surfacing the
raw txz error: distinguish low disk space (reporting actual free space), a
download/network failure, and a genuine bad hash. Store a short summary plus a
full actionable message in the marker.

ShowPlugins.php shows the short cause as a visible second line under the
"update validation failed" status and puts the full guidance in the tooltip,
so the status answers "why did this fail and what do I do" instead of raising
questions.

Wording follows existing GUI conventions: lowercase status label like the other
plugin statuses (up-to-date, cannot check, not available) and terse messages in
the style of "Not enough free space, need at least %s MB". The hook runs without
the gettext setup, so its strings are plain (the prior code also echoed
untranslated reasons); only ShowPlugins.php uses _().
…slated text

The rank logic matched the status cell against the hardcoded English
"update validation failed", but the label is translated via _(). In non-English
locales the match failed and the row sorted to the bottom (rank 4) instead of
the top with updates (rank 0). Track the state with a locale-independent
$validation_failed flag and rank on that instead.
@elibosley elibosley force-pushed the fix/plugin-update-validation-visible branch from c5dc579 to 665b5ff Compare June 19, 2026 14:37
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