Skip to content

fix(bootstrap) handle when the runfiles env vars are not correct#3644

Open
adhoc-bobcat wants to merge 1 commit intobazel-contrib:mainfrom
adhoc-bobcat:inherited_runfiles_fix
Open

fix(bootstrap) handle when the runfiles env vars are not correct#3644
adhoc-bobcat wants to merge 1 commit intobazel-contrib:mainfrom
adhoc-bobcat:inherited_runfiles_fix

Conversation

@adhoc-bobcat
Copy link

This change addresses an issue that has existed since 1.7.0 where Python binaries launched as subprocesses could incorrectly inherit and use runfiles environment variables (RUNFILES_DIR, RUNFILES_MANIFEST_FILE) from the parent process.

Why this change is needed:

When a Python binary spawns another Python binary, the child process inherits the environment variables. If the parent had runfiles-related environment variables set, the child would attempt to use the parent's runfiles tree, which is incorrect and leads to import errors if the child has different dependencies or a different runfiles layout.

Behavior Before:

A child Python process would trust and use any existing RUNFILES_DIR and RUNFILES_MANIFEST_FILE environment variables. If these were set by a parent Python process, they would point to the parent's runfiles, causing the child to fail when trying to load its own resources or dependencies.

Behavior After:

The Python bootstrap scripts now include a check to validate the inherited runfiles environment variables. If the runfiles variables exist but do not point to the correct location for the current binary, the bootstrap script will unset both RUNFILES_DIR and RUNFILES_MANIFEST_FILE from the environment. This allows the subsequent fallback logic in the bootstrap process to correctly locate the runfiles for the current process, ensuring dependencies are resolved properly. This modification has been applied to both bootstrap template files.

This change ensures that even nested Python binary calls correctly find their respective runfiles.

Fixes #3518

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves a long-standing issue where Python subprocesses could inherit and incorrectly use runfiles environment variables from their parent processes, leading to import errors. The changes introduce robust validation within the Python bootstrap scripts to ensure that each Python binary correctly identifies and utilizes its own runfiles, thereby guaranteeing proper dependency resolution across nested process calls.

Highlights

  • Runfiles Environment Variable Handling: Implemented a mechanism in Python bootstrap scripts to validate and unset 'RUNFILES_DIR' and 'RUNFILES_MANIFEST_FILE' if they are inherited incorrectly by child processes, preventing erroneous runfiles resolution.
  • Improved Subprocess Reliability: Ensured that Python binaries spawned as subprocesses correctly locate their own runfiles, even when parent processes have conflicting runfiles environment variables set.
  • Documentation Updates: Updated 'python/features.bzl' to reflect version '1.9.0' and added a 'versionchanged' note to the 'whl_library' rule documentation regarding reproducibility.
  • Enhanced Testing for Nested Binaries: Added new test infrastructure, including a 'py_library' and modifications to existing test binaries and verification scripts, to thoroughly test the correct behavior of runfiles in nested Python binary calls.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • python/features.bzl
    • Updated the 'versionadded' tag for feature detection to '1.9.0'.
  • python/private/pypi/whl_library.bzl
    • Modified '_whl_library_impl' to return 'repo_metadata(reproducible=True)' when 'enable_pipstar' and 'enable_pipstar_extract' are true.
    • Added a 'versionchanged' note to the 'whl_library' docstring, indicating that it is now marked as reproducible under specific conditions.
  • python/private/python_bootstrap_template.txt
    • Added logic to clear 'RUNFILES_DIR' and 'RUNFILES_MANIFEST_FILE' from the environment if the initially found runfiles directory does not contain the main relative path.
  • python/private/stage2_bootstrap_template.py
    • Implemented logic to clear 'RUNFILES_DIR' and 'RUNFILES_MANIFEST_FILE' from the environment if the initially found runfiles directory is incorrect.
  • tests/bootstrap_impls/bin_calls_bin/BUILD.bazel
    • Added a new 'py_library' target named 'inner_lib'.
    • Added 'deps' on ':inner_lib' to 'inner_bootstrap_system_python' and 'inner_bootstrap_script' binaries.
  • tests/bootstrap_impls/bin_calls_bin/inner.py
    • Added logging for 'RUNFILES_DIR' and 'RUNFILES_MANIFEST_FILE' environment variables.
    • Included a 'try-except' block to import 'inner_lib' and log its success or failure.
  • tests/bootstrap_impls/bin_calls_bin/inner_lib.py
    • Added a new Python file defining a simple 'confirm' function.
  • tests/bootstrap_impls/bin_calls_bin/outer.py
    • Removed 'check=True' from 'subprocess.run' call to allow inspection of non-zero exit codes.
    • Added 'sys.exit(result.returncode)' to propagate the child process's exit code.
  • tests/bootstrap_impls/bin_calls_bin/verify.sh
    • Added extraction and logging of 'INNER_RUNFILES_DIR', 'INNER_RUNFILES_MANIFEST_FILE', and 'INNER_LIB_IMPORT' from test output.
    • Added a new check to verify that 'inner_lib' was successfully imported.
Activity
  • No activity has been recorded for this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a fix for an issue where Python binaries launched as subprocesses could incorrectly inherit and use runfiles environment variables from the parent process. The change correctly validates the inherited runfiles environment variables and unsets them if they are incorrect, allowing the child process to locate its own runfiles. This is implemented in both python_bootstrap_template.txt and stage2_bootstrap_template.py. The PR also includes comprehensive tests to verify this fix by checking that a nested binary can successfully import its dependencies. Additionally, there are some unrelated but correct changes to whl_library.bzl to improve reproducibility of repository rules. The changes are well-implemented and look good.

There was still an issue where the runfiles environment variables could
be set for a parent Python binary, and if that spawned another Python
binary (directly or indirectly), the child would try to use the parents
runfiles.

This was confirmable by adding a py_library dependency to the existing
bin_calls_bin test, and having inner.py try to import it.

A workaround sugggested in the bug for code outside of rules_python was
to remove RUNFILES_DIR from the environment inherited by the child when
launching the child process, though in some cases you might need to also
remove RUNFILES_MANIFEST_FILE, but working around the issue is not very
satisfactory.

Diving into the bootstrapping process, it seemed like the proper fix was
to conditionally unset them, if they were not correct. I found
equivalent places in both bootstrap template files, and if the test to
confirm "runfile_dir" was correct fails, the bootstrap code itself now
removes those invalid values from the environment.

Later bootstrap code assumes they are set correctly, if set. When they
are not set, it goes through some fallback logic to locate them.

By conditionally unsetting them, the fallback logic is not invoked when
it isn't necessary, shortening the bootstrap process.

With that change, the modified tests now pass.

Fixes bazel-contrib#3518
@adhoc-bobcat adhoc-bobcat force-pushed the inherited_runfiles_fix branch from ab8d50f to a53de8e Compare March 4, 2026 20:40
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.

RUNFILES_DIR inheritance causes issues when non-Python process invokes py_binary

1 participant