| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Description:
I saw that actions/setup-python added a new input, pip-install, with version 6.1.0 (in #1201).
This appears to be the core of the change:
setup-python/src/setup-python.ts
Lines 26 to 37 in 83679a8
| async function installPipPackages(pipInstall: string) { | |
| core.info(`Installing pip packages: ${pipInstall}`); | |
| try { | |
| const installArgs = pipInstall.trim().split(/\s+/); | |
| await exec('python', ['-m', 'pip', 'install', ...installArgs]); | |
| core.info('Successfully installed pip packages'); | |
| } catch (error) { | |
| core.setFailed( | |
| `Failed to install pip packages from "${pipInstall}". Please verify that the package names, versions, or requirements files provided are correct and installable, that the specified packages and versions can be resolved from PyPI or the configured package index, and that your network connection is stable and allows access to the package index.` | |
| ); | |
| } | |
| } |
Unfortunately, I think any widespread usage of this input is going to cause significant negative effects:
Justification:
Per above: explicitly encouraging users to do global-state package installations like this is going to cause a lot of confusing error messages for people with Python codebases. It's also a step backwards in terms of dependency auditability/discoverability.
Are you willing to submit a PR?
Yes, I'd be happy to send a PR reverting this.
| Back | FazBrowse Home | New Git URL |
Activity
woodruffw commented on Dec 1, 2025
Also, for context: I believe the only reason this actually works at the moment is because of a "temporary workaround" in the Linux runner images themselves: actions/runner-images#10794
Once that workaround is removed (which it should be, because it's roughly as dangerous in terms of breakage as this change), this action input will stop working (since pip will refuse to install into an externally-managed environment).
v-priyagupta108 commented on Dec 2, 2025
Hi @woodruffw 👋,
Thank you for the feature request. We'll investigate it and get back to you as soon as we have updates.
v-aparnajyothi-y commented on Dec 16, 2025
Hello @woodruffw, thanks for raising this and for outlining the security considerations. We really appreciate the clarity here. We took a closer look at this as part of the investigation for this issue.
The current behavior is intentional. The pip-install input was introduced as an opt-in feature to offer flexibility without impacting existing workflows. By keeping it optional, users who need a quick setup of packages or work with ephemeral runners can leverage this convenience, while workflows that require strict reproducibility, isolation, or auditability remain completely unaffected. This design helps balance convenience with safety, giving advanced users the flexibility they need without introducing unintended risks for the broader ecosystem.
As part of the investigation, we also validated this behavior across different runner types:
On GitHub-hosted runners, and on self-hosted runners where actions/setup-python installs its managed Python distribution, the action operates on a Python environment that it owns and controls (not the system Python). This environment does not include the EXTERNALLY-MANAGED marker defined by PEP 668, so pip-install works as expected. please find the screenshots for reference
The primary exception is Ubuntu 24+ environments that rely on the system Python (/usr/bin/python3). In these cases, PEP 668 is enforced by the operating system, and pip correctly refuses to install packages into an externally managed environment. If the temporary workaround on the runner images is removed, direct pip install calls including those triggered via the pip-install input will be blocked by design.
In other words, pip-install is expected to work consistently on all runners where the Python runtime is managed by actions/setup-python, and may be ignored only when workflows intentionally or implicitly use a system-managed Python that enforces PEP 668 (notably Ubuntu 24+).
If it helps, we can expand the documentation with guidance along the following lines to better set expectations for opting into this feature:
Note: The pip-install input installs Python packages directly into the runner’s Python environment managed by actions/setup-python. These packages may not be visible inside isolated virtual environments used in later steps.For production workflows, we strongly recommend installing dependencies within virtual environments and using lockfiles (for example, requirements.txt, poetry.lock) to ensure consistent, deterministic, and auditable builds.
Please feel free to reach out if you have further concerns or would like to discuss this in more detail and happy to continue the conversation :)
woodruffw commented on Dec 16, 2025
Hi @aparnajyothi-y, thanks for the response.
To be clear: I'm not saying the behavior is unintentional, I'm saying that it's intentional and wrong. Python's packaging standards and standard tooling are pretty clear about the risk of installing directly into global environments, even on ephemeral runners. It's my opinion that GitHub's actions ecosystem should be a leading example of doing Python (and other language ecosystem) packaging correctly and in a standards-conformant matter, not a source of inertia/friction. Encouraging people to do global installs via a pip-install option does the opposite of that.
(This is not principally a security concern either, to be clear: it's purely a matter of doing something that Python packaging standards increasingly consider unacceptable and unsupported, meaning that even if you consider it supported, Python's standard tooling is increasingly likely to break it on your behalf.)
TL;DR: You're right that this won't appear to break anything on GitHub-managed Python installations, because you're dropping the EXTERNALLY-MANAGED marker. However, that appearance is because you're explicitly removing the guardrails that Python packaging has standardized to prevent dependency hell. In other words: you're deferring the breakage to users themselves, where it's less obvious what went wrong (and gets redirected to tools like pip instead, which have no way to fix it). The correct thing to do is forbid global environment modification, or at least not make it as easy as possible with new inputs.
If you're intent on keeping this functionality, then a warning that this input can cause resolution breakage would be good. I think your current proposed warning unfortunately doesn't state this strongly enough: the problem isn't that the dependencies may not be visible, but that they may be visible to individual environments and thus change Python package version resolution in difficult to diagnose and reproduce ways.
v-aparnajyothi-y commented on Jan 14, 2026
Hello @woodruffw, Thanks for the detailed clarification, @woodruffw. we understand and respect the position you’re taking here.
We agree that Python packaging standards are increasingly explicit about discouraging global environment modification, and we don’t intend pip-install to represent a best-practice or recommended workflow. It’s an opt-in convenience intended for narrow CI scenarios where the Python runtime is fully managed by setup-python, and not for production or reproducible dependency management.
We also acknowledge the dependency on current runner behavior, and the point that removing guardrails can defer breakage to users. Based on this feedback, we agree the documentation should be strengthened to more clearly warn about potential resolution breakage and standards alignment not just visibility concerns.
We’ll continue to evaluate whether additional guardrails or constraints are appropriate here, while coordinating with runner-images behavior to avoid surprising users.
woodruffw commented on Jan 14, 2026
Thanks for your detailed response @aparnajyothi-y.
I find it unintuitive that setup-python, as the primary gateway for Python on one of the world's largest CI/CD platforms, wouldn't want to adhere to best practices, particularly in newly added features. I also think the unfortunate reality is that people will use this feature in production contexts, because the presence of such a feature in setup-python conveys an official/mature status that documentation alone will struggle to correct for.
With that said, I understand that you have compatibility constraints that mean you can't just undo this change. However, I really do hope that you consider deprecating and removing it in a future major release, as Python packaging itself will almost certainly allow any lingering support for this pattern to continue to atrophy.
(In the mean time, those documentation changes would indeed be great, thank you for acknowledging them.)
nathanblair commented on Jan 27, 2026
I don't think this is even working as expected.
I have
- name: Setup Python uses: actions/setup-python@v6 with: pip-install: dotenvAs a step in a workflow. When I try to run a simple python script to
I get the error
Traceback (most recent call last): File "/home/runner/_work/org/repo/./tool", line 20, in <module> from dotenv import find_dotenv, load_dotenv, set_key, get_key ModuleNotFoundError: No module named 'dotenv'If its not immediately clear where pip-install is installing packages or even what additional steps are necessary to consume those installed packages, in addition to being against the grain of modern python packaging practices, I'm not sure what value this option is really providing.
v-gowridurgad commented on May 11, 2026
Hi @nathanblair, We've investigated this and found that the Python version is missing from the workflow, which is causing the problem.
The pip-install input only works when a Python version is being installed by the action. The feature needs to run python -m pip install against a known, controlled Python environment. If a Python version is not specified in the workflow, the action skips the Python installation process and silently ignores the pip-install input, resulting in packages never being installed and the ModuleNotFoundError.
To resolve this, add the python-version input to the setup step:
- name: Setup Python uses: actions/setup-python@v6 with: python-version: ‘3.12’ pip-install: dotenvWe tested this configuration and confirmed that dotenv installs correctly using the pip-install input when a Python version is specified. Attached is a screenshot for reference.
Additionally, we acknowledge the limitations raised regarding this feature, including concerns around dependency tracking, security tool visibility, and alignment with modern Python packaging practices. We will be updating our documentation to better communicate these important limitations to help users make informed decisions about when this feature is appropriate for their workflows.
v-gowridurgad commented on Jul 8, 2026
Hi @woodruffw, thanks for raising this and for the detailed discussion here. Considering all the concerns discussed, we have decided to remove the pip-install input support and have raised PR #1336 for that change. Since this is a breaking change, the removal is planned for an upcoming major release.
4 remaining items
v-gowridurgad commented on Jul 23, 2026
Hi @MichaIng, thanks for sharing the use case and the additional context. We understand that pip-install was convenient for quickly provisioning tools in disposable CI environments, and we recognize that its removal means some workflows now need to be updated.
That said, based on the broader community feedback and the concerns raised around global installation behavior, we already removed pip-install and we’re not planning to restore it.
If you still need that behavior, please continue using v6. Otherwise, please use pip install explicitly in your workflow.
woodruffw commented on Jul 27, 2026
#1336 is merged, so I think my request here is finished.
Thanks a ton!
MichaIng commented on Jul 29, 2026
@gowridurgad
I know it is too late now, and the feature of course was nothing essential, just allowed a minor simplification for something which can be done with a single additional line/step. So I do not ask for reverting it back in, and wouldn't find it reasonable now either. However, let me express why I think this feedback loop was very odd, which might be relevant for future decisions, in general and around this EXTERNALLY-MANAGED marker in general:
In most of my workflows, I do not even create any venv, but just install the tool I need to use, like pyspelling or such, via pip directly into the runner's user environment. Reproducability for the pyspelling installation (anyway as pre-compiled wheel from PyPI) does not matter. For such cases, pip-install was a neat simplification, and totally legit and safe to use.
And if I see this all wrong, and there are better arguments against module installs into the runner user environment, then pip must not be installed at all, but instead venv (optionally virtualenv) only, which installs pip into created venvs by default. Or setup-python could create and activate a venv directly, which would have been another way to keep pip-install in place, without needing to deal with EXTERNALLY-MANAGED. The situation now is inconsistent.
mara004 commented on Jul 29, 2026
If I may add my two cents, the actual root issue here is that distributions haven't yet managed to make a user-level venv or similar the default installation mode. Related ideas were actually outlined in PEP 668 itself, sec. "System Python", but introducing the "externally managed" marker had been considered justified independent of these considerations.
While that is understandable and correct, the effect that distributors just set EXTERNALLY-MANAGED and call it a day instead of setting up things properly and fixing any issues that need to be fixed in order to enable this approach is unfortunate all the same.
MichaIng commented on Jul 29, 2026
And in how far does this add to an argument against runner user level package installs in GitHub Actions?
mara004 commented on Jul 29, 2026
Because it is altogether wrong to ever install packages in a way that affects system programs unless that is your actual objective.
MichaIng commented on Jul 29, 2026
But the runner user Python environment does not affect system programs. And again, these are temporary build/test systems altogether, reset after every run. AFAIK there are not even Python programs running in any system service of these runner images. Basically what I said in my 2. point.
mara004 commented on Jul 29, 2026
I'm afraid it does. That's what causes all this mess. Please read PEP 668.
MichaIng commented on Jul 29, 2026
PEP 668 is explicitly about OS distribution packages. setup-python does not touch those or any Python environment in the system search path or anything below /usr and /lib. The Python instance's primary environment is at /opt/hostedtoolcache/Python/3.*/x64/lib/python3.*/site-packages, and pip install installs packages to /home/runner/.local/lib/python3.*/site-packages/.
mara004 commented on Jul 29, 2026
I'm guessing it may indeed be harmless if the python versions don't match up. Good point.
If it's the same version though, user site-packages are bound to affect system programs.
MichaIng commented on Jul 29, 2026
I mixed up "system service" (which would never pick up any of those environments or the Python instance itself, unless manually created to explicitly do so), and "system program", i.e. a Python CLI tool in PATH.
So yes, for CLI tools, this is theoretically possible:
Is there an actual case where this caused issues? Pretty unrealistic that someone would install Python dependencies via pip as runner user, but a Python tool via apt as root, in a GitHub Actions workflow, without knowing that one affects the other. And this theoretical case has not been raised by OP here, instead 2 points which are simply false or do not apply in the context of setup-python. And the point with uv is even more confusing, as it can consider and install into system and user environments just like pip via --system and --user flags. Of course it respects EXTERNALLY-MANAGED as well just like pip. Again, this is no Python/tool-side enforcement, but an optional enforcement from distros.
EDIT: Btw, does someone know whether pip-install installed packages to /opt/hostedtoolcache/Python/3.*/x64/lib/python3.*/site-packages or /home/runner/.local/lib/python3.*/site-packages? Has only minor relevancy now, but could have been some hardening against above issue, since any Python tool installed via apt uses /usr/lib/python3 explicitly (not /opt/hostedtoolcache/Python/3.*/x64/bin/python3), hence wouldn't consider /opt/hostedtoolcache/Python/3.*/x64/lib/python3.*/site-packages at least.
dalcinl commented on Jul 30, 2026
Folks, what if we instead go for a feature request such that the following
will create virtual environment, install packages (if the input value is not empty), and then activate the venv? The first part is trivial (modulo deciding the venv location), the second part is just pip install, the last part is just adjusting PATH and adding VIRTUAL_ENV to the runner environment.
This is an feature be trivially provided by the community in a new action. However, the task is so frequent that IMHO it would make total sense for the feature to be provided by actions/setup-python.
mara004 commented on Jul 30, 2026
If there is one lesson learned from this thread, I believe such options are just wrong, even if it's a venv.
You're delegating control to another action, and if that action's inputs or their processing change, things may break, causing you extra work, or you may want additional control over the venv creation and installation process that the virtual-environment harness you're suggesting would not provide.
venv creation & package installation is trivially doable on your own in a step.
This is transparent: it is immediately clear where the venv is created, under what name, and which options are used.
A harness option is just plain intransparent.
MichaIng commented on Jul 30, 2026
Agreed, pip-install was the quick&dirty way to skip/merge a separate step in the workflow, when really just needing a particular package/tool to do something else, where you explicitly do not need the control and reproducability of a venv. It felt somehow natural, to extend just the very environment setup-python creates/manages. If you need a venv at all, you often want more control. So people would likely then ask for a venv-path and venv-flags option, and at some point one needs to ask what the benefit of learning (and maintaining) a full 1:1 wrapper is.
It would have made sense as a way to rescue the pip-install option, when taking the arguments raised here serious. But that is now too late.
Consequently, if these arguments are taken serious, it would make more sense to remove pip entirely (including pre-installed python3-pip, python3-setuptools, /etc/pip.conf etc) from the runner images and the hostedtoolcache, and instead setup a venv automatically with setup-python. That way, workflows which use plain pip after setup-python would remain functional. It would be still possible to create and use another venv, so those workflows which do that now would remain functional, too, but could be simplified. I'm not voting for this without external pressure, but the current situation seems inconsistent and contradicting: removing pip-install to encourage people using venv, while keeping python3-pip at system level, pip at runner user level, and /etc/pip.conf with break-system-packages. If people in charge decide that this is all wrong, despite the counter-arguments I raised above, then I'd at least strongly vote for everything possible to keep existing workflows functional, by auto-creating + activating a venv without the need to set any additional option.