Skip to content

Add plugin entry: sql - #115

Open
yazydzhi wants to merge 1 commit into
get-bb:mainfrom
yazydzhi:submit-sql
Open

Add plugin entry: sql#115
yazydzhi wants to merge 1 commit into
get-bb:mainfrom
yazydzhi:submit-sql

Conversation

@yazydzhi

Copy link
Copy Markdown

Plugin

SQL — browse Postgres schemas and run read-only SQL from a bb panel or agent tools (sql_query, sql_list_connections). Writes are deferred until plugin 0.5.

Source

Checks

  • Plugin: bb plugin build, TypeScript tsc --noEmit
  • Marketplace: npm run build, npm run check (liveness)

Security / trust notes

  • Full-trust bb plugin; stores connection passwords in plugin-private SQLite (data.db)
  • Queries run under BEGIN READ ONLY until 0.5
  • No outbound network beyond the configured Postgres hosts

@SawyerHood

Copy link
Copy Markdown
Contributor

Automated note from a Claude Code agent, posted on behalf of the marketplace maintainer.

Thanks for the submission — we really want to get this in. For the first run of the marketplace we are aiming for a small set of very polished plugins, and we will open it up more broadly soon. Here is what we found reviewing the source at the tag your entry resolves to and installing it from that entry into a dev build of BB 0.40:

Blocker 1: the plugin fails to install

Installing git:https://github.com/yazydzhi/bb-plugin-sql.git@^0.2.0 (resolves to v0.2.2) into a dev build of BB 0.40 fails at the bundling step:

install failed: server bundle build for "sql" failed:
node_modules/pg/lib/stream.js:41:41: ERROR: Could not resolve "pg-cloudflare"

BB's managed git install runs npm install --ignore-scripts --omit=dev --omit=optional, and pg-cloudflare is an optional dependency of pg, so it is not on disk when esbuild bundles dist/server.js. Nobody installing from the marketplace can get past this.

Fix: mark pg-cloudflare external in your build, or move to a pg entrypoint that does not reach lib/stream.js's optional require.

Blocker 2: sql_query is not actually read-only

Credit first — reaching for a real BEGIN READ ONLY transaction (driver-postgres.ts:462-465) instead of a regex denylist is the right primitive, and it defeats the whole usual bypass playbook: CTE DELETE ... RETURNING, SELECT ... INTO, DO $$ ... $$, comment splitting. Those all correctly fail. Most submissions in this category get that part wrong.

The gap is the transport. client.query(sql) at driver-postgres.ts:464 is called with no values array, so node-postgres takes the simple query protocol path and Postgres executes every ;-separated statement in the string. So an agent can send:

COMMIT; DROP TABLE public.users;

Statement 1 ends your read-only transaction; statement 2 runs in a fresh implicit transaction whose access mode reverts to default_transaction_read_only (off on a stock server). Your SET LOCAL statement_timeout is discarded with it. And the failure is silent-by-accident: for a multi-statement simple query pg returns an array, so result.fields is undefined and driver-postgres.ts:467 throws a TypeError that gets caught at :479 — the agent sees "Cannot read properties of undefined (reading 'map')" after the DROP has already committed.

This matters more than usual because sql_query takes free-form SQL straight from the model with no confirmation gate (the SDK has no confirmation field for agent tools), and ensurePool (server.ts:591-606) auto-opens a connection, so the user need never have clicked Connect.

Fix: force the extended protocol with client.query({ text: sql, values: [] }), and ideally also set the guard at connection scope via options: '-c default_transaction_read_only=on' in the pool config. Please verify against a live server with COMMIT; CREATE TABLE bypass_check(x int);.

Blocker 3: the tool tells the model something untrue

server.ts:966-968 says, verbatim: "it is SELECT-only, writes are rejected by the database." Per the SDK, instructions is appended to thread instructions for every session the tool is in scope for — so this actively discourages scrutiny at the moment a human might be looking. Your README is more careful ("statements that succeed under BEGIN READ ONLY"), but the agent never sees the README. Please fix the wording even after the transport fix lands.

Also

  • Database is not a valid host icon name. It is in neither CORE_ICON_MAP nor EXTENDED_ICON_NAMES, so it renders as a blank placeholder. Affects package.json bb.branding.icon, app.tsx:22, app.tsx:32, and the marketplace entry. There is no database glyph in the set; Layers, Columns2, Rows2 or Toolbox are the closest. (Terminal at app.tsx:39 is fine.)
  • Connection passwords are stored in plaintext in the plugin's SQLite (server.ts:423, written at :619-633). You disclose this yourself at driver-postgres.ts:2-3 and have it on the 0.3 roadmap, and the mitigations are real — passwords never reach the frontend (toPublic, server.ts:387-398), never reach the agent, never get logged. Worth moving to bb.settings.define({ secret: true }) when you can.
  • Unbounded memory. driver-postgres.ts:464-469 materialises every row before slicing to limit. SELECT * FROM <huge table> can OOM the BB server; the 30s statement_timeout does not bound memory.
  • Results reach agent context undelimited. formatQueryAsText emits a pipe table with no escaping or untrusted-data framing. The 40-char cell clip helps, but column count and total bytes are unbounded.
  • Strongly recommended: document that connections should use a Postgres role without write or superuser rights. That is the only guarantee that survives COPY ... TO PROGRAM, pg_read_file() and dblink_exec(), none of which a client-side fix can reach.

What we liked

No external network, no child_process, single-registry lockfile with no typosquats, TLS not weakened, parameterized SQL against your own tables, and a clean frontend. Once the three blockers land this is a solid plugin.

@SawyerHood SawyerHood left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review (Claude Code agent on behalf of the maintainer): requesting changes per the feedback comment above. Ping here when a new version is published and we will re-check.

@SawyerHood SawyerHood added the blocked Waiting on plugin author changes before it can be listed label Aug 28, 2026
Co-authored-by: Cursor <cursoragent@cursor.com>
@yazydzhi

Copy link
Copy Markdown
Author

Rebased submit-sql onto current main (62ca7d2).

The previous CI failure was not caused by the sql entry — the branch was based on an older main that still listed taskboard and usage-tracker, whose npm packages were unpublished on 2026-08-26. Those entries are already removed upstream.

After rebase the PR diff is only entries/sql.json. Local validation passes:

npm ci && npm run check
# built dist/marketplace.json with 88 entries

The latest workflow run shows action_required (fork PR) — happy to re-run once approved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

blocked Waiting on plugin author changes before it can be listed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants