mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-06-12 13:23:31 +00:00
fix(plugins): stop core updates from resurrecting uninstalled built-in plugins (#368)
* fix(plugins): stop core updates from resurrecting uninstalled built-in plugins Built-in plugins (e.g. web-ui-info, starlark-apps) are committed into the repo under plugin-repos/. When a user uninstalls one, a subsequent core `git pull` update restores the committed files, so the plugin reappears on every update. The update endpoint stashes the deletion and never pops it, and `git pull` faithfully restores any committed file whose deletion was never committed — so excluding plugin-repos/ from the stash can't fix this (it would only make `git pull --rebase` fail on a dirty tree). Add a persistent uninstall registry (config/uninstalled_plugins.json, gitignored) that survives restarts, unlike the existing in-memory tombstone: - Uninstall records the plugin id; install clears it. - purge_uninstalled_plugins() re-removes any recorded plugin whose directory reappears on disk; called after a successful git-pull update and at web startup (covers manual `git pull` on the Pi too). - The state reconciler also refuses to auto-repair a persistently uninstalled plugin. Wires up mark_recently_uninstalled in the uninstall flow (previously only referenced by tests) via the new persistent record. Adds regression tests covering record/forget/purge lifecycle, persistence across manager instances, and corrupt-registry tolerance. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(plugins): validate uninstall-registry ids and lock registry writes Address review feedback on the persistent uninstall registry: - Critical: validate plugin ids on read/record and add a containment guard in purge_uninstalled_plugins. A corrupt or hand-edited registry entry of "" resolves to the plugins root, so purge could have deleted every plugin; traversal ids ("..", "../x") could target paths outside the root. Invalid ids are now dropped on read, refused on record, and never removed unless the path is a direct child of the plugins directory. - Major: guard record/forget read-modify-write with a lock so concurrent install/uninstall requests can't lose updates. - Minor: narrow the startup and post-update purge exception handlers from bare Exception to (OSError, RuntimeError). Adds regression tests for empty-id, traversal-id, and invalid-record cases. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -79,6 +79,21 @@ plugin_manager = PluginManager(
|
||||
cache_manager=None # Not needed for web interface
|
||||
)
|
||||
plugin_store_manager = PluginStoreManager(plugins_dir=str(plugins_dir))
|
||||
# A core `git pull` update (or any checkout) restores built-in plugins
|
||||
# committed under plugin-repos/, even ones the user uninstalled. Re-remove any
|
||||
# the user previously uninstalled at startup so a manual update on the Pi
|
||||
# doesn't resurrect them.
|
||||
try:
|
||||
_purged = plugin_store_manager.purge_uninstalled_plugins()
|
||||
if _purged:
|
||||
logging.getLogger(__name__).info(
|
||||
"Re-removed %d uninstalled plugin(s) restored since last run: %s",
|
||||
len(_purged), ", ".join(_purged),
|
||||
)
|
||||
except (OSError, RuntimeError) as _purge_err:
|
||||
logging.getLogger(__name__).warning(
|
||||
"Startup plugin purge failed: %s", _purge_err
|
||||
)
|
||||
saved_repositories_manager = SavedRepositoriesManager()
|
||||
|
||||
# Initialize schema manager
|
||||
|
||||
Reference in New Issue
Block a user