CI: update actions - #879
Conversation
|
This patch has been generated with this thing https://github.com/dnicolodi/update-github-actions I always thought that things like dependabot are more of a liability than a resource and I wondered how difficult it would be to write a script that does the same thing locally. Turns out it is quite easy and I am very surprised that something similar does not exist yet. This implementation is very crude, but it works. |
c7a5e89 to
5d0417f
Compare
6392975 to
064fdc3
Compare
064fdc3 to
db86480
Compare
The flop [sic] side of this is that in exchange for getting rid of the possibility that a GitHub.com Inc owned and operated repository has its tags maliciously retagged to point to malicious contents, you have added the possibility that the commit sha1 hash points to completely arbitrary (malicious) contents from a fork. Any and every sha1 commit pinned action has to be manually reviewed, independently, by:
"Best practices" isn't simply carrying a lot of weight in that sentence, it's outright something that opinionated people disagree whether it is best practices or worst practices. I fall into the latter camp, and have been known to accuse the OpenSSF of being an extractive corporate-motivated drain on the FOSS community precisely over this. |
Thanks @eli-schwartz for the perspective. I share your opinion that the eventuality of the tag being redirected to something malicious is very low. I don't know if that is lower or higher than someone constructing a SHA1 collision. I thought I was the only one being sceptical of the effectiveness of pinning via the commit hash, and I do not have time (nor the competences, probably) to do a complete assessment of the security threat, thus I trusted what the (loud fraction of the) community seems to agree upon.
I think that pinning actions via the commit hash implicitly replaces the entity the users need to trust form from the one publishing the actions to the maintainers of the repository using them. There are also tools (like I am happy to keep pinning the tag, instead of the commit. However, so far (in almost all cases) we just pinned the major version of the actions. This leaves the door open for picking the latest minor and patch version release, without cooldown time (another "best practice" becoming popular of later). Should we switch to pin the exact version? |
|
I don't think the commit hash pin for GitHub-owned actions is very useful either way. However for random actions from third-parties it does help I believe; there's quite a few of those we use. Switching over the
I'm not sure I understand - that cannot resolve to a fork unless you've already done
https://github.com/davidism/gha-update exists and we've been using that in SciPy et al. for a while; its maintainer is well-known (e.g., he's a Python Discourse moderator). Dependabot: 100% agreed, really don't like it. |
Thanks. I'm surprised I didn't find it in my searches. |
I don't see it difficult to have a different policy for different repository owners. However, should we keep pinning the major version only, or the full version? Namely, should it be
|
|
I'm fine with either |
It is with the deepest dismay and regret that I must inform you your reasonable expectations are nonetheless entirely 100% wrong in EXTREMELY SECURITY-CRITICAL WAYS. (shouty-case because this must not be ignored or overlooked) Mechanically, the git protocol doesn't care what it asks for over the wire. An sha1 commit hash is "just another type of ref". And frankly when cloning a repo specifically in order to detach at some pinned reference, fetching by sha1 ref is good for efficiency! You avoid downloading large amounts of content you don't actually need that occurred later on the master branch (or with --depth, earlier too). Git supporting cloning by sha1 is a public service that happens to have sharp edges. On forges such as codeberg.org, forks are isolated. You can push to a fork and then swap out the {repo_slug}/commit/{sha1} for the originating repo's slug and the result of that url is a "404 not found" if the commit hasn't been pushed to the originating repo via e.g. a Pull Request. On GitHub it is a webpage displaying the commit contents with an added little yellow notebox saying "this commit isn't on any branch, be cautious". This happens on GitHub because all repositories in a fork network have the same By default, git allows you to clone and checkout any sha1, regardless of reachability from a public branch or tag. The most common scenario where users face this issue is when using git submodules, which, like GHA pinning, record a sha1 in the committed tree metadata. It has to for reproducibility, and it has to checkout a repeatable submodule even if the clone url for that submodule (operated by someone else) has chosen to force push and get rid of a commit sha1 that you rely on and need. It is unfortunately not nearly as well known as it should be, but git submodules can therefore logically contain sha1 commits that were never part of the repo, and in practice this is also a viable attack on any project with submodules:
For submodules present on GitHub, a GitHub-to-GitHub clickable link to the submodule will be present in diff and tree views, so you can follow it and see the yellow notebox. People may or may not do so. For best effect, an attack would use cross-forge submodules to decrease the chance anyone will manually construct the url to check up on it. GHA has a very similar problem. The only difference between it and a submodule is that there is no clickable link to the submodule so it is even harder to check. Also, third party contributors are more likely to submit PRs to update a GHA pin than they are to submit PRs updating a submodule. ... tl;dr every commit object within a GitHub fork network is fetchable from all repositories in that fork network, without ever having been present in the repo you fetched from, despite the fact that they really shouldn't be. |
"Do you trust actions/checkout to follow SemVer?" (yes) |
Pin actions not owned by GitHub via commit hash. For these actions, the commit has seems a more stable and trustworthy identifier than the tag.
db86480 to
d3e6f7f
Compare
I went for this compromise. |
|
FWIW we rejected it in xz as well: tukaani-project/xz#227 |
|
@eli-schwartz you're completely right, thanks for the reminder! I think I knew that once and shelved it on tape storage. When using |
Follow best practices and switch to pinning actions by commit hash rather than by major version number.