Skip to content

feat(foundryup): avoid unnecessary downloads and verify hashes of downloaded binaries upon install #10902

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

zerosnacks
Copy link
Member

@zerosnacks zerosnacks commented Jul 2, 2025

Motivation

Closes: #10755
Closes: #9519

Solution

With the release workflow we now generate attestation artifact links alongside the release: nightly-e0d3e2a842fb5fcff4e02ad0ac0ae72bbdd4f5b3

We downloads the attestation artifact .txt based on the architecture. If an attestation artifact .txt is found in the release we continue and extract the link from the text file. This link points to the actual attestation artifact (.sigstore). We download this artifact and extract the base64 encoded payload from it, this contains the SHA256 hashes. We store these hashes in a global HASH_NAMES / HASH_VALUES arrays that we can access later by lookup.

Next we check the SHA256 sum of the current binaries of the version to install against the hashes of the verification artifact (so not necessarily the one activated but rather the binaries stored in ~/.foundry/versions/). If these two do not match we can assume the local version is out of date and we need to download the binaries. If there is an exact match we know they are up to date and we can exit early, preventing an unnecessary download. Previously we would always download the binaries no matter what.

Finally, once the binaries are downloaded, we match the newly downloaded binaries against the earlier stored HASH_NAMES / HASH_VALUES. This should always match exactly, if it does not there is a potential security issue as the user is installing a version that is different than the one produced by the release workflow.

Includes a -f / --force flag to skip verification and force fresh install

Related book PR: foundry-rs/book#1591

Note

  • Previously we used HASHES[bin] with declare -A, this is not compatible with MacOS.

To do

  • Check compatibility on default MacOS install
  • Check compatibility on Windows and find exact equivalents
  • Test case of mismatching hashes, an error should be thrown - maybe we can request the user to report this?

PR Checklist

  • Added Tests
  • Added Documentation
  • Breaking changes

…ng binaries against artifact, correctly handle releases without artifacts attached
@zerosnacks
Copy link
Member Author

zerosnacks commented Jul 2, 2025

Install stable, does not have attestation files linked in its release:

foundryup -i stable


.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx

 ╔═╗ ╔═╗ ╦ ╦ ╔╗╔ ╔╦╗ ╦═╗ ╦ ╦         Portable and modular toolkit
 ╠╣  ║ ║ ║ ║ ║║║  ║║ ╠╦╝ ╚╦╝    for Ethereum Application Development
 ╚   ╚═╝ ╚═╝ ╝╚╝ ═╩╝ ╩╚═  ╩                 written in Rust.

.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx

Repo       : https://github.com/foundry-rs/foundry
Book       : https://book.getfoundry.sh/
Chat       : https://t.me/foundry_rs/
Support    : https://t.me/foundry_support/
Contribute : https://github.com/foundry-rs/foundry/blob/master/CONTRIBUTING.md

.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx

foundryup: installing foundry (version stable, tag stable)
foundryup: checking if forge, cast, anvil, and chisel for stable version are already installed
################################################################################################################# 100.0%
foundryup: no attestation found for this release, skipping SHA verification
foundryup: binaries not found or do not match expected hashes, downloading new binaries
foundryup: downloading forge, cast, anvil, and chisel for stable version
################################################################################################################# 100.0%
forge
cast
anvil
chisel
foundryup: downloading manpages
################################################################################################################# 100.0%
foundryup: no attestation found for these binaries, skipping SHA verification for downloaded binaries
foundryup: use - forge 1.2.3-stable (a813a2cee7 2025-06-08T15:42:40.147013149Z)
foundryup: use - cast 1.2.3-stable (a813a2cee7 2025-06-08T15:42:40.147013149Z)
foundryup: use - anvil 1.2.3-stable (a813a2cee7 2025-06-08T15:42:40.147013149Z)
foundryup: use - chisel 1.2.3-stable (a813a2cee7 2025-06-08T15:42:40.147013149Z)

Install nightly, this one has attestation artifacts linked:

foundryup -i nightly-e0d3e2a842fb5fcff4e02ad0ac0ae72bbdd4f5b3


.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx

 ╔═╗ ╔═╗ ╦ ╦ ╔╗╔ ╔╦╗ ╦═╗ ╦ ╦         Portable and modular toolkit
 ╠╣  ║ ║ ║ ║ ║║║  ║║ ╠╦╝ ╚╦╝    for Ethereum Application Development
 ╚   ╚═╝ ╚═╝ ╝╚╝ ═╩╝ ╩╚═  ╩                 written in Rust.

.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx

Repo       : https://github.com/foundry-rs/foundry
Book       : https://book.getfoundry.sh/
Chat       : https://t.me/foundry_rs/
Support    : https://t.me/foundry_support/
Contribute : https://github.com/foundry-rs/foundry/blob/master/CONTRIBUTING.md

.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx

foundryup: installing foundry (version nightly, tag nightly-e0d3e2a842fb5fcff4e02ad0ac0ae72bbdd4f5b3)
foundryup: checking if forge, cast, anvil, and chisel for nightly-e0d3e2a842fb5fcff4e02ad0ac0ae72bbdd4f5b3 version are already installed
####################################################################################################################################################################### 100.0%
foundryup: found attestation for nightly-e0d3e2a842fb5fcff4e02ad0ac0ae72bbdd4f5b3 version, downloading attestation artifact, checking...
####################################################################################################################################################################### 100.0%
foundryup: binaries not found or do not match expected hashes, downloading new binaries
foundryup: downloading forge, cast, anvil, and chisel for nightly-e0d3e2a842fb5fcff4e02ad0ac0ae72bbdd4f5b3 version
####################################################################################################################################################################### 100.0%
forge
cast
anvil
chisel
foundryup: downloading manpages
####################################################################################################################################################################### 100.0%
foundryup: verifying downloaded binaries against the attestation file
foundryup: forge verified ✓
foundryup: cast verified ✓
foundryup: anvil verified ✓
foundryup: chisel verified ✓
foundryup: use - forge 1.2.3-nightly (e0d3e2a842 2025-07-02T10:58:11.775748718Z)
foundryup: use - cast 1.2.3-nightly (e0d3e2a842 2025-07-02T10:58:11.775748718Z)
foundryup: use - anvil 1.2.3-nightly (e0d3e2a842 2025-07-02T10:58:11.775748718Z)
foundryup: use - chisel 1.2.3-nightly (e0d3e2a842 2025-07-02T10:58:11.775748718Z)

Install nightly again:

foundryup -i nightly-e0d3e2a842fb5fcff4e02ad0ac0ae72bbdd4f5b3


.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx

 ╔═╗ ╔═╗ ╦ ╦ ╔╗╔ ╔╦╗ ╦═╗ ╦ ╦         Portable and modular toolkit
 ╠╣  ║ ║ ║ ║ ║║║  ║║ ╠╦╝ ╚╦╝    for Ethereum Application Development
 ╚   ╚═╝ ╚═╝ ╝╚╝ ═╩╝ ╩╚═  ╩                 written in Rust.

.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx

Repo       : https://github.com/foundry-rs/foundry
Book       : https://book.getfoundry.sh/
Chat       : https://t.me/foundry_rs/
Support    : https://t.me/foundry_support/
Contribute : https://github.com/foundry-rs/foundry/blob/master/CONTRIBUTING.md

.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx

foundryup: installing foundry (version nightly, tag nightly-e0d3e2a842fb5fcff4e02ad0ac0ae72bbdd4f5b3)
foundryup: checking if forge, cast, anvil, and chisel for nightly-e0d3e2a842fb5fcff4e02ad0ac0ae72bbdd4f5b3 version are already installed
####################################################################################################################################################################### 100.0%
foundryup: found attestation for nightly-e0d3e2a842fb5fcff4e02ad0ac0ae72bbdd4f5b3 version, downloading attestation artifact, checking...
####################################################################################################################################################################### 100.0%
foundryup: version nightly-e0d3e2a842fb5fcff4e02ad0ac0ae72bbdd4f5b3 already installed and verified, activating...
foundryup: use - forge 1.2.3-nightly (e0d3e2a842 2025-07-02T10:58:11.775748718Z)
foundryup: use - cast 1.2.3-nightly (e0d3e2a842 2025-07-02T10:58:11.775748718Z)
foundryup: use - anvil 1.2.3-nightly (e0d3e2a842 2025-07-02T10:58:11.775748718Z)
foundryup: use - chisel 1.2.3-nightly (e0d3e2a842 2025-07-02T10:58:11.775748718Z)

Install nightly with --force:

foundryup -i nightly-e0d3e2a842fb5fcff4e02ad0ac0ae72bbdd4f5b3 --force


.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx

 ╔═╗ ╔═╗ ╦ ╦ ╔╗╔ ╔╦╗ ╦═╗ ╦ ╦         Portable and modular toolkit
 ╠╣  ║ ║ ║ ║ ║║║  ║║ ╠╦╝ ╚╦╝    for Ethereum Application Development
 ╚   ╚═╝ ╚═╝ ╝╚╝ ═╩╝ ╩╚═  ╩                 written in Rust.

.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx

Repo       : https://github.com/foundry-rs/foundry
Book       : https://book.getfoundry.sh/
Chat       : https://t.me/foundry_rs/
Support    : https://t.me/foundry_support/
Contribute : https://github.com/foundry-rs/foundry/blob/master/CONTRIBUTING.md

.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx

foundryup: installing foundry (version nightly, tag nightly-e0d3e2a842fb5fcff4e02ad0ac0ae72bbdd4f5b3)
foundryup: downloading forge, cast, anvil, and chisel for nightly-e0d3e2a842fb5fcff4e02ad0ac0ae72bbdd4f5b3 version
####################################################################################################################################################################### 100.0%
forge
cast
anvil
chisel
foundryup: downloading manpages
####################################################################################################################################################################### 100.0%
foundryup: skipped SHA verification for downloaded binaries due to --force flag
foundryup: use - forge 1.2.3-nightly (e0d3e2a842 2025-07-02T10:58:11.775748718Z)
foundryup: use - cast 1.2.3-nightly (e0d3e2a842 2025-07-02T10:58:11.775748718Z)
foundryup: use - anvil 1.2.3-nightly (e0d3e2a842 2025-07-02T10:58:11.775748718Z)
foundryup: use - chisel 1.2.3-nightly (e0d3e2a842 2025-07-02T10:58:11.775748718Z)

…one currently in use, also make sure to activate it before exiting
@zerosnacks zerosnacks moved this to In Progress in Foundry Jul 2, 2025
@zerosnacks zerosnacks changed the title feat(foundryup): verify hashes of downloaded binaries upon install feat(foundryup): avoid unnecessary downloads and verify hashes of downloaded binaries upon install Jul 2, 2025
@grandizzy
Copy link
Collaborator

grandizzy commented Jul 2, 2025

Some scenarios to consider

  • for backwards compatibility, if attestation file doesn't exist then ignore verification
  • maybe add a force flag to ignore any validation
  • versions could be installed but not actively used (like v1.0.0 is installed locally but stable is the current one), so probably we should compare with binaries within versions dir

@zerosnacks
Copy link
Member Author

zerosnacks commented Jul 2, 2025

Good call!

  • for backwards compatibility, if attestation file doesn't exist then ignore verification

This is currently the case, see stable example above - we skip the verification step if the attestation file in not available

  • maybe add a force flag to ignore any validation

Done, I did make it so that -f / --force forces a fresh install without verification. I think this matches the expectation of a --force flag. We also can't avoid a fresh install because we don't have attestation artifacts to match against.

  • versions could be installed but not actively used (like v1.0.0 is installed locally but stable is the current one), so probably we should compare with binaries within versions dir

This is currently the case, we look now in the versions directory for a matching tag. So instead of matching against /home/zerosnacks/.foundry/bin/forge we match against /home/zerosnacks/.foundry/versions/<TAG>/forge and we activate w/ use if there is a match.

@grandizzy
Copy link
Collaborator

grandizzy commented Jul 7, 2025

all good tested on Win

  • installing nightly-e0d3e2a842fb5fcff4e02ad0ac0ae72bbdd4f5b3 (foundryup -i nightly-e0d3e2a842fb5fcff4e02ad0ac0ae72bbdd4f5b3) proper validates and avoids downloading binaries on subsequent runs - expected
  • installing stable (foundryup) succeed (no attestation files present) - expected
  • installing nightly (foundryup -i nightly) fails (wrong attestation files kept from nightly-e0d3e2a842fb5fcff4e02ad0ac0ae72bbdd4f5b3 but newer binaries built) - expected

@grandizzy grandizzy marked this pull request as ready for review July 7, 2025 10:58
Copy link
Contributor

@0xrusowsky 0xrusowsky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the logic makes sense to me.

as a side note though, despite docs are probably more suited than the actual implementation, imo it is worth explicitly stating the security risks of running with the --force flag

@grandizzy
Copy link
Collaborator

the logic makes sense to me.

as a side note though, despite docs are probably more suited than the actual implementation, imo it is worth explicitly stating the security risks of running with the --force flag

good point, yeah, docs should explicitly say that running with --force is discouraged and that verify does not mean people should skip their own due diligence

@zerosnacks
Copy link
Member Author

zerosnacks commented Jul 7, 2025

the logic makes sense to me.

as a side note though, despite docs are probably more suited than the actual implementation, imo it is worth explicitly stating the security risks of running with the --force flag

I've updated the documentation in the book here: https://76c73263.foundry-book.pages.dev/introduction/installation#verifying-the-integrity-and-provenance-of-binaries that points out you can at any time manually verify the integrity of the binary as well (this shows valid matches for all releases going back to the point where this was introduced).

--force effectively is what users have been doing until now and the same assumptions hold - it also double serves as an escape hatch in case for any reason the verification does not work (Github down, issues w/ specific architecture / OS, etc..).

I think once we are sure --force is only used in exceptional cases we can clarify the security issue with skipping the verification step more but open to clarifying / updating the current docs in the book

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: In Progress
Development

Successfully merging this pull request may close these issues.

feat(foundryup): verify hashes of downloaded binaries upon install bug(installer): foundryup should only download when updates are available
3 participants