This is an automated email from the ASF dual-hosted git repository. rusackas pushed a commit to branch tdd/issue-29934-url-handling in repository https://gitbox.apache.org/repos/asf/superset.git
commit 9443ff5f5bf1ffbb38d9d5a24bd53788f263b592 Author: Claude Code <[email protected]> AuthorDate: Sat Jul 11 11:15:12 2026 -0700 test(core): pin trailing-slash inconsistency across security API (#29934) Regression test for #29934: sibling /api/v1/security/* endpoints handle a misspelled (wrong trailing-slash) URL inconsistently. `login` (declared without a trailing slash) returns 404 for the extra-slash variant, while `csrf_token` and `guest_token` (declared with a trailing slash) return a 308 redirect for the missing-slash variant. The test asserts a wrong-slash misspelling is handled uniformly across the siblings; it fails (red) on master where the statuses diverge (404 vs 308 vs 308). Closes #29934 Co-Authored-By: Claude Opus 4.8 <[email protected]> --- tests/unit_tests/security/api_test.py | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/unit_tests/security/api_test.py b/tests/unit_tests/security/api_test.py index 624d7f5faa1..1423a90dc84 100644 --- a/tests/unit_tests/security/api_test.py +++ b/tests/unit_tests/security/api_test.py @@ -66,6 +66,50 @@ def test_csrf_exempt_blueprints_with_api_key(app: Any, app_context: None) -> Non assert "ApiKeyApi" in {blueprint.name for blueprint in csrf._exempt_blueprints} +def test_security_api_trailing_slash_handled_consistently(client: Any) -> None: + """Regression for #29934: sibling ``/api/v1/security/*`` endpoints handle a + misspelled (wrong trailing-slash) URL inconsistently. + + Three routes live under the same ``/api/v1/security/`` prefix but are + declared with different slash conventions: + + * ``login`` -> ``@expose("/login")`` (no trailing slash, FAB) + * ``csrf_token`` -> ``@expose("/csrf_token/")`` (trailing slash, Superset) + * ``guest_token`` -> ``@expose("/guest_token/")`` (trailing slash, Superset) + + Because of that mix, a client that gets the slash "wrong" is treated three + different ways by Werkzeug routing: + + * ``POST /api/v1/security/login/`` -> 404 (no redirect for the extra slash) + * ``GET /api/v1/security/csrf_token`` -> 308 redirect to the canonical URL + * ``POST /api/v1/security/guest_token`` -> 308 redirect to the canonical URL + + A user hitting one misspelled security URL gets a clean redirect while + another gets a hard 404, which is exactly the inconsistency reported in the + issue. This asserts the *desired* contract — that a trailing-slash + misspelling is handled uniformly across the sibling endpoints — so it fails + (red) on master where the responses diverge, and would pass once the slash + conventions are unified. It does not prescribe which uniform behavior is + correct (all-redirect or all-404), only that they agree. + """ + # (method, canonical route, misspelled route) + misspelled = [ + ("post", "/api/v1/security/login/"), + ("get", "/api/v1/security/csrf_token"), + ("post", "/api/v1/security/guest_token"), + ] + statuses = {} + for method, url in misspelled: + response = client.open(url, method=method.upper(), follow_redirects=False) + statuses[url] = response.status_code + + # All three siblings should treat a wrong trailing slash the same way. + assert len(set(statuses.values())) == 1, ( + "Inconsistent handling of misspelled (wrong trailing-slash) security " + f"URLs: {statuses}" + ) + + def test_rls_rule_schema_accepts_dataset_scoped_rule() -> None: """A rule with an integer ``dataset`` and a ``clause`` loads unchanged.""" result = RlsRuleSchema().load({"dataset": 41, "clause": "tenant_id = 1"})
