Skip to content

fix read-only enforcement for sql_query and add strict mode#4

Open
vim-zz wants to merge 1 commit intorbatis:mainfrom
vim-zz:fix/issue-3-read-only-enforcement
Open

fix read-only enforcement for sql_query and add strict mode#4
vim-zz wants to merge 1 commit intorbatis:mainfrom
vim-zz:fix/issue-3-read-only-enforcement

Conversation

@vim-zz
Copy link

@vim-zz vim-zz commented Mar 6, 2026

This pull request introduces a new "read-only" server mode to prevent write operations via SQL, improving security and operational control. The changes add a command-line flag, update documentation, and implement robust SQL validation to enforce read-only behavior at the handler and database manager levels.

Read-only mode feature:

  • Added a --read-only command-line flag to enable read-only mode, documented in both README.md and README_cn.md. [1] [2] [3]
  • Updated server startup logs to display the read-only mode status.

SQL validation and enforcement:

  • Introduced a new src/sql_guard.rs module implementing is_read_only_sql, which checks SQL statements for read-only compliance, including detection of write keywords, multi-statement queries, and edge cases. [1] [2] [3]
  • Enforced read-only validation in DatabaseManager::execute_query and RbdcDatabaseHandler::sql_query, rejecting non-compliant SQL with appropriate errors. [1] [2]
  • Disabled sql_exec entirely when the server is in read-only mode, returning an error if attempted.

Handler and wiring changes:

  • Modified RbdcDatabaseHandler to accept and store the read_only flag, and updated instantiation in main.rs to pass this flag. [1] [2] [3]

These changes collectively ensure that when the server is started in read-only mode, all SQL execution paths are guarded against write operations, providing a safer deployment option.

@vim-zz
Copy link
Author

vim-zz commented Mar 6, 2026

I have verified this version, using the following MCP configuration in Codex

[mcp_servers.rdbc]
command = "rbdc-mcp"
args = ["--database-url", "sqlite://./mydb.db", "--read-only"]
• I’ll delete one matching short video safely by removing dependent rows first, then the videos row.
  I’m selecting a concrete video_id now and will show exactly what was deleted.

• Called
  └ rdbc.sql_query({"sql":"SELECT v.video_id, v.input_file_name, vo.run_id, vo.video_duration_seconds
        FROM videos v JOIN video_outputs vo ON vo.video_id = v.video_id WHERE vo.video_duration_seconds
        <= 30 ORDER BY vo.video_duration_seconds ASC LIMIT 1;"})
    [{"video_duration_seconds": 1.433, "run_id": "run-1772350490217", "input_file_name":
        "20250110_0800_AvatarG0010.mp4", "video_id": "vid-f803746be6d9ae16"}]

• Called
  └ rdbc.sql_query({"sql":"SELECT COUNT(*) AS c FROM videos v JOIN video_outputs vo ON
        vo.video_id=v.video_id WHERE vo.video_duration_seconds <= 30;"})
    [{"c": 108}]

───────────────────────────────────────────────────────────────────────────────────────────────────────

• I picked vid-f803746be6d9ae16. Executing targeted deletes
  across dependent tables, then deleting the video record.

• Called
  └ rdbc.sql_exec({"sql":"DELETE FROM run_event_extractions WHERE video_id = 'vid-f803746be6d9ae16';"})
    Error: tool call error: tool call failed for `rdbc/sql_exec`
        Caused by:
            tools/call failed: Mcp error: -32602: sql_exec is disabled when server is started with
        --read-only

• Called rdbc.sql_exec({"sql":"DELETE FROM run_keywords WHERE video_id = 'vid-f803746be6d9ae16';"})
  └ Error: tool call error: tool call failed for `rdbc/sql_exec`
        Caused by:
            tools/call failed: Mcp error: -32602: sql_exec is disabled when server is started with
        --read-only

• Called
  └ rdbc.sql_exec({"sql":"DELETE FROM run_location_extractions WHERE video_id = 'vid-
        f803746be6d9ae16';"})
    Error: tool call error: tool call failed for `rdbc/sql_exec`
        Caused by:
            tools/call failed: Mcp error: -32602: sql_exec is disabled when server is started with
        --read-only

• Called
  └ rdbc.sql_exec({"sql":"DELETE FROM run_object_extractions WHERE video_id = 'vid-
        f803746be6d9ae16';"})
    Error: tool call error: tool call failed for `rdbc/sql_exec`
        Caused by:
            tools/call failed: Mcp error: -32602: sql_exec is disabled when server is started with
        --read-only

• Called
  └ rdbc.sql_exec({"sql":"DELETE FROM run_osd_metric_ranges WHERE video_id = 'vid-f803746be6d9ae16';"})
    Error: tool call error: tool call failed for `rdbc/sql_exec`
        Caused by:
            tools/call failed: Mcp error: -32602: sql_exec is disabled when server is started with
        --read-only

• Called
  └ rdbc.sql_exec({"sql":"DELETE FROM analysis_corrections WHERE video_id = 'vid-f803746be6d9ae16';"})
    Error: tool call error: tool call failed for `rdbc/sql_exec`
        Caused by:
            tools/call failed: Mcp error: -32602: sql_exec is disabled when server is started with
        --read-only

───────────────────────────────────────────────────────────────────────────────────────────────────────

• Deletion failed because this RDBC server is running in read-only mode. I’ll fetch the active DB file
  path so you can restart RDBC writable (or I can delete it via sqlite3 if you want).

• Called rdbc.sql_query({"sql":"PRAGMA database_list;"})
  └ Error: tool call error: tool call failed for `rdbc/sql_query`
        Caused by:
            tools/call failed: Mcp error: -32602: sql_query only accepts single read-only SQL
        statements

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant