NPV-169: detect too-broad with expressions; ratchet them down#142
NPV-169: detect too-broad with expressions; ratchet them down#142lucasew wants to merge 1 commit intoNixOS:mainfrom
with expressions; ratchet them down#142Conversation
|
I'm just taking a look myself, I'll try to create a trampoline for the kind of ratchet you'll need |
|
I was playing on how to implement the validation itself and, after a lot of rust struggle, there it is: https://github.com/lucasew/playground/tree/master/projetos/20250108-with-detector-rust I may start using it more tho. |
a2ce768 to
b0edbd7
Compare
|
I rebased from #144 for the primitives |
src/files.rs
Outdated
| ) -> validation::Result<BTreeMap<RelativePathBuf, ratchet::File>> { | ||
| process_nix_files(nixpkgs_path, nix_file_store, |nix_file| { | ||
| if let Some(open_scope_with_lib) = find_invalid_withs(nix_file.syntax_root) { | ||
| // TODO: what do I return |
There was a problem hiding this comment.
Take a closer look at #145, which is pretty much what you need, except that
Lines 19 to 34 in 003a4ad
file_is_str (or a different name in your case) will be a RatchetState, which should be Tight if the code is as desired and it can't be improved further, and Loose if there's an improvement to make.
|
The xrefcheck fail is related to a non-related test to this PR, a broken symlink but it seems on purpose to test a scenario |
infinisil
left a comment
There was a problem hiding this comment.
I'm only reviewing the diff to #144 with this comparison. My feedback:
- You should document the new check here, describing exactly how it behaves. Based on that I also feel like the error message should be changed, because it doesn't seem to be just about top-level
with's. - You should add a test that ensures an existing top-level with doesn't give an error if it still exists after a PR, similar to this test from #145
- The code should have more code comments explaining what it does
However, I guess most importantly, I don't think there's yet any consensus among Nixpkgs committers as to whether such a check is wanted or how exactly it should behave. Of course with the code here already written, it's easy to change the behavior, so I'd engage in NixOS/nixpkgs#371862, emphasising that you can easily change the code as desired, and maybe even make a Discourse post to get more input.
Sorry for the delayed reviews, am quite busy, but already thanks a lot for moving forward with improving CI, this is very valuable work!
e716f34 to
205d2c8
Compare
|
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: https://discourse.nixos.org/t/best-practices-with-with/58857/6 |
45493b0 to
2713203
Compare
Reworked this PR, addressing comments
with expressions that may shadow scope
philiptaron
left a comment
There was a problem hiding this comment.
This looks good to me, but I want @mdaniels5757 to have a look.
| /// Processes all Nix files in a Nixpkgs directory according to a given function `f`, collecting the | ||
| /// results into a mapping from each file to a ratchet value. |
There was a problem hiding this comment.
Why were all of these comments removed?
2713203 to
74de0ce
Compare
mdaniels5757
left a comment
There was a problem hiding this comment.
High-level review:
- I don't take issue with the code in general, and I support instituting these ratchet checks at least for
meta = with lib; - But:
- I don't understand what's "top-level" about the
withintests/nowith-meta-toplevel-lib/main/test.nix. Top-level, in my head, means something like{ lib, stdenv }: with lib; stdenv.mkDerivation { ... }. So I think the error message (and the variable names/comments) should have this modified. - Is there enough of a consensus for this? On one hand, I don't really see one in #292468, on the other, my sense of the vibes is that, although there are dissenters, at a minimum
meta = with lib; { ... }is generally Considered Harmful™. But I am not so confident that everything of the formswith foo; { ... },with foo; with bar; ..., orwith foo; let ...; in ...is also Considered Harmful™.
- I don't understand what's "top-level" about the
3900888 to
d31ac5b
Compare
|
This is a little too tight of a ratchet. |
d31ac5b to
0643593
Compare
b08cd7a to
32decc6
Compare
Add a ratchet check that prevents introducing new top-level `with` expressions whose body contains attr sets, let-in bindings, or nested with expressions. Existing instances are grandfathered via the ratchet. Co-authored-by: Lucas Eduardo Wendt <lucas59356@gmail.com>
32decc6 to
54115a5
Compare
|
I think I'm a lot happier with this. Check out the docs on https://github.com/NixOS/nixpkgs-vet/wiki/NPV-169. |
with expressions that may shadow scopewith expressions; ratchet them down
Docs LGTM |
|
Hmm. I rigged the ratchet to log whenever instances of TopLevelWithMayShadowVariablesAndBreakStaticChecks (old) and OverlyBroadWith (new) are present. I ran once for each of those, with current nixpkgs (623d84aa5a78836aecb316f4818c12706db75b77, Tue Feb 17 21:42:36 2026 +0000) as both the base and new commit. Here is the diff of the files flagged by each (TopLevelWithMayShadowVariablesAndBreakStaticChecks is on the left, OverlyBroadWith is on the right)Some observations:
All of those came from the set of files that were only flagged by OverlyBroadWith. I'm not quite sure what to propose about this (maybe require both the conditions from TopLevelWithMayShadowVariablesAndBreakStaticChecks and OverlyBroadWith be satisfied to issue a Problem)? But the three files linked are really quite reasonable, so I don't think this can be merged as-is. |
The PR adds NPV-169, a ratchet check that flags top-level
withexpressions whose body contains attr sets,let-inbindings, or nestedwithexpressions, since these can shadow variables and break static analysis.Existing instances are grandfathered via the ratchet mechanism — only newly introduced uses are flagged. It extends the
Fileratchet with atop_level_withfield and theDoesNotIntroduceToplevelWithsratchet typeTest cases
nowith-basicwith lib; 2has no shadowing constructs in bodynowith-meta-toplevel-libwith lib; { ... }shadows via attr setnowith-meta-with-maintainerswith lib.maintainers; [ ... ]is fine (no attr set/let/nested with)nowith-nixos-submodule-shadowwith lib.types; attrsOf (...)nowith-nixos-submodule-shadow-changednowith-nixos-submodule-shadow-do-not-touch-if-not-changednowith-nixos-submodule-unshadowlib.types.prefix instead ofwithnowith-nixos-submodule-unshadow-inheritinheritinstead ofwithThis PR is reworked from original contributions from @lucasew.