an uninstalled plugin's grants stop breaking the permissions screen
Uninstalling music left its grants in role_permissions. The keys stop existing when the plugin unmounts, so the settings page — which loads every grant and submits them all back — failed with "Unknown permission 'music'" for a row nobody could see, edit or remove through the UI. Nothing could be saved again without editing the database. Two changes, because either alone leaves half the problem. Uninstall now revokes the plugin's grants, across every role rather than one. A deliberate exception to "uninstall deletes nothing": a grant is the PLATFORM's record of who may reach the plugin, not anything the plugin stored. Reinstalling means granting again, which is the honest behaviour — the alternative is access silently returning. And the write DROPS an unknown key instead of refusing the request, so every server already in this state is unblocked without touching its database. That is what the resolver already does on read, so the write now agrees with it. The cost is that a typo in a hand-made API call is ignored rather than reported — worth less than a settings page that cannot be used. The response returns what was dropped, so it is not silent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ import { deleteProcess, processStatus, startProcess, stopProcess } from '../app-
|
||||
import { addPluginToEcosystem, pluginProcessName, removePluginFromEcosystem } from './ecosystem';
|
||||
import { discoverPlugins } from './discover';
|
||||
import { fetchPlugin } from './fetch';
|
||||
import { revokeGrantsForPermissions } from 'officerdb';
|
||||
import { publishAssets, unpublishAssets } from '../app-store/assets';
|
||||
import { publishAffordances, unpublishAffordances } from '../affordances/publish';
|
||||
import { refreshPluginMounts, snapshotPlugins } from './mount';
|
||||
@@ -430,6 +431,20 @@ export async function uninstallPlugin(appName: string, onStep?: OnStep, onLog?:
|
||||
|
||||
// The one thing uninstall IS allowed to delete: published assets are copies, and the originals are
|
||||
// still in the plugin's own directory. Nothing a user made is in there.
|
||||
// Its grants go too. The keys stop existing when the plugin is unmounted, and a grant naming one is a
|
||||
// row nobody can see, edit or remove through the UI — which made the whole permissions screen
|
||||
// unsaveable, because the page submits every grant it loaded and the write refused a key it no longer
|
||||
// recognised. Reported on a real server after uninstalling music.
|
||||
//
|
||||
// This is a deliberate exception to "uninstall deletes nothing": a grant is the PLATFORM's record of
|
||||
// who may reach the plugin, not anything the plugin stored. Reinstalling means granting again, which
|
||||
// is the honest behaviour anyway — the alternative is access silently returning.
|
||||
if (plugin) {
|
||||
const keys = plugin.manifest.permissions.map((p) => p.key);
|
||||
const revoked = await revokeGrantsForPermissions(keys).catch(() => 0);
|
||||
if (revoked) await step(steps, onStep, `grants: ${revoked} removed for ${keys.join(', ')}`);
|
||||
}
|
||||
|
||||
await unpublishAssets(appName);
|
||||
// Same reasoning: a copy, with the original still in the plugin's directory. Removed so an agent stops
|
||||
// being told about a surface that is no longer there — an affordance for an uninstalled plugin is
|
||||
|
||||
Reference in New Issue
Block a user