Pinning a result inserts a sql_workbench_result_snapshot row as a top-level action. With QQQ core permission enforcement on (QInstance.enforcePermissionsInCoreActions, QRun-IO/qqq#1075), that insert is checked against the session's permissions. getUserPermissionNames() granted only read/edit/delete on snapshots, so every user's pin was denied.
kof22.com hit this when it turned enforcement on (KofTwentyTwo/Website-Backend#107) and had to grant the insert by hand. This PR adds insert to the user set, so hosts don't need to.
Record locks are unchanged: a user can still only pin results to their own notebooks. Notebook versions and the execution audit need no grant, because their inserts run nested inside another action (trusted) or as the system user.
New test NotebookServiceTest.testUserPermissionsSufficeWithCoreEnforcement. With enforcement on and only the user permission set, it creates, updates, runs, pins, unpins and deletes. The test was red before the fix (QPermissionDeniedException on the pin).
CHANGELOG (RC.3 section, Fixed) and the README permissions table.
## What
Pinning a result inserts a `sql_workbench_result_snapshot` row as a top-level action. With QQQ core permission enforcement on (`QInstance.enforcePermissionsInCoreActions`, QRun-IO/qqq#1075), that insert is checked against the session's permissions. `getUserPermissionNames()` granted only `read`/`edit`/`delete` on snapshots, so **every user's pin was denied**.
kof22.com hit this when it turned enforcement on (KofTwentyTwo/Website-Backend#107) and had to grant the insert by hand. This PR adds `insert` to the user set, so hosts don't need to.
Record locks are unchanged: a user can still only pin results to their own notebooks. Notebook versions and the execution audit need no grant, because their inserts run nested inside another action (trusted) or as the system user.
## Changes
- `SqlWorkbenchQBitConfig.getUserPermissionNames()`: adds `sql_workbench_result_snapshot.insert`.
- New test `NotebookServiceTest.testUserPermissionsSufficeWithCoreEnforcement`. With enforcement on and only the user permission set, it creates, updates, runs, pins, unpins and deletes. The test was red before the fix (`QPermissionDeniedException` on the pin).
- CHANGELOG (RC.3 section, Fixed) and the README permissions table.
## Test plan
- [x] `./mvnw verify` passes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What
Pinning a result inserts a
sql_workbench_result_snapshotrow as a top-level action. With QQQ core permission enforcement on (QInstance.enforcePermissionsInCoreActions, QRun-IO/qqq#1075), that insert is checked against the session's permissions.getUserPermissionNames()granted onlyread/edit/deleteon snapshots, so every user's pin was denied.kof22.com hit this when it turned enforcement on (KofTwentyTwo/Website-Backend#107) and had to grant the insert by hand. This PR adds
insertto the user set, so hosts don't need to.Record locks are unchanged: a user can still only pin results to their own notebooks. Notebook versions and the execution audit need no grant, because their inserts run nested inside another action (trusted) or as the system user.
Changes
SqlWorkbenchQBitConfig.getUserPermissionNames(): addssql_workbench_result_snapshot.insert.NotebookServiceTest.testUserPermissionsSufficeWithCoreEnforcement. With enforcement on and only the user permission set, it creates, updates, runs, pins, unpins and deletes. The test was red before the fix (QPermissionDeniedExceptionon the pin).Test plan
./mvnw verifypasses.🤖 Generated with Claude Code