Skip to content

Add --experimental_strict_repo_env option#24404

Closed
Silic0nS0ldier wants to merge 1 commit intobazelbuild:masterfrom
Silic0nS0ldier:strict-repo-env
Closed

Add --experimental_strict_repo_env option#24404
Silic0nS0ldier wants to merge 1 commit intobazelbuild:masterfrom
Silic0nS0ldier:strict-repo-env

Conversation

@Silic0nS0ldier
Copy link
Copy Markdown
Contributor

@Silic0nS0ldier Silic0nS0ldier commented Nov 20, 2024

This PR introduces a new flag --experimental_strict_repo_env which stops repository rules and module extensions from inheriting the client environment (making --repo_env=NAME more than just an advisory notice).

When enabled up to 2 environment variables will still be forwarded (unless overridden or explicitly removed via --repo_env==VARNAME, see #26300 for more details);

  • PATH - All platforms
  • PATHEXT - Windows

See test_execute_environment_strict_vars in src/test/shell/bazel/starlark_repository_test.sh for a demonstration.

Note that the behavior is different to the similarly named --incompatible_strict_action_env, which stops all environment variables (--action_env affects actions with use_default_shell_env = True) except those specified within the defining rule. This is by design as repository rules operate in an inherently non-hermetic domain, covering roles such as integrating with the C/C++ toolchain installed on the host. It does not make sense to lock down environment variables by default, this is best left up to individual projects and users.

This flag is marked experimental to allow for testing and requirement discovery (e.g. env vars other than PATH that should be included).

Closes #10996

@Silic0nS0ldier Silic0nS0ldier marked this pull request as ready for review November 20, 2024 03:11
@github-actions github-actions bot added team-ExternalDeps External dependency handling, remote repositiories, WORKSPACE file. awaiting-review PR is awaiting review from an assigned reviewer labels Nov 20, 2024
@Silic0nS0ldier
Copy link
Copy Markdown
Contributor Author

The CI failure flushed out a potential bug. --repo_env=NAME results in reading values from the server process with System.getenv when clientEnv.get should have been used.

With this issue, any changes to NAME in the client environment won't propagate until the server restarts.

@fmeum
Copy link
Copy Markdown
Collaborator

fmeum commented Nov 21, 2024

With this issue, any changes to NAME in the client environment won't propagate until the server restarts.

Could you split the fix into a separate PR? That would make it easier to cherry-pick into patch releases and Bazel 8.

Since --strict_repo_env will require users to allowlist env variables, I think that we should also ignore --action_env for repo rules when the flag is enabled. Otherwise users migrating to the flag may accidentally hurt their cache hit ratio and require another migration down the line.

@Silic0nS0ldier
Copy link
Copy Markdown
Contributor Author

Stale environment issue split to #24433 (this PR is dependent on the fix for tests to pass, so I'll leave it here as well and rebase once merged).

@Silic0nS0ldier
Copy link
Copy Markdown
Contributor Author

Since --strict_repo_env will require users to allowlist env variables, I think that we should also ignore --action_env for repo rules when the flag is enabled. Otherwise users migrating to the flag may accidentally hurt their cache hit ratio and require another migration down the line.

My initial thoughts were to keep this as a project preference, since currently many repository rules are heavily influenced by the host environment (sometimes intentionally). But if this change is being viewed as something to move towards, it may make sense to classify this as an incompatible change like with --incompatible_strict_action_env to signify a potential flip in a later release.


On a related note, there are a few places that use the "old" repo environment in src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java.

  1. The vendor command (used in downloader).
  2. The registry (bzlmod) factory (used in downloader).

And for sake of completion, the client environment is directly used in these places.

  1. The credential helpers. Used in many places, including remote execution/caching.
  2. The download manager (one of the instances at least...).
  3. SpawnAction and ExtraAction instances (most likely used for --action_env=NAME). Usage unfortunately allows for some ambiguity.
  4. The volatile input map (date format via SOURCE_DATE_EPOCH).
  5. The standalone test strategy (for ${inherited} which I'm not familiar with).
  6. The symlink tree strategy helper (for symlink creation via a separate process).
  7. WriteAdbArgsAction action, for user home directory (HOME).
  8. CppCompileAction spawn.
  9. JavaCompileAction spawn.
  10. The "run" command (what you'd expect and as part of configuring test environment emulation).
  11. MobileInstallCommand subprocess. Running the mobile-install deployer.
  12. Passed into SkyframeExecutor (which likely ultimately is the source for most other things listed here).
  13. The sandboxing spawn strategies (via special env provider).
  14. The local spawn strategy (as above).
  15. The worker spawn strategy (as above).

The only spot of concern for me here is the download manager. Seems like in its current state, this PR may introduce some fragmentation (though such fragmentation would have already been possible with --repo_env, the new flag just makes it much more substantial).

@Silic0nS0ldier Silic0nS0ldier requested a review from a team as a code owner November 21, 2024 11:39
@Silic0nS0ldier Silic0nS0ldier requested review from aranguyen and removed request for a team November 21, 2024 11:39
@fmeum
Copy link
Copy Markdown
Collaborator

fmeum commented Nov 21, 2024

Thanks for compiling this list, I'll have to think about this more.

Since some repo rules do depend on the environment quite heavily, have you considered making this behavior configurable on the repository_rule call instead?

@Silic0nS0ldier
Copy link
Copy Markdown
Contributor Author

Since some repo rules do depend on the environment quite heavily, have you considered making this behavior configurable on the repository_rule call instead?

No, but only because I didn't think to.

I'm not sure what such an API would look like. There is repository_rule(..., environ = [...]) (to mark variables that will trigger a refetch) however that is deprecated in favor of repository_ctx.getenv. The same cannot be said for module_extension(..., environ = [...]) strangely.

Some questions (not necessarily directed at anyone, just to help with ideation).
Should this be implemented as a binary switch that limits variables to only those explicitly listed by --repo_env? Should they be able to give a strict list of env inputs? What of the existing dynamic dependency mechanism (.getenv)? Should --strict_repo_env be a part of the design, as a way to change default environment variable inclusion behavior? Should there be any default inclusions (like PATH) and should rules be able to opt into a completely bare environment?

Looking even further beyond this, a case could even be made for sandboxing certain repository rules. The download repos created by npm_translate_lock (Rules JS) come to mind, although such repos could hypothetically be implemented with a special "download action" (to allow cache hits with few/no downloads) or more likely a slightly different design to be compatible with vendoring. This is all well outside beyond the scope here though.

@peakschris
Copy link
Copy Markdown

Keenly awaiting this one, thank you for this work 👍

@Silic0nS0ldier
Copy link
Copy Markdown
Contributor Author

What I'm currently thinking here is;

  • PATH is always inherited.
  • PATHEXT is always inherited on Windows (affects PATH lookup).
  • --repo_env can override the latter and apply to all.
  • environ (argument) and getenv can pull in additional env vars from the client env.
  • environ (attribute) no longer works as a way to peak at the environment without making it a tracked dependency.

That represents a fairly significant expansion vs. the original scope, something that ought to go through the proposal process first.

That all said, I do have a need to fully lock-down the repo environment (an extreme that is not suited to all) and would rather not leave this in limbo. So here is my plan;

  1. Incompatible flag to disable --[host_]action_env=NAME=VALUE side effect.
  2. Flag to make repo env explicit (not layer over the client env).
  3. (eventually) A proposal for env management. Maybe repo focused, maybe more.

@peakschris
Copy link
Copy Markdown

This looks great! I did have one query:

environ (argument) and getenv can pull in additional env vars from the client env.

With --strict_repo_env enabled, will environ(argument) allow repo rules to pull in additional env vars that have not been 'permitted' via --repo_env?

copybara-service bot pushed a commit that referenced this pull request Jun 4, 2025
This adds a new flag `--incompatible_repo_env_ignores_action_env` which when flipped stops `--action_env=NAME=VALUE` from affecting repository rule and module extension environments.

Split from #24404.

Closes #25238.

PiperOrigin-RevId: 767031987
Change-Id: I1683935ab2728f6bbfcf499ea8a598770002020d
bazel-io pushed a commit to bazel-io/bazel that referenced this pull request Jun 4, 2025
This adds a new flag `--incompatible_repo_env_ignores_action_env` which when flipped stops `--action_env=NAME=VALUE` from affecting repository rule and module extension environments.

Split from bazelbuild#24404.

Closes bazelbuild#25238.

PiperOrigin-RevId: 767031987
Change-Id: I1683935ab2728f6bbfcf499ea8a598770002020d
@peakschris
Copy link
Copy Markdown

We are being impacted by this (we have tools that modify the current shell environment, and they are invalidating our builds), so I wondered if you would update on plans?

In the meantime, is there any workaround, other than wrapping all bazel calls in a wrapper that sanitizes the environment?

github-merge-queue bot pushed a commit that referenced this pull request Jun 10, 2025
This adds a new flag `--incompatible_repo_env_ignores_action_env` which
when flipped stops `--action_env=NAME=VALUE` from affecting repository
rule and module extension environments.

Split from #24404.

Closes #25238.

PiperOrigin-RevId: 767031987
Change-Id: I1683935ab2728f6bbfcf499ea8a598770002020d

Commit
216ae9d

Co-authored-by: Jordan Mele <jordan.mele@outlook.com.au>
@Silic0nS0ldier
Copy link
Copy Markdown
Contributor Author

For those interested in this change, #26300 may also be of interest.

@keith
Copy link
Copy Markdown
Member

keith commented Sep 10, 2025

I would still love to see this land pre 9.0

@Silic0nS0ldier Silic0nS0ldier force-pushed the strict-repo-env branch 2 times, most recently from 9d8285c to 06a5aa7 Compare October 5, 2025 12:37
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces the --experimental_strict_repo_env flag to control environment variable inheritance for repository rules and module extensions. When enabled, only PATH, PATHEXT (on Windows), and variables explicitly specified via --repo_env are inherited, improving build hermeticity while maintaining necessary environment access for repository operations.

Key Changes

  • Added --experimental_strict_repo_env command-line flag to enable strict environment filtering
  • Separated environment variable handling into repoEnvFromOptions (filtered set) and repoEnv (full set) in CommandEnvironment
  • Updated repository and module extension code to accept both repository-specific and client environment variables, using the appropriate set based on the flag

Reviewed Changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/main/java/com/google/devtools/build/lib/runtime/CommonCommandOptions.java Adds the new --experimental_strict_repo_env option definition and documentation
src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java Implements environment variable filtering logic, tracking default inherited vars (PATH, PATHEXT) in repoEnvFromOptions
src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java Wires up the repo environment supplier to use filtered or full environment based on flag state
src/main/java/com/google/devtools/build/lib/bazel/repository/RepositoryFetchFunction.java Adds repoEnvironmentSupplier parameter to support environment filtering
src/main/java/com/google/devtools/build/lib/bazel/bzlmod/SingleExtensionEvalFunction.java Adds repoEnvironmentSupplier parameter for module extension environment handling
src/main/java/com/google/devtools/build/lib/bazel/bzlmod/RegularRunnableExtension.java Updates to pass through repo environment supplier for extension execution
src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleExtensionContext.java Accepts separate repo and client environment variables
src/main/java/com/google/devtools/build/lib/bazel/repository/starlark/StarlarkRepositoryContext.java Updated to use separate repoEnvVariables and clientEnvVariables parameters
src/main/java/com/google/devtools/build/lib/bazel/repository/starlark/StarlarkBaseExternalContext.java Refactors environment variable handling, renaming for clarity and using appropriate environment for different operations
src/main/java/com/google/devtools/build/lib/starlarkbuildapi/repository/RepositoryModuleApi.java Updates documentation to reference the new flag and marks module extension environ parameter as deprecated
src/test/shell/bazel/starlark_repository_test.sh Adds test validating strict environment behavior with default and explicit variables
src/test/java/com/google/devtools/build/lib/skyframe/*.java Updates test infrastructure to pass both environment suppliers to functions
src/test/java/com/google/devtools/build/lib/bazel/repository/*.java Updates test setup to provide both repo and client environment variables
src/test/java/com/google/devtools/build/lib/bazel/bzlmod/*.java Updates test infrastructure for new constructor signatures
src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisMock.java Updates mock setup with dual environment suppliers
src/main/java/com/google/devtools/build/lib/skyframe/packages/BazelPackageLoader.java Updates to provide both environment suppliers to repository fetch function

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Member

@meteorcloudy meteorcloudy left a comment

Choose a reason for hiding this comment

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

Thanks, looks good, just a few minor comments from me and Copilot

@peakschris
Copy link
Copy Markdown

Would it be possible to get this in 8.x?

@meteorcloudy
Copy link
Copy Markdown
Member

meteorcloudy commented Nov 19, 2025

We don't want to delay 8.5 release any further so will mark this one for later 8.x minor release.

@meteorcloudy meteorcloudy added the potential 8.x cherry-picks Potential cherry-picks for the next 8.x release. We'll consider a new 8.x release if enough issues g label Nov 19, 2025
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@meteorcloudy meteorcloudy added awaiting-PR-merge PR has been approved by a reviewer and is ready to be merge internally and removed awaiting-review PR is awaiting review from an assigned reviewer labels Nov 21, 2025
@github-actions github-actions bot removed the awaiting-PR-merge PR has been approved by a reviewer and is ready to be merge internally label Nov 25, 2025
bazel-io pushed a commit to bazel-io/bazel that referenced this pull request Nov 25, 2025
This PR introduces a new flag `--experimental_strict_repo_env` which stops repository rules and module extensions from inheriting the client environment (making `--repo_env=NAME` more than just an advisory notice).

When enabled up to 2 environment variables will still be forwarded (unless overridden or explicitly removed via `--repo_env==VARNAME`, see bazelbuild#26300 for more details);
- `PATH` - All platforms
- `PATHEXT` - Windows

See `test_execute_environment_strict_vars` in `src/test/shell/bazel/starlark_repository_test.sh` for a demonstration.

Note that the behavior is different to the similarly named `--incompatible_strict_action_env`, which stops _all_ environment variables (`--action_env` affects actions with `use_default_shell_env = True`) except those specified within the defining rule. This is by design as repository rules operate in an inherently non-hermetic domain, covering roles such as integrating with the C/C++ toolchain installed on the host. It does not make sense to lock down environment variables _by default_, this is best left up to individual projects and users.

This flag is marked experimental to allow for testing and requirement discovery (e.g. env vars other than `PATH` that should be included).

Closes bazelbuild#10996

Closes bazelbuild#24404.

PiperOrigin-RevId: 836494750
Change-Id: Ic05e5ca47a14badb2cd23f810e775c3341ddfaa8
github-merge-queue bot pushed a commit that referenced this pull request Nov 25, 2025
This PR introduces a new flag `--experimental_strict_repo_env` which
stops repository rules and module extensions from inheriting the client
environment (making `--repo_env=NAME` more than just an advisory
notice).

When enabled up to 2 environment variables will still be forwarded
(unless overridden or explicitly removed via `--repo_env==VARNAME`, see
#26300 for more details);
- `PATH` - All platforms
- `PATHEXT` - Windows

See `test_execute_environment_strict_vars` in
`src/test/shell/bazel/starlark_repository_test.sh` for a demonstration.

Note that the behavior is different to the similarly named
`--incompatible_strict_action_env`, which stops _all_ environment
variables (`--action_env` affects actions with `use_default_shell_env =
True`) except those specified within the defining rule. This is by
design as repository rules operate in an inherently non-hermetic domain,
covering roles such as integrating with the C/C++ toolchain installed on
the host. It does not make sense to lock down environment variables _by
default_, this is best left up to individual projects and users.

This flag is marked experimental to allow for testing and requirement
discovery (e.g. env vars other than `PATH` that should be included).

Closes #10996

Closes #24404.

PiperOrigin-RevId: 836494750
Change-Id: Ic05e5ca47a14badb2cd23f810e775c3341ddfaa8

Commit
60bc017

Co-authored-by: Jordan Mele <jordan.mele@outlook.com.au>
aranguyen pushed a commit to aranguyen/bazel that referenced this pull request Nov 26, 2025
This PR introduces a new flag `--experimental_strict_repo_env` which stops repository rules and module extensions from inheriting the client environment (making `--repo_env=NAME` more than just an advisory notice).

When enabled up to 2 environment variables will still be forwarded (unless overridden or explicitly removed via `--repo_env==VARNAME`, see bazelbuild#26300 for more details);
- `PATH` - All platforms
- `PATHEXT` - Windows

See `test_execute_environment_strict_vars` in `src/test/shell/bazel/starlark_repository_test.sh` for a demonstration.

Note that the behavior is different to the similarly named `--incompatible_strict_action_env`, which stops _all_ environment variables (`--action_env` affects actions with `use_default_shell_env = True`) except those specified within the defining rule. This is by design as repository rules operate in an inherently non-hermetic domain, covering roles such as integrating with the C/C++ toolchain installed on the host. It does not make sense to lock down environment variables _by default_, this is best left up to individual projects and users.

This flag is marked experimental to allow for testing and requirement discovery (e.g. env vars other than `PATH` that should be included).

Closes bazelbuild#10996

Closes bazelbuild#24404.

PiperOrigin-RevId: 836494750
Change-Id: Ic05e5ca47a14badb2cd23f810e775c3341ddfaa8
@Silic0nS0ldier
Copy link
Copy Markdown
Contributor Author

Any chance of backporting this to 8.6.0? Given it didn't make the cut for 8.5.0?

@fmeum
Copy link
Copy Markdown
Collaborator

fmeum commented Jan 7, 2026

If we backport this, we should also backport #28168.

@Silic0nS0ldier
Copy link
Copy Markdown
Contributor Author

Yikes. I'm surprised --incompatible_repo_env_ignores_action_env (#25238) and --experimental_strict_repo_env (this) caused an issue. I thought CommandEnvironment (where these are handled) was sufficiently disconnected from Skyframe, such that changes would have triggered invalidations.

@Wyverald
Copy link
Copy Markdown
Member

Wyverald commented Jan 8, 2026

@bazel-io fork 8.6.0

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

Labels

potential 8.x cherry-picks Potential cherry-picks for the next 8.x release. We'll consider a new 8.x release if enough issues g team-Configurability platforms, toolchains, cquery, select(), config transitions team-ExternalDeps External dependency handling, remote repositiories, WORKSPACE file.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

strict_action_env equivalent for repository rules

9 participants