Plugins: one tracked manifest for builtin, official and third-party plugins, and nothing installed outside a manifest #1263
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#1263
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The idea
One manifest, tracked in core, describes every plugin Postulo knows about: the builtin ones, the official ones, and, by the administrator's choice, third-party ones. Installing and upgrading are one click from that list. A plugin is never added except through a manifest: there is no install from a bare URL, a file or a pip name.
What exists today (read from
main, 2026-11-13)catalogue/official/(plugins.toml, a signedindex.json) lists six plugins: helloworld, templates, apprise, dav, imap, paperless. Each release has a wheel URL, SHA-256, compatible Postulo versions, provides and requires.plugins/catalogue.pyverifies, in order and fatally: the index signature (Ed25519), the plugin and version, the Postulo compatibility, the wheel's SHA-256. An index is fetched only when an administrator opens the page and asks.name|url|public-keyinPOSTULO_PLUGIN_CATALOGUES; without the key there is no catalogue.plugins/installing.pysnapshots and rolls back, so a failed upgrade costs nothing.Wanted
builtinwith the version they ship with and no wheel; mcp, chromium, firefox and thunderbird get entries or a stated reason they have none (the extensions are not Python wheels). The page shows one list, three origins (builtin, official, third-party), with the origin on each row.plugins/views.pyandinstalling.pyfor any route that installs from a file, a URL or a pip name; if one exists, remove it or put it behind a documented, off-by-default setting for development, with the reason in the decision.2026-12-31and is signed with a key held only in Vaultwarden. The release recipe (the 0.5.0 notes) gets a step that re-signs and republishes the index, a check in CI that the index is not within 30 days of expiry, and a page message that says an expired index cannot be used and why, instead of an empty list.Left to #1187
Detecting that an update exists and the one-click upgrade (with the setting the maintainer decided, enable/disable, off by default) stay in #1187; this issue supplies the manifest it reads. Linked both ways.
Tests
The list shows the three origins; a builtin row has no install or remove button but shows its version; a third-party catalogue is added with a key, an unsigned or wrong-key index is refused with a message; the pinned catalogue cannot be removed; no route installs from outside a manifest; an index close to expiry fails CI; an expired index gives the explicit message.
Strings go through Weblate only. Related: #1187, #1252, #1253 to #1262, #729 (the official catalogue), #1170.
Related: #1264 (an administrator can hold a plugin or pin it to a version).