Hacker News new | past | comments | ask | show | jobs | submit login
Rust without crates.io (thomask.sdf.org)
252 points by todsacerdoti 10 months ago | hide | past | favorite | 236 comments



> What’s interesting is that this problem is largely solved for C and C++: Linux distributions like Debian package such a wide range of libraries that for many things that you want to develop or install, you don’t need any third-party libraries at all.

This does not reflect my observations at all. It works if you’re an end user and the software you want has been packaged. But if either of those is not the case, you’re left in the mud. Rather, you end up with builds that are difficult to set up or reproduce except on specific platforms, require a lot more maintenance over time because bitrot occurs naturally (your code depends on libexample 1, but Debian only package version 2 now, so good luck dusting off that project you made five years ago and getting it to build again), vendoring upon vendoring, more diverse and generally lower-quality dependencies for a particular task, and other problems like these. You’ve solved one problem, but at a very significant cost that must be acknowledged, even if you decide it’s still worth it.

Take an app written five years ago that depends on majorish C++ libraries, and there’s a fair chance compiling it will be a nightmare and require invasive surgery due to version incompatibilities. It’s not improbable that the most pragmatic solution may be to find and rebuild the transitive package tree for some older version of some package, and that’s generally quite painful (and can be outright incompatible).

Take an app written five years ago in pure Rust, and it’ll almost certainly (p>0.99) still work fine. Take an app written five years ago in Rust that binds to some C/C++ library, and there’s a fair chance you’ll run into trouble, but it will almost certainly be a good deal easier to resolve, much more likely to work with only a version bump and no other changes than in C/C++.

As a developer, I know which general mode of operation I prefer. Debian are welcome to twiddle the dependencies in the way that suits their chosen requirements, but the canonical sources are still crates.io, and I know that when they’ve stopped packaging example-1.0.0, I won’t be beholden to their packaging but can just use `cargo build` and it’ll still work (contingent upon extern bindings).

I’m dubious that any meaningful curation is happening, and curious if there’s even cursory review of crate contents. But most of all, I’d be interested in a statistical comparison of the crates that Debian ships with the most-downloaded crates from crates.io. I suspect the sets would look very similar.


Yeah. The part that gives me goosebumps with that proposal is: as an author of some not very popular packages, what do I do? Is it my job to package and promote my packages on Debian, redhat, homebrew, and all the others? Do I need usage before they’ll pick it up? Sounds like a chicken and egg problem. And doing all that packaging work sounds like a boring, time consuming job that I don’t want.

It’s also quite common for me to pull out bits of code I’ve written that I want to share as a dependency between different programs I write. I have dozens of packages in npm along these lines - and it’s quite elegant. I factor out the code, package it independently, write a readme and some tests and publish it. My other packages can then just depend on the brand new package directly. In this brave new world the author is proposing - what? I make a .deb, argue for it on some mailing lists I’m not on, wait who knows how long, eventually gain permission to depend on my own code, then realise I can’t install it on my Mac laptop and do the same dance in homebrew? Oh - there’s a bug. Better manually update all the package repositories? Sounds like a complete nightmare to me.

I’m sympathetic to the problem. Supply chain attacks are way too easy. But maintaining up to date packages on every single Linux distribution, homebrew, ports, and whatever windows does sounds like a full time job. A boring full time job. And it would still not work as well for my users, because when a new feature is released in one of my upstream dependencies I can’t use it until all of those package repositories ship the new version of my upstream dependency too. I’d rather eat sand.

“It works for C/C++” by making developers working in those languages pay in blood for every dependency they pull in. You can tell by looking at just how few dependencies the average C program uses. It’s like that because of how painful it is. Anything under a certain size tends to get either reinvented every time, badly (hash table libraries in C) or vendored (eg json parsers). Common libraries like rust’s rand don’t exist in C because it’s just too much effort to pull in dependencies. So everyone rolls their own crappy version instead. Ask GTA5 how well that went for them. And that’s not the developer ecosystem I want to work in. It’s frankly a terrible proposal.


>I’m sympathetic to the problem. Supply chain attacks are way too easy

This is the crux as to why crate.io is great: you have one official place for packages that can be continuously audited and monitored. This is the way to do security, in my opinion, because you are always able to look at incoming and outgoing packages.

Now, you can argue if we are doing enough with this, and that is definitely up for debate, however, I contend that the premise of having one canonical place for package origination and hosting makes it easier to monitor for security purposes


I - and many others - don’t think this is enough to mitigate supply chain attacks. It’s too easy for a malicious developer to add cryptolocker ransomware in a point release. But I also don’t think having a package in Debian will somehow magically solve this problem either. Debian package maintainers do not - and never have - done security audits on the packages they add. It’s magical thinking to assume using packages in Debian will somehow protect you from supply chain attacks. Asking developers to keep their dependency trees small so we can minimise the risk is a losing battle. Using lots of small, popular dependencies is just too convenient.

There is a solution out there that I wish got more traction. And that is, capability based security. The idea is simple: we partition programs into application code and library code. Library code can never access the filesystem or network (or other protected data) directly. And this is enforced by the compiler or language runtime. Application code can. If you want a library to interact with a file, you first open the file in application code and pass the file handle to the library. Similar wrappers can be made for directories, network sockets and so on. If I want express to listen on a specific port, I pass it that port in a capability object. Not just an integer. (Eg app.listen(net.listenPort(8000))). The amount of code that would need to be changed is tiny since well behaved libraries don’t usually need many capabilities to do their job.

It is ridiculous that my 3rd party json library can invisibly access all the sensitive files on my computer. With capabilities, we take that privilege away. I have no problem trusting a random json library if it literally only has access to the json string I pass it. If we had a capability based security model, I would have no qualms about pulling in hundreds of transitive dependencies. My libraries can still only access exactly what I pass them.

Unfortunately this problem requires language level buy-in. It would be very hard to retrofit rust to work this way and that’ll probably never happen. Raw pointers and inline assembly also make a bit of a mess of things too. (Though pointer provenance might help). But a man can dream… Maybe in rust’s successor.


This is similar to how WASI (standard system interfaces) for WASM work.


Yeah I'm really keen for that - though I think compiling a bunch of dependencies into individual wasm modules will be kind of awful to use in practice.

Apparently in firefox they've been compiling some of their dependencies using wasm, then translating the wasm back to C. The end effect of all that is that it gives C code wasm's sandboxing and safety. I wonder what it would look like to do that without needing wasm as a middle step.


You don't need the language to be involved to use this strategy, if you can rely on the OS. Lots of programs are structured this way already: open your secure port as root, then daemonize as an untrusted user.

However, I quite like the idea of using the application/library interface to enforce the restrictions structurally, rather than temporally.


> open your secure port as root, then daemonize as an untrusted user.

That works for server applications. Well - so long as bad things don’t happen in a static initializer before the process drops privileges. But I also want it to work for other kinds of applications. I want to be able to fearlessly depend on a library and not need to worry about that library attacking my computer. Then we can have our cake and eat it too with big dependency trees made up of lots of small libraries written by untrusted contributors.

Another nice thing about this is it doesn’t depend on OS level capability support. Once implemented in a language, it should be pretty easy to make it work on every OS.

Interestingly, this is something wasm provides out of the box. And Firefox’s weird “compile deps with wasm as convert the result back to C” also achieves this end.


Creator of Packj [1] here. How do you envision sandboxing/security policies will be specified? Per-lib policies when you've hundreds of dependencies will become overwhelming. Having built an eBPF-based sandbox [2], I anticipate that accuracy will be another challenge here: too restrictive will block functionality, too permissive defeats the purpose.

1. https://github.com/ossillate-inc/packj flags malicious/risky NPM/PyPI/RubyGems/Rust/Maven/PHP packages by carrying out static+dynamic+metadata analysis.

2. Sandboxing file system w/o superuser privileges: https://github.com/sandfs/sandfs.github.io


Cool library!

I’m not imagining something that specifies policies at all. Capability based security systems shouldn’t need them. Instead, the main application can create capabilities programmatically - for example by opening a file for reading. The file handle is a capability. Libraries you call don’t get access to the OS, or anything outside their module scope that hasn’t been passed in as an explicit parameter. A 3rd party library can access the file handle you pass it as a function argument, but it can’t ask the OS to open any other files on your computer. Or open a network socket.

OS APIs aren’t in a scope that any of the libraries you use have access to.

There are a few things capabilities need to be able to do. They need to be able to be tightened. (So for example, if you have a file with RW flags, you can make a copy of the file handle that’s read only). And they need to be unforgeable (file handles can’t be created from an integer file descriptor). We’d also need a handful more “file handle” like objects - and this is where granularity matters. Like we need an equivalent for directories that gives you access to everything recursively in that directory and nothing outside of it.

If the library I call delegates some work to another library, it’s pretty simple. It just passes its file handle through to the other library as a function argument. There’s no policy to maintain or update. Nothing even changes from the point of view of the original caller.

The tricky part is stuff like debug output, environment variables (NODE_ENV=production) or stdout. Do libraries implicitly get access to stdout or not? Maybe they get stderr but not stdout, and they can open new temp files? You would also need to restrict JavaScript code from arbitrarily messing with the global scope or global libraries like String.

But honestly, any answer to these problems would be a massive improvement over what we have now. Being able to know your binary search library can’t make network requests, and that your database can’t interact with files outside its database directory would do so much for supply chain security it’s not funny. A good capability system should just change the APIs that your software can use a bit. Generally in good ways that make dependencies more explicit. Done right, there shouldn’t be any new syntax to learn or deno style flags to pass at the command line or anything like that.


That’s like saying it’s best to run everything on AWS, because there’s only one place to monitor for outages.

That’s the exact opposite of how supply chain mitigation works.


It's not at all like saying that.

If you want to mitigate downtime in your supply chain then diversity is good. If you want to mitigate security vulnerability then it's bad.

Imagine you have 100 api servers that all have database credentials. If one server goes down you have 99 working servers (ideally). If one is compromised then the attacker has your database credentials, game over.


When you make a new library for C/C++, you generally just install it locally at first (pkg-config and PKG_CONFIG_PATH make this trivial). It doesn't (need to) get packaged by a distribution until a program using it is packaged. You don't need to do this yourself, unless you yourself use a distribution and want it packaged there.

As for the amount of dependencies, you have to wonder if it's better to have tonnes of small dependencies or whether it's better to have a few bigger ones. When I need something in a library, I don't make a new library for it, I first try contributing to it, and failing that I vendor and patch it. I feel this is less common in the brave new world of everyone just doing whatever and pushing it to a largely unmoderated repository...


I suppose I could manually traverse my whole dependency tree myself and install all those packages myself. Set up cmake and pkg-config for all of them. If anyone else wants to try out my software, they’d have to manually look up all the dependencies in my github (?) and install those too. And hope the versions all line up nicely - which is a big if during development. Maybe I could script all of that dependency tracing - if only there were some standard software to do that. Guess not.

If C/C++ is all you know, you’re used to how painful all of that is. But what you’re proposing is a significantly worse experience in every way compared to what I can do with cargo or npm today. None of the claimed benefits seem remotely worth the cost of wading back into C dependency management hell. And cargo and npm show just how unnecessary all that pain is in C!

Just make good tooling. We can have nice things. I stopped using C not because I decided to write assembler. I stopped when better languages came along. You want me to stop using cargo? Nobody wants to go back to manual dependency management. Make something better.


> And cargo and npm show just how unnecessary all that pain is in C!

Leftpad would like a word.

Every dependency is a liability. It's another thing to vet, another thing which can disappear. Having few dependencies in c is a feature, not a bug. The approach to dependencies in rust was a major turn off to me. I recall 15 just to get random numbers in the intro tutorial. No thanks.


Just in case you don’t know, packages can no longer be pulled from npm by the developer. At least not without emailing someone. And you need a very good reason - like that version is ransomware.

The particular pulled package version identifier (foo@1.0.1) can also never be reused. If you audit 1.0.1, it will never change out from under you.

The leftpad fiasco was hilarious and embarrassing. But it can’t happen again because of changes in npm policy.


Keeping track of C/C++ dependencies is basically the point of Linux distros...

Cargo's main problem is that it's (mostly) rust only. Same problem that pip/npm have, relegating you to (mostly) single-language silos.


> Keeping track of C/C++ dependencies is basically the point of Linux distros...

Judging by the proliferation of docker I don’t think they’re doing a great job of even that. Docker shouldn’t be needed if apt was up to the task. Nixos is a much better design imo.

> Cargo's main problem is that it's (mostly) rust only.

True. But apt’s main problem is that it only works on a few distributions of Linux. Limiting the users of my rust library to rust developers is usually not a problem. Limiting the users of my rust library to the people who use homebrew or arch or something is not fine. And I don’t want to redo all the packaging work on every operating system and major Linux distribution. Life is too short for this make work BS. Especially given it could be automated away anyway. Rust packages already explicitly define all their dependencies. Why can’t apt just generate .dpkgs from my Cargo.toml?

Apt’s other problems are that packages need to be installed globally. And they make a mess of versions. And there’s no feature flags. Run `apt search vim` some time and see how many packages they have! Or the same for llvm. It’s a dog’s breakfast.

The time that cargo’s rust focus hurts it is with binary packages. It’s not enough for ripgrep to live in cargo since it’s designed to be useful for people who aren’t rust developers. And I don’t have a good answer for how to solve that. I wish I did.


We'll this also works for rust libraries as they're usually useless for other languages, whereas libraries like gdal, opencv, fftw, etc. can be used by many languages. (Though to be fair, until rust gets a stable ABI it's not going to be a good choice for this sort of thing).

I personally consider docker/podman just completely punting on dependency management, and try to avoid them, but I'm probably in the minority...


Rust has a stable C export ABI.


Funnily enough, the most notable rust-implemented with C ABI shared library I'm aware of (librsvg) just became available on crates.io a few months ago...


...except pip/npm often build C or C++ while packages install, at least in some cases.

And Rust has the same issues, at least when shipping or consuming libraries with C APIs is in the picture.


Yes, sometimes, but it won't resolve C/C++ dependencies in general.


meson actually solves this problem on the build system, their wrap subsystem allows you to use the system provided lib if found, or fetch from a database during the build process if not.

best of both worlds, imo.


If you're smart about it you're not gonna have a very deep or wide dependency tree for your own deps. If you need more than maybe two of your own deps, maybe you need to reconsider how you structure your libraries, or you can join multiple libraries into the same project/build system umbrella (e.g. glib/gobject or the whole of QtBase)


Why would I want to join unrelated modules together into a kitchen sink library? The only benefit of that is to work around bad dependency management systems that make dependencies a hassle to work with. But otherwise, they’re a bad idea. Packages should do one thing and do it well. If I want a good random number library, I don’t want to import bob’s junk draw of random code. I want a small, reusable random number library. I want one that I chose. And my users want one they chose. And if that choice is bad, I want to be able to replace it without throwing out half my ecosystem or breaking downstream compatibility.

QtBase is a symptom of C++’s bad package management. 8 unrelated utilities should be in 8 small packages that users can pick and choose based on their needs.


It's less a workaround around bad dependency management, and more about the fact that it's simply easier to reason about a smaller set of dependencies regardless of the ecosystem. This includes both vetting, ensuring version compatibility, checking license compatibility and reducing the SBOM, as well as governance over the project and integration between different modules.

Too often have I seen the equivalents of frameworks in other languages being split over sometimes hundreds of packages, that don't always make it clear that they're to be updated in tandem, what their exact relationship is, and that the same organization manages all of them.

As for QtBase, it's a superproject, but that doesn't mean that you can't use its individual modules separately, and depending on the distro (e.g. debian) install them separately as well. A singular project installing multiple related libraries makes a lot of sense.


> This includes both vetting, ensuring version compatibility, checking license compatibility and reducing the SBOM, as well as governance over the project and integration between different modules.

Auditing large code bases takes disproportionately longer than auditing small code bases. So I don’t think that’s a win. License compatibility is trivial to check. SBOM is strictly larger if I pull in a kitchen sink package because I’m probably not using most of the stuff inside. Better to just pick out the components I want.

The one thing I’ll grant you is that shared ownership and visibility means it’s less likely that one rogue person will sneak ransomware into the dependencies.

Personally I’d love a capability based package manager that lets me pass a package exactly the capabilities it needs to do what I downloaded it for. Why does every package need access to my files when I install or run it? That’s ridiculous. Totally unnecessary and a massive security risk. We could solve that C++ style by hobbling package managers and using fewer, jumbo packages. But that doesn’t solve the root problem. I want a package system in a language which lets me pass capabilities to each library I use, when I need to use them. Eg “Please open your web server on the port associated with this capability token.” This needs language support too but it’d be so much better from a security point of view than anything that came before.


> or you can join multiple libraries into the same project/build system umbrella (e.g. glib/gobject or the whole of QtBase)

This also seems worse than the status quo. So instead of having 3 or 4 dependencies I now only one that combines 20 different ones I don't need.


This is an example where your tooling limits your solution space. There’s nothing inherently wrong with a deep or wide dep tree.


Why is this inherently better than better tooling for dependency management?


> It doesn't (need to) get packaged by a distribution until a program using it is packaged.

I think this is a key difference in approach. In languages with their own packaging systems, you routinely package libraries before there are programs using them. Publishing them on Crates/PyPI/npm/whatever is the bare minimum if you expect anyone to use them!

The number of tiny dependencies can go too far - I don't think I need to mention left-pad. But the difficulty of using dependencies in C/C++, and the results of reinventing stuff, vendoring, or using kitchen-sink dependencies like Qt, don't seem optimal either. There must be a happy medium somewhere.


As I said in another thread, I think the happy medium is lots of small packages (people want that). And a capability security model within programming languages so small dependencies are limited to interacting with their parameters (and any resources their parameters provide them) and can’t speak to the OS directly. That would solve 98% of the supply chain problem.

Leftpad has already been solved by a npm policy change forbidding packages from being unpublished.


> As for the amount of dependencies, you have to wonder if it's better to have tonnes of small dependencies or whether it's better to have a few bigger ones.

You don't have to wonder, we've done the experiment. Anyone working in an ecosystem with non-joke package management knows that tonnes of small dependencies are a lot better.


C++ apps don't pull in that few dependencies. Take something modern that needs to talk over flatbuffs or protobuffs and maybe has a web ui based on emscripten? Then run ldd on it and recoil in horror. C++ dependency trees now often have a hundred or more items. Many of those are packaged with the OS, but that really shouldn't comfort you.


It kind of does comfort me that they are packaged with the OS, because it's an OS problem (and is relatively major) if they are broken.


It often takes months for distros as large as rhel to fix med. Or even high severity CVE. That is assuming your OS is getting updated properly. Maybe it is a container and you are doing that as part of your pipeline. But all that it means having the dependency in an rpm or deb file vs in a github repo pulled by conan or similar, is that there is someone you can sue that is supposed to notice the cve and roll out a new rpm or deb file. They aren't doing massive pipelines full of fuzzers and custom unit tests for all those packages, they are just... packaging... them. Otherwise we wouldn't be seeing things like the curl and openssl vulns. Yes you might have some recourse to bug rhel to fix it, where a crate author might not care, but that really isn't the experience I am having. If anything I end up pulling dependencies into my system to build if I can so I don't have to wait on the OS company. Between corporate IT and the OS companies delay as middle-men, my OS based dependencies are always the most aged and vulnerable of all my dependencies.


> In this brave new world the author is proposing - what?

In practice, you just vendor your code as part of the source package. It's the distro maintainers' job to factor it out as a separate dependency.


If you do this, remember to provide an option to factor it out. Meson (mesonbuild.org) makes this completely trivial and pitfall-free, and you should use it if you can't get away with just installing your libraries locally.


I went to mesonbuild.org and it doesn't match the description (some sort of betting site? I didn't stick around ...), and a search turned up:

https://mesonbuild.com/


Thanks, I mistyped it.


> as an author of some not very popular packages, what do I do?

Depends. Do you want your software to be used by users? For me as a user, software that is not in distribution repository almost does not exist. It is too much hassle to install, manage and uninstall it compared to installing software from Linux distribution. If i really, really need it, i will make exception, but that are individual cases.


> “It works for C/C++” by making developers working in those languages pay in blood for every dependency they pull in.

I think the industry may have thrown the baby out with the bath water. Now they're is a complete aversion to RYO anything, no matter how simple. Personally, I'm waiting for the pendulum to swing back towards the middle a bit more.


Eh. I love rolling my own lots of things. At some point I really want to make a little OS kernel. How hard can it be?

But then there’s things like rust’s rand crate which implements about 10 different random number generators, all with different properties around speed, whether they’re cryptographically secure and so on. And fed from a variety of entropy sources to make it work everywhere from Linux to windows to wasm. Look at this documentation. It’s an absolute master class.

https://rust-random.github.io/book/guide-rngs.html

Do you need this? Probably not. You can probably get by with some wrapper around ar4random or whatever the recommended entropy source is today on your particular operating system. But I’ll be honest, until the day I decide to care about how rngs work, I’m going to just import the rand package. And serde & friends for json support. Criterion for benchmarking. And so on.

Cargo is full of great libraries that are much higher quality than anything I’d ever throw together in a side project. For most of this stuff, you’d be mad to roll your own.

This thread has reminded me that lots of people don’t know how nice it is to use a package manager like cargo. Here’s my favorite crate browsing website. You can see the most popular packages in every category and search. Look how much great stuff is in here. It’s humbling.

https://lib.rs/


>Yeah. The part that gives me goosebumps with that proposal is: as an author of some not very popular packages, what do I do? Is it my job to package and promote my packages on Debian, redhat, homebrew, and all the others? Do I need usage before they’ll pick it up? Sounds like a chicken and egg problem. And doing all that packaging work sounds like a boring, time consuming job that I don’t want.

Github premium (or similar) will have an army of AI builder bots that spin up VMs and modify your codebase until it works, then send you PRs to approve. People would pay a ton for that service. All your projects, automatically maintained and packaged.


You create apt, rpm repos.

And users install from there.

Not saying that's a nice answer, but that is the answer.


You create apt, rpm repos. And arch. And gentoo. And FreeBSD ports. And homebrew and macports. And whatever windows does. And you need that to be true, on all those systems, for all your dependencies too. And at a recent, usable version.

Or, I just use cargo. Up to date version. One command install that works on every operating system. Project scoped dependencies - so there’s no need for sudo, and different projects can depend on different versions of their dependencies. And I can publish new versions of my packages with 1 command and they’re available everywhere.

Just in my house I have a Linux mint workstation, a windows gaming pc, a FreeBSD server and a Mac laptop. Cargo lets me publish code that all of them can consume with 1 command. So does npm.

So long as apt is worse than cargo I won’t use it for this stuff. Why does everything have to get installed system wide? Nix doesn’t need that. Why doesn’t it have a programmatic mirror of cargo so we don’t need to mirror rust projects in it by hand? Why do major versions have different package names? And why don’t packages support feature flags? Last time I looked there were about 30 vim packages with random combinations of feature flags set. Why can’t evergreen packages like nodejs or cargo stay up to date in Debian? Old nodejs is useless because it can’t run modern JavaScript.

I really want apt to solve all these problems because I hate docker. If apt and friends did their job well, docker wouldn’t be necessary or popular.

Cargo isn’t pretty either. But it has all the features I need to get my job done. Make apt a compelling tool and I’ll switch to it. The feature list developers want is hardly a mystery.


Correct, there are many operating systems.

That is why each modern language has introduced their own package manager.


I assume you’re being flippant, but it’s kind of true. You support 20 different things by making a 21st thing that papers over all of them. And along the way you can try to fix some of the design problems.

The web. The C programming language. Electron. It’s a tale as old as time.


Users install from there, so long as they're using Linux, a Debian or Red Hat based distro, and have sudo access. As you say, not such a nice answer.

For certain kinds of software, this approach is getting more viable, thanks to containers. In some contexts, you can tell everyone to run your software in a container with a specific Linux distro inside. But that software is often distributed as container images directly, rather than distro packages to be used in containers.


As a distro contributor, I don't share these views at all. Yes, it's sometimes a bit of a pain when some application needs an older, incompatible library, but in 99% of the cases, the fallout is minor, or there's some compatibility library or shim I can install. The advantage of doing this being that the old application will now support all modern audio/video formats (e.g. ffmpeg) and the new graphical and audio subsystems on linux (e.g. sdl), as well as whatever security fixes.

If I really need an old library, it's generally not hard to install that in a temporary prefix and set the relevant PATH variables for it, though I do wish this was easier sometimes. It gets better as more projects just use pkg-config.

That all said, Meson[1] solves all of these issues in a way that keeps both developers and distributions/users happy. But as is with all things C, getting everyone and especially windows users to adopt it is gonna take a good while.

[1]: https://mesonbuild.org/


> As a distro contributor, I don't share these views at all.

That's because you're in the very small group of people that knows how your distro's packaging process works in detail. The majority of developers don't use Linux at all, and those that do typically know just enough to install a few blessed packages, not enough to hunt down and install the correct shim in a temporary directly.

Multiply that lack of training by the dozens of Linux distros being used by users of a language, and it's no wonder most modern languages have a standard language-specific package manager. The alternative is for them to be constantly fielding impossible-to-answer questions from developers who (unlike you) don't understand their distro well enough to make compilation work.

