Remove a skill's grants when it is uninstalled, so a new skill under that name starts on no Bot - #558
Closed
zopeVaibhav wants to merge 1 commit into
Closed
zopeVaibhav wants to merge 1 commit into
zopeVaibhav wants to merge 1 commit into
Conversation
zopeVaibhav
requested review from
MikeRyanDev,
davidmckayv,
guidovizoso,
mxmzb and
tylerslaton
as code owners
September 15, 2026 13:15
zopeVaibhav
force-pushed
the
fix/skill-uninstall-grants
branch
5 times, most recently
from
September 15, 2026 16:57
38e8a0e to
1700f3c
Compare
…that name starts on no Bot
zopeVaibhav
force-pushed
the
fix/skill-uninstall-grants
branch
from
September 15, 2026 17:03
1700f3c to
0e38336
Compare
davidmckayv
added a commit
that referenced
this pull request
Sep 15, 2026
Uninstalling a skill deleted the skill row but left its tool grants, which are keyed by slug. A new skill created under the same slug then inherited them and was offered on the old Bots with no grant action — a quiet privilege carry-over. uninstallSkill now removes the skill's grants and the skill itself in one transaction, and a migration drops any grants already orphaned this way. Originally #558 by zopeVaibhav, folded in here with the migration renumbered from 0037 to 0040 (0037 through 0039 are the composio migrations already on main), because the fork branch could not take the change directly.
Contributor
|
Landed in #563 — your fix with the migration renumbered 0037→0040 (0037-0039 are the composio migrations already on main). GitHub wouldn't let me push the renumber to this branch, so I folded it in there, credited to you. Thanks! |
Contributor
|
Superseded by #563 — merged. Thanks @zopeVaibhav. |
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.
What this changes
Fixes #557.
Uninstalling a skill deleted its row in
skillsand left its rows inplugin_grants, whoserefis plain text with no foreign key.listForAgentresolves skill grants by slug, and any signed-in person may write a slug nobody holds, so the next skill written under that name was offered on every Bot the old one had been granted to. That included Bots its author does not own and Bots the deployment shares with everybody. The grant route refuses exactly that when asked directly (server/src/plugins/routes.ts:780), and the leftover row got there without asking.uninstallSkillnow deletes the skill's grants and the skill in one transaction. Migration0040_drop_orphaned_skill_grantsdeletes theskillgrants earlier uninstalls already left behind, because a deployment that has uninstalled a granted skill is exposed until they are gone. A grant naming no skill was never listed or offered anywhere, so removing those rows changes nothing a person can see.The fix sits at removal rather than at read time on purpose. Filtering
listForAgentby ownership would also hide skills an administrator put on a Bot the skill's author does not own, which the grant route allows (server/src/plugins/routes.ts:765). Both delete statements namekind = 'skill', somcpandbotgrants in the same table are untouched. Theskill_uninstalledaudit row is unchanged. The tenant package already refuses to grant a skill it did not write (server/src/tenant-package.ts:914) and needed nothing.Where it runs
POST /api/plugins/grantschecks that the skill exists and then inserts without a lock, so a grant committed in the moment after an uninstall commits could still leave a row. Only the skill's owner or an administrator may grant it, so nobody else can arrange that. Closing it means locking the skill row in the generic grant path, which I kept out of this change.Boundary and audit
configuration.changedrow it did before. The grants it now removes are not recorded one by one, in the same way that deleting a Bot cascades its grants away.Changelog
UnreleasedinCHANGELOG.md.Proof
server/tests/skill-uninstall-grants.integration.test.tsdrivescreatePluginRoutesas non-administrators against a migrated test database. It covers a person's skill reused by another person, a deployment skill on a shared Bot reused by a person, and a check that uninstalling removes that skill's grants and leaves another skill's grant on the same Bot.On
mainata96d88cthe file fails 3 of 3, and the failures are the bug itself. Alice's Bot is offered"instructions": "Bob's words.", the shared Bot is offered"instructions": "Alice's words.", and all three grants are still inplugin_grants. In the same run, each direct grant attempt is refused with 403, so the ownership rule was working and was bypassed.On this branch:
skill-ownership.integration.test.tsandskill-tools.integration.test.ts, the three files pass 29 of 29.DELETE 1: only theskillgrant naming a missing skill went, and the live skill grant and themcpandbotrows with the samerefstayed.migrations applied successfully, 38 rows in__drizzle_migrations).bun run typecheckexits 0,bun run lintchecks 747 files with no fixes, andbun run format:checkchecks 732 files with no fixes.bun testwithTEST_DATABASE_URLset: 3750 pass on this branch against 3747 onmain, exactly the three new tests. Both runs show the same 8 fails and 6 errors, and every one is aCannot find modulein a directory that sits outside the bun workspaces (agent-bot,agent-langgraph,agent-mastra,desktop) and had no install of its own in the fresh worktrees. None of them involve this change.