Hacker News new | ask | show | jobs
by epage 814 days ago
For some more detail on the choices that went into this, see https://www.reddit.com/r/rust/comments/1b92j0k/sudors_depend...

For myself, I think people focus too much on "dependency count" and not what those dependencies represent. For example

- If a subset of a package is pulled out, it is no longer a "zero dependency" package and some people look down on it.

- Whether you use a dependency or write your own, the logic has to exist. The main question is if there is a difference in priorities.

Applying those

- I really wonder about their claim that using clap took more code than doing it themselves. I also wonder about "not using many features" as there are a lot of usability features in clap that aren't items you check off on a list. If dropping clap, it should have been replaced with https://docs.rs/lexopt/ rather than rolling their own

- While rpassword had its problems, it would have been better to work upstream or create your own competition to upstream, rather than locking away the improvements within sudo-rs

- I think its the right choice to keep glob. So long as it implements the spec of interest, bringing it in doesn't buy you much while keeping it external gives you the whole "many eyes" situation

- I agree about dropping `thiserror`. It can be nice for prototyping or high churn code but if you write-and-forget your errors, you are carrying around that weight for nothing.

- Its unclear why they merged all of the sudo-* packages into sudo-rs. I wonder if those would have been cases where they benefit everyone for being split out for reuse.

5 comments

I don't have any special insight to this decision, but

> - Its unclear why they merged all of the sudo-* packages into sudo-rs. I wonder if those would have been cases where they benefit everyone for being split out for reuse.

You play to your audience. If someone decides not to use sudo-rs because it's in multiple packages, that may be a bad reason, but they're still not choosing it, and that's a worse world than if they did.

I would probably do the same thing, even though I am very much on the other side of this debate from the zero-dependency folks. The intended audience is probably much more full of folks who do believe that.

Agree the dependency count is mostly meaninglessly.

What matters is how many vaguely defined "entities" (people/groups/companies) you trust and how trustable each of them is.

Also there are not really zero dependency libraries, you always have some dependencies, e.g. the compiler implicitly is a dependency too. And so is your build system, and your languages standard library, and libc, etc. etc. So obsessing with "0" is like obsessing with "1.0" releases or abusing type systems, i.e. not helpful at all.

Additionally you can have "crate" dependencies, but you pin (or even vendor) them and give them a though "supply chain risk" review and them keep them pinned or require a another review. Sure you still have to keep track of stuff like bug fixed yanked versions etc. But for a lot of smaller crates it's feasible. In difference to some other languages it's quite easy to do so in rust (for many crates, for larger ones which have a lot of functionality where you might need bug fixes, maybe even for security this isn't that viable, but then in most projects there is only a very small number of such dependencies if any (e.g. tokio, rustls).

> how trustable each of them is

I think this is the important point. They’ve removed clap (argument parsing library) as a dependency, but they continue to trust cargo (the rust build tool) that uses that library and is primarily maintained by the same developer?

I feel like if they’re willing to trust the developers of the standard library and the official compiler and build tool, then they might as well trust clap as well.

This feels like removing dependencies just to say they did. But it may turn out well. Maybe there are “dependency skeptics” who will be won over when they see fewer dependencies.

Clap ends up in your binary, Cargo does not.
if cargo was malicious it would affect the binary, which is the point
Trusting trust Steve.
Agreed with everything you’ve pointed out. There seems to be an implicit assumption that all dependencies are bad, even though it’d actually be better to refactor their own code to a crate under their maintenance. Almost as if they think the people evaluating the security of this will apply a simple heuristic like “if number of deps is more than x, this software is insecure”.
Ya it feels funny projects that think dropping major packages like CLAP that have thousands of eyes on it, for a new hand rolled implementation is somehow ... safer/better by default.

Replacing and removing dependencies is great, if your really sure somehow your code is actually improving the situation and not just shifting the issue into a new chunk of code your going to have to worry about.

I'd like to respond to a few things. I think using dependency count as a metric is a bad idea, that metric could easily be lowered by just copying all the code over to your project. As you rightfully say, the logic has to exist one way or another. Our approach definitely wasn't that though: it was and is never our goal to have no dependencies, but we do think that dependencies should be part of the safety story, i.e. is a dependency better or worse than what you would write yourself based on your specific use case. This needle will fall much much quicker towards writing it yourself for something like sudo, but still, at least the considerations you make should stay the same, even if the decision ends up being different. Considerations such as: is the communication with the dependency team worth it for the amount of code we save, are their goals aligned with ours, is the number of transitive dependencies that I take within my codebase with this dependency small enough, how much code am I actually saving, would I even be able to do this myself, could I help the wider community with my contributing back to that dependency, etc. I do feel that right now more often than not dependencies are just bolted onto a project as needed, and no consideration is given to any burden such a dependency might have. Aside from that, I think at least a much better metric would be something like 'teams', 'groups' or 'projects' needed to keep your project working. Still not perfect, nor is any other metric, but sometimes it helps to quantify things.

Some responses to your notes:

- The trouble is that we had to re-implement an existing CLI, and as you might expect with something that evolved over a period of some 30 years, there are quite a few weird behaviors in sudo. We initially had a mostly working implementation based on clap, but could not get some parts of the CLI to parse nicely, i.e. the code just looked hacky, and had to do all kinds of post-processing to complete the parsing of the CLI, resulting in lots of additional code. Maybe we should have looked at something like lexopt, but we just went ahead and did it ourselves initially just to see how it would go, we kind of liked the result and never looked at any alternative implementations. I do believe we looked at clap alternatives for a little while to see if something would make our parsing a little easier, but lexopt didn't surface at that time for whatever reason. We're not perfect either. I do think our parsing is pretty decent though.

- We did think about contributing back, but in the end we wanted a little more control over where the password (or more precisely 'hidden input') was stored in memory, and needed some specific parts for handling TTYs (given our setuid context) resulting in us quickly deconstructing rpassword until almost nothing of it was left. I think it's a little hard to contribute those things back, but as a side project I'd love to contribute some of the changes we made back to rpassword, there just wasn't the time to do it at that time as it would be quite a bit of work.

- Glob is a hard one, as the Rust crate is not entirely compatible with how the original sudo works. But the logic has to be there one way or another and if we have to decide between libc (i.e. probably C code) and Rust, we'd prefer to go with Rust of course. That already resulted in an issue being opened for incompatibilities of course, but it's a hard one: I'd prefer to keep the Rust code, so I hope that someone who manages glob at least agrees that it should be as compatible as possible. But I can't and don't have the expectation that their team has the same priorities, and thus we are back at one of the reasons why a dependency might not always be worth it. There's always choices to be made. For now though, we'll keep the Rust crate dependency, as it works well enough!

- Thiserror is great for prototyping, but loses its value quickly once you know what kind of errors you have, it just takes a few lines of extra code. But, thinking about teams etc: given that it is not that big, and is created and maintained by dtolnay, whose code you probably already use in multiple ways in nearly any other project, it's not the worst either. For sudo-rs though, I still think it was the better choice to remove it.

- All the sudo-* packages were mostly removed because we didn't want to expose any public API for all that internal stuff. Our initial goal is to get sudo the CLI application working, not to provide all the building blocks while the API is still in flux. We initially put it all in separate crates because of compilation time worries, but in the end those worries were unfounded. It's one of those things where Rust is still somewhat limited: we can't specify these sort of semi-private dependencies in the crates ecosystem right now, if we would have been able to specify 'nobody but us can use these as a dependency' they would have probably stayed as separate crates.

BTW: I'd like to thank you for continuing to work on Clap! There might have been a time I would have been a little worried about all the breaking changes and churn happening, but since that has stabilized I couldn't be happier! I don't think there's anyone on the sudo-rs team that had anything against clap, and I did not want to single out clap in our post specifically, so I hope you don't consider it an attack against clap. At least personally I use clap in basically every other project with a CLI.