Skip to content
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

lib: add randomHash helper #362599

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

boltzmannrain
Copy link
Contributor

Similar to lib.fakeHash but value is different each time. This is useful to avoid locking when rebuilding multiple packages and/or for multiple architectures.

With lib.fakeHash multiple FOD builds on same machine would assume that output with fakeHash can be produced so only one FOD build at a time would be allowed to save efforts _if_ all those builds would produce same output with fakeHash. But actual reason to use fakeHash is letting the build fail and produce hash mismatch error with real hash value, so it makes more sense to let all fake hash FODs be different

Randomness code is partially borrowed from https://github.com/figsoda/rand-nix/blob/main/default.nix

Admittedly this is a little ugly, but if only used during local rebuilds might be good enough.

Things done

  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandboxing enabled in nix.conf? (See Nix manual)
    • sandbox = relaxed
    • sandbox = true
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 25.05 Release Notes (or backporting 24.11 and 25.05 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
  • Fits CONTRIBUTING.md.

Add a 👍 reaction to pull requests you find important.

Similar to `lib.fakeHash` but value is different each time. This is
useful to avoid locking when rebuilding multiple packages and/or for
multiple architectures.

With `lib.fakeHash` multiple `FOD` builds on same machine would assume
that output with `fakeHash` can be produced so only one `FOD` build at
a time would be allowed to save efforts `_if_` all those builds would
produce same output with `fakeHash`. But actual reason to use `fakeHash`
is letting the build fail and produce hash mismatch error with real
hash value, so it makes more sense to let all fake hash FODs be different

Randomness code is partially borrowed from https://github.com/figsoda/rand-nix/blob/main/default.nix

Admittedly this is a little ugly, but if only used during local rebuilds
might be good enough.
@@ -329,6 +329,7 @@ let
fakeHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
fakeSha256 = "0000000000000000000000000000000000000000000000000000000000000000";
fakeSha512 = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
randomHash = builtins.hashString "sha256" (builtins.readFile /proc/sys/kernel/random/uuid);
Copy link
Member

Choose a reason for hiding this comment

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

This cannot take effect in flakes I suppose?

Copy link
Contributor Author

@boltzmannrain boltzmannrain Dec 8, 2024

Choose a reason for hiding this comment

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

I guess not, and there's no --argstr to pass it from shell either NixOS/nix#5663

Some alternative approaches could be

  • external script driving multiple builds and substituting fakeHash per invocation & package
  • tweaking Nix to allow FOD without outputHash, it will fail but won't wait on other FODs
  • tweaking Nix to treat lib.fakeHash FOD specially, so not locking
  • replacing FOD outputHash with completely different flow for things that aren't just fetches
    • replace pinning outputHash with trush of substitution / attestation that a given unsafe derivation should produce given output
    • maybe distinguish between output value trust and trust to allow building it without full sandbox
    • that should make maintaining packages simpler, Hydra would sign outputs and signatures aren't persisted in nixpkgs, consumers may decide to trust Hydra or take the risk of building, but package maintainer doesn't need to do anything
  • having pseudo-random hash where sources of entropy could be
    • user-supplied salt
    • system argument (not sure how it works with flakes)
    • package name
    • current Git commit or tree hash (in case of flakes)
  • having multiple fakeHash values
    • weaker version of user salt
    • still locks for different systems unless values are per-system
    • still locks if several builds reuse the value

Copy link
Member

Choose a reason for hiding this comment

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

tweaking Nix to treat lib.fakeHash FOD specially, so not locking

Probably the only correct way.

@infinisil
Copy link
Member

infinisil commented Dec 8, 2024

The use case makes sense, but I feel a bit uneasy about having such an impure function in lib, it definitely doesn't work with Flakes, and it also only works on Linux. It also depends on Nix internally not caching file contents to work. So if it all, the name should indicate that, something like lib.unsafeLinuxRandomHash, and the docs should also have big warning signs about it.

A better solution would be to implement this in Nix, e.g. by having it treat all-zero hashes specially, so if you could file an issue tracker in the Nix repo that would be great. Otherwise I think I'm generally fine with having this, I can't imagine a better workaround.

@infinisil
Copy link
Member

infinisil commented Dec 8, 2024

Although, having just written this, how about something like lib.fakeHash' "<string>" where the resulting hash depends on the given string. It's not as easy to use, but you can do lib.fakeHash' "a", lib.fakeHash' "b".

This has the added benefit that you can know which failing hash corresponds to which source location. We can even take it a step further and require <string> to be hexadecimal, such that you can get

lib.fakeHash' "123" == "1230000000000000000000000000000000000000000000000000"

Therefore making it even easier.

@boltzmannrain
Copy link
Contributor Author

boltzmannrain commented Dec 8, 2024

Although, having just written this, how about something like lib.fakeHash' "<string>" where the resulting hash depends on the given string. It's not as easy to use, but you can do lib.fakeHash' "a", lib.fakeHash' "b".

This has the added benefit that you can know which failing hash corresponds to which source location. We can even take it a step further and require <string> to be hexadecimal, such that you can get

lib.fakeHash' "123" == "1230000000000000000000000000000000000000000000000000"

Therefore making it even easier.

Maybe it should take multiple strings so that users could do lib.fakeHash' [ pname ] or lib.fakeHash' [ pname stdenv.hostPlatform.system ] or similar, and ideally not having to type as much. lib.fakeHash' pname and lib.fakePerPlatformHash' pname as an option

@infinisil
Copy link
Member

I'd prefer keeping it simpler without arrays, you can do lib.fakeHash' "${pname}-${platform}" instead. And we can't have lib depend on pkgs, though pkgs.fakeHash could.

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

Successfully merging this pull request may close these issues.

3 participants