mcp: validate data product names before interpolating into SQL#35780
Conversation
|
Thanks for opening this PR! Here are a few tips to help make the review process smooth for everyone. PR title guidelines
Pre-merge checklist
|
6ba5a4c to
f1995cf
Compare
ggevay
left a comment
There was a problem hiding this comment.
I'm wondering, couldn't we instead use something like StrExt::quoted? The quotation should make any SQL keywords not be parsed as keywords, but parsed as part of the name. Also, StrExt::quoted makes sure to escape quotation marks, so the user can't break out of the quotation.
src/environmentd/src/http/mcp.rs
Outdated
|
|
||
| let make_err = || { | ||
| McpRequestError::QueryValidationFailed(format!( | ||
| "Invalid data product name: {}. Expected a fully qualified name like '\"database\".\"schema\".\"name\"'", |
There was a problem hiding this comment.
Why not allow an unqualified name? Actually, the test
assert!(validate_data_product_name("my_view").is_ok());
seems to indicate that we do allow unqualified names.
There was a problem hiding this comment.
Ops yes, the error message was misleading! We do accept unqualified names. Updated the message to show both forms as examples.
b07130d to
d56cb23
Compare
@ggevay I think The other thing is the name arrives from The AST validation approach makes sure the name is safe to interpolate as-is without transforming it. But I might be missing something, do you have a different approach in mind? |
|
Ah yes, My problem with the PR's approach is that it is a lot of brittle code to maintain. E.g., when someone later adds to the AST, they'll have to not forget to update this code as well. This could be enforced somewhat by relying more on pattern matching, with no wildcards, so that one would get compile errors in But another alternative approach would be to call |
d56cb23 to
b28e655
Compare
|
@ggevay ah nice suggestion, just implemented it, much cleaner! Added a public fn safe_data_product_name(name: &str) -> Result<String, McpRequestError> {
let parsed = parse_item_name(name).map_err(|_| ...)?;
Ok(parsed.to_ast_string_stable())
}Thanks for the suggestion and let me know what you think! |
ggevay
left a comment
There was a problem hiding this comment.
LGTM, thanks for iterating on it!
src/environmentd/src/http/mcp.rs
Outdated
| /// Validates that a data product name is a safe SQL identifier. | ||
| /// | ||
| /// The name is interpolated into `SELECT * FROM {name}`, so we parse a | ||
| /// synthetic query and inspect the AST to ensure nothing beyond a bare |
b28e655 to
64be1e0
Compare
Validates that data product names passed to read_data_product are syntactically valid SQL identifiers by parsing a probe query locally, preventing malformed or injected names from reaching the database as opaque SQL errors.