-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Forbid wildcard dependencies on crates.io #1241
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| - Feature Name: N/A | ||
| - Start Date: 2015-07-23 | ||
| - RFC PR: | ||
| - Rust Issue: | ||
|
|
||
| # Summary | ||
|
|
||
| A Cargo crate's dependencies are associated with constraints that specify the | ||
| set of versions of the dependency with which the crate is compatible. These | ||
| constraints range from accepting exactly one version (`=1.2.3`), to | ||
| accepting a range of versions (`^1.2.3`, `~1.2.3`, `>= 1.2.3, < 3.0.0`), to | ||
| accepting any version at all (`*`). This RFC proposes to update crates.io to | ||
| reject publishes of crates that have compile or build dependencies with | ||
| version constraints that have no upper bound. | ||
|
|
||
| # Motivation | ||
|
|
||
| Version constraints are a delicate balancing act between stability and | ||
| flexibility. On one extreme, one can lock dependencies to an exact version. | ||
| From one perspective, this is great, since the dependencies a user will consume | ||
| will be the same that the developers tested against. However, on any nontrival | ||
| project, one will inevitably run into conflicts where library A depends on | ||
| version `1.2.3` of library B, but library C depends on version `1.2.4`, at | ||
| which point, the only option is to force the version of library B to one of | ||
| them and hope everything works. | ||
|
|
||
| On the other hand, a wildcard (`*`) constraint will never conflict with | ||
| anything! There are other things to worry about here, though. A version | ||
| constraint is fundamentally an assertion from a library's author to its users | ||
| that the library will work with any version of a dependency that matches its | ||
| constraint. A wildcard constraint is claiming that the library will work with | ||
| any version of the dependency that has ever been released *or will ever be | ||
| released, forever*. This is a somewhat absurd guarantee to make - forever is a | ||
| long time! | ||
|
|
||
| Absurd guarantees on their own are not necessarily sufficient motivation to | ||
| make a change like this. The real motivation is the effect that these | ||
| guarantees have on consumers of libraries. | ||
|
|
||
| As an example, consider the [openssl](https://crates.io/crates/openssl) crate. | ||
| It is one of the most popular libraries on crates.io, with several hundred | ||
| downloads every day. 50% of the [libraries that depend on it](https://crates.io/crates/openssl/reverse_dependencies) | ||
| have a wildcard constraint on the version. Almost all of them them will fail | ||
| to compile against version 0.7 of openssl when it is released. When that | ||
| happens, users of those libraries will be forced to manually override Cargo's | ||
| version selection every time it is recalculated. This is not a fun time. | ||
|
|
||
| Bad version restrictions are also "viral". Even if a developer is careful to | ||
| pick dependencies that have reasonable version restrictions, there could be a | ||
| wildcard constraint hiding five transitive levels down. Manually searching the | ||
| entire dependency graph is an exercise in frustration that shouldn't be | ||
| necessary. | ||
|
|
||
| On the other hand, consider a library that has a version constraint of `^0.6`. | ||
| When openssl 0.7 releases, the library will either continue to work against | ||
| version 0.7, or it won't. In the first case, the author can simply extend the | ||
| constraint to `>= 0.6, < 0.8` and consumers can use it with version 0.6 or 0.7 | ||
| without any trouble. If it does not work against version 0.7, consumers of the | ||
| library are fine! Their code will continue to work without any manual | ||
| intervention. The author can update the library to work with version 0.7 and | ||
| release a new version with a constraint of `^0.7` to support consumers that | ||
| want to use that newer release. | ||
|
|
||
| Making crates.io more picky than Cargo itself is not a new concept; it | ||
| currently [requires several items](https://github.com/rust-lang/crates.io/blob/8c85874b6b967e1f46ae2113719708dce0c16d32/src/krate.rs#L746-L759) in published crates that Cargo will not: | ||
|
|
||
| * A valid license | ||
| * A description | ||
| * A list of authors | ||
|
|
||
| All of these requirements are in place to make it easier for developers to use | ||
| the libraries uploaded to crates.io - that's why crates are published, after | ||
| all! A restriction on wildcards is another step down that path. | ||
|
|
||
| Note that this restriction would only apply to normal compile dependencies and | ||
| build dependencies, but not to dev dependencies. Dev dependencies are only used | ||
| when testing a crate, so it doesn't matter to downstream consumers if they | ||
| break. | ||
|
|
||
| # Detailed design | ||
|
|
||
| Alter crates.io's pre-publish behavior to check the version constraints of all | ||
| compile and build dependencies, and reject those that have no upper bound. For | ||
| example, these would be rejected: | ||
|
|
||
| * `*` | ||
| * `> 0.3` | ||
| * `>= 0.3` | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, both of those would be fine (I didn't even realize they existed!)
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| While these would not: | ||
|
|
||
| * `>= 0.3, < 0.5` | ||
| * `^0.3` | ||
| * `~0.3` | ||
| * `=0.3.1` | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In that case, I'll ask, will
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| # Drawbacks | ||
|
|
||
| The barrier to entry when publishing a crate will be mildly higher. | ||
|
|
||
| In theory, there could be contexts where an unbounded version constraint is | ||
| actually appropriate? | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From the RFC above,
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's totally possible for a crate to say There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My comment is merely stating that we probably want to add a note that this could cause size bloat in the drawbacks section. |
||
|
|
||
| # Alternatives | ||
|
|
||
| We could continue allowing these kinds of constraints, but complain in a | ||
| "sufficiently annoying" manner during publishes to discourage their use. | ||
|
|
||
| # Unresolved questions | ||
|
|
||
| Should crates.io also forbid constraints that reference versions of | ||
| dependencies that don't yet exist? For example, a constraint of `>= 0.3, < 0.5` | ||
| where the dependency has no published versions in the `0.4` range. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bad version restrictions are also viral the other way around: There can always be a unneccessarily strict version constraint hiding "five transitive levels down". Manually searching the entire dependency graph is not a solution to this, as you'd have to publish your own versions of all the crates that recursively depend on this overly strict crate if the author does not update the version requirements by themselves – which means that the alternative this RFC is suggesting also carries this risk.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NB. this exact point is made above #1241 (comment) .