Skip to content

test(app-root): close two blind spots in the subdirectory redirect tests#42016

Open
sadpandajoe wants to merge 2 commits into
apache:masterfrom
sadpandajoe:test/harden-subdirectory-redirect-tests
Open

test(app-root): close two blind spots in the subdirectory redirect tests#42016
sadpandajoe wants to merge 2 commits into
apache:masterfrom
sadpandajoe:test/harden-subdirectory-redirect-tests

Conversation

@sadpandajoe

@sadpandajoe sadpandajoe commented Jul 13, 2026

Copy link
Copy Markdown
Member

SUMMARY

Two tests in the subdirectory-deployment suite passed for the wrong reason. Neither
would have caught the regression it was written to guard against. Test-only — no
production code changes.

1. The sanctioned-callers invariant scan skipped an entire module.

test_get_explore_redirect_url_sanctioned_callers scans the source tree to assert
that get_explore_redirect_url is called from exactly two places. To avoid matching
the helper's own def line, it skipped superset/views/utils.py — the defining
module — wholesale. That also blinded it to any genuine call added inside that same
module, which is precisely what the scan exists to catch.

It now walks the AST and counts only ast.Call nodes, so the defining module is
scanned like any other. The definition is a FunctionDef, not a Call, so it is
excluded by shape rather than by path — no path special-casing is needed at all.
Parsing rather than pattern-matching also means a mention of the helper in a comment,
docstring, or string literal cannot be mistaken for a call site, which matters
precisely because bringing views/utils.py into scope is what this change does.

Mutation-verified in both directions: injecting a call to get_explore_redirect_url
into a module now fails the assertion, where the old scan passed silently; and a file
that names the helper only in a comment, docstring, or string literal is correctly
not counted as a caller.

2. The unsafe-redirect test could not distinguish a safe rejection from a crash.

test_protocol_relative_url_falls_through_to_warning_page_under_subdir asserted only
status_code != 302. The external-URL branch calls render_app_template, which needs
a Jinja loader the minimal test app does not have — so the request was actually raising
TemplateNotFound and returning 500. 500 != 302, so the test passed, while
asserting nothing about the behavior it names.

render_app_template is now stubbed, and the test asserts the status code, the response
body, and the absence of a Location header. It's parametrized over three unsafe
shapes: protocol-relative (//host), backslash-prefixed (\\host), and an absolute URL
on a non-configured host. This gives the warning-page branch its first real coverage in
this module.

TESTING INSTRUCTIONS

  • pytest tests/unit_tests/views/test_redirect_view_subdirectory.py — 12 pass (was 10;
    the one weak test became three real ones).
  • pytest tests/integration_tests/views/test_explore_redirect.py — 16 pass.

To confirm the hardened scan actually bites, temporarily add a call to
get_explore_redirect_url inside superset/views/utils.py and re-run — it fails with
views/utils.py listed among the callers. To confirm it does not over-match, add a
file that merely mentions get_explore_redirect_url() in a comment or string — the
scan ignores it.

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

@codecov

codecov Bot commented Jul 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 64.49%. Comparing base (bd9ba24) to head (4633ccc).
⚠️ Report is 2 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #42016      +/-   ##
==========================================
- Coverage   65.05%   64.49%   -0.57%     
==========================================
  Files        2747     2747              
  Lines      153842   153843       +1     
  Branches    35270    35268       -2     
==========================================
- Hits       100088    99221     -867     
- Misses      51844    52712     +868     
  Partials     1910     1910              
Flag Coverage Δ
hive 39.06% <ø> (+0.01%) ⬆️
mysql 57.89% <ø> (+<0.01%) ⬆️
postgres 57.94% <ø> (+<0.01%) ⬆️
presto 41.04% <ø> (+0.01%) ⬆️
python 58.15% <ø> (-1.17%) ⬇️
sqlite 57.55% <ø> (+<0.01%) ⬆️
unit ?

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Both tests passed while failing to check what they were named for.

The sanctioned-callers scan for `get_explore_redirect_url` skipped
`superset/views/utils.py` wholesale to avoid matching the helper's own
definition. That also hid any genuine new *call* added inside that module —
precisely the regression the scan exists to catch. Exclude the definition by
shape (a lookbehind on `def `) rather than by path, so the file is scanned
like any other. Verified by injecting a caller into `views/utils.py`: the
scan now fails and names it.

The unsafe-redirect test asserted only `status_code != 302`. The
external-warning branch calls `render_app_template`, which needs a Jinja
loader the minimal test app does not have, so the branch actually raised
`TemplateNotFound` and returned 500 — and 500 satisfies `!= 302`. The test
would equally have passed on a 404 or an unrelated crash, so it never
distinguished "the user was shown a warning" from "the handler blew up".
Stub `render_app_template`, then assert the status, the rendered body and the
absence of a `Location` header. Extend it over the protocol-relative and
external-host shapes, which gives the warning-page branch its first real
coverage here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sadpandajoe sadpandajoe force-pushed the test/harden-subdirectory-redirect-tests branch from dc10400 to f982d02 Compare July 14, 2026 18:29
The sanctioned-callers scan matched `get_explore_redirect_url(` as raw
text, so a mention of the helper in a comment, docstring, or string
literal counted as a call site. Since this test scans `views/utils.py`
(the definition module), an innocent comment there would have added the
file to `callers` and failed CI for no reason.

Walk the AST and count only `ast.Call` nodes. This also drops the
`(?<!def )` lookbehind: the definition parses to a `FunctionDef`, not a
`Call`, so it is excluded by shape rather than by text, while the module
stays in scope — a genuine new call added inside it is still caught.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@bito-code-review

Copy link
Copy Markdown
Contributor

Bito Review Failed - Technical Failure Bito encountered technical difficulties while starting a code review session. To retry, type /review in a comment and save. If the issue persists, contact support@bito.ai.

@sadpandajoe sadpandajoe marked this pull request as ready for review July 14, 2026 21:59
@sadpandajoe sadpandajoe requested review from rusackas and yousoph July 14, 2026 22:00
@bito-code-review

bito-code-review Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #351665

Actionable Suggestions - 0
Review Details
  • Files reviewed - 2 · Commit Range: f982d02..4633ccc
    • tests/integration_tests/views/test_explore_redirect.py
    • tests/unit_tests/views/test_redirect_view_subdirectory.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant