The package manager in GitHub Actions might be the worst package manager in use today: https://nesbitt.io/2025/12/06/github-actions-package-manager.html
The package manager in GitHub Actions might be the worst package manager in use today: https://nesbitt.io/2025/12/06/github-actions-package-manager.html
@andrewnez thank you for documenting all of this. The scope of the problem, and GH’s lack of addressing it despite being reported, is horrifying. Very relieved to see gitlab understands the issue and has put in some reasonable mitigation and warnings.
@andrewnez cargo has such a vast degree of the problems you correctly assign to github actions and it is very specifically because any of the guarantees cargo provides for itself are completely unavailable to any build script. this means shared mutability retrofitted onto a subdir of ~/.cache and that is actually the best possible case. cargo specifically is the reason rustc remains so difficult to bootstrap because you absolutely 100% cannot send the output of one build script to another without shared mutable state
@andrewnez a lockfile is only as trustworthy as the things it had control over and with cargo that means checksums of source tarballs and even source checkouts aren't immutable. you absolutely can access the filesystem location cargo caches you in and use that as a release-specific mutable cache for your build script. no one has to know!
@andrewnez i think there's a slippage of terminology here too:
The core problem is the lack of a lockfile. Every other package manager figured this out decades ago: you declare loose constraints in a manifest, the resolver picks specific versions, and the lockfile records exactly what was chosen.
for one, the resolver is only as powerful as the constraints. if your constraints are limited to name and simple version matching, then a lockfile is indistinguishable from a manifest—we see this from pip freeze, which is actually quite notable for not being a lockfile.
@andrewnez python has per-platform and per-python-version constraints, for which you'll need something like pip install --report to get a "locked" experience. that feature was a generalization of my work here https://github.com/pantsbuild/pants/pull/8793 which was able to lazy-load python requirements upon execution.
the poetry package manager has a truly fascinating system where it resolves a dependency tree across several target platforms at once. it's able to do this though because python packaging protocols have had a lot of people caring about them for many years.
@andrewnez Yikes, it's worse than I thought. Thanks for the writeup.
Maybe they'll get around to fixing things after the AI bubble bursts... ?
@andrewnez sometime I feel all these github action should have been just a python/bash script...
especially when you need 100 commits to get it right and had to trust the code of 2-4 contributors/organisations to do so.
this would make more sense to me : https://docs.astral.sh/uv/guides/scripts/#declaring-script-dependencies
with https://github.com/astral-sh/uv/issues/6318