fix(plugins): persist plugin enable/config and restore configuration on restart#339
Closed
rmyndharis wants to merge 1 commit into
Closed
fix(plugins): persist plugin enable/config and restore configuration on restart#339rmyndharis wants to merge 1 commit into
rmyndharis wants to merge 1 commit into
Conversation
…on restart Enabling, disabling, or configuring a plugin only mutated in-memory state: the storage setters update an existing registry entry, but no entry was ever created, so every write silently no-op'd and the change was lost on restart while the API still reported success. A registry entry is now created when a plugin loads, so enable/disable/config writes persist, and a plugin's saved configuration is restored on the next start. Boot never auto-enables a plugin (the entry's status is reset to INSTALLED to match the freshly-loaded runtime), so a previously enabled plugin is re-enabled by an explicit admin action rather than re-executing plugin code at startup; its config is preserved. Built-in engine config stays env-driven each boot (the live default merges over persisted operator overrides), so a changed .env value is never frozen to a first-boot snapshot. registry.json is written owner-only since plugin config can hold secrets.
Merged
rmyndharis
added a commit
that referenced
this pull request
Jun 19, 2026
* fix(webhook): deliver session lifecycle events and key webhook hardening (#335) * fix(security): pin outbound webhook and media fetches to validated IP (#338) * fix(plugins): persist plugin enable/config and restore (#339) * fix(message): persist bulk-sent messages, sanitize SSRF (#340) * fix(engine): return the real id for forwarded messages (#341) * fix(security): harden outbound requests, IPv6 SSRF (#344) * fix(security): secret-file perms, key pepper, allowedIps (#345) * fix(storage): bound tar imports, contain storage keys (#346) * fix(session): reconcile late acks, serialize reactions (#348) * fix(contract): webhook timeout, bounded shutdown, 501 (#350) * feat(session): force-kill a stuck session (#352) * merge #343 * merge #351 * chore(release): v0.4.3 — CHANGELOG, version bump (package.json/dashboard/swagger), README + docs
Owner
Author
|
Shipped in v0.4.3 (integrated via the release PR #354 and tagged |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Enabling, disabling, or configuring a plugin only changed in-memory state. The storage setters (
setPluginStatus/setPluginConfig) update an existing registry entry, but no entry was ever created —setPluginEntryhad zero callers — so every write was a silent no-op. The API still returned{success: true}, yet on restart an enabled plugin came back disabled and its saved configuration (including secrets such as an API key) was gone.Fix
ensureRegistryEntry), so subsequent enable/disable/config writes actually persist.INSTALLEDto match the freshly-loaded runtime, so a previously-enabled plugin is re-enabled by an explicit admin action (which runs the lifecycle) rather than re-executing plugin code at startup. The runtime and the registry never disagree about status.{...envDefault, ...persistedOperatorOverrides}, so a changed.envvalue (e.g.PUPPETEER_EXECUTABLE_PATHon a new image) always wins and is never frozen to a first-boot snapshot; an operator's explicit overrides still win for the keys they set.registry.jsonis written owner-only (0600), since plugin config can now hold secrets at rest.Compatibility
No API or response-shape change; non-breaking. Behavior change: after a restart, an enabled plugin must be re-enabled (its configuration is preserved) — a deliberate, security-conscious choice so startup never auto-runs plugin code.
Tests
INSTALLED,builtIn) and a status write then persists across a simulated restart.INSTALLEDafter restart (no auto-enable, no registry/runtime divergence).registry.jsonis written without group/other access.