This is an automated email from the ASF dual-hosted git repository.
hainenber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new 958d1ab256a test(rls): assert dataset search returns all mask matches
(#29707) (#41968)
958d1ab256a is described below
commit 958d1ab256a84e171cbf02761538e5c61c39eeda
Author: Evan Rusackas <[email protected]>
AuthorDate: Sun Jul 12 06:23:29 2026 -0700
test(rls): assert dataset search returns all mask matches (#29707) (#41968)
Co-authored-by: Claude Code <[email protected]>
---
.../security/row_level_security_tests.py | 56 ++++++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/tests/integration_tests/security/row_level_security_tests.py
b/tests/integration_tests/security/row_level_security_tests.py
index ac5fbce4453..a3f2c394152 100644
--- a/tests/integration_tests/security/row_level_security_tests.py
+++ b/tests/integration_tests/security/row_level_security_tests.py
@@ -469,6 +469,62 @@ class TestRowLevelSecurityWithRelatedAPI(SupersetTestCase):
assert all("birth" in table_name.lower() for table_name in
received_tables)
assert len(result) >= 1 # At least birth_names should be returned
+ @pytest.mark.usefixtures("load_birth_names_data")
+ def test_rls_tables_related_api_returns_all_masked_matches(self):
+ """
+ Regression for #29707: the RLS dataset selector's async search must
+ return *every* dataset whose name matches the typed mask, not a
+ truncated subset. The reporter had two "birth" datasets (birth_names
+ and birth_france_by_region) and searching "birth" showed an
+ incomplete list. This exercises the backend ``related/tables``
+ endpoint that feeds that selector to prove whether the search-by-mask
+ lookup is the culprit.
+ """
+ self.login(ADMIN_USERNAME)
+
+ birth_names = self.get_table(name="birth_names")
+ # Create a sibling dataset whose name also contains the "birth" mask,
+ # mirroring the two-dataset scenario from the issue.
+ sibling = SqlaTable(
+ table_name="birth_france_by_region",
+ database=birth_names.database,
+ schema=birth_names.schema,
+ )
+ db.session.add(sibling)
+ db.session.commit()
+
+ try:
+ # Datasets in the metadata DB that match the "birth" mask. Keep a
+ # sorted list rather than a set so datasets that render the same
+ # display name (same table/schema across databases) are not
+ # collapsed, which would let the multiplicity disagree with the
+ # API's row count below.
+ expected = sorted(
+ t.name
+ for t in db.session.query(SqlaTable)
+ .filter(SqlaTable.table_name.ilike("%birth%"))
+ .all()
+ )
+ # Both datasets must be present in the ground truth for the
+ # assertion below to be meaningful.
+ bare_names = {name.split(".")[-1] for name in expected}
+ assert "birth_names" in bare_names
+ assert "birth_france_by_region" in bare_names
+
+ params = rison.dumps({"filter": "birth", "page": 0, "page_size":
100})
+ rv =
self.client.get(f"/api/v1/rowlevelsecurity/related/tables?q={params}")
+ assert rv.status_code == 200
+ data = json.loads(rv.data.decode("utf-8"))
+ received = sorted(table["text"] for table in data["result"])
+
+ # The masked search must return *all* matching datasets (preserving
+ # multiplicity), and the advertised count must not under-report
them.
+ assert received == expected
+ assert data["count"] == len(expected)
+ finally:
+ db.session.delete(sibling)
+ db.session.commit()
+
def test_rls_tables_related_api_with_filter_no_matches(self):
self.login(ADMIN_USERNAME)
# Test with filter that should match nothing