codeant-ai-for-open-source[bot] commented on code in PR #42928:
URL: https://github.com/apache/superset/pull/42928#discussion_r3742439556


##########
superset/commands/sql_lab/estimate.py:
##########
@@ -150,6 +163,16 @@ def run(
 
         sql = self._sql
         if self._template_params:
+            # Check access before rendering the Jinja template (mirrors the
+            # SQL Lab execute path).
+            security_manager.raise_for_access(
+                database=self._database,
+                sql=sql,
+                catalog=self._catalog,
+                schema=self._schema or None,
+                template_params=self._template_params,
+                force_dataset_match=True,
+            )

Review Comment:
   **Suggestion:** `validate()` already invokes `raise_for_access`, but `run()` 
invokes it a second time whenever template parameters exist. This repeats 
SQL/Jinja parsing and authorization hooks, and because template rendering can 
execute macros or observe changing state, the second authorization pass can 
produce different results or reject a request that passed the first pass. 
Perform the access check once and reuse the validated/rendered result. 
[performance]
   
   <details>
   <summary><b>Severity Level:</b> Minor ๐Ÿงน</summary>
   
   ```mdx
   - โš ๏ธ Templated cost estimates perform authorization twice.
   - โš ๏ธ Database-backed Jinja macros may execute repeatedly.
   - โš ๏ธ SQL Lab estimation incurs unnecessary parsing overhead.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=2c8306869d1d49d5af574a06c15ecf0e&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=2c8306869d1d49d5af574a06c15ecf0e&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent ๐Ÿค– </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/commands/sql_lab/estimate.py
   **Line:** 165:175
   **Comment:**
        *Performance: `validate()` already invokes `raise_for_access`, but 
`run()` invokes it a second time whenever template parameters exist. This 
repeats SQL/Jinja parsing and authorization hooks, and because template 
rendering can execute macros or observe changing state, the second 
authorization pass can produce different results or reject a request that 
passed the first pass. Perform the access check once and reuse the 
validated/rendered result.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F42928&comment_hash=e43c87b360bd92721c3eedd5411d4fe0d3aac7afd03a0ae34cf96cf87a130701&reaction=like'>๐Ÿ‘</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F42928&comment_hash=e43c87b360bd92721c3eedd5411d4fe0d3aac7afd03a0ae34cf96cf87a130701&reaction=dislike'>๐Ÿ‘Ž</a>



##########
superset/db_engine_specs/postgres.py:
##########
@@ -641,12 +641,11 @@ def get_default_schema_for_query(
         """
         Return the default schema for a given query.
 
-        This method simply uses the parent method after checking that there 
are no
-        malicious path setting in the query.
+        This method simply uses the parent method after checking that the query
+        cannot rebind the schema used to resolve unqualified table names.
         """
         script = process_jinja_sql(query.sql, database, template_params).script

Review Comment:
   **Suggestion:** This renders and parses the Jinja query during PostgreSQL 
schema resolution, but the security-manager flow then calls `process_jinja_sql` 
again for table authorization and execution renders the template once more. 
Database-backed macros such as partition helpers therefore run multiple times 
during one request, potentially repeating database queries and producing 
different validation and execution SQL for non-idempotent macros. Reuse a 
single rendered result or avoid rendering again during schema resolution. 
[performance]
   
   <details>
   <summary><b>Severity Level:</b> Major โš ๏ธ</summary>
   
   ```mdx
   - โš ๏ธ SQL Lab Jinja macros may execute multiple times per query.
   - โš ๏ธ Repeated macro calls can produce inconsistent validation and execution 
SQL.
   - โš ๏ธ Additional database-backed macro queries increase request latency.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=7dc825a8d1134bd9b4b0eecd1fc83dd0&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=7dc825a8d1134bd9b4b0eecd1fc83dd0&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent ๐Ÿค– </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/db_engine_specs/postgres.py
   **Line:** 647:647
   **Comment:**
        *Performance: This renders and parses the Jinja query during PostgreSQL 
schema resolution, but the security-manager flow then calls `process_jinja_sql` 
again for table authorization and execution renders the template once more. 
Database-backed macros such as partition helpers therefore run multiple times 
during one request, potentially repeating database queries and producing 
different validation and execution SQL for non-idempotent macros. Reuse a 
single rendered result or avoid rendering again during schema resolution.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F42928&comment_hash=aad94fdf8601adc6183451064697c7c12758b0a80902ab3ae43266363bed55af&reaction=like'>๐Ÿ‘</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F42928&comment_hash=aad94fdf8601adc6183451064697c7c12758b0a80902ab3ae43266363bed55af&reaction=dislike'>๐Ÿ‘Ž</a>



##########
superset/sql/parse.py:
##########
@@ -2074,48 +2254,88 @@ def process_jinja_sql(
     :returns: JinjaSQLResult containing the processed script and table 
references
     :raises SupersetSecurityException: If SQLGlot is unable to parse the SQL 
statement
     :raises jinja2.exceptions.TemplateError: If the Jinjafied SQL could not be 
rendered
+    :raises SupersetParseError: If a partition macro references a table that
+        cannot be determined statically
     """
 
     from superset.jinja_context import (  # pylint: 
disable=import-outside-toplevel
         get_template_processor,
+        NoOpTemplateProcessor,
     )
 
     processor = get_template_processor(database)
     ast = processor.env.parse(sql)
 
     tables = set()
 
+    def raise_for_unresolvable_macro() -> Any:
+        raise SupersetParseError(
+            sql,
+            database.db_engine_spec.engine,
+            message=(
+                "Unable to determine the table referenced by a partition "
+                "macro; use a single constant table reference"
+            ),
+        )
+
     for node in ast.find_all(nodes.Call):
-        if isinstance(node.node, nodes.Getattr) and node.node.attr in (
-            "latest_partition",
-            "latest_sub_partition",
+        if (
+            isinstance(node.node, nodes.Getattr)
+            and node.node.attr in PARTITION_MACRO_NAMES
         ):
-            # Try to extract the table referenced in the macro.
+            # Extract the table referenced in the macro. The reference must
+            # be statically evaluable; otherwise raise rather than render.
             try:
+                if len(node.args) != 1:
+                    raise nodes.Impossible()
                 tables.add(
                     Table(
                         *[
                             remove_quotes(part.strip())
                             for part in 
node.args[0].as_const().split(".")[::-1]
-                            if len(node.args) == 1
                         ]
                     )
                 )
             except nodes.Impossible:
-                pass
+                raise_for_unresolvable_macro()
 
             # Replace the potentially problematic Jinja macro with some benign 
SQL.
             node.__class__ = nodes.TemplateData
             node.fields = nodes.TemplateData.fields
             node.data = "NULL"
 
-    # re-render template back into a string
-    code = processor.env.compile(ast)
-    template = Template.from_code(processor.env, code, 
globals=processor.env.globals)
-    rendered_sql = template.render(processor.get_context(), **(template_params 
or {}))
+    # Render the neutralized template once, using the same context
+    # ``process_template`` builds at execution time, so the validated SQL
+    # matches the executed SQL. A no-op processor runs the raw SQL at
+    # execution time, so validate that raw SQL directly.
+    if isinstance(processor, NoOpTemplateProcessor):
+        rendered_sql = processor.process_template(sql)
+    else:
+        code = processor.env.compile(ast)
+        template = Template.from_code(
+            processor.env,
+            code,
+            globals=processor.env.globals,
+        )
+        # Replace live partition macros with stubs so a call that survives
+        # neutralization (e.g. via a dynamic attribute lookup) does not
+        # execute during this render.
+        context = processor.get_template_context(**(template_params or {}))
+        if (engine := getattr(processor, "engine", None)) and isinstance(
+            context.get(engine), dict
+        ):
+            context[engine] = {
+                key: (
+                    (lambda *args, **kwargs: raise_for_unresolvable_macro())
+                    if key in PARTITION_MACRO_NAMES
+                    else value
+                )
+                for key, value in context[engine].items()
+            }
+        rendered_sql = template.render(context)

Review Comment:
   **Suggestion:** The validation path now renders the template directly, but 
unlike `BaseTemplateProcessor.process_template`, this call does not translate 
Jinja rendering failures into Superset's typed template exceptions. Because 
`raise_for_access` invokes `process_jinja_sql` before the later `run()` 
try/except, an undefined variable or other template error can escape as a raw 
Jinja exception instead of the expected `SupersetErrorException`. Use the 
processor's error-handling path or wrap this render consistently. [error 
handling]
   
   <details>
   <summary><b>Severity Level:</b> Major โš ๏ธ</summary>
   
   ```mdx
   - โŒ SQL validation can return raw template-rendering failures.
   - โš ๏ธ Clients lose the expected structured validator error response.
   - โš ๏ธ Authorization and validation endpoints handle identical templates 
inconsistently.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=bfff5b10405f46219c8f6fcc6ab9f029&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=bfff5b10405f46219c8f6fcc6ab9f029&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent ๐Ÿค– </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/sql/parse.py
   **Line:** 2335:2335
   **Comment:**
        *Error Handling: The validation path now renders the template directly, 
but unlike `BaseTemplateProcessor.process_template`, this call does not 
translate Jinja rendering failures into Superset's typed template exceptions. 
Because `raise_for_access` invokes `process_jinja_sql` before the later `run()` 
try/except, an undefined variable or other template error can escape as a raw 
Jinja exception instead of the expected `SupersetErrorException`. Use the 
processor's error-handling path or wrap this render consistently.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F42928&comment_hash=7ca541c54a3572891b8e54e1f6c256c1625e1d62fdb66d386f1225e4e7ba8b0b&reaction=like'>๐Ÿ‘</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F42928&comment_hash=7ca541c54a3572891b8e54e1f6c256c1625e1d62fdb66d386f1225e4e7ba8b0b&reaction=dislike'>๐Ÿ‘Ž</a>



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to