Repository navigation
feat(connections): edit a SQLite database on an SSH server in place - #2835
Merged
Merged
Conversation
…run on the server
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
Signed-off-by: Ngô Quốc Đạt <datlechin@gmail.com>
This branch was successfully deployed
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.
Fixes #2831.
What this adds
A SQLite Remote Database File connection gains an Open menu beside the path: On the Server (new) or As a Read-Only Copy (today's behaviour). On the Server runs your statements on the SSH host against the live database, so the sidebar, grid, SQL editor and structure edits all read and write the file the server's own programs are using.
New connections default to On the Server; saved connections keep the read-only copy.
Why it works this way
SQLite's file locking is only reliable for a process on the same machine as the file (sqlite.org/useovernet.html), so a client that wrote across the network would corrupt the database. The only safe way to edit a live remote SQLite database is to run the SQL on the server. Measured across the runtime matrix, no mainstream desktop client does this today: TablePlus, DataGrip and DBeaver either open a read-only copy or decline.
How it works
libsqlite3throughctypesand speaks a length-prefixed binary protocol on stdio.RemoteSQLiteTransportManager/RemoteSQLiteTunnel). Each accepted client presents a random per-connection token, then gets a fresh exec channel; the SQLite plugin dials the loopback port as if it were a database server.SQLiteExecutionBackend: the existing localsqlite3path and a new agent backend that talks to the loopback socket. Every metadata, structure and write path is unchanged; it just runs over whichever backend the connection selected.Nothing installed on the server, no port opened, no new credential. The server needs
python33.6+, which every mainstream cloud image already ships; when it is missing, the connection fails inline and names the read-only copy as the fallback.Runtime facts, measured
Verified in Docker across the target matrix (scripts committed under the branch's investigation, results in the PR discussion):
libsqlite3, and typed values, declared types, 64-bit integers, blobs, the busy timeout, query cancel (interrupt + reusable connection) and row counts all match the local driver.python3with its standard library is present by default on Ubuntu/Debian/RHEL cloud images; thesqlite3CLI is not, which is why the agent useslibsqlite3viactypesrather than the CLI.Security
sqlite3authorizer denyingfts3_tokenizerandload_extension.fts3_tokenizer('name', <blob>)registers an arbitrary pointer as a tokenizer and dereferences it; measured, that segfaults the process on every server build and on the app's own libsqlite3. The same authorizer is now installed on the local SQLite backend too, closing that crash primitive for ordinary local files.READWRITEwithoutCREATE(a mistyped path fails instead of making an empty database) and without URI mode, and never enables extension loading. It binds parameters, runs one statement per request, and self-terminates on an idle deadline so a crashed or sleeping Mac never leaves a lock on the server.execute_querynow refuses statements that read or write files or run server-side code (ATTACH, LOAD, VACUUM INTO), matching what the MCP server already enforced throughExternalStatementGate. Without this, the AI path was a read-only-external and filesystem/code bypass, larger still on a connection that executes on an SSH server.Tests
python3is absent): typed values and declared types match the local driver,INSERTreports its row count,fts3_tokenizerandload_extensionare denied, and a missing file fails without being created. This exercises the exact Python program that ships.remoteFileAccessdecodes as the read-only copy, each mode resolves to the right transport, a file-backed connection never resolves to a plain SSH tunnel, and the Read-Only Safe Mode floor applies to the copy but not the live session.UI automation for the Open pop-up was left out: the connection form's transport pane is not driven deterministically by the existing UI suites, and the pop-up's behaviour is covered by the model and transport tests instead.
Not in this PR
DuckDB/libSQL/Beancount live mode (no standard-library runtime to open them on the server), iOS (its own SQLite and SSH stacks), and a remote file browser.
Verification
build(app + bundled SQLite plugin): PASStest(RemoteSQLite suites + ConnectionTunnelKind, SafeModeFloor, ConnectionFormTransport, SSHConfiguration neighbours): PASSlint: cleandocs: PASS@TaskLocalmacro issue; the SQLite plugin compiles clean.A screenshot of the new Open pop-up in the connection form is pending and will be added to
docs/connections/remote-database-files.mdx.