feat(nl2sql): prompt-injection boundary defence + EXPLAIN dry-run pre-flight#257
Merged
Merged
Conversation
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="src/mcpg/tools.py" line_range="3164" />
<code_context>
question: str,
schema: str,
execute: bool = False,
+ explain_preflight: bool = True,
table_filter: tuple[str, ...] | None = None,
max_tokens: int = DEFAULT_MAX_TOKENS,
</code_context>
<issue_to_address>
**issue (bug_risk):** Adding `explain_preflight` before `table_filter` changes positional argument order and can break existing callers.
Because this is a public-facing function, inserting `explain_preflight` before `table_filter` changes the positional argument order and can silently misroute arguments for any existing positional callers. To avoid breaking those callers, consider adding `explain_preflight` at the end of the parameter list or making new parameters keyword-only.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Contributor
|
Warning Gemini encountered an error creating the review. You can try again by commenting |
Defence-in-depth at the prompt layer for translate_nl_to_sql (the AST allowlist stays the enforcement backstop): - Wrap the user question in <user_request>...</user_request> delimiters. - System prompt instructs the model to treat that text as data (never instructions) and to REFUSE any out-of-scope request (write/DDL, secrets, 'ignore previous instructions', ...) by emitting the sentinel '-- MCPG_REFUSED: <reason>'. - translate detects the sentinel (JSON sql field or bare reply) and returns TranslationResult(refused=True, refusal_reason=...) with empty sql, never forwarding it to SafeSqlDriver / execution. Adds refused / refusal_reason to the result (return-shape snapshot regenerated; tool input surface unchanged). 3 new unit tests cover the delimiter wrap, the JSON-field sentinel, and the bare-line sentinel. This is the first of the two remaining security-hardening.md items; the EXPLAIN dry-run pre-flight is a fast-follow on this branch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0122yLZLJ8t4W43sdN6BmTZc
Second of the two remaining security-hardening.md items. Before returning or executing the generated SQL, run a non-executing EXPLAIN (reusing mcpg.query.explain_query, so it's SafeSqlDriver-validated) to catch queries that pass the structural allowlist but reference a non-existent column/table or mistype something: - Planner rejection -> structured error='query invalid: <message>' with the SQL returned for inspection; nothing executed. - Pre-flight statement_timeout -> degrade to 'skip, proceed' (don't block a valid translation). - New explain_preflight tool arg (default on); bypassable per call. Surface snapshot regenerated (translate_nl_to_sql gains explain_preflight). 2 new unit tests (invalid-query surfaced; bypass when disabled) + an EXPLAIN route in the nl2sql test schema so the default-on pre-flight passes. Completes security-hardening.md — both NL->SQL items now shipped. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0122yLZLJ8t4W43sdN6BmTZc
cc1ebfa to
04b7d74
Compare
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.
Summary
Ships the two remaining
security-hardening.mditems — both scoped totranslate_nl_to_sql, both now ✅.1. Prompt-injection boundary defence. Defence-in-depth at the prompt layer (the AST allowlist stays the enforcement backstop):
<user_request>…</user_request>delimiters.-- MCPG_REFUSED: <reason>.translate_nl_to_sqldetects the sentinel (in the JSONsqlfield or a bare reply) and returnsTranslationResult(refused=True, refusal_reason=…)with emptysql— never forwarding it toSafeSqlDriver/ execution.2. EXPLAIN dry-run pre-flight. Semantic validation before returning/executing:
EXPLAIN(reusingmcpg.query.explain_query, so the SQL isSafeSqlDriver-validated first) to catch queries that pass the structural allowlist but reference a non-existent column/table or mistype something.error="query invalid: <message>"(SQL returned for inspection, nothing executed). A pre-flightstatement_timeoutdegrades to "proceed" rather than blocking a valid translation.explain_preflighttool arg (default on), bypassable per call.Surface/return-shape changes:
TranslationResultgainsrefused/refusal_reason; the tool gains theexplain_preflightinput. Both contract snapshots regenerated (diffs scoped to exactly these). 5 new unit tests (delimiter wrap, JSON-field + bare-line refusal, invalid-query pre-flight, pre-flight bypass); 101 unit + contract tests green; ruff/mypy clean.Roadmap linkage
Advances roadmap row: N/A — clears the two open items in
docs/security-hardening.md(marked ✅ in this PR).Checklist
ruff,ruff format, andmypy src/mcpgpassCHANGELOG.mdupdated under[Unreleased]src/mcpg/_vendor/🤖 Generated with Claude Code
Generated by Claude Code
Summary by Sourcery
Strengthen nl2sql security and robustness by adding prompt-injection refusal handling and an EXPLAIN-based semantic pre-flight check, and surface these via extended TranslationResult and tool parameters.
New Features:
Enhancements:
Documentation:
Tests:
Chores: