Dtui – TUI for introspecting the state of the system/session dbus
github.com
github.com
tbh I think it's a natural outcome of any system where it's easy and reliable to add a dependency......
.. and where there isn't any ongoing feedback about the costs associated with doing so (binary side, build time, etc) so you don't notice things slowly getting worse. It's just "rust builds are slow" not "why does this one thing I don't use take two minutes".
I'm not convinced the large number is actually a problem, but the lack of feedback definitely is.
Supply chain security always matters, and the more random dependencies you introduce, the worse it gets.
- what does it to justify its inclusion
- who wrote it
- who else has commit access to the repositories
- how do these people secure their git access
- are these people susceptible to state actor pressure
- will these people never in the future add new maintainers who are moles/blackmailable/have sloppy security hygiene
By glancing the direct dependencies of this project it is pretty easy to see why they have been selected. Yes, it would be more prudent to check all transitive dependencies as well, in addition to reviewing their source code, but frankly that's just too much effort. Does this mean the dependencies are random?
But it does seem like it would be cool to have a tool to collect as much of that information as possible.
E.g. if a library provides a pure function, does it matter if the owner changes? It's still pure. If it becomes not-pure, yes that's immediately concerning, but in the meantime its ability to do anything nefarious is infinitely smaller than most current module systems allow, and your review-budgets should probably be spent elsewhere.
On package level it might be easier? But then again you need to have quite fine-grained capabilities to describe what a package should be able to do. Of course, in Rust all unsafe code would need to be out (and it would be its own capability), but it still leaves exploiting the compiler bugs. For malicious changes that would of course be the vector to exploit and it might be very difficult to automatically detect them.
For TUI it uses ratatui.
The transitive dependencies can get quite large, though! I've never found the direct dependencies of any package to have superfluous dependencies (perhaps I haven't looked carefully enough?); they are always seem to be useful or easily provide functionality users expect to see, such as nice command line options and nice usage for them.
I think part of the issue is that it's just so easy to get a package included in "the" central registry, and for many programming adepts that's like a badge of honor. So you get many tiny libraries, and many turn into balls of mud. Then they learn about reuse and happily pull in all dependencies they can think of.
In Rust there seems to be a tendency to keep stuff out of the standard library, so everyone depends on their favorite solutions to everyday problems, which depends on their favorites and so on.
But it is a problem, because somewhere along the line one of those indirect dependencies is going to start conflicting with something else in the graph; the bigger the graph, the more conflicts.
And finally risk, because if a major indirect dependency goes belly up, that may well cause serious problems for your direct dependencies, which then makes it your problem. Also directly related to graph size.
Rust is statically compiled, so it’s possible to have different versions of the same dependency in your dependency graph without build issues. Yes, that can lead to binary bloat and slower build times and some related problems, but in practice the compiler is good at dealing with those issues.
I agree that having a great number of sources needed to build your program is worrying from the point of supply chain attack, but at the same time most developers enjoy focusing on the core problem they are solving, not problems that others have already solved for them.
Vendoring dependencies might be a partial solution, though practically speaking it seems locking dependencies via git hashes would be effectively the same.
I've seen other projects just include entire third party software repositories into their source tree rather than use a dependency manager, which works, I guess, but doesn't make the dependency tree all that obvious.
When I use languages that don't have an easy dependency manager, I often still try to use common libraries, but I find that there are fewer easy dependencies. In C, I would just not bother with async I/O rather than import a library that makes it easy to do. I would use a shitty "works-for-me" string replace rather than a compliant parser for formats like JSON or XML. I'd steal some random SHA code rather than link to a library.
I don't think this is that much of a problem as long as you're somewhat conservative in the kinds of dependencies you add. There's a trade-off between doing something yourself (and thus correctness) or stealing/vendoring the source code, and making use of a thriving library ecosystem.
Part of this might be because some core Rust facilities are lacking. For example, many projects use the "anyhow" library for error handling. It could also be because having a good package manager makes it so easy to add dependencies, and that reduced friction just naturally makes people tend to add many dependencies.
Rust has deliberately taken a “batteries not included” approach due to learned experiences in python, where many std-lib packages are basically abandoned/not recommended anymore.
This gives the ecosystem time to develop better approaches to things, rather than ossifying around the initial implementation.
Yes, it does lead to a larger set of dependencies, but some of the most common packages (including anyhow) were written and are maintained by members of the rust lang organization/team itself.
I don't quite blame them, remembering how Python's ecosystem tried to mimic Java back in the day, how PHP tried, consciously or not, to do the same.
I'm just wondering what the 2024-2025 dominant fad is going to look like.
Small dependencies are not inherently good. Large dependencies are not inherently bad.
It doesn't need to be a ragequitting and taking the toys away. If you are accustomed to having long chains of small twisty dependencies, all it takes is one Jia Tan of the Rust world to subtly alter a dependency of a dependency of a high profile dependency to own almost anything written in Rust. The said dependency can even ship precompiled bits of who-knows-which provenance, citing the same excuse as the one the author of serde used.
I don't know if Rust has the same quirk as JS/npm where a project can transitively depend on several versions of a module and they can coexist. Imagine a crate fixing some nasty shit, but some transitive dependency still pinning a vulnerable version.
I contrast this with Go that has a rich enough standard library so you rarely need a dependency, and you don't need any for mundane stuff, and it makes you think hard about every dependency you introduce. And they got burned early enough so vendoring is a Good Thing now.
And then I compare it with Perl, in that on one hand, it has lots of core modules, but then its standard library is lacking in weird places making you reach for CPAN in 100% of the cases writing a non-trivial program (HTTP/TLS comes to mind), and it would be similar to Rust except that CPAN is very slow-paced these days.
I'm curious to see how it all evolves.
It is also very tedious to vet a large dependency, as there's so much code to review.
> It all works well if everyone wants to play nice, but this doesn't scale.
There are tools like cargo-crev to help scale up the "hey I reviewed the code here and if you trust me, you can trust my review."
> I don't know if Rust has the same quirk as JS/npm where a project can transitively depend on several versions of a module and they can coexist.
Yes, on purpose. Rust will try to unify them as much as possible, but if two dependencies rely on incompatible versions, you'll get two.
Note that they'll be different types, so if you try and use a foov1 where a foov2 is needed, you'll get a compile error.
> Imagine a crate fixing some nasty shit, but some transitive dependency still pinning a vulnerable version.
This goes both ways: you could also have some code depending on an older, secure version, and a newer one is the one with the vulnerabilty.
But also, the way you phrase this makes me think you may misunderstand some details about how this happens: each crate doesn't pin its own version, exactly. The entire dependency graph is looked at holistically. But as I said above, you can still get situations like this, so this is very nitpicky.
> And they got burned early enough so vendoring is a Good Thing now.
You can absolutely trivially vendor your Rust dependencies as well. It's built into the tooling.
> I'm curious to see how it all evolves.
Absolutely. Me too.
upvoted as we need as much visibility on all this mess.
What are you referring to? And what's wrong with trusting the BIOS for that specific thing when you already trust it for everything else?
if you can't trust your BIOS, how are you going to be able to trust anything else on your system?
It all starts with the BIOS being (password or otherwise) protected to not be modifyable without authentication and then goes into secure booting your signed UKI (or whatever other signed way). From there you can have it mount your encrypted drive or load another signed root image.
That is like the minimum needed to be able to trust that what you are running is indeed something you can trust and nothing random has been inserted inbetween.
The odds I'll try it without having any idea of what it'll be are low. And this one might be really interesting and innovative!
Edit: Ooh I see it now, thanks @dodos! My mistake, it didn't load before. Please flag this embarrassment :)