Skip to content

fix(plugins): persist plugin enable/config and restore configuration on restart#339

Closed
rmyndharis wants to merge 1 commit into
mainfrom
fix/plugin-registry-persistence
Closed

fix(plugins): persist plugin enable/config and restore configuration on restart#339
rmyndharis wants to merge 1 commit into
mainfrom
fix/plugin-registry-persistence

Conversation

@rmyndharis

Copy link
Copy Markdown
Owner

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 — setPluginEntry had 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

  • A registry entry is created when a plugin loads (ensureRegistryEntry), so subsequent enable/disable/config writes actually persist.
  • Configuration is restored on the next start — a plugin's saved config survives a restart instead of resetting to empty.
  • Boot never auto-enables a plugin. The entry's status is reconciled to INSTALLED to 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.
  • Built-in engine config stays env-driven each boot. The runtime config is {...envDefault, ...persistedOperatorOverrides}, so a changed .env value (e.g. PUPPETEER_EXECUTABLE_PATH on 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.json is 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

  • A registry entry is created on load (complete, INSTALLED, builtIn) and a status write then persists across a simulated restart.
  • An operator's config is restored on the next load; an env-derived built-in config is not frozen (a changed default wins on the second boot).
  • A re-registered plugin reports INSTALLED after restart (no auto-enable, no registry/runtime divergence).
  • registry.json is written without group/other access.
  • Full backend suite 733/733; dashboard build + lint clean.

…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.
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
@rmyndharis

Copy link
Copy Markdown
Owner Author

Shipped in v0.4.3 (integrated via the release PR #354 and tagged v0.4.3). Thanks! 🎉

@rmyndharis rmyndharis closed this Jun 19, 2026
@rmyndharis rmyndharis deleted the fix/plugin-registry-persistence branch June 19, 2026 18:33
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