feat(#3): workbench data as standard QQQ tables secured by record locks (1.0.0-RC.2) #5

Merged
KofTwentyTwo merged 4 commits from feature/3-standard-qqq-tables into develop 2026-10-12 17:27:41 +00:00
KofTwentyTwo commented 2026-10-12 11:17:36 +00:00 (Migrated from github.com)

Closes #3. Owner requirement (James, 2026-10-12): the workbench's notebooks, shares/library and audit must be standard QQQ tables in the app; the notebook UI can stay custom.

What changes

  • Six standard tables in the sqlWorkbench app (notebook, cell, share, pinned result, version, execution audit): nav children (no processes in the nav), record views with child lists, edit, export, audits, developer mode. Nothing is hidden any more.
  • Record security locks (core-enforced, so table UI, /qqq/v1 table API, export, PVS lookups, processes and the workbench endpoints alike):
    • notebook = owner (sqlWorkbenchUser on ownerUserId) OR a share audience (read-only sqlWorkbenchAudience on share.audienceKey through share->notebook);
    • cells / versions / pinned results lock through their notebook (one and two joins);
    • share rows: notebook owner or the named audience; executions: their userId;
    • admins (sqlWorkbenchAdmin.hasAccess) get sqlWorkbenchAllAccess.
    • SqlWorkbenchSecurity.applyToSession(qInstance, session, groups) puts the keys in a session (none without workbench access).
  • New sqlWorkbenchNotebookShare (USER / GROUP / ALL = library). Publishing writes an ALL share; visibility follows the shares. Record actions: Share Notebook, Duplicate Notebook, Restore Version.
  • Per-table permissions (READ_INSERT_EDIT_DELETE), listed per role: getUserPermissionNames(), getSharePermissionNames(), getAdminPermissionNames().
  • Customizers keep the notebook invariants identically for the notebook UI and the tables: owner from the session, cell validation/order, one version per change, share keys, append-only versions and audit (admins included), pinned results only from pinning, cascades.
  • NotebookService and history run as the caller through the same actions (no system-user bypass); its explicit owner/share checks stay as defense in depth. The review fixes (single-use executionUuid / 409, executable-comment classifier, CSV injection guard, ...) are untouched.
  • DDL: share table + idempotent backfill of library shares (docs/ddl/postgres.sql). README (permissions, administering via tables, adopting/upgrading) and DESIGN (ER diagram, security model) updated.

Depends on QQQ

QRun-IO/qqq#1074 (#1073): partial updates of child rows were always denied by joined write locks (e.g. editing only a cell's content via the v1 API). This PR builds against QQQ 4.1.0-RC.3 for now; it moves to 4.1.0-RC.4 once that candidate is published, and stays draft until then (the matrix test exercises those partial updates).

Tests

  • TableSecurityMatrixTest: owner / other user / user-share / group-share / library / other sharer / admin / outsider x all six tables x v1 query, count, get, export, insert, update, delete, core actions, PVS lookups, record actions, notebook endpoints; append-only enforcement even for admins with ad hoc permissions; mixed batches; re-targeting; planting ownership; invariants through the tables.
  • PostgreSQL (Testcontainers): lock queries with DISTINCT de-dup over TEXT columns.
  • Locally with the QQQ fix: 108 unit + 7 integration tests green, 93% instruction coverage. An independent security review found no high-severity issue; its medium/low findings are fixed in the second commit.

Coordination: the audit agent's docs PR #2 is already in develop; this PR edits the same README sections (Adopting in another app) to match RC.2.

🤖 Generated with Claude Code

Closes #3. Owner requirement (James, 2026-10-12): the workbench's notebooks, shares/library and audit must be standard QQQ tables in the app; the notebook UI can stay custom. ## What changes - **Six standard tables** in the `sqlWorkbench` app (notebook, cell, share, pinned result, version, execution audit): nav children (no processes in the nav), record views with child lists, edit, export, audits, developer mode. Nothing is hidden any more. - **Record security locks** (core-enforced, so table UI, `/qqq/v1` table API, export, PVS lookups, processes and the workbench endpoints alike): - notebook = owner (`sqlWorkbenchUser` on `ownerUserId`) OR a share audience (read-only `sqlWorkbenchAudience` on `share.audienceKey` through share->notebook); - cells / versions / pinned results lock through their notebook (one and two joins); - share rows: notebook owner or the named audience; executions: their `userId`; - admins (`sqlWorkbenchAdmin.hasAccess`) get `sqlWorkbenchAllAccess`. - `SqlWorkbenchSecurity.applyToSession(qInstance, session, groups)` puts the keys in a session (none without workbench access). - **New `sqlWorkbenchNotebookShare`** (USER / GROUP / ALL = library). Publishing writes an ALL share; `visibility` follows the shares. Record actions: Share Notebook, Duplicate Notebook, Restore Version. - **Per-table permissions** (READ_INSERT_EDIT_DELETE), listed per role: `getUserPermissionNames()`, `getSharePermissionNames()`, `getAdminPermissionNames()`. - **Customizers** keep the notebook invariants identically for the notebook UI and the tables: owner from the session, cell validation/order, one version per change, share keys, append-only versions and audit (admins included), pinned results only from pinning, cascades. - `NotebookService` and history run **as the caller** through the same actions (no system-user bypass); its explicit owner/share checks stay as defense in depth. The review fixes (single-use executionUuid / 409, executable-comment classifier, CSV injection guard, ...) are untouched. - DDL: share table + idempotent backfill of library shares (`docs/ddl/postgres.sql`). README (permissions, administering via tables, adopting/upgrading) and DESIGN (ER diagram, security model) updated. ## Depends on QQQ QRun-IO/qqq#1074 (#1073): partial updates of child rows were always denied by joined write locks (e.g. editing only a cell's content via the v1 API). This PR builds against QQQ 4.1.0-RC.3 for now; it moves to 4.1.0-RC.4 once that candidate is published, and stays draft until then (the matrix test exercises those partial updates). ## Tests - `TableSecurityMatrixTest`: owner / other user / user-share / group-share / library / other sharer / admin / outsider x all six tables x v1 query, count, get, export, insert, update, delete, core actions, PVS lookups, record actions, notebook endpoints; append-only enforcement even for admins with ad hoc permissions; mixed batches; re-targeting; planting ownership; invariants through the tables. - PostgreSQL (Testcontainers): lock queries with DISTINCT de-dup over TEXT columns. - Locally with the QQQ fix: 108 unit + 7 integration tests green, 93% instruction coverage. An independent security review found no high-severity issue; its medium/low findings are fixed in the second commit. Coordination: the audit agent's docs PR #2 is already in develop; this PR edits the same README sections (Adopting in another app) to match RC.2. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.