Skip to content

fix(testing): harden Flutter test env against host-Python leakage - #6772

Open
FeodorFitsner wants to merge 2 commits into
mainfrom
fix/flutter-test-env-hardening
Open

fix(testing): harden Flutter test env against host-Python leakage#6772
FeodorFitsner wants to merge 2 commits into
mainfrom
fix/flutter-test-env-hardening

Conversation

@FeodorFitsner

@FeodorFitsner FeodorFitsner commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Description

Follow-up to #6747 (already merged as a7c7b5e), which stripped PYTHONPATH/PYTHONHOME from the flutter test subprocess so an IDE-injected debugger/sitecustomize path could not reach the interpreter embedded in the app under test.

Two more host-Python knobs reach that interpreter through the same mechanism:

  • PYTHONEXECUTABLE - macOS framework builds use it to seed sys.executable; a host value points at the IDE's interpreter, not the packaged app's. Now removed.
  • PYTHONNOUSERSITE - user site-packages is opt-out, so leaving it unset lets a host ~/.local/lib/pythonX.Y/site-packages whose version matches the embedded interpreter leak in exactly the way fix(testing): prevent host Python env from leaking into Flutter tests #6747 set out to prevent. Now set to 1 rather than removed.

The environment is built in a _flutter_subprocess_env() helper instead of inline at the call site. That gives the rationale one home, parallels _flutter_path_env in flet_cli.commands.test (which builds the env for the pytest subprocess), and makes the part that is actually testable - which variables are dropped and which survive - unit-testable without launching Flutter.

PATH, and every FLET_* and SERIOUS_PYTHON_* variable the native build phase needs, remain untouched.

Also adds the changelog entry #6747 shipped without, credited to @PythBuster.

Test code

packages/flet/tests/test_flet_test_app_env.py covers a host environment shaped like an IDE-launched pytest run:

HOST_ENV = {
    "PATH": "/usr/local/bin:/usr/bin",
    "PYTHONPATH": "/Applications/PyCharm.app/Contents/plugins/python/helpers/pydev",
    "PYTHONHOME": "/opt/homebrew/opt/python@3.13/Frameworks/Python.framework",
    "PYTHONEXECUTABLE": "/opt/homebrew/bin/python3.13",
    "FLET_TEST_FLUTTER_EXE": "/opt/flutter/bin/flutter",
    "SERIOUS_PYTHON_SITE_PACKAGES": "/tmp/app/site-packages",
    ...
}

asserting the three variables are stripped, PYTHONNOUSERSITE=1 is set, the build variables survive verbatim, absent variables don't raise, and os.environ itself is not mutated.

uv run --group test pytest packages/flet/tests - 232 passed, 8 skipped.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

Checklist

  • I signed the CLA.
  • I have performed a self-review of my own code.
  • My code follows the style guidelines of this project.
  • I have commented my code, particularly in hard-to-understand areas.
  • My changes generate no new warnings.
  • New and existing tests pass locally with my changes.
  • I have made corresponding documentation changes, if applicable.
  • I have added changelog entries for user-facing changes, if applicable.
  • I have updated release guide pages and website/sidebars.yml for breaking changes, removals, and deprecations, if applicable.

Additional details

Unverified by a real device run: the PYTHONNOUSERSITE/PYTHONEXECUTABLE cases are reasoned from CPython's initialization behaviour rather than reproduced, since triggering them needs a host user site directory matching the embedded interpreter's version. The original PYTHONPATH failure in #6747 is direct evidence that this class of variable does reach the embedded interpreter.

Separately, the entry for #6769 landed under ## 0.86.6 instead of the unreleased ## 0.86.7 section - looks like a stale-branch merge artifact, left alone here.

Summary by Sourcery

Prevent host Python configuration from leaking into the Flutter integration test app environment and add coverage and changelog entry for the behavior.

Bug Fixes:

  • Ensure Flutter integration tests start reliably by stripping host Python configuration variables from the flutter test subprocess environment and disabling user site-packages.

Enhancements:

  • Centralize construction of the flutter test subprocess environment in a dedicated helper for clearer rationale and testability.

Documentation:

  • Document the integration-test environment hardening in the changelog, including behavior around host Python variables and IDE-injected paths.

Tests:

  • Add unit tests validating the Flutter test subprocess environment excludes host Python configuration, preserves required build variables, sets PYTHONNOUSERSITE, and does not mutate os.environ.

Follow-up to #6747, which stripped PYTHONPATH/PYTHONHOME from the
`flutter test` subprocess so an IDE-injected debugger/sitecustomize path
could not reach the interpreter embedded in the app under test.

Two more host-Python knobs reach that interpreter the same way:

* PYTHONEXECUTABLE - macOS framework builds use it to seed sys.executable,
  and a host value points at the IDE's interpreter, not the packaged app's.
* PYTHONNOUSERSITE - user site-packages is opt-out, so leaving it unset lets
  a host ~/.local/lib/pythonX.Y/site-packages whose version matches the
  embedded interpreter leak in. It is now set rather than removed.

The environment is built in a `_flutter_subprocess_env()` helper instead of
inline at the call site, which gives the rationale one home and makes the
part that is actually testable - which variables are dropped and which
survive - unit-testable without launching Flutter.

Adds the changelog entry #6747 shipped without.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 14, 2026

Copy link
Copy Markdown

Deploying flet-website-v2 with  Cloudflare Pages  Cloudflare Pages

Latest commit: 5561c64
Status: ✅  Deploy successful!
Preview URL: https://f3da3d3d.flet-website-v2.pages.dev
Branch Preview URL: https://fix-flutter-test-env-hardeni.flet-website-v2.pages.dev

View logs

The unit suite runs as `uv run --no-dev --group test`, whose environment has
only pytest and pytest-asyncio - numpy, pillow and scikit-image live in the
`dev` group. Importing `flet.testing.flet_test_app` therefore fails at
collection in CI with `ModuleNotFoundError: No module named 'numpy'`, which is
why no unit test imported that subtree before.

Move the helper to `flet.utils.environment.without_host_python_config()`, a
module with no dependencies beyond the stdlib, and have `flet_test_app` call
it. The function never needed anything from `FletTestApp` - it is a pure
transform over an environment mapping - and it now takes the mapping as an
optional argument, so the tests exercise it without touching `os.environ`.

Verified by importing the module with numpy/PIL/skimage blocked on the meta
path, reproducing the CI environment.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant