3 releases (breaking)
new 0.3.0 | Apr 8, 2025 |
---|---|
0.2.0 | Apr 4, 2025 |
0.1.0 | Apr 3, 2025 |
#111 in Command line utilities
278 downloads per month
39KB
763 lines
jas
Just an installer.
This tool is meant to be used in situations where you want to install a script or binary in a reliable way, that is, you want to specify the SHA-256 checksum so that you can be sure that you are executing the thing you expected. I wrote this tool in response to yet another GitHub Action supply chain attack. See the Background section for more details.
Installation
cargo install --debug jas@0.3.0
and add ~/.jas/bin
to your PATH.
Usage
To install Typos from GitHub into ~/.jas/bin
, you can use:
jas install \
--gh crate-ci/typos@v1.31.1 \
--sha f683c2abeaff70379df7176110100e18150ecd17a4b9785c32908aca11929993
This command uses the SHA for the MacOS aarch64 release.
To get the SHA for other platforms, you can use sha --url
.
For example,
jas sha \
--url github.com/crate-ci/typos/releases/download/v1.31.1/typos-v1.31.1-x86_64-unknown-linux-musl.tar.gz
Usage in GitHub Actions
For example, to install and run typos
v1.31.1, you can use the following job in your GitHub Actions workflow:
jobs:
typos:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- run: cargo install --debug jas@0.3.0
- run: >
jas install
--gh crate-ci/typos@v1.31.1
--sha f683c2abeaff70379df7176110100e18150ecd17a4b9785c32908aca11929993
--gh-token ${{ secrets.GITHUB_TOKEN }}
- run: typos .
As stated above, the benefit of this is that you can be sure which version of the binary you are using. If someone changes the binary, the SHA will change and your CI will fail.
The --gh-token
is optional but recommended inside GitHub Actions because otherwise this tool might be rate limited when determining which assets are available in the release.
The limit is 60 requests per hour per IP address.
Normal GitHub Actions such as
- uses: JamesIves/github-pages-deploy-action@v4
receive the GITHUB_TOKEN
by default via the github.token
context.
If you don't want to use a GITHUB_TOKEN
it is also possible to manually specify the --url
instead of --gh
.
Background
This tool is primarily intended to be used in CI as a workaround for GitHub Actions's poor security guarantees.
For example, recently the tj-actions/changed-files
Action caused many repositories to leak their secrets.
As with many problems, multiple things have to go wrong for this to happen.
First, someone gained access to changed-files
and inserted malicious code.
Then, the attacker was able to not only change the latest release, but also tags for older releases.
This is a fundamental problem for GitHub Actions.
It is possible to retroactively change the tags.
So even clients that pinned to an older version of changed-files
would start using the malicious version.
For example, changed-files
was at v46.0.1 at the time of the attack.
This means that if you would use
- uses: tj-actions/changed-files@46
then this would be interpreted by GitHub as 46.0.1
and you would automatically start using the malicious version.
However, even if you pinned to an older release like 46.0.0
:
- uses: tj-actions/changed-files@46.0.0
you would still not be safe since the attacker has changed the tag for 46.0.0
.
The new/old way to solve this is to use explicit commit hashes.
For example, changed-files
now advises to use this:
- uses: tj-actions/changed-files@823fcebdb31bb35fdf2229d9f769b400309430d0 # v46
Pinning is a lot safer, but unfortunately Git at the time of writing still uses SHA-1. Although Git runs a hardened version of SHA-1, git-scm.com states that:
Thus it’s considered prudent to move past any variant of SHA-1 to a new hash. There's no guarantee that future attacks on SHA-1 won’t be published in the future, and those attacks may not have viable mitigations.
Furthermore, I personally dislike this hash pinning approach since it doesn't specify the version. That's why it is very common to see the version number specified in the comment, as is done here. The problem with this approach is that the comment can now become out of sync with the actual version.
This tool is a workaround for this problem for situations where executables (binaries or scripts) are available. It turns the syntax into:
- run: >
jas install
--gh crate-ci/typos@v1.31.1
--sha f683c2abeaff70379df7176110100e18150ecd17a4b9785c32908aca11929993
Now it's clear which version is being used. When it downloads a binary, it will verify the SHA-256 checksum. If this checksum does not match, the tool will fail.
Unlike the GitHub Actions syntax, the version cannot become out of sync with the hash. Also, with this method, you know exactly what you run. With GitHub Actions, even when the commit hash is pinned, the dependencies could still change if I understand correctly.
How does this compare to cargo install
Compared to GitHub Releases, cargo install
already provides much better security guarantees.
As far as I understand, unlike with GitHub Releases it is not possible to change published versions after publication.
So if an attacker manages to publish a new malicious version on crates.io
, then this would not affect older versions pinned to an explicit version.
Instead, the attacker would need to hack crates.io
itself to change older versions.
Depending on the threat model it can still be useful to confirm the sha of course.
To answer the question, in most cases I would say that installations via cargo install crate@x.y.z
are much safer than uses: owner/repo@x.y.z
.
The only problem could be that compilation of the crate takes long.
jas
avoids this problem by downloading the binaries from the release.
Dependencies
~22–34MB
~621K SLoC