Repository navigation
fix: do not let elan-init modify the runner's persistent PATH - #189
Merged
austinletson merged 2 commits intoOct 12, 2026
Merged
Conversation
`install_elan.sh` already puts `$HOME/.elan/bin` on `$GITHUB_PATH`, so the additional persistent-environment edit elan-init performs by default is redundant on GitHub-hosted runners and harmful on self-hosted ones. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Collaborator
|
Thanks for the fix! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
scripts/install_elan.shruns the elan installer on every job without--no-modify-path:curl https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh -sSf | sh -s -- -y --default-toolchain noneTwo lines later the same script does the thing GitHub Actions actually wants:
So
lean-actionis already responsible for makingleanandlakeresolve inlater steps, and the persistent-environment edit elan-init performs on top of
that is redundant. On GitHub-hosted runners it is harmless, because the VM is
discarded. On self-hosted runners it is not: it permanently mutates the account
that runs the jobs.
What the default does on Windows
do_add_to_pathin elan opensHKCU\Environment, prepends$ELAN_HOME\binto
PATH, writes it back asREG_EXPAND_SZand broadcastsWM_SETTINGCHANGE.no_modify_pathis a clap flag insrc/elan-cli/setup_mode.rsand is read fromnowhere else, so there is no environment variable a runner operator can set to
opt out. Setting
ELAN_HOMEdoes not help either — it only changes which pathgets written.
On Linux and macOS the same default appends an
export PATH=...line to~/.profile(and~/.bash_profile/~/.zprofilewhen present), so self-hostedrunners there have a smaller version of the same problem.
Why it matters on self-hosted runners
Concretely, on a Windows box running four self-hosted runners, each with its own
ELAN_HOMEso that concurrent jobs do not contend over one toolchain:Every job prepends
C:\actions-runner\<runner>\.elan\binto the operator'suser
PATH. Because elan prepends, those entries land ahead of theoperator's own
~\.elan\bin.An interactive
lakethen resolves to a runner's shim, and.elan\bin\lake.exestays open for the duration of that build.elan installs its shims as hardlinks to a single
elan.exe, and the next jobon that runner re-runs the installer, which tries to recreate the link set.
Windows will not relink a running image, so the job fails about 24 seconds in
with:
That posts a red required check on whatever PR happened to be queued.
The operator cannot fix this from their side: stripping the entries only lasts
until the next job re-adds them,
ELAN_HOME/HOMEdo not suppress the write,and reordering
PATHdoes not help because elan prepends.The change
Pass
--no-modify-path. The flag is accepted byelan-init.sh, which forwardsits arguments verbatim to the downloaded binary.
Nothing in the action depends on the behaviour being removed:
install_elan.shinvokes
lean/lakeby absolute path within its own step, and every laterscript (
config.sh,lake_build.sh, …) calls barelake/elan, which resolvethrough the
$GITHUB_PATHentry this script writes.Verification
On Windows, against current elan, with a throwaway
ELAN_HOME:--no-modify-path:HKCU\Environment\PATHgains the$ELAN_HOME\binentry at position 1.--no-modify-path: elan installs normally (lean --versionandlake --versionboth succeed) andHKCU\Environment\PATHis byte-identicalbefore and after.
Notes
No functional test is added. The behaviour this removes is invisible on
GitHub-hosted runners by construction, so a test would only re-assert that
leanandlakestill resolve in later steps — which the existing functionaltests already cover, and which is the actual regression risk here. Happy to add
a Windows test that snapshots
HKCU\Environment\PATHacross the action if youwould like one.