[Pre-RFC] DNS domains as package namespaces

I'm aware of [lib.name], and as you note it's confusing to users. For example, this is permitted in the current implementation:

[package]
name = "fa47a84c-a7a9-4cc2-bdd4-e8aedf4f96b0"

[lib]
name = "xml"

And such a package could be depended on like this:

[dependencies]
xml = { package = "fa47a84c-a7a9-4cc2-bdd4-e8aedf4f96b0", version = "1.0.15" }

I've considered doing that, but it feels kinda slightly hostile, so I wanted to see if there was some other way to be able to publish my packages without completely going against current best practices.

That's the thing.. there is no standard package for anything (except for what's in the standard library itself of course). Certain packages may have nicer names, but that doesn't mean that they're the best package implementing that thing for your given use case. json gets to use the name json simply because it was the first crate that implemented JSON, that doesn't mean it's the best or "standard" JSON crate, just that it's the one that got there first.

1 Like

Certain packages may have nicer names, but that doesn't mean that they're the best package implementing that thing for your given use case.

It ... kinda does, though? The json crate might not necessarily work for everything I want to do with JSON (e.g. it doesn't provide an event-based parser), but if you go to https://crates.io/search?q=json it's the top spot (screenshot) and seems to be the standard way of dealing with JSON in Rust.

If I ever do need an equivalent to Go's json.Decoder then I'll probably write my own (done it before 18 years ago), and the name of that crate would be json.

json gets to use the name json simply because it was the first crate that implemented JSON, that doesn't mean it's the best or "standard" JSON crate, just that it's the one that got there first.

I understand that the current lack of namespaces means that there can be only one json crate on crates.io. This thread is an attempt to convince the team to relax that constraint.

2 Likes

While it is often true that the simply named crate is well implemented and suffices for most purposes, that's not always true.

For instance, as noted earlier in this thread there are numerous crates for dealing with http servers, and the crate named http is not necessarily the best for it.

When I need a crate for something, I search for it on crates.io and look at the top couple results to figure out which meet my requirements and seem well implemented. What those crates are called barely matters to me (and I think most rust developers would agree with me).

So, while I do think that there are reasons that namespaces crate named could be a good idea, I don't think "so that crates can use the 'canonical' name" is a good argument for it. I really see no difference between using a crate called jmillikin.github.io/fuse and a crate called jmillikin_fuse, and would not assume any difference in quality between either of them and the crate just called fuse based simply on their names.

1 Like

I think you'll have a hard time convincing people if that's your stance. Even with namespaces there can only be one json, that won't change. You can have jmillikin.github.io/json, but that's not called json, just like jmillikin_json is not called json. All this argument amounts to is having a nicer way to make distinguishing crate names, but that's not enough motivation for a change this big.

3 Likes

I think you'll have a hard time convincing people if that's your stance. Even with namespaces there can only be one json , that won't change. You can have jmillikin.github.io/json , but that's not called json , just like jmillikin_json is not called json .

The package jmillikin.github.io/json contains the crate json, whereas the package jmillikin_json contains the crate jmillikin_json.

The purpose of namespaces is to allow multiple crates with the same name to have different package names, which is a useful feature for a package registry that tries to be a central place for an entire language's library ecosystem to register packages.

All this argument amounts to is having a nicer way to make distinguishing crate names, but that's not enough motivation for a change this big.

It's not a particularly big change (see the diffstat for the linked branches in the first post) and the value of allowing more people contribute packages to the Rust ecosystem is significant.

1 Like

As already mentioned in this thread you can make the package jmillikin_json contain the crate json. It can be a bit confusing to users, but there's no technical difference between the two. You could get the exact same result by allowing the characters / and . in package names, there's no need to use namespacing for it. Hence there must be some other more important reason for namespacing. My point is that you should focus more on them.

It might not be big in code, but it is big in how users interact with crates.io

1 Like

I thought of another way to explain it, by analogy with lib.name.

If you have a package at https://crates,io/crates/some-example-lib, the name that will be exposed to rustc is expected to be some_example_lib. The transformation from crates.io package name to rustc library name is simple to understand and can be implemented mechanically.

The lib.name field can be overridden with an ~arbitrary value, for example I could use it so that the https://crates,io/crates/some-example-lib package was exposed to rustc as completely_different_name. This severs the connection between the package named and the library name -- it's no longer possible to predict what the library would be called.

If I were to publish a package https://crates,io/crates/jmillikin-serde-json then the only obvious choice for the name that's exposed to rustc is jmillikin_serde_json. If I were to set lib.name to serde_json then that would be confusing -- it's different from what users expect, and there's no way to predict it. There's no mechanical transformation that can be applied to the string "jmillikin-serde-json" to produce "serde_json" without generating incorrect results for similar names.

The reason to have a delimiter like jmillikin/json or (jmillikin)json is so that the mechanical transformation of a package name to a library name remains possible.

Concerns about the possibility of changing usernames have caused jmillikin-json to be a valid package name but jmillikin/json to be an invalid package name -- the latter uses a namespace syntax, and namespaces can't be usernames, because usernames are mutable.

From the perspective of the crates.io database the strings "john-millikin.com/json" and "john-millikin-com-json" aren't materially different, but to everything downstream of crates.io the difference is important because the former can be parsed to extract the library name and the latter can't.

If you're OK with a package being published with the name "john-millikin-com-json" and lib.name = "json", then why would you not want to allow the semantically equivalent and much easier to work with "john-millikin.com/json" package name?

1 Like

This seems to missing "multiple prefixes per account"—which is in fact arguably also GitHub's model. GitHub allows accounts to create organizations, which serve as (among other things) namespaces for repositories independent of the user which created them.

The crates.io equivalent would be to allow users to create namespaces which they own, tied to their accounts, and then publish packages under those namespaces. This has a key disadvantage over domains which is that you would need anti-squatting/impersonation moderation to ensure that if Google wants to own the google namespace they can, but it seems worth at least mentioning as an alternative (especially since it slots in naturally with the existing system of "first come, first served" names managed by crates.io).

(You would presumably limit the number of namespaces a user can create and, e.g., allocate more if their crates actually get used by somebody; I'm unsure what the relevant policies are but they necessarily already exist for crates themselves, presumably as part of the anti-squatting rules you mention.)

Whether namespaces are human-meaningful is entirely irrelevant here—the relevant part of your UUID example is that you never have a many-one relationship between crates and namespaces. If you used meaningless namespaces but continued to allow multiple crates under one namespace you would have the exact same problems.

While it is true that these are not literally reconcilable, the more specific issue is that you cannot:

  • Couple crates permanently to a specific namespace (such that the namespace is part of its immutable name).
  • Either of:
    • Allow transfer of ownership of crates tied to a namespace without transferring ownership of the namespace as a whole.
    • Couple namespace to the identity of the owner (legal or otherwise) and allow transfer of ownership at all (from the perspective of crates.io anyway; if the owner is an organization then ownership of the owner can change, but that happens independently of and invisibly to crates.io).

In particular, one thing which you could do in the case of "namespaces are just a thing you register with crates.io" is say that you can transfer ownership of namespaces as a whole, but not move crates between namespaces. This works naturally for something like cranelift but less naturally for people who want to publish their own xml library as {name}/xml.

I think moving between namespaces should be thought of as renaming[1], not merely transfer of ownership, but regardless, I wanted to narrow the specific contradiction.

Finally, I want to remark that I think you're trying to solve 3 loosely related problems:

  • The cranelift/umbrella project example where multiple crates—possibly with versions updated independently, etc., rather than in lockstep, are nonetheless closely coupled under one umbrella project and, further, it's useful to distinguished crates which are officially part of the project and third-party integrations.
  • "I want to publish my library called xml but xml already exists" (note that in this case, I would argue xml@example.com is actually more "natural" than example.com/xml; rather than breaking lexicographical search it is exactly placing the relevant part—that it is an xml crate—first and the irrelevant disambiguation that it happens to come from somebody called example.com second.
  • "My name is Google and I would like people to know that" (Google may also want the second usecase too).

I think the first case is more accurately referred to by the term "namespace"—a namespace is a name prefix which is fundamentally part of the name and just comes with a canonical way to split it into a prefix and an abbreviation for cases where there are multiple things with the same prefix.

It is possible that one sufficiently clever feature can address all of these cases, but:

  • one is for hierarchical projects where the namespace is semantically more significant than the specific module (lexicographically first),
  • one is for deconflicting the global namespace by adding some arbitrary extension to a crate you wish could just be called xml, where the "namespace" is semantically less significant (and so should be lexicographically second), and
  • one is about prominently displaying owner identity and doesn't actually need the "namespace" anywhere in the name, though it's probable that Google would also want to not worry about conflicting names.

The fact that the first case "wants" the namespace to be lexicographically first as namespaces typically are while the second case "wants" it to be lexicographically last bodes ill for the existence of a "sufficiently clever feature" that addresses everything.


  1. It seems like perhaps Cargo should support "migration notices" where—with all the same authority as needed to publish a new version—you can publish a notice that future updates to the crate will happen under a different name. This would be mildly annoying since it may create situations where you want to say "crate foo with a version between X and Y" but crate foo was renamed to bar between X and Y and now you're either out of luck or need the ability to say "[crate foo > X OR crate bar < Y] as foo". Regardless, this addresses the issue of renaming rather which is only relevant insofar as the addition of namespaces may create more demand for renaming crates. ↩︎

1 Like

To clarify, I'm trying to solve the second one (multiple packages with the same crate name but different package names). The other two use cases (grouping by umbrella project, brand reputation) just sorta come along for the ride as a result of the imposed requirements.

I would personally be fine with the option to publish a crate with an opaque UUID namespace, since that solves the problem I care about, but that wouldn't be accepted, hence the use of domains to support the other two use cases too.

(note that in this case, I would argue xml@example.com is actually more "natural" than example.com/xml ; rather than breaking lexicographical search it is exactly placing the relevant part—that it is an xml crate—first and the irrelevant disambiguation that it happens to come from somebody called example.com second.

I'm not sure I follow, sorry, though that might be because I'm used to the left-to-right order used by other package managers, Rust mod hierarchy, XML namespaces, and so on. Every sort of scoping/namespacing system I know of is big-endian.

If you were looking at a group of dependencies, wouldn't you normally want them ordered as (namespace, name) instead of (name, namespace)?

I think the first case is more accurately referred to by the term "namespace"—a namespace is a name prefix which is fundamentally part of the name and just comes with a canonical way to split it into a prefix and an abbreviation for cases where there are multiple things with the same prefix.

Is it the term that's causing confusion? This may be a dumb question to ask, but if it was called a "scope" would that be clearer as to the intent?

  • one is for deconflicting the global namespace by adding some arbitrary extension to a crate you wish could just be called xml, where the "namespace" is semantically less significant (and so should be lexicographically second), and

To clarify, the crate would be named just xml. It's the package name that would be longer.

A good crate (library/binary) name is short and descriptive. A good package name is globally unique and unambiguous. The current coupling of those two into a single identifier within crates.io is unfortunate, because the goals are at cross-purposes.

I want to make crates names a subdivision of package names, have crate names be short and descriptive (but non-unique), and have package names be unique and unambiguous (but long).

1 Like

Why does this require namespaces vs. just expanding the character set allowed in package names?

Why does this require namespaces vs. just expanding the character set allowed in package names?

If you just expand the character set without introducing some form of access control then individual users could publish with names like google.com/protobuf or rust-lang.org/libc.

This would violate the crates.io team's requirement that the name of a crate should not mislead regarding which individual or organization is responsible for it.

(my understanding is that in today's world the rules against publishing google-protobuf-official or rust-libc are enforced manually; namespaces are an opportunity to bake that enforcement into the ACL layer)

I agree that this is the way namespaces are typically handled; however, in the case where the semantic name of the crate is xml and the "namespace" is just a disambiguating tag. There is no important relationship between example.com/xml and example.com/http for any purposes except a dependency audit to view your attack surface for supply chain vulnerabilities. (But in that case you want to group by crates.io owner, not by domain name space.)

By contrast, xml and example.com/xml are very closely related: they're two crates doing the same thing! Similarly http and example.com/http. It seems to me that in most lists, it makes more sense for example.com/xml to appear with xml and example.com/http to appear with http, which is the claim I was making.

How would this work with crate ownership? (This may very well be addressed in epage's prior collection of this topic.) If I add another developer as a maintainer (uploader) of the package, do I need to somehow give access to my domain?What if I later want to no longer maintainer? Do I have to transfer domain ownership too? What if I still have crates I'm continuing to maintain? Or do I have to somehow communicate with all consuming projects about the new domain? Feels like a wonderful gap for social engineering to crack in and get a few users to use a trojaned crate.

1 Like

I believe your questions are addressed in the first post.

In the original proposal:

  • Crate ownership semantics are unchanged. The existing permissions logic crates.io is what determines who can publish updates to a crate.
  • If you transfer ownership of your crate then the new owner will be able to publish updates to it.
  • Crates can't be renamed, so if you want to transfer ownership then you can either:
    • add them as an owner to the existing crate (under the original namespace), or
    • they can publish a new crate under a namespace they control, and users would have to update their dependencies to reference the new name.
  • Granting permission to publish a updates to a crate does not require you to transfer ownership of the domain.

In the thread there were some discussions of possible adjustments to make the access control stricter, including:

  • Requiring domain control be verified for each published update.
    • This would prevent publishing updates to crates under a domain that lapsed.
  • Having crates.io keep track of domain ownership.
    • If a domain lapses and someone else leases it then they wouldn't be able to publish new crates without asking the crates.io administrators for help.

Feels like a wonderful gap for social engineering to crack in and get a few users to use a trojaned crate.

This proposal does not add new vectors for social engineering. Some of the proposals remove vectors by requiring additional authorization when creating or updating a namespaced package.

1 Like

Wouldn't this apply to domains as well?

I think you underestimate how much that can be for certain population especially that it requires having a credit card or bank account. In my childhood/college I was more active in FLOSS community but at the same time I had very tight budget. Not it is much cheaper but I also have much less time to be engaged in FLOSS community...

Other costs are not necessarily impossible to get. For example schools and libraries have computer labs. They are also de-facto necessities - if you are in school/college you probably need something to write coursework, have internet connection and have electricity. I doubt that incremental cost of rust contributions are $15/year.

6 Likes

No, because domain names are like package names -- the name itself is immutable, it's only the ownership records the name points to that change.

If someone does not have access to any source of funding or online payments then:

  1. The global namespace is still available, they have not been restricted in any way by the addition of domain-based namespaces.
  2. Many sites offer free subdomains with static file hosting. The major code hosts (GitHub, GitLab, Codeberg, Sourcehut), network service providers (Cloudflare Pages, Google AppEngine), various small hosts (Neocities, Nekoweb).
  3. Schools and universities have domain names. If someone is in university and wants a free file host to put up a ~500 byte JSON file so they can publish Rust packages under jdoe.class2026.compsci.someuniv.edu/ then I'm sure the undergrad managing the website would be open to the idea.

My high school didn't provide students with any website. My uni did, as roughly fixedsubdomain.myuni.nl/~sNNNNNN where NNNNNN is your student number, which would not be enough under your proposal. Also once I was done with uni, they removed my account and associated website. I believe only phd students and professors got permanent access under their name rather than a number. And that is still assuming you have enough money to attend uni in the first place.

My point is that there is a wide variety of ways that people can get access to a DNS domain name for free. Not every option will be available to every person, but every person will almost certainly have several options.

And there are just as many ways to loose access to it, especially the free ones, as you often are not the actual owner. Which brings you back to the "names change" and how domain expiry is handled, which has caused significant issues in the website space (e.g. advertizing and bookmarks to previously trusted domains being used for scams). And there are enough people that setup "temporary" domains without being aware/acknowledging potential issues once you no longer own the domain because you think it is no longer relevant to you. At that point it becomes a liability you either continue paying for or risk it being abused if it has become popular enough.

I really don't think we should or want to extend that into a dependency system, where a domain expiry could easily lead to RCE on a dev machine unless cases like these are really solved.

2 Likes