It's far easier for the language to have a single cross-platform package management system where the answer is usually as simple as "X, or Y if you're on Windows".


> The advantage of doing this being that the old application will now support all modern audio/video formats (e.g. ffmpeg) and the new graphical and audio subsystems on linux (e.g. sdl), as well as whatever security fixes.

That's the theory. In practise, it just means small app developers putting up with:

1) #ifdefs for different versions of same libraries in different distros

2) distro specific bug reports for an operating system with less than 2% user base

3) binary releases that target just 'Linux' being out of question for most proprietary applications / apps that can't/won't be included in distro repositories for various reasons.

It's not as if distro maintainers will test your random little application every time they update ffmpeg anyway. It's the users, for whom the application breaks.


I just don't attempt to compile C/++ software these days because the process is always an absolute nightmare where you have to attempt to compile, then google the error to see what package it's related to, try to work out what the distro name for this package is, install, recompile, repeat 10 times. And hope you don't get completely stuck where you distro just doesn't have the package or version you need.

Something in rust is always just `cargo run` and you're done.


Well, clearly what I wrote has resonated with people, as this is now my second-highest-voted comment, currently at +101.

(My >4000 comments range in score from −4 to +76 plus one outlier at +287 because people really hate stale bots on issue trackers. See https://news.ycombinator.com/item?id=32541391 for methodology. This comment has also clearly evoked a strong emotional reaction.)

All I can say is that I’ve had a lot of trouble over the years building older C/C++ software, often seeking to consume it from Python but sometimes just from C/C++. Maybe if I lived and breathed those languages I’d cope better, but at the very least they consistently take extra effort that requires at least mildly specialised knowledge, compared with my experiences of pure-Rust or even mostly-Rust software.


I too have moaned and ranted about this the problem with installing "modern", dependency heavy apps -- it's to the point where it's borderline anxiety inducing. I take the upvotes as a sign it's widespread. There are examples of a really valuable package that myself and two coworkers independently have given up installing because the dependency nightmare was just too horrid (a C++ app).

When I started using Rust it truly felt like magic. I could any app by anyone and essentially `cargo build` would always just work. So effortlessly.


Update after another day and a half just because this thread has fascinated me because it’s my second clear outlier: it’s now up to +162, over double my third-highest. Also the immediate parent to this comment has been at +2, −0, +1 and is back to −0 as I write and I’m not really sure why (I’m just describing facts, right?) but that’s part of the fun! I won’t try to predict where this one ends up :-).


I voted it down because numbers don't really mean anything. Top-level comments that directly disagree with the article always do good if they don't get drowned out by another comment doing the same, especially when it's a controversial topic or a comment that directly reinforces people's preconceptions on a topic (and the article is about dispelling the preconception). You pointing it out doesn't add anything to the discussion.

My best comment by far is one on an article about linux support for laptops being great, talking about all the problems I've experienced in recent years, even though I do agree with the article's core statement.


I’ve given plenty of top-level dissenting and affirming opinions, probably at least a few hundred, probably less than a thousand (wild estimate based on the total and memory of likely patterns). The highest I’ve got before was +74 on a positive one (detailing my experiences with fraudulent YouTube Content ID claims of public domain melodies) and +73 on a negative one (detailing specific technical problems on an Informational-class RFC—yes, both of these were much more specific than the current case). Fundamentally such numbers may not mean anything, but when you get one that’s more than double the next highest from such a collection is very likely to mean something. And the final paragraph of my follow-up comment certainly added something (I wouldn’t have posted the number without it).

If someone had written approximately the comment I wrote first, I’d have upvoted it, because it matches my experience.


(wrong link, you mean .com)


Take a look at nix-shell scripts. Much simpler, lightweight and faster alternative to Docker and friends for being able to build a project forever. Start of a build script from a C project of mine:

  #!/usr/bin/env nix-shell
  #! nix-shell -i fish --pure
  #! nix-shell -I https://github.com/NixOS/nixpkgs/archive/4ecab3273592f27479a583fb6d975d4aba3486fe.tar.gz
  #! nix-shell --packages fish gcc gnumake gmp git cacert
  ...build script goes here...
-i fish: I am using fish shell.

--pure: Environment is as pure as it can reasonably get.

--packages: Packages from nixpkgs to be made available in the environment.

-I <github_commit_hash>: pinned to a specific git commit of nixpkgs. This script will give you the exact same environment with the exact same packages with exact same dependencies forever.

You can drop into a shell with the exact same configuration by using the cli command nix-shell with the same options.

Admittedly this is not as declarative as using flakes, since it's a script, but hey, I'm lazy, still didn't sit down to learn them once and for all.

Reference: https://nixos.org/manual/nix/stable/command-ref/nix-shell


> Take a look at nix-shell scripts. Much simpler, lightweight and faster alternative to Docker and friends for being able to build a project forever.

As researchers using nix derivations to preserve usability of code meant to be archived with our papers, we found that it was not particularly effective for this task. Even with nixpkgs pinning, our code failed to compile after only a few years. Outside of nixos itself, it does not appear that the build environment is the same; aspects of compilation change, and we ended up needing to change compiler flags a few years later, while expecting that we might need to again at some point.

Overall nix has been quite disappointing for us from an archival standpoint.


Things shouldn't change if the nixpkgs version didn't change, you didn't disable the sandbox, and you don't have master branches of random repos as dependencies. If that's the case, sounds like a major nix bug.

If the sandbox is disabled (as it is by default outside of nixos I believe) then yes, you need to be very careful that there is no outside state that leaks into your build (usually through environment variables, PATH but not only - GCC is a big offender here), which sounds like what happened in your case? For archival purposes you really should be enabling the sandbox.


Thanks: it does seem like the lack of sandboxing is the major problem here. A difficulty in this sort of archiving is that we're not trying to make it so that we can build the code: we're trying to make it so that any reader in the future can. Close to zero of those readers are likely to be using nix for anything else, or to have any experience with nix (or any other approach we might take).

Our approach was to make a script for nix-shell that would put the readers in an environment where they could run the code, compiling specific (old) versions of two research software packages. But I think the problem here is that in writing the derivations here, we didn't put gcc in the build inputs. So the system's compiler ended up being used, and with the old, finicky code, compiler flags needed to change. A frustration here is that it appears sandboxing can't be enabled for nix-shell, a problem that has been known for close to a decade [2]. But in our case, if we can get the build inputs to be reasonably complete on our own, it should improve the situation for our readers in the future.

[1]: https://github.com/DNA-and-Natural-Algorithms-Group/SST-sequ... [2]: https://github.com/NixOS/nix/issues/903


Nix-shell scripts are ad-hoc, what nix does here is to provide an environment. Nix derivations are different and can be fully declarative and pure. Nixpkgs pinning does not mean specific nixpkgs commit pinning or pinning a specific version of a package. You can do these as well. I wonder what was the underlying reason for your condition.


Just curious, have you written anything up about these experiences with Nix? I've been learning it recently and the reproducibility angle is a huge part of why, if it's oversold then I feel like I should reevaluate how much time I'm putting into it.


> Even with nixpkgs pinning, our code failed to compile after only a few years. Outside of nixos itself, it does not appear that the build environment is the same; aspects of compilation change, and we ended up needing to change compiler flags a few years later, while expecting that we might need to again at some point.

Was this using flakes or no?

Since you mention pinning, I'm guessing not.

An experience report, even if brief, would be very valuable to a Nix/NixOS community working seriously on reproducibility.


You might give GNU Guix a try, combination of guix time-machine and guix shell -C should give you the exact same environment each time without fear of being affected by the rest of the system (with the obvious exception of the linux kernel).

And it seems to be popular in science circles.


RPM .spec is more readable, IMHO.

Archive of system repo + mock + SRPM does the same thing, but offline.


Rpm assumes deps and toolchain and doesn’t prevent accidental dependencies last I used it, admittedly many years ago. Are builds somehow done in a limited chroot now? Is the toolchain version dependency tracked and managed?


In Fedora, mock[0] is used to build packages in clean chroot for multiple of distros. In SuSE, Open Build Service[1] i used.

[0]: https://fedoraproject.org/wiki/Using_Mock_to_test_package_bu...

[1]: https://en.opensuse.org/openSUSE:Build_Service_Tutorial


What about the toolchain being used, is that some how understood to be part of the result? This seems to be often overlooked. In nix the toolchain is considered an input I believe and taken into the output derivations hash. Meaning a toolchain change results in a new package (rightfully so!)

What if you need different versions of the same package to support end applications?


It's even worse when you consider cross-platform or even cross-distro builds. Take a C++ application developed on Linux and try to build it on Mac, or vice versa. This can be really painful even without waiting 5 years because oftentimes two different package managers have incompatible versions of packages, or even if the versions are the same they're built with different settings/features. Not to mention the pain of search paths and filenames differing across platforms and breaking assumptions in build systems.


As a C++ dev myself, and lots of past experiences with code archeology, nowadays I wouldn't even bat an eye before reaching for a Docker container of the appropriate system version, where to build an old and unmaintained C or C++ codebase. Otherwise, pain ensues...

If we add loading binary libs built for an older system, then there is no question. Who wants to deal with incompatible versions of the GLIBC?


> Take an app written five years ago that depends on majorish C++ libraries, and there’s a fair chance compiling it will be a nightmare

Interesting. My experience doesn't back this up at all. I may have issues with 20+ year old code, but I don't remember ever having anything but minor issues otherwise.

I wonder what the difference between us is?


C++ is horrendous when it comes to backwards compatibility and builds.

If you believe that you won't run into a compiler bug in a large enough sampling of C++ code to build against you are misrepresenting reality or haven't ever looked at the gcc or clang bug trackers.

Rust actually does a really nice job along these lines by continuously building and running test for some subset of crates in crates.io

The only thing maybe even close to that with gcc/clang involved I've seen is nixos's hydra.


> If you believe that you won't run into a compiler bug

I never made anything like that claim. Nor was I making any comment about the utility of something like crates.io.

I was just relating my personal real-world experience working with code. Interesting that I got downvoted, as if what I've experienced in my career was somehow wrong. I certainly wouldn't claim that devs reporting the opposite experience from mine are wrong. It's just that the difference is stark, and I was curious as to why.


No subset, all of crates.io gets built for every beta amd then stable right before release looking for any changes from the prior stable.

Note that this is not all Rust code that exists, but it does help a lot.


> If crates.io goes down or access is otherwise disrupted then the Rust community will stop work.

As someone who has worked in a big corporate their entire career this statement is bizarre. This has been solved for Java for over a decade.

Builds don't access the internet directly. You host a proxy on-premise (Nexus/Artifactory/etc) and access that. If the internet location is down, you continue as normal.

> You need only one author in your maybe-hundreds-of-dependencies tree to be hacked, coerced or in a malicious mood for you to have a really bad day.

There are products (Nexus Firewall) that can check dependencies for vulnerabilities and either block them from entering the network or fail CI pipelines.


The main problem the author is talking about is actually about version updates, which in Maven as well as crates.io is up to each lib's author, and is not curated in any way.

There's no technical solution to that, really. Do you think Nexus Firewall can pick up every exploit, or even most? How confident of that are you, and what data do you have to back that up? I don't have any myself, but would not be surprised at all if "hackers" can easily work around their scanning.

However, I don't have a better approach than using scanning tools like Nexus, or as the author proposes, use a curated library repository like Debian is doing (which hopefully gets enough eyeballs to remain secure) or the https://github.com/crev-dev/cargo-crev project (manually reviewed code) also mentioned. It's interesting that they mention C/C++ just rely on distros providing dynamic libs instead which means you don't even control your dependencies versions, some distro does (how reliable is the distro?)... I wonder if that could work for other languages or if it's just as painful as it looks in the C world.


Everyone is focusing on Nexus Firewall. Nexus/Artifactory themselves are private repos/proxies/caches that are in widespread use in the Java world so up to a point most companies prune their own repos.

This is NOT standard practice in the JS/Python/PHP/whatever world because these products do not exist or are not widely available, everyone "drinks" directly from the open internet source.

Yes, again, solutions exist, technically, but how many companies do you know, especially smaller ones, that do this?

For Java almost every company bigger than 5 devs tends to set up their own Maven repo at some point, many do it on day 1 because at least 1 dev is familiar with this practice from their former BigCo and it's easy to set up Nexus/Artifactory.


Artifactory works well with as a proxy for pip for Python


Yeah, I know that these days they can do everything, but the cultural bias is there.

The average Java dev will try to reach for Artifactory/Nexus much sooner than the average Python/Ruby/PHP/Javascript/... dev, in my experience.


