Conversation
The ability to substitute inputs was removed in NixOS#10612 because it was broken: with user-specified inputs containing a `narHash` attribute, substitution resulted in an input that lacked the attributes returned by the real fetcher (such as `lastModified`). To fix this, we introduce a new input attribute `final`. If `final = true`, fetching the input cannot add or change any attributes. We only attempt to substitute inputs that have `final = true`. This is implied by lock file entries; we only write a lock file if all its entries are "final". The user can specified `final = true` in `fetchTree`, in which case it is their responsibility to ensure that all attributes returned by the fetcher are included in the `fetchTree` call. For example, nix eval --impure --expr 'builtins.fetchTree { type = "github"; owner = "NixOS"; repo = "patchelf"; final = true; narHash = "sha256-FSoxTcRZMGHNJh8dNtKOkcUtjhmhU6yQXcZZfUPLhQM="; }' succeeds in a store path with the specified NAR hash exists or is substitutable, but fails with error: fetching final input '{"final":true,"narHash":"sha256-FSoxTcRZMGHNJh8dNtKOkcUtjhmhU6yQXcZZfUPLhQM=","owner":"NixOS","repo":"patchelf","type":"github"}' resulted in different input '{"final":true,"lastModified":1718457448,"narHash":"sha256-FSoxTcRZMGHNJh8dNtKOkcUtjhmhU6yQXcZZfUPLhQM=","owner":"NixOS","repo":"patchelf","rev":"a0f54334df36770b335c051e540ba40afcbf8378","type":"github"}'
We haven't added the narHash attribute yet at that point. And if the caller uses getAccesor() instead of fetchToStore() (e.g. in `nix registry pin`), the narHash attribute will never be added. This could lead to a mismatch.
…astModified
Fixes flake-regressions/tests/DeterminateSystems/fh/0.1.10:
error: fetching final input '{"final":true,"narHash":"sha256-0dZpggYjjmWEk+rGixiBHOHuQfLzEzNfrtjSig04s6Q=","rev":"9ccae1754eec0341b640d5705302ac0923d22875","revCount":1618,"type":"tarball","url":"https://api.flakehub.com/f/pinned/nix-community/fenix/0.1.1618%2Brev-9ccae1754eec0341b640d5705302ac0923d22875/018aea4c-03c9-7734-95d5-b84cc8881e3d/source.tar.gz"}' resulted in different input '{"final":true,"lastModified":1696141234,"narHash":"sha256-0dZpggYjjmWEk+rGixiBHOHuQfLzEzNfrtjSig04s6Q=","rev":"9ccae1754eec0341b640d5705302ac0923d22875","revCount":1618,"type":"tarball","url":"https://api.flakehub.com/f/pinned/nix-community/fenix/0.1.1618%2Brev-9ccae1754eec0341b640d5705302ac0923d22875/018aea4c-03c9-7734-95d5-b84cc8881e3d/source.tar.gz"}'
Fixes flake-regressions/tests/DeterminateSystems/eva/0.1.0: error: 'lastModified' attribute mismatch in input 'https://api.flakehub.com/f/pinned/ipetkov/crane/0.14.1/018ac45c-ff5e-7076-b956-d478a0336516/source.tar.gz?narHash=sha256-mnE14re43v3/Jc50Jv0BKPMtEk7FEtDSligP6B5HwlI%3D', expected 1695511445
roberth
left a comment
There was a problem hiding this comment.
I think we're onto something, but I'm not completely certain that this solves the whole problem, and a partial solution will lead to complexity we'll have to maintain indefinitely. Let me explain.
A related problem that's not solved by this feature is the forward compatibility to add new metadata attributes (like lastModified but new) to an input type.
A possible solution to that is to have an attributes = ["lastModified" "fancyNewAttr"]; argument, and then only return the requested attributes.
The default attributes (when unset) could then be compatible with the current behavior.
This way, we only return attributes that are expected by the caller, and final, as used in fetching/substitution becomes a derived property: whether all requested attributes are already specified in the input attrset.
(This PR also needs docs and tests, and while particularly the prior could be a useful way to think about the design, these are of secondary concern to the design question)
That's not a big problem: the fetcher can simply not return the new attribute if the input is marked as final. In fact, this PR does just that in the tarball fetcher. |
|
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: https://discourse.nixos.org/t/2024-10-23-nix-team-meeting-minutes-189/54841/1 |
This fixes the error
'{"__final":true,"lastModified":1686592866,"narHash":"sha256-riGg89eWhXJcPNrQGcSwTEEm7CGxWC06oSX44hajeMw","owner":"nixos","repo":"nixpkgs","rev":"0eeebd64de89e4163f4d3cf34ffe925a5cf67a05","type":"github"}' resulted in different input
'{"__final":true,"lastModified":1686592866,"narHash":"sha256-riGg89eWhXJcPNrQGcSwTEEm7CGxWC06oSX44hajeMw=","owner":"nixos","repo":"nixpkgs","rev":"0eeebd64de89e4163f4d3cf34ffe925a5cf67a05","type":"github"}'
in flake-regressions/tests/nix-community/patsh/0.2.1 (note the lack of
a trailing '=' in the NAR hash in the lock file).
|
Belated team discussion notes from 2 weeks ago:
|
We now just check that the fetcher doesn't change any attributes in the input, and return all the original attributes (i.e. discarding any new attributes and keeping any attributes that the fetcher didn't keep).
|
Simplified the semantics of |
roberth
left a comment
There was a problem hiding this comment.
Making final a non-Input argument may be a lot cleaner.
Otherwise, some comments.
|
This passed the full flake regressions test suite. |
It's now only allowed in fetchFinalTree, which is not exposed to users but only to call-flake.nix.
|
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: https://discourse.nixos.org/t/2024-11-06-nix-team-meeting-minutes-192/55847/1 |
roberth
left a comment
There was a problem hiding this comment.
One more suggestion, but let's move forward.
| static RegisterPrimOp primop_fetchFinalTree({ | ||
| .name = "fetchFinalTree", | ||
| .args = {"input"}, | ||
| .fun = prim_fetchFinalTree, | ||
| .internal = true, | ||
| }); | ||
|
|
There was a problem hiding this comment.
| static RegisterPrimOp primop_fetchFinalTree({ | |
| .name = "fetchFinalTree", | |
| .args = {"input"}, | |
| .fun = prim_fetchFinalTree, | |
| .internal = true, | |
| }); |
Couldn't we construct the primop on the fly when loading call-flake.nix?
That way we don't need internal and internalPrimOps.
There was a problem hiding this comment.
That seemed tricky since this happens in libfetcher rather than libexpr, so it's not clear how to construct a singleton value. Or we could allocate a new PrimOp every time, but that would leak.
|
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: https://discourse.nixos.org/t/nix-copying-a-store-path-into-the-store/60409/10 |
Motivation
The ability to substitute inputs was removed in #10612 because it was broken: with user-specified inputs containing a
narHashattribute, substitution resulted in an input that lacked the attributes returned by the real fetcher (such aslastModified). This could result in a different evaluation result, depending on whether the input was substitutable.To fix this, we introduce a new input attribute
__final. This is for internal use only (specifically, bycall-flake.nix) and may be removed in the future. If__final = true, fetching the input cannot change any attributes and we ignore any new attributes returned by the fetcher. For example:Note the absence of the
lastModifiedattribute usually returned by thegithubfetcher.We only attempt to substitute inputs that have
__final = true. This is implied by lock file entries; we only write a lock file if all its entries are "final".Context
Priorities and Process
Add 👍 to pull requests you find important.
The Nix maintainer team uses a GitHub project board to schedule and track reviews.