This is exactly why cargo uses a lock file that does pin your dependencies as described for binary crates, but does not use the same mechanism for libraries. https://doc.rust-lang.org/cargo/faq.html#why-do-binaries-hav...
Crate C depends on them both. It now can't bring in updates to A until B does, and when B updates that's a breaking change, so it better bump its major version.
Take a look at this trick, for example, for foundational crates updating their major version: https://github.com/dtolnay/semver-trick
Now imagine that being an issue every single patch update.
Granted that the supply chain attack defense would fall on the hands of the users of the library. Unless the library writer aggressively pins of dependencies on the Cargo.toml (not the default semver action), problematic, but at least Cargo allows multiple versions of dependencies on a program, on Python for instance this is much complicated scenario (but still the smallest of the dependencies problems there).
For the new guidance: https://doc.rust-lang.org/nightly/cargo/faq.html#why-have-ca...
See also https://blog.rust-lang.org/2023/08/29/committing-lockfiles.h...
If you pin your dependencies, when something you depend on fixes a security bug you don't get the fix unless you notice the new release and realize you need to apply it.
If you do not pin your dependencies, then your code will randomly break because you are depending on something that changed (Hyrums law). You push to CI and now you have build failures to fix unrelated to your change in the best case. In the worst case everything builds and you ship to customers who discover the issue (even if you have a great manual test plan that would have discovered it: if it is the last build before release you probably don't run the full plan)
I don't have a good answer here. I'm in the pin everything camp, and can report it is hard to notice all changes upstream. It was just a few years ago we finally threw away a computer with Windows XP with no service packs - it sat in a closet for years untouched just in case we had to rebuild some old software.
When I'm developing, I frequently grab latest versions. Until i share, I want to keep up to date.
- `Cargo.lock`: handled implicitly so long as you check it in which, as of rust 1.74 (next release), `cargo new` will scaffold all projects this way by default.
- `Cargo.toml`: requires using a `=` version requirement. We generally recommend against pinning this way; see https://doc.rust-lang.org/cargo/reference/specifying-depende...
> For crates where you don’t need or want new features, bug fixes etc, you could consider pinning their versions.
It seems to me that you should _always_ pin your dependency versions. I'd go so far as to say that build tools shouldn't even have an option to automatically pull the latest - "version" should be a required field for all dependencies (and, ideally, that gets decorated with a hash after the first download).
Yes this means you might miss out on security fixes that you'd otherwise get automatically. But having the code that you run & ship change absent your intention just feels like a bizarre default approach.