EnxDev commented on code in PR #45342:
URL: https://github.com/apache/superset/pull/45342#discussion_r4288284089


##########
superset/commands/dataset/update.py:
##########
@@ -283,6 +291,7 @@ def _validate_sql_access(
                     sql=sql,
                     catalog=catalog,
                     schema=schema,
+                    allow_dataset_editorship=False,

Review Comment:
   Confirmed, and fixed in 2f33d895be. `_validate_sql_access` now runs when the 
SQL text changes or when the SQL is kept but the connection, catalog, schema or 
`template_params` change. It checks the effective SQL and passes the effective 
template params, so Jinja SQL is checked against the table it actually renders 
to. Empty values compare as `None`, so a client echoing `""` for an unset field 
doesn't trigger a check and #20382 editors can still edit metadata.
   
   The legacy `/datasource/save/` path compared schema and catalog but not 
`template_params`, so I added it there too and pass the parsed params to the 
check.
   
   Tests: schema-only and template-params-only updates on a virtual dataset now 
run the check with editorship off (both fail without the change), and a 
metadata-only update or one that echoes the stored values skips it. The legacy 
save tests got a template-params case.



##########
superset/common/query_context_processor.py:
##########
@@ -1031,7 +1031,10 @@ def raise_for_access(self) -> None:
         # caller is not allowed to access.
         if self._qc_datasource.type == DatasourceType.QUERY:
             try:
-                security_manager.raise_for_access(query=self._qc_datasource)
+                security_manager.raise_for_access(
+                    query=self._qc_datasource,
+                    allow_dataset_editorship=False,

Review Comment:
   Yes, fixed in 2f33d895be. `GetExploreCommand` and `check_query_access` both 
pass `allow_dataset_editorship=False`. The author bypass returns before the 
table loop, so the query's own author still gets through. Everyone else now 
needs real data access on the tables the query reads. Added a test where a 
non-author is the editor of a same-named dataset and gets denied. It fails 
without the change.



##########
superset/commands/dataset/importers/v1/utils.py:
##########
@@ -585,6 +605,22 @@ def import_dataset(  # noqa: C901
     if not ignore_permissions:
         try:
             security_manager.raise_for_access(datasource=dataset)
+            # The datasource check accepts editorship of the dataset itself,
+            # and an overwrite or restore only requires editorship of the row
+            # being replaced. Without this check an editor could re-import a
+            # ``SELECT 1`` decoy as a physical dataset over an arbitrary
+            # table. A physical dataset that is new or bound to a different
+            # table must be authorized by data access on that table.
+            if not dataset.sql and _table_binding(dataset) != previous_binding:
+                security_manager.raise_for_access(
+                    database=dataset.database,

Review Comment:
   I tried to reproduce this one and it doesn't get as far as the check. 
`import_dataset` calls `SqlaTable.import_from_dict` without 
`allow_reparenting`, so the lookup filters on `database_id == <new id>` as well 
as the uuid/unique-constraint match. When the config points at a different 
database it never matches the existing row. It builds a new `SqlaTable` with 
the same uuid, and the `if dataset.id is None: db.session.flush()` just above 
this block fails on `uq_tables_uuid` before any `raise_for_access` runs. So an 
overwrite can't move a dataset to another connection, and `dataset.database` 
can't be stale here.
   
   I wrote the test you suggested (existing row with `database` loaded, then an 
overwrite with a new `database_uuid`, for both physical and virtual). It fails 
with `IntegrityError: UNIQUE constraint failed: tables.uuid` with or without 
resolving the database by id, so I left the code as is. If you'd still like the 
check to resolve `Database` from `database_id` as a guard in case reparenting 
is ever allowed, I can add it.



-- 
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