Only because of company culture, in most enterprise projects I work on, doesn't matter the stack, everything gets legal and IT approvement into the internal Nexus.

Devs might do whatever they feel locally, however if those files are going through CI/CD their dependencies better be in Nexus.


We use Artifactory as a PyPI mirror and a private package index and it works really great.


It works in the C world because everyone is super fixated on library compatibility, and the programs are expected to be rebuilt by the distribution when necessary. When an API is broken, this entails a new major version and installing both versions side by side until all maintained software is ported. This doesn't happen often enough to be an issue - that's the perk of having a really mature ecosystem.


On the other hand, having tasted Nix, the process you are describing seems as backwards and archaic as operating punched card computers to me. So much wasted human time, serving a need (of an ecosystem) now obsolete, thanks to Nix.


I'm trying to use Guix (just prefer it due to the language, Guile, over Nix) but unfortunately it doesn't have a lot of software packaged yet. I tried to build a project I have but it doesn't even have a "builder" for the language I used , Dart (which compiles to binary on all OSs), and I can't find out how to create a "builder" for it... someone did this for Nix to build pub packages so it's possible, but it seems if you want to use Nix/Guix you're stuck on a very limited set of things you can use? Is that a fair analysis? Do you have hints to build your own software when it's not available on Nix/Guix?


In general adding a build system to Guix works like this:

1. Git clone https://git.savannah.gnu.org/git/guix.git

2. Nicolò Balzarotti already has a work in progress patchset adding Dart itself--see https://issues.guix.gnu.org/44926 . Patch your guix checkout with the files you can download on that page via the downarrow buttons on the right.

3. Create a file guix/build-system/dart.scm (I'd copy it from guix/build-system/dub.scm and then s/dub/dart/g and s/ldc/dartcc/g) or whatever it is. This file is the "front end" and is support for dart for the guix package manager script.

4. Create a file guix/build/dart-build-system.scm (I'd copy it from guix/build/dub-build-system.scm and then s/dub/dart/g). This file is the "back end" and is responsible for the build of your package inside a new container.

5. Add references to your new files to gnu/local.mk

6. In your user package script (whatever you want to compile in dart), add #:use-module (guix build-system dart) near the top and then add (build-system dart-build-system) to your package.

7. guix environment --pure guix

8. ./bootstrap

9. ./configure --localstatedir=/var

10. make -j5

11. exit

12. ./pre-inst-env guix build -f yourpackage.scm or whatever

13. Fiddle with the "invoke" parts in guix/build/dart-build-system.scm until your user package works.

14. Submit your results to 44926@debbugs.gnu.org or guix-devel@gnu.org (no need to be subscribed).

As you can see, adding a new programming environment is quite some work. Because every programming environment has its own idiosyncracies, I don't think it can be avoided even in principle.


Thanks for the detailed information. Looks like it's a huge effort. That Pull Request is adding Dart 2.8 while the current version is 3.1.5 (and it's released often, at least once a month). Most pub packages don't even work on Dart 2.x anymore. An unrelated question: what do you mean by my "guix checkout"? I saw this in some docs (to add guile-guix to the guile load path so emacs can help me write guix code) and I don't know where that is as I am using Guix OS (in a VM) and as far as I know there's no sources in it?


>what do you mean by my "guix checkout"

I mean the working copy (the local directory) created by git clone.

>Looks like it's a huge effort.

Probably.

I've never used Dart in my life, so I don't have so much Dart-specific information, sorry.

> That Pull Request is adding Dart 2.8 while the current version is 3.1.5 (and it's released often, at least once a month). Most pub packages don't even work on Dart 2.x anymore.

Then as a next step you (or someone) would probably add another dart package for version 3, building it with Dart version 2 (is that how the dart build works? Probably).

>as I am using Guix OS (in a VM) and as far as I know there's no sources in it?

Just do the git clone. The guix package manager is a regular program (with source on git) like any other.

I always use a git clone of the guix master branch (for like 6 years now) and it was never a problem. But if you instead want to use the version used by your OS, do guix build -S guix . It will unpack the source of the current guix and tell you where it is. I wouldn't bother doing the latter though.

Also, basically there's a guix daemon that does the build container management (think of it as something like dockerd) and then there's the guix frontend. I'd never do "make install" in the guix working copy--so the guix daemon will not be fucked with. The ./pre-inst-env allows you to run the local directory guix frontend without installing it.


See https://news.ycombinator.com/item?id=38171379

Also, nix can do arbitrary building (arbitrary commands). You don’t need a specialized builder. You can write a specialized builder for your language too, if it doesn’t exist.


Coding mainly in C for 20 years, I've never had a program break on minor version of system shared library conflict. Occasionally need to recompile on OS version update when the major version increments.


The C community basically doesn't bother with libraries. They're so cumbersome to do in C that you'll tend to only have, like, 20 giant libraries in your (non-vendored) dependencies.


That does not solve supply chain attacks.


It solves most supply chain attacks. Distro maintainers are users, not developers. They put the needs of a user first, and their work is reviewed during submission. If one of them goes rogue, the damage is usually caught before reaching the user and otherwise minimal, as the update is simply reverted by other maintainers and a different maintainer can take over their packages.


Sorry, I misread jjgreen's comment. I 100% agree with what you are saying.


> There's no technical solution to that, really.

There is. Theoretically speaking, you could confine libraries to their own sandbox.

But Rust can't do that.


Do you have other info on languages that do? In my mind, if a library is compromised and incorporated in software that touches sensitive data then there's no way to meaningfully sandbox it. Sure, the library lives in the sandbox, but so does the stuff you're trying to protect. I'm not sure that's a Rust-specific problem.


Java (look up Security Manager).

Unfortunately it is deprecated and scheduled for removal because too much security is annoying and not enough people care to use it.


The library should live in its own sandbox, separated from the rest of the system including any other libraries. All system calls have to go through a permissions system that (e.g.) denies access by default.

There is at least one language that tries to do that (someone posted it here in a comment some time ago, but I can't find it).


And this is easy to do with Rust as well. The article mentions both major options: store your dependencies in your repo using the built-in `cargo vendor` command, or run a mirror like panamax that just mirrors all of crates.io (or just the packages you need, but then you run into issues with updating if crates.io is ever down).

Mirroring all of crates.io takes about a terabyte of storage, not much bandwidth and is really easy to set up, but judging by the download numbers of obscure packages there are only about 20 places in the world doing that. Maybe people haven't bothered because crates.io is so stable, maybe everyone goes the vendoring route instead.


Why would you ask panamax to mirror everything though? You are maintaining a manifest of all your organizations dependencies right? Why would I mirror ancient versionsbof clap and that crate that checks your aol mail? Also, nexus doesn't have a functioning cargo plugin, it is community made and stagnant. Artifactory does support it. And I'm guessing artifactory is what most people are using for a private registry too given the state of the others.


Mirroring everything gives me the ability to not just build existing software independently of crates.io outages or decisions, but also to not be impacted in software development by such incidents. To me development involves using packages or package versions I might not have used before.

Of course if your development is already set up in a way that prevents you from easily adding, experimenting with or updating dependencies, maybe because of how the vetting process works, that might not be an issue for you. And many places are completely fine with just being able to build


Having worked in enterprise software, it has been my experience that the majority of in-house repos operate in a caching mode and not mirroring. The critical element is being able to build things in CI that are being PR'd/reviewed or are already merged and in both cases the relevant dependencies should already be cached. That and being able to re-build any tagged releases, again should be cached. New libraries being temporarily unavailable are generally not going to hold up critical processes, and the upstreams have been available enough for that to never be a serious issue.


Agreed - I can't remember what was used at my last job but you submitted a package to be mirrored and then each night it pulled in any new releases.


I'm quite happy -- even in commercial development -- to not be able to download new things if the package source is down. But not being able to access my existing dependencies is a blocker: I must be able to redeploy my own stuff, and to make fixes that don't involve version bumps.

It's unlikely that I'll need a new dependency at the exact moment that the source is down, but fairly likely that if the source is down then I'll want to build something. For personal projects I'll have stuff cached locally, and I don't mind so much if I need to wait for CI. For work stuff I need to be able to fetch my dependencies in CI.

Also, hammering upstream with requests for every single build is both slow and also sort of rude.


Yeah, that makes sense and we should probably expand a bit. I can't imagine wanting versions that are older than anything we support or what those things bring in. Also we prune stuff that gets unmaintained or has a cve pop up. And we don't mess with copyleft, not against it, but when everything is statically linked you get into incompatible combinations quickly.


These days some laptops have enough storage to comfortably mirror all of multiple language package repositories especially if you use a compressed volume for them.


> `cargo vendor`

I had no idea \o/ Thanks!


> As someone who has worked in a big corporate their entire career this statement is bizarre. This has been solved for Java for over a decade.

> Builds don't access the internet directly. You host a proxy on-premise (Nexus/Artifactory/etc) and access that. If the internet location is down, you continue as normal.

Right now I'm using Sonatype Nexus (the free version) for my personal needs: https://www.sonatype.com/products/sonatype-nexus-repository

And I do mean most things: apt packages, Docker images, Helm charts, as well as packages for Go, Java, .NET, Node, Python and Ruby, maybe even more in the future. I'm very glad that it is possible to do something like that, but honestly it's hard to do and I can easily see why most wouldn't bother: even though the configuration UI is okay and you can create users with appropriate permissions, you'll still need to have plenty of storage, manage updates and backups, setup automated cleanup tasks (especially for Docker images), in addition to the whole process on the developer's side sometimes being a nuisance.

With npm you get --registry which is one of the simpler approaches, Ruby Gems needed some CLI commands along the lines of "bundle config mirror" and other stuff, Maven needs an XML file with the configuration, in addition to publishing your own packages to those also needing more configuration. Sadly, it seems like this fragmentation of approaches is unavoidable and complexity increases with the amount of languages you use.

On the bright side, I keep control over my data, as well as have really good download/upload speeds, even on a cheap VPS. Plus you learn some vaguely useful things the more you explore if you want to go further, like how I also start with Debian/Ubuntu base container images and provision whatever tools or runtimes I need for more specialized images (e.g. my own JDK, .NET, Node etc. images).


I don't know if they ever implemented it, can it offload the storage to S3? The cost is peanuts and you stop bothering about the annoying recurrent storage issues.


> I don't know if they ever implemented it, can it offload the storage to S3?

There are actually multiple different kinds of blob store backends: https://help.sonatype.com/repomanager3/nexus-repository-admi... though so far I've only used the File one, because my servers have incremental backups that can be restored in a few clicks (that I've sometimes done in the past).


The UI does leave a lot to be desired, definitely! I wish they'd add specific UIs for the different formats.

I agree with the pain that some languages/package managers add as well. Its a shame package managers aren't necessarily designed to easily support writing your own mirror or switching repository.

Fair play for running your own Nexus for personal use!


> There are products (Nexus Firewall) that can check dependencies for vulnerabilities

Products can only do best effort scanning for known patterns of vulnerabilites. Those are only added after someone (or something) discovers it and verifies that it's not a false alarm. In between the time gap, scanners are ineffective and anything in your infrastructure can run the malicious code and get hacked. (Google supply chain incidents on npm or pypi.)

In general, there is always a way to bypass it, since the language is turing complete and unsandboxed. Anything going beyond that is a lie, or simply impractical. Systems with latest software and antivirus get hacked all the time. Nothing can really stop them. Why?

- https://web.archive.org/web/20160424133617/http://www.pcworl...

- https://security.stackexchange.com/questions/201992/has-it-b...

- https://en.wikipedia.org/wiki/Rice%27s_theorem

> and either block them from entering the network or fail CI pipelines.

Also, relying solely on an endpoint security product for protection is dangerous since antiviruses themselves get hacked all the time. Sonatype for an example:

- https://nvd.nist.gov/vuln/search/results?form_type=Basic&res...


My research is about detecting semantically similar executable code inside obfuscated and stripped programs. I don't know what commercial antivirus or vulnerability scanners use internally, but it's possible to generate similarity scores between an obfuscated/stripped unknown binary and a bunch of known binaries. I suspect commercial scanners use a lot of heuristics. I know IDA Pro has a plugin for "fingerprinting" but it's based on hashes of byte sequences and can be spoofed.

My approach is basically: train a model on a large obfuscated dataset seeded with "known" examples. While you can't say with certainty what an unknown sample contains, you can determine how similar it is to a known sample, so you can spend more of your time analyzing the really weird stuff.

The hardest part in my opinion is generating the training data. You need a good source code obfuscator for your language. I've seen a lot of papers that use obfuscator-llvm[1] to obfuscate the IR during compilation. I use Tigress[2] to obfuscate the source code because it provides more diversity, but it only supports C.

[1]: https://github.com/obfuscator-llvm/obfuscator/wiki/Installat...

[2]: https://tigress.wtf/


Great work! For unobfuscated or lightly packed ones, I guess your approach could mostly work.

One question: how do you detect when a binary is intentionally made to statically look similar to one binary, while its behavior actually mimics another?


That's a good question. There are Tigress transformations [1,2] that seem highly relevant to this goal, but they're harder to work with because the resulting C code isn't always compilable without errors.

In my work I'm not looking for intentional spoofing, but the obfuscations I do use [3,4,5,6,7] end up building very similar control flow structures for different functions. Maybe that fits the spirit of your question... Let me know if not.

So far I'm doing purely static analysis and control flow, but the broader field of reverse engineering includes dynamic/symbolic analysis where you track values through a running/simulated program. Great results but very costly to run.

I've been focusing on making cheap/static analysis better, so I haven't explored the dynamic/symbolic side at all yet.

[1]: https://tigress.wtf/virtualize.html

[2]: https://tigress.wtf/jitter.html

[3]: https://tigress.wtf/flatten.html

[4]: https://tigress.wtf/split.html

[5]: https://tigress.wtf/merge.html

[6]: https://tigress.wtf/encodeArithmetic.html

[7]: https://tigress.wtf/inline.html


> There are products (Nexus Firewall) that can check dependencies for vulnerabilities and either block them from entering the network or fail CI pipelines.

Once they're known. I suppose nexus firewall let log4j pass.


I’ve been building Packj [1] to detect publicly UNKNOWN dummy, malicious, abandoned, typo-squatting, and other "risky" PyPI/NPM/Ruby/PHP/Maven/Rust packages. It carries out static/dynamic/metadata analysis and scans for 40+ attributes such as num funcs/files, spawning of shell, use of SSH keys, network communication, use of decode+eval, etc. to flag risky packages. Packj Github action [2] can alert if a risky dependency is pulled into your build.

1. https://github.com/ossillate-inc/packj 2. https://github.com/ossillate-inc/packj-github-action


It let log4j pass for as long as it was known to be good. Within hours of the CVE opening the tool was blocking it. The purpose of dependency firewalls is to avoid two things: known badly vulnerable packages AND known malicious packages that serve no other purpose than to steal data or drop a trojan. No security is 100% bulletproof, but it's really surprising how much of the damage is done by 7 year old CVEs. Firewalls can be useful in exactly that.


> Once they're known.

Isn't that how life works? Unknown unknowns? :-)

> I suppose nexus firewall let log4j pass.

It should be reasonable to assume that a product dedicated to something will, on average, do this job better/faster than a random developer, though. Since that's their job.

So Nexus Firewall presumably blocks these vulnerabilities faster than the average app/system developer notices them. There's value in reducing the delta between the vulnerability exploit day and an entire ecosystem being patched/fixed.


Debian devs also let log4j pass.


It's pretty absurd to expect distribution maintainers to be discovering 0days.


Yes, but nothing can prevent you from consuming unknown vulnerabilities.

Once log4shell was discovered it was trivial to eliminate it from the organisation. We knew exactly what projects were using it and updated them accordingly. Access logs showed us that it was no longer used and we delete it.


Every serious enterprise runs a Rust proxy - and indeed Artifactory / Azure Artifacts and others support this.


Sure, Artifactory, etc. have their places. But I am objecting to your "no true scotsman"[1] type of argument. Furthermore, the most bizarre setups I have seen have been in "serious" enterprises. Hardly an endorsement.

1: https://en.wikipedia.org/wiki/No_true_Scotsman


I have to agree with the poster you are replying to. If an entity is not doing the bare minimum to QA software supply chain, then they are not "serious". That being said, I have seen many a large enterprise that do not treat software development as a serious endeavor and it shows.


Gitlab has this built in as well.

EDIT: Has a proxy for packages.

https://docs.gitlab.com/ee/user/packages/package_registry/


That isn't a proxy, it's a registry for packages you build


Has which built in?


Package registry proxy (linked in original comment)


I have CI pipelines fail when Github goes down because of crates.io being inaccessible.

Does anyone have a proxy for Rust? I'd love to run it. Please. Someone... help

edit: just learned Panamax exists for this... will try it


You are fundamentally limiting your ability to build Rust projects if you rely on the system's package manager.

A Rust program `p` can depend on `q` and `v` which depend on `u`, but `q` requires `u` @ 1.0.0 and `v` requires `u` @ 2.0.0. In the Debian world, you would have to change `p` and `v` to support a mutually compatible version of `u`. If those changes introduce bugs, they're Debian's bugs, but the author of `p` is the one who gets the reports.

Cargo naturally handles this case, it installs multiple incompatible versions at unique locations in its cache, and correctly invokes the system linker to link the compiled objects correctly. If `p` was a C program, we could not handle this case, because `u` would be a shared library and you cannot link two different versions of the same shared object into a single address space at runtime (if they were static libraries, a sufficiently smart build system could deal with it, just like cargo - but there is no unified build system and package manager for C, so good luck).

Further, Cargo creates lock files for your projects, and authors commit and push them for executables. If you build against a lockfile. This prevents most of the cases that the author is bemoaning. People don't run Cargo update willy nilly.

Frankly, the "problems" the author is claiming don't exist in practice and the "solution" makes life worse as a Rust developer.

I'm getting tired of hearing people praise broken package managers like Debian. They make life worse for everyone for no benefit. How many times do people need to read testimony that "C/C++ package management sucked and Rust is great just for Cargo alone!" before they get it?


Lock files are only one part of the solution. Even with a lock file dependencies need to be fetched from somewhere and if a particular version of a package was deleted by its author then you're back to case one.

"People don't run Cargo update willy nilly."

We don't know the same people then. Most devs like to keep their stuff up to date. Auditing the dependencies tree before updating a lock file is like reading a ToS. Most people don't even if they should.The problem of securing the chain of production is not solved with a simple lock file.


> Even with a lock file dependencies need to be fetched from somewhere and if a particular version of a package was deleted by its author then you're back to case one.

That's not quite correct. Even if a library version is yanked (which hides it in crates.io and makes it so cargo will skip that version during resolution), if it appears in a lock file, cargo will dutifully find it and use it. This is explicitly to avoid the leftpad behavior of a library disappearing breaking your build.


They get fetched from your local cargo cache, unless you purged that too. You're also not back to case 1, you get a compilation error that tells you that the package doesn't exist and you'll need to audit a replacement. This is a lot better than trusting someone to drop a replacement in automatically. But if you want that, there's cargo update - and like you said, it has issues (because updating dependencies always has issues).

> The problem of securing the chain of production is not solved with a simple lock file.

I didn't say it was. I said the issues the author describes almost all are. Relying on distro maintainers doesn't solve them either.


Unless you build and release on your own dev machine the local cache will usually not help you.


The author makes one big assumption - that the packaged code in Debian is better because it has been reviewed and vetted by someone competent. If this was true, it would make this approach worthwhile, but I don't think it is. The author could have pointed to some data that demonstrates this, but didn't. I remain unconvinced.

As far as I can tell, this is more about the feeling of security because of familiarity. I can completely understand why they would feel more comfortable using something they've successfully used for many years, but that feeling doesn't actually translate to improvements in security. There is a feeble attempt to suggest that slowing down the rate of change improves security, but I would prefer to have the latest versions of the language toolchain and libraries available immediately, so I can make a decision on what to use myself.

If security actually needs to be addressed, it's going to be by paying maintainers and paying people to review dependencies. And that would likely be in the framework of PyPI/crates.io/npm, because none of them place constraints on where the code can be used, unlike using a single Linux distro's package manager.


>The author makes one big assumption - that the packaged code in Debian is better because it has been reviewed and vetted by someone competent.

They do not make this assumption, and in fact state the opposite.


They state that

> They might decide to give the diff at least a cursory look, which is better than nothing.

So yes, they do value the cursory review, which isn’t that useful. And they talk up the security benefit of only pulling in a subset of published updates, which is even more dubious.

Contrast this with the approach that Google is taking here - https://opensource.googleblog.com/2023/05/open-sourcing-our-.... Actual, careful review of the code that anyone can take advantage of. And no limitation of having to choose one flavour of one OS. This review helps you audit your supply chain regardless of OS you’re developing and deploying on.


You read and quoted the third point. Now why you don't read and quote the first two?


> There is no mediation of any kind between when a new library/version is published and when it is consumed.

> A simple time delay will allow egregious malware like malicious build.rs scripts to be caught, whether that’s the super-long Debian stable cycle or even the several days required to migrate from unstable to testing.

Normal cargo + crates.io usage has the same property via the existence of lockfiles. For most people that care about stability, this will provide a natural delay (which you can also see in crates.io download graphs) to consuming the latest version.

-----

The other points brought up in the article are definitely valid, but if that's the main strategy of defense you are looking for, you might already have it.


> if that's the main strategy of defense

mostly, there can be a small attack gap when adding new dependencies to the project and at the specific point in time when you run `update`

through you can also pin versions in `Cargo.toml` and then review any updates, maybe except for a few highly trusted sources (it's a bit annoying and costly (time wise) but viable)

Through trying to vendor things, especially with Debian, seems like a horrible solution. And there is a lot of precedence for this causing tons of headaches, wrong bug reports and similar for developer (== time loss == time is money so we could probably be speaking about multiple millions of monetary damages).

Through I have been thinking for a while that it could be interesting to have a partial crates.io "proxy" which only contains and updates crates which have gotten a "basic screening" in all of their code and dependencies probably with some tool assistance this might not find bugs but it should find many forms of supply chain attacks. Through given that this is costly to provide it probably would not be a free service.


> there can be a small attack gap when adding new dependencies to the project

Most package managers will keep the versions of transitive dependencies as unchanged as possible when adding a new direct dependency.

Of course if the only solution to satisfy the dependencies of the new direct dependency is to upgrade a transitive dependency, that will be done.

(I've seen a lot of people treat dependency additions as completely unpredictable operations that regenerate the whole lockfile in the past, which is why I wanted to clear this up.)


> Normal cargo + crates.io usage has the same property via the existence of lockfiles. For most people that care about stability, this will provide a natural delay (which you can also see in crates.io download graphs) to consuming the latest version.

Be aware however that lock files are ignored by default. You need to specify "--locked" if you want Cargo to use the "locked" versions from Cargo.lock.

> By default, the Cargo.lock file that is included with the package will be ignored. This means that Cargo will recompute which versions of dependencies to use, possibly using newer versions that have been released since the package was published.

https://doc.rust-lang.org/cargo/commands/cargo-install.html#...


This is installing binaries from crates.io directly (i.e. running "cargo install ripgrep" instead of "sudo apt..." or whatever equivalent). Admittedly, this is often a suggested installation method for some built-in-Rust tools, but it's usually an option of last resort, and most people should be using their usual package manager for this.

Cargo does respect the package lock file when building a project from source (i.e. when you checkout a project, and run `cargo build` in that project directory). This happens, for example, when running builds in CI, or preparing a new release for each individual package manager.


I responded in a sibling comment because it came first.


This only applies to the `cargo install` command to install binaries from crates.io.

If you work in a repository on your own project and use basically any other cargo command (e.g. `cargo build`, `cargo run`), the lock file is of course taken into account (otherwise it would be near-useless).


Right but that's not the only use case for `cargo install`. You can also use it to install binaries system wide from cloned repositories (`cargo install --path .`). I use this often for small utilities (for which I have no intention of publishing to crates.io) or when testing before packaging for Arch.


These concerns pertain to every language using a centralized package authority. None of them-- crates.io, npm, pypi, hex -- are adequately funded by the multi-billion dollar industries they enable. So, they aren't as resilient and secure as they can be. The solution isn't to create yet another package authority but to reinforce those that the ecosystems are already relying on.


Npm is owned by Microsoft no?



In my opinion this just fragments the rust ecosystem and creates more problems than it solves. What about to just have mirrors of crates.io?

And I completely disagree that that someone else than the authors should distribute or manage the package. They know the best how and what there is to do in certain situation (security fixes and so on). Of course it is good to have independent reviews, but these independent people should not be in charge of updating, maintaining and updating these packages/libraries.


Having worked with C/C++ projects. Managing dependencies is downright painful. About the best option we found was to treat everything as build from source and then git submodule our dependencies in. This is still not good but at least it gave us a consistent environment.


> Managing dependencies is downright painful.

The risk when it is too easy is that you suddenly pull half of the Internet into your project. In C++, the cost of having a dependency makes me choose carefully if I want a dependency or not, and if I do, if I want this particular dependency (Who develops it? Is it maintained? If it stops being maintained, can I easily move to an alternative, or could I take over maintenance? ...).

> About the best option we found was to treat everything as build from source and then git submodule our dependencies in.

If you mean having a git submodule and doing something like `add_subdirectory(dependencyA)` in CMake, please don't do that. Building from source is fine, but then you can totally install the dependency locally and have your build system (be it CMake, Meson, ...) fetch it. At least I started doing it the way it is described here [1] and it works well for me.

[1]: https://www.acarg.ch/posts/cmake-deps/


Requirement to "install dependencies locally" is part of the pain with C++ dep management. Not having to do it makes builds much easier to define, as you don't need to supports lots of distros and hope that everyone of them is up to date.


I don't know, I feel like it is a bit of a tradeoff.

You can totally say "here is my code, it's open source, and the build system will look for those dependencies on the system" and let the users (who are developers) handle the dependencies the way they want. This way the user gets to choose if they trust the dependencies or not. Ideally the distro ships with those dependencies, and the user can just install them (better: write a package that depends on those dependencies and install that).

It seems like developers don't really know how to do that anymore, and language package managers allow them to not learn about it. But at the cost of control: they don't know anymore what dependencies they are pulling, or even how many they are pulling.

The modern way seems to be mostly about productivity, and therefore devs don't want to learn anything about dependencies, they want everything to "just work". But that is arguably bad for security.


I remember doing that whenever I wanted to build a C program on GitHub from source. “Oh cool, so I’m going to need these 8 dependencies. Let’s see which ones are supported on my distribution. Ok, I have 6 of them but 2 are weird versions from many years ago. No way that will cause problems! The other 2 I can install from source - oh, but the latest version of this dependency in git needs something else I don’t have…” and there goes my whole evening.

Is my computer more secure for it? Am I in more control? Absolutely not. I have weird 3rd party programs installed in weird places all over my system. I have a computer that is almost impossible to rebuild if my hard drive dies. Finally I can make fragile builds that might have bugs that nobody else can reproduce because of the idiosyncratic combination of package versions I’m using.

This is so unbelievably worse than cargo or npm. With cargo I can take any package on GitHub and reasonably install and run it on any computer I own (running any OS) with one command. The only time this breaks down is when part of the dependency tree is C code. It’s miraculous.

Give me that experience in apt and I’m there. But the experience apt currently provides is unbelievably bad for developers compared to cargo/npm/etc. I can only assume nobody who works on Debian has seriously tried npm or cargo.


> oh, but the latest version of this dependency in git needs something else I don’t have…” and there goes my whole evening.

Why not start by building the version of that dependency supported by the project you want to build? It's not like you ask cargo to take the latest versions of all the dependencies, is it?

> This is so unbelievably worse than cargo or npm.

I agree that in many cases it is less convenient. But in your example, 6 out of the 8 dependencies come from distro packages, which I think is better. For the last two, you could actually contribute community packages.

Have you ever tried Arch Linux, for instance? There is the Arch AUR where the community can contribute packages. I don't remember having had to compile a dependency from source, because everything I need is either in the official repo, or on the AUR. It is explicit when I need to get it from the AUR, so I know that I may want to pay more attention to what I am pulling. And usually I do and have a quick look at the package recipe (and its dependencies). In this case I would have to check 2 of them, and not 8, which is a big win.

That is of course less convenient, but I believe it is more secure. I see it as a tradeoff.


> Why not start by building the version of that dependency supported by the project you want to build?

Because I don’t know which version that is half the time. Does the readme say to use version 2.2 or 2.0.1? Are they meaningfully different? Maybe 2.2 is needed to be compatible with something else on my system. (Nvidia has entered the chat). I have no idea what is in the changelog of some random dependency that I’ve never heard of before - and I just remembered, I don’t care. I never care.

> For the last two, you could actually contribute community packages. Have you ever tried Arch Linux, for instance?

That sounds like an even more effective way to waste an entire evening. Maybe multiple evenings! When I see a cool program someone’s written that I want to play around with, what better use of my time could there possibly be than figuring out how to submit community made packages to arch Linux for the random dependencies of some random software someone linked me? All this before I’ve even built the program I want to try out? No thanks.

And how is it more secure? Do programs magically get security audits as part of their addition to arch Linux community packages?

Your comment reminds me of that infamous response in Dropbox’s “Show HN” thread. “Well, the problem Dropbox solves sounds like something easily done with rsync which is already part of arch Linux. Have you tried arch Linux? Instead of starting a billion dollar company, you could submit a simple bash script as a community contribution to arch. Using a bash script in arch Linux is of course less convenient. But I believe it is a trade off.”

And to answer the unspoken question, no. Arch Linux doesn’t have the tens of thousands of up to date packages that are already in cargo. And are already available on every operating system under the sun. Manually adding them to arch sounds like a pointless task that would only serve to make updating my dependencies more difficult and make my software less compatible on all the other systems it already, effortlessly works on. (Like Debian, FreeBSD, macOS and windows.)


> Does the readme say to use version 2.2 or 2.0.1? Are they meaningfully different?

If the library is done right, then 2.2.0 should work if it requires 2.0.1, and the reverse may not work (if the program you want uses a feature that was added after 2.0.1).

> and I just remembered, I don’t care. I never care.

Yeah, I think it is a big reason why language package managers are so popular: most don't care.

> When I see a cool program someone’s written that I want to play around with, what better use of my time could there possibly be than figuring out how to submit community

First, probably those packages were already contributed by someone else. Someone who cared.

Then... for the rare packages that may not already be there, I would hope that you could consider spending a couple hours contributing something back to the community you are most likely using for free and complaining about. For most libraries it should not even take two hours, except maybe the first time ever you do it.

> And how is it more secure? Do programs magically get security audits as part of their addition to arch Linux community packages?

As I said above, the ones that are shipped by the Arch official repo seem more secure. For the community ones, it's less clear, but I would argue that AUR users are at least not less likely to review a package than the cargo users are to review a transitive dependency.

> Using a bash script in arch Linux is of course less convenient. But I believe it is a trade off.”

Well if you want to use this as an argument, you should say why it is a tradeoff. Why is it a tradeoff? Are you saying that rsync is more secure than dropbox, but less convenient?


> Then... for the rare packages that may not already be there, I would hope that you could consider spending a couple hours contributing something back to the community you are most likely using for free and complaining about.

Is me volunteering my time and expertise to write and publish opensource code not virtuous enough? “If you really loved opensource, you’d also do this other task constantly that doesn’t even take 2 hours each time”.

Why does arch even need rust packages to be added by hand? I’ve already programmatically expressed the contents and dependencies of my rust package. And so have all my dependencies. Why not just mirror that programmatically if you want my dependency tree in arch?

> the ones that are shipped by the Arch official repo seem more secure. For the community ones, it's less clear, but I would argue that AUR users are at least not less likely to review a package than the cargo users are to review a transitive dependency.

It seems more secure? You’re making security assessments based on vibes?

I can’t speak for others, but I’m personally much more likely to review my dependencies in rust or npm than in Debian or whatever because the source code is available and linked from the cargo package page. And I can control+click in to my dependencies (or debug into them) and read their code. And with npm they all live in node_modules. Source and all. I dive in there all the time. Does arch do that too? I have no idea where to look for the source code of a package I installed using apt. I’d probably need to Google the package and hope apt hasn’t patched it in any significant ways that make the version on GitHub out of date.


Just to be clear: I mentioned arch as an example of a distro that has a very active community repo (AUR).

> It seems more secure? You’re making security assessments based on vibes?

I shared an opinion, I am not publishing a security paper. You also say a ton of apparently uninformed stuff that expresses your "feeling". Like "with Arch I would constantly have to contribute packages myself" (Did you try it? Do you have statistics and proofs?). You are entitled to disagree with my opinion, just as I am entitled to have one.

I think that we won't agree here, and for the record I was not saying that language package managers were fundamentally bad. I was merely noting that I see pros and cons on both approaches. I tend to defend the "distro maintainers" side more often, because in my experience, most developers don't know about it.

> I have no idea where to look for the source code of a package I installed using apt. I’d probably need to Google the package and hope apt hasn’t patched it in any significant ways that make the version on GitHub out of date.

Exactly my point. You don't like the distro way because you don't know anything about it. Not saying it is not a valid point: you are entitled to your opinion.

My opinion is that there are pros with distro package managers, like the fact that maintainers put together a set of packages that they ship as a distribution (that is the whole point of a distribution).


I agree that we probably won’t agree on this.

Re: security, specifics matter. AUR “feeling” more secure than cargo doesn’t mean it is. If the principle reason to use it is security, tell that story. How is it better?

> You don't like the distro way because you don't know anything about it.

I’ve been using Linux since a version of Slackware I installed off floppy disks. I remember trying apt for the first time and thinking it was an absolute revolution. The best thing since sliced bread. I haven’t tried arch but for what it’s worth, gentoo gets the source thing right. You can see the source of anything on your system with 1 command. And better yet, it all builds. There’s no stupid -dev version of packages like there is in apt (that drives me nuts). I’ve still never submitted a package to any package manager - and maybe you’re right. Maybe I should.

I’m upset by all of this because I want apt and arch and all the rest to be better. But as far as I can tell, apt hasn’t improved in decades. And now docker (which I hate even more) has come along and solved a bunch of apt’s problems for it by making something even uglier on top. What I want is a package manager with these features:

- Reproducible, hermetic environments (nix)

- Local dependency installation (nix, docker, cargo, npm)

- Cross-platform packages (docker, cargo, npm. Nix is trying but not there yet)

- Cross language packages (nix, apt, docker)

- Feature flags (cargo)

- Support for the same package to be depended on at multiple different versions in the dependency tree (cargo, npm)

- Semver API compatibility checks (nobody does this, but Cargo is working on it.)

- Simple, cross platform publishing. None of this “here’s how you install it on a few Linux flavours we got working manually”. I don’t want to have to play a guessing game of which distributions package which dependencies and what they call them. (Cargo and docker do a good job of this)

- Support for binaries and libraries (apt, cargo, npm, nix. Basically everything but docker.)

- I can just take a random project on github and run it reliably without spending hours pissfarting around first. (Cargo, npm. Apt gets negative points because software packaged with apt breaks so often on newer Ubuntu / Debian distributions.)

I can’t speak for arch but apt doesn’t cut the mustard any more. I wish it did. But it doesn’t. And no amount of “just work around it by manually submitting more packages to this one distribution specific package manager” will satisfy me. I change computer and Linux distribution all the time. I want something that works reliably everywhere. The other day I ran some rust code I wrote on FreeBSD. There are about 100 transitive dependencies, and I bet almost none of them test on FreeBSD. But it doesn’t matter. Once I had rust installed, I checked out the project and ran cargo test. Everything built and worked perfectly. That is how good life is with cargo. Or docker or npm. Or even Python once you get your head around conda or venv.

It’s 2023 and that’s table stakes for a package manager. Distribution specific package managers need to keep up because they don’t pass muster any more.


> Re: security, specifics matter. AUR “feeling” more secure than cargo doesn’t mean it is.

I specifically mentioned the official ones, not the AUR. The story is that the maintainers of a distro check (on a best-effort basis) the packages they ship, and the distros that have a security team patch them when CVEs are announced. Not sure how that would not seem more secure than e.g. pip, where I don't think there is any kind of check (before or after the package has been published).

> Or even Python once you get your head around conda or venv.

For what it's worth, I have this third-party project that used to work and now always fails to install because of some dependency issues in pip. For me it's been broken for years now, I always need to go fiddle with it, `pip install <package>` just doesn't work (it installs something that then complains about a dependency missing, and I can't install the dependency because of some incompatibility reason). I have never had an issue with Arch or Alpine.

I am not a huge fan of writing apt recipes, I like the pacman/apk ones a lot more.

> It’s 2023 and that’s table stakes for a package manager. Distribution specific package managers need to keep up because they don’t pass muster any more.

I do agree with you that there are many issues and I would like it to work better. But one thing I would like to see is devs learning how the tools work and trying to "do things properly". Too many people throw their project in a docker container just because they have no clue how to use their build system correctly, or how to install a dependency properly.

I see a lot of "I use this because it just works and I don't need to understand how", and it feels like this brought us stuff like docker-for-absolutely-everything and ElectronJS. Nix seems nice, but if people can't even be bothered to learn how to use SemVer properly, I don't see how they would ever get the motivation to even consider Nix.


My experience of using the AUR is that a decent part of the packages I try to install fail to build, which is certainly pretty secure.


Yeah I guess YMMV, I personally never had issues. Maybe once in a while a package has an issue and there are already comments on the AUR website so I don't even need to debug it myself. Maybe I had to debug once in ten years or something.


> There is the Arch AUR where the community can contribute packages. I don't remember having had to compile a dependency from source, because everything I need is either in the official repo, or on the AUR

When you install from AUR you are compiling from source though. Unless you're using chaotic aur, which only packages a subset of what's available.


Yes, my mistake, and good catch! I meant "having to write the recipe myself".


I am a developer, I know what dependencies I am pulling in my projects, what they do and I even read the code. What good will offloading this to my users do? They have to decide whether they trust my apps with all its dependencies, they can do that by reviewing the code of all deps transitively, but there is not much difference between a dependency from the distro repository and the dependency from crates.io.

> Ideally the distro ships with those dependencies

This is all good and well in the world where there is one single Linux distro, but usually you want to target all mainstream distros and macOS and Windows and what now. Depending on system packages becomes a brittle solution in these cases, since who knows which version of the necessary lib is packaged on this ancient Debian installation. If you depend on a newer version, then you are just forcing you users-developers to either spend time packaging it properly or just running `make install` and littering the system with untracked files. Honestly, stuff like `cargo` fixes this elegantly so I never have to think about it again.


> I am a developer, I know what dependencies I am pulling in my projects, what they do and I even read the code.

I am convinced that you are more the exception than the rule. For node projects that pull hundreds packages transitively, I can't believe for one second that the devs even read the list (and even less that they would start considering reviewing the code).

> but there is not much difference between a dependency from the distro repository and the dependency from crates.io

Who reviews what goes into crates.io? I know for a fact that other package repositories don't have any check at all: anyone can push anything. Whereas the distro repository is reviewed by the distro maintainers. Big distros have a security team even.

I think that is a noteworthy difference.

> but usually you want to target all mainstream distros and macOS and Windows and what now.

Of course, usually you want everything, for free, and for yesterday. But let's be realistic: the vast majority of projects don't have users on all the mainstream distros, macOS and Windows. I would start by maintaining a package for my preferred distro, and maybe one for Ubuntu. But maintaining a package should not mean "building a .deb": ideally you should use the program on that system so that you actually test it.

If someone wants it in another distro, they can write and maintain a package for that distro. And again ideally they use it themselves.

I believe that distro maintainers are responsible for distributing software for their distros. And for that they can rely on contributions and community repos, of course.

But projects that target 50 platforms and offer 50 binaries to download even though nobody has ever even installed 48 of them are missing the point, IMO. It is great if cargo allows you to say "builds for 50 different OSes", but if nobody ever tested them, to me it's just marketing.


> Whereas the distro repository is reviewed by the distro maintainers. Big distros have a security team even.

I don't think it globally matters and it certainly does not scale. Are you saying that Debian devs review all code in their repos? I doubt that, and they're certainly let log4j into their repos.

We already have pretty good automated tooling for detecting known vulnerabilities in deps, and updating and rebuilding is not hard. I don't see the added value of Debian's managing build-time deps of my apps.

It should be the devs' responsibility to audit code they use in their projects (including the toolchain), as well as it should be their responsibility to package, maintain and support the final product. I wouldn't want to support copies of my projects which were somehow modified by the 3rd-party maintainers before being provided to end users.

> the vast majority of projects don't have users on all the mainstream distros, macOS and Windows

I don't need to go far, if we're talking for example about some internal corporate tools, then the vast majority of projects have the majority of their users on macOS and Windows. In rare cases some deb-based usage is supported on best effort, but any other distro -- good luck!

The situation is not much different with some public projects, almost all devs don't go further than "supply a .deb and be done", and it's lucky if they support even that.

> It is great if cargo allows you to say "builds for 50 different OSes", but if nobody ever tested them, to me it's just marketing.

Cargo is not an end-user package management tool, it's a build tool for devs, which is then used for building deb, yum, whatever packages you need. It tracks mostly just build-time deps, and for everything else such as glibc, sqlite, any other .so I have no choice other than apt on Debian. This is fine with me.


> Are you saying that Debian devs review all code in their repos?

Well they certainly do patch a fair amount of vulnerabilities faster than I would. Everytime I checked because I was concerned about a vulnerability, it had already been patched.

> I don't see the added value of Debian's managing build-time deps of my apps.

I can trust the Debian security team to do a better job than I would. I definitely do not trust arbitrary developers about security. If there is one thing I have learned from the software industry, it is that almost nobody cares about security. Turns out that the people in distro security teams generally do care about security.

> I wouldn't want to support copies of my projects which were somehow modified by the 3rd-party maintainers before being provided to end users.

Well maintainers can and sometimes do that. But of course if you don't want them to distribute your project, that's your right. Maintainers usually don't run after devs to work for them for free :-).

Also note that some distributions are not the typical general-purpose Ubuntu. Maybe an embedded IoT distribution wants to use your library, and maybe they want to harden it, or something. If you have an open source license, it is totally their right to do whatever they want.


> The risk when it is too easy is that you suddenly pull half of the Internet into your project. In C++, the cost of having a dependency makes me choose carefully if I want a dependency or not, and if I do, if I want this particular dependency (Who develops it? Is it maintained? If it stops being maintained, can I easily move to an alternative, or could I take over maintenance? ...).

There is no such risk, as you're not playing a roulette. No one is pulling a gun to your head and forcing you to pull in hundreds of dependencies.

You can do exactly the same in Rust as you do in C++ and be conservative in what you use for dependencies. This is what I do, and it works great.

Now, that said, I agree that for the ecosystem as a whole this is a problem and people do tend to be too trigger happy when pulling in dependencies.


I understand that you agree with my point, but you disliked my wording? :-)


> this problem is largely solved for C and C++: Linux distributions like Debian package such a wide range of libraries that for many things that you want to develop or install, you don’t need any third-party libraries at all.

Even if it were solved on Linux (and it isn't, at least not for "our" dependencies), this doesn't help MacOS and Windows users. And no, Homebrew and Chocolatey (or whatever) don't háve all needed packages either.

Crates.io does have problems, the main one being non-existent namespaces.


I love the absence of namespace personally. No name collisions!


Why is a Debian developer a better gatekeeper against supply chain attacks than the developer of a popular Rust library?

For me the alternative to Crates.io/npm/PyPi is a "platform release" like Android where a bunch of stuff is signed off by a corporation.


I would assume that the Debian _maintainer_ cares about what is being shipped with Debian. And for each dependency (transitive or not), the Debian maintainer has to make sure that it is shipped by Debian, and therefore has to not only know about the dependency, but also to make a package out of it (if it is not already being shipped by Debian).

Whereas the developer of a popular Rust library most likely just added some dependencies that were convenient, and doesn't know the full story of the transitive dependencies.

To me it is much more likely that somebody at Debian _saw_ the dependency being shipped than an arbitrary Rust developer, who probably does not even know how many dependencies are being shipped with their program.


because it often takes so long to do any updates that people just give up on updating in time, weather that is for bug fixes or for injecting supply chain attacks /s/j


Well if nothing else, it's the difference between one person being able to ship something vs needing at least one person to review before shipping.


Debian developers go through a long step-by-step process to get in that position. Volunteering as a package maintainer first, getting Debian dev to advocate for you, cross-checking people passports, doing interview/exams to become a DD.

DDs review the libraries they package. All uploads are personally signed to keep people accountable.

Instead opening a github account and developing a library can be done anonymously and there's been supply chain attacks done this way.


maybe adaptation: debian has higher adaptation than rust, meaning more people will start screaming if something wrong is going.


I'm not sure how one would define "adaptation" (presumably meaning "adoption", ie: how widely used something is) in a way that could have debian have a higher adoption than rust: rust ships in programs within many linux distributions and other operating systems (mac os and windows). rust is used in widely used programs/kernels (Firefox, Chrome, Linux itself, Windows) that span further than debian itself.

All this is to say: a large amount of debian users likely are using rust, and an even larger amount of non-debian users is likely to be using rust.


> rust is used in widely used programs/kernels (Firefox, Chrome, Linux itself, Windows)

those few narrow components likely have good support.


> Rust as we know it stops if this one particular web service goes down.

True that, but that is only because we got used to not having to download dependencies manually (like with C). The option of "download all of your dependencies by hand and slap them in a directory" is always there, only instead of invoking ./configure with --with-libxyz=PATH or setting XYZ_PATH you modify a Cargo.toml.

> this problem is largely solved for C and C++: Linux distributions like Debian package such a wide range of libraries that for many things that you want to develop or install, you don’t need any third-party libraries at all.

That's rich. If that was the case, there would be no Docker. What about Windows? On Windows installing C/C++ libraries is a massive PITA. What about if your distro packages the wrong library version, or it's been built with a set of flags you can't use? The whole point is moot IMHO. A small part of why we ship libraries through package managers is because disk space was scarce years ago and it's arguably "safer" to build shared objects (at least for C libraries, C++ has templates so shared objects is a recipe for disaster and requires rebuilding everything anyway). The critical reason why we have a `libxyz` package in the average distro is because _C/C++ build system is a massive mess_, and that's the only sane way to distribute and allow people to build packages without wasting several hours to find and gather all dependencies.

This approach has considerable downsides, so that's why we now have Flatpak and the like.


I don't agree. IMHO Building on top of shared libraries with stable interfaces managed by a distribution package manager is the better approach. All this fast changing dependencies where you then end up having multiple installed at the same time in different containers, statically linked programs, or whatever is a complexity, security, and long-term maintenance nightmare.


What I really miss is a common format for package managers with a uniform, simple and well documented API and a fully FOSS implementation. Dependency resolution and garbage collection would probably still be unique to each format, but maybe even this could be unified for some cases.

This way you would only need one service for all your needs. Everyone could host their own proxy/cache/mirror/repository. BOMs would be simpler. CVEs easy to attach and query. Tools could handle multiple different package types. Auth could be shared and simplified as well. Less reliance on a single provider. Projects with multiple languages would be easier. New tools that need packages would not need to invent everything from scratch.

This of course only slightly helps with the trust problem, but at least offers a common way to attach things like CVEs or if someone has reviewed a package/version and share some effort between different platforms. In the end you still need people to put in the effort to actually review the packages.


> What I really miss is a common format for package managers with a uniform, simple and well documented API and a fully FOSS implementation.

RPM? You'll never get everyone actually on a single format, but even then between LSB and just its actual popularity it has support on most distros (even if only by way of converters like alien)


RPM seems to be focused on Linux and globally managing the whole system though, but yeah, something like that. Probably would require to work more like in cargo or npm with a per-project list.

Agreeing on one format is kind of the point. I know it is difficult, but I think it is possible if at least a few implementations agree on something. Maybe some kind of "backend" like LLVM which could be used by cargo, npm, maven, etc. to configure their resolution strategy. Probably only a dream though.


My experience of OS packages of python libraries was pretty awful. They are out of date and it was impossible to deal with conflicting versions of a shared library that maybe two different applications needed.

Switching to VMs and Docker containers helped but really this was a band-aid to deal with the fact that you couldn't depend on an OS package manager to handle this well.

Packaging up Rust libraries with the OS package manager is just going to have the same problems.


i would rather have one source of fragile success (crates.io) than millions of points of constant failure. (Cmake, ninja, automake, etc etc)

dynamic linked libraries are a way to save tiny amounts of RAM and disk space while wasting millions of hours of people's time.


> If crates.io goes down or access is otherwise disrupted then the Rust community will stop work. It is profoundly unresilient to have a single point of failure like this. Certainly some people will have vendored their deps and others will have a panamax mirror handy, but for most, Rust as we know it stops if this one particular web service goes down.

If you can’t wait for recovery, I’m pretty sure cargo can pull source from any accessible git repo.

> There is no mediation of any kind between when a new library/version is published and when it is consumed. You need only one author in your maybe-hundreds-of-dependencies tree to be hacked, coerced or in a malicious mood for you to have a really bad day.

How is this prevented on Linux distros? Surely not every piece of code is being audited to prevent supply chain attacks?


Personally, I really like the solution that Go has come up with. Go does have the huge downside that its system needs some centralized servers (and possibly worse depending on how you look at it, defaults to Google's for them), but it has the huge upside that it avoids any particular single point of failure. If you are using a module proxy (like the default,) you can still fetch dependencies from GitHub packages when GitHub is down since it can grab through the module proxy. But if the module proxy is down, it can just fetch the package from GitHub instead. It's also possible to add multiple proxies to the GOPROXY variable, if you wanted extra redundancy.

But what makes this design especially nice, in my opinion, is that it means that you can host Go modules anywhere, so as long as you follow some conventions. And because of the GOPROXY mechanism, even if your site is a little unreliable, it shouldn't generally be much of an issue. The sumdb and lockfiles additionally helps ensure that the integrity of existing published versions of packages can't be compromised even if e.g. somebody acquires the domain later on.

I'm not saying this is perfect, but it's a really nice blend of properties. If you're going to have to have a centralized entity that provides package services, making it work like this prevents a hard-dependency on a centralized party to handle package management while reducing some of the security and reliability concerns of self-hosting package repositories. Admittedly, this would lose some of its luster if a lot of packages became unavailable because the GOPROXY stopped caching them and they were long removed from the Internet; but OTOH, things eventually disappearing is always going to be a concern on the Internet, as the act of keeping things online is an active effort that requires time and money. As of today, I think this remains a sensible compromise.

This doesn't solve curation at all, but that's kind of the thing; if programming language package management is the wrong place to gate insecure or potentially even malicious packages packages, then they may as well not colocate packages to specific central locations, either.


So now you replace your trust in crates.io with trust in the debian repository (which god knows how many people have access to?). At least on crates you get to know who is maintaining the package.


Debian requires much more strict authentication.


Your trust in crates.io extends to their authentication, which is subcontracted to GitHub (and only GitHub) so Microsoft. Debian? Microsoft? ... that's a tricky one.

https://github.com/rust-lang/crates.io/issues/326


Wow, I’m more bothered by all the faffing around they do on that issue (write an RFC before developing, but discuss it on this issue more before writing an RFC) than the actual issue of a single auth provider.


Debian's internal procedures are arcane for sure, I'm not involved so don't see it as issue. It's having a single authentication provider which is Microsoft that I'd object to, and that would put me off using crates.io at all.


On unstable there's the "-Z no-index-update" flag which "ensures that Cargo does not attempt to update the registry index. (...) to avoid the network latency for updating the index each time"

https://doc.rust-lang.org/nightly/cargo/reference/unstable.h...


Following stable options are often more then enough:

`--locked` might not prevent index updates, but prevent any changes in used code, i.e. only what is in the lockfile will be used

`--frozen` like locked but also requires the (download?) cache to be up to date

`--offline` prevent index updates and downloads

So if you have everything in the download cache `--offline` is like `-Z no-index-update` and `--locked` is most times good enough because since partial indices where added the index updates don't consume much time at all.


Similarly being unhappy with pulling dependencies without using a system package manager, in part because it seemed tricky to make them work with a compiler version from system repositories, this is something I wanted to try as well, and finally tried now. After having rustc installed, had to install 157 more packages in order to get argument parsing (librust-clap-dev), but it is still faster than cargo updating its package index, and then it actually builds!

Would be even better if the dependency tree for a basic package was more modest, about 157 times smaller.


FWIW, I noticed that librust-argparse-dev is also packaged for Debian, and it comes without additional dependencies. It also builds fine when pulled from crates.io directly, while using rustc version from Debian repositories, unlike clap. So whether it is crates.io or system repositories, it may be worthwhile to spend more time looking for more lightweight and stable alternatives; most commonly suggested ones are not necessarily that.


If you used cargo, you would only have 27 dependencies pulled in for clap. I'm guessing the bulk of those dependencies are the optional dev-dependencies that are pulled in during builds, and often include things like criterion for benchmarking which has a few dependencies of its own.


Yeah making Rust dependencies anything at all like C/C++ dependencies or tying them to the system package manager sounds just absolutely terrible to me. I don't want to get too deep here, all I know is compiling a C++ project can be a clusterfuck nightmare full of completely nonsense errors and the whole apt/deb interface is not very intuitive either.

On the other hand, compiling Rust projects is easy. Works great. There are very good reasons for language toolchains to remain independent at all levels from OS toolchains.


> It is profoundly unresilient to have a single point of failure like this.

Try telling this to GitHub customers. Half the world was unable to work in the last GitHub outage. Not to mention NPM.


Using Debian [EDIT: APT] and indirectly `/usr/share/*` looks like a regressive solution. It’s a package manager used by a subset of Linux distributions.


You just need to repeat the work for each linux distribution package manager, and then again for Windows, and then again Mac and iOS. Simples!


The developer world can be roughly split up into two camps. Those that are developing software for a single tightly specced hardware/OS combo, and those that are developing software that can be installed by as many people as possible. Neither of them are wrong in their respective approach, but those in the first camp won't care about or understand the problems faced by those in the second camp.


I think you very nicely sum up the real reason for all these arguments on independent repositories versus distributions.

It's really two worlds, and it seems that most people belonging to one don't fully understand the problems faced in the other, even though they think they do.


If your target is Debian, then that's not really a problem? I do a similar thing with Python (target is Debian, only use apt-able dependencies, no packaging problems).


If you're only targeting one specific version of one specific distro on one arch, then 93% of all packaging problems tend to go away, and almost any approach will work.


The positive side is that Debian isn’t the packager of record, so to speak: simplifying quite a bit, it’s pretending to be crates.io, just with a subset of the contents. That means that the developer doesn’t need to worry about it and can continue using Cargo and crates.io like normal, and the Debian packager, if there is one, just needs to translate Cargo.toml’s [dependencies] section into whatever Debian uses, and Debian-package any theretofore-unpackaged dependencies.

All up, this makes it genuinely practicable. I’m still not convinced it’s worthwhile (and it does make life a bit harder in other ways, especially in ways that I’m sure will become more apparent over time as the system gets used increasingly), but it’s not as unreasonable as it may initially sound.

Really, what’s being presented is Rust without crates.io (the domain name and content host), but with crates.io (the packages).


Having vetted repositories of libraries looks neat but it's harder in practice than what the article lets appear.

A problem for such repositories like the Debian one is that it can only contain vetted versions of libraries. Many Rust libraries are still 0.x and have changing API and frequent updates, which makes it hard to vet all dependencies, especially when an update implies updates of the dependents.


Perhaps this should be an incentive for library authors to finalize the 1.0 API and accept that there's eventually going to be a 2.x down the road, a "less is more" approach.


> If crates.io goes down [...] certainly some people will have vendored their deps and others will have a panamax mirror handy, but for most, Rust as we know it stops.

So, there are solutions already.

> There is no mediation of any kind between when a new library/version is published and when it is consumed.

No one is forcing you to stay automatically up-to-date. I personally on changes in critical libraries before updating.

> Any tampering with crates.io itself (espionage, disgruntlement, national security) could have an incredibly wide blast radius, or a incredibly wide set of targets from which to choose.

Repeat of point 1.

> Since crates.io is the source for crates, it is normal for both developers and CI machines to be hitting this web service all the time. Opportunities for mischief are exacerbated when clients are phoning home so frequently.

Again, point 1.

> So what’s the alternative?

Given there's only 2 problematic points in this list and you have pointed to solutions already, I don't see any need for an alternative.


> What’s interesting is that this problem is largely solved for C and C++: Linux distributions like Debian package such a wide range of libraries that for many things that you want to develop or install, you don’t need any third-party libraries at all.

How is this not a third-party library, and how is this not exactly the same problem as with Crates.io?


Where I work we use Artifactory as a proxy and a private package hosting service. It works great but it could be better.

Especially when it comes to flat downloads with no underlying package manager like Yocto/Bitbake and some are just terrible to setup like NugGets. The fact is, most languages or frameworks were just not designed with private repositories in mind. This is made worse when you have to make these private repositories integrate with non-developer environments like a CI worker node or a BitBake recipe.

BitBake has a flat cache for downloads and binary builds and you can setup remote caches online for example and it works great. There is a dire need for some kind of universal caching protocol. Downloading files addressed by content through a proxy should be trivial and universal.


Even if we put away conversation about OS-provided vs. direct-from-developer libraries, why would one want centralized repositories like crates.io, instead of decentralized CVSs like Git, and just link Git URL like dependencies? Seems to me that such centralized repositories have all common disadvantages of centralized solutions, but without their advantages.


Cargo already supports using git repos as package sources, but it's painful to use due to slowness of the git protocol. HTTP registry updates are nearly instant in comparison.

If git was the only option, most people would probably just use GitHub, which is merely changing one big host for another.

When it's actually decentralized, when developers use their own git URLs on their own domain, suddenly you have to worry about things like the domains expiring. You have to worry about security practices of every single host. crates.io is a big target, but they know it and act accordingly.

crates.io doesn't allow deleting of packages, but an arbitrary git URL can disappear causing a "left-pad" incident.

Some of these problems could be solved with another protocol better suited for decentralization (where the data is immutable and content addressable, and identities are private keys rather than domains), but that's way more complex than "just use git".


Using cargo (the build tool), you can add dependencies using Git URLs. Referencing crates.io is just "the usual way" to add dependencies. Git repositories can disappear (becoming private, author changes username, etc.), crates.io is more resilient than the average OSS project repo.

Most people use one of a handful of Git hosts anyway (GitHub, GitLab, ...) so Git dependencies are still like a huge centralized repo.


"There is no mediation of any kind between when a new library/version is published and when it is consumed."

In the corporate world this solved by using an intermediary like Nexus or JFrog.


The issue with the Rust ecosystem, and other similar "move fast and break things" npm-like ecosystems is not the lack of review per se, but the fact that most modules are microdependencies, or depend on them, each with its own maintainer, and it's very easy to end up with 100-300 dependencies(with a slightly lower number of authors) in the most trivial use cases. In the C++ world libraries tend to be larger, with multiple maintainers, or even unified into a single meta library like boost, which alleviates trust issues to a degree. Some degree of vetting at the level of distros like RedHat further lowers the risks.

The current situation with the language ecosystems is basically "we must build this very lax system with as few friction moments as possible, or else our language would be outcompeted by a language with laxer requirements" and "We must make our ecosystem grow, grow, grow! Externalities down the line be damned!", i.e. it's a capitalism, careerism influenced situation imho. So we have "You must vet all the 300 modules and their updates yourself" as the result. Requiring module authors to unify into meta projects to review each other's commits is perceived as laughable, unneeded self-hindrance. Same goes for separating the ecosystem into vetted(stable)/unvetted(unstable).


This is an issue caused by the fact we sold software as being FREE and now businesses have an expectation that software is free to make; thank you random guy in Nebraska.

I would love to have a paid curated package repository, but it would be really hard to sell.

I know a handful of companies who care that much about their security not to depend on OSS libraries. Even FANG don't care.

If you can raise some money and get enough sales firepower to close big contracts with the few security conscious actors, this might become reality.


It's like complaining about hardware stores because you can buy your wood from the lumberjack and nails from the blacksmith.

I'd rather have a system devoid of emotional biases, transparent and introspectable and rely on automated tooling to constantly monitor my dependencies.


I stopped reading when he said C/C++ does it better


Progress.


Problems of Rust: In Rust, there is a central package registry (crates.io), but there is a lack of ability to add dependencies using git URLs.

Problems of Swift: Swift can add dependencies using git URLs, but there is no central package registry.

Both languages should have a central package registry and the ability to add dependencies using git URLs, as it would make flexible dependency management much easier. For a central package registry, it makes it easier to find popular packages, but it has a problem of centralization.


Rust does have this: you can specify dependencies from other registries or Git repositories pretty easily. (See https://doc.rust-lang.org/cargo/reference/specifying-depende... for the exact Cargo.toml syntax.)


> but there is a lack of ability to add dependencies using git URLs.

There is absolutely no lack of that in cargo; this is literally the first sentence in the relevant section in the doc (https://doc.rust-lang.org/cargo/reference/specifying-depende...):

Your crates can depend on other libraries from crates.io or other registries, *git repositories*, or subdirectories on your local file system.


Rust does support adding deps using git urls, alternate repositories, filesystem paths, and even multiple sources for one dep.

https://doc.rust-lang.org/cargo/reference/specifying-depende...


I was wrong :(


[flagged]


Maybe if we work hard enough, we can have a big “can I use” table of rust dependencies which shows which versions of everything are available in which operating systems and what the package has been renamed to in each case. “Oh I could use rand but the latest version isn’t in gentoo so that would knock out 5% of my users.” Maintaining and stressing over that sounds like greeeaaaat fun. “Oh cool! An important new feature landed in rust stable. I can’t wait for 6 months to pass before the new rust compiler comes to Debian. Then another 6 months for my dependencies to use it. Then another 6 months before I can use it! Isn’t software great?”


I think that there is a real point in talking about the security risk from having it too easy to fetch tons of dependencies. That's literally code that gets downloaded and run on the user's machine, I would always feel safer if the dev had at least an idea about the dependencies they pull.

You can also have a mixed approach, where you depend on the system libraries for those that are maintained by the distro, and build/handle the remaining dependencies manually. That is an incentive to actually use the libraries that are maintained by the distro, which is a good thing IMO: not every library gets to be distributed by Debian, there is some level of quality control there.


Lot of backlash against author’s suggestions. I guess it will take a DDoS attack on crates.io to convince this crowd. Can’t wait for that to happen.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: