 Yeah. So this talk is about cargo deny, which is a tool that we have made to help us manage our dependencies. So we're going to talk a little about the situation and why we made this tool, and what the idea of it is, and then go through what it currently offers and possible future support. A little bit about me. I've been in game development for about 13 years. Bennett's smaller companies, larger companies, and now very small companies. Right now I'm at Embark. We're a game development studio, and we're running an engine and platform in Rust, as well as other stuff, not in Rust. So yeah, so here's the situation about why we created the tool, and it is totally our fault. So give a context of where most of us are coming from. We've been in game dev for quite a while, and generally game development is in large monorapository style code bases, and it's basically very few external dependencies, and all the external dependencies that you do have are rendered typically into the code base, where they rot. Basically, as a consequence of vendoring there's extremely little interaction with game development in general and open-source software. So even though some software is used, like a typical example would be Zlib or other compression libraries. Like they get pulled down, they get vendored, and basically that's it. There's no more interaction, there's no bug reports, there's no PRs, there's no, hey, could you add this feature? That's important to us. Usually it's added internally, never shared with anyone else. And this would be what I would call classical game dev. Not everyone operates this way, but this is the modus operandi. And so if you turn to the Rust ecosystem, the Rust ecosystem is basically complete and the other opposite of this, right? Pretty much everything is shared and public, and if it's not public at the beginning, it eventually becomes public, or at least people can talk openly about what they're working on, even if it's not actual public code. And obviously everyone knows it's quite large. I think this screenshot was taken two days ago or something. And yeah, there's a huge, but being a huge package, well, not compared to MPM, but a large package repository with a lot of crates, there's a huge number of axes that have different levels of quality and commitment from maintainers. And yeah, there's just a huge amount of options available across the ecosystem. So going back to game development, like when we started the company, like obviously most game development is done in C++. So going to Rust was a big kind of thing that we wanted to do. And obviously one of the motivating factors for this was using this amazing crate ecosystem. So we use quite a lot of external dependencies on our main primary project right now, about 400 plus. And we tend to keep all of them up to date. We kind of tend to live ahead. We update sometimes several times a day, sometimes, but typically on a weekly cadence. And we actually have never rendered any dependencies. We always fork, use a patch to get repository until our PR is merged, and then return back to the original project. And so we're kind of working quite differently from how we used to work. So yeah, so the problem that comes with this, the created ecosystem is moving quite quickly. We're updating quite frequently. And you can't just look at the cargo lock file or cargo tree or license hound or all of the kind of stuff all the time is just extremely tedious. And while cargo gives some tools, it doesn't actually give you a complete picture of the crates because it doesn't really have that capability because people have different use cases and different requirements. And it's kind of up to you. And basically, we have this cadence now of updating quite frequently. And the Rust ecosystem is obviously moving quite fast and moving faster in terms of new crates. And some crates get updated multiple times a day. And we basically want to keep this cadence for now. Maybe we'll change it in the future. But for now we want to be updating quickly and fastly, getting new features, fixing bugs, all that kind of stuff. So that's where cargo deny comes in. So basically our kind of high concept of the tool is that it's a linter for your crate graph. So the idea is to kind of treat your crate graph as a code and basically do what Clippy does, which is look for things that you've configured for and warn you or error and basically make sure that as your crate graph changes, your expectations are met every time. And so what we're checking for currently are licenses, bands, or basically saying I don't want particular crate or crates in my dependency graph, duplicate versions of crates, security advisories, and sources of your crates. Licenses, so yeah, we just had a little bit of information about licenses. So kind of, again, going over this crates usually specify their license terms and the cargo metadata. And this is kind of pretty typical one, MIT or Apache 2. And then they also have the ability to give a relative path to a license file. But you have to manually inspect that because cargo doesn't care about it. And so basically the question we wanna ask is are all the crates that we're using, using licenses that we find acceptable and then making sure that that holds true over time. So if we add new crates, it has licenses that we find acceptable and then it's also possible for crates to change licenses when they make a version change, sometimes even in patch versions. And so basically this is a short snippet of a configuration that you could have. So basically say you can configure what happens with unlicensed crates, crates that have copy left, and then a set of licenses that you explicitly allow as well as kind of exceptions for cases where you maybe don't wanna blank it or allow a particular license across all the crates possible, but on a particular crate. And then you can have other things like FSF-free or OSI-approved as well. Basically what it does is evaluates the SPDX expression that's gathered from the crate. And so in this case, because we explicitly allow both MIT and Apache 2, it evaluates to true because both sides of the expression are true. And this works for basically all SPDX expressions including ones that actually aren't representable in cargo because they're parsing in cargo for the license field is actually not correct. And so as we saw earlier, there are some caveats to this. Right now there's only kind of two sources of input, which is the license field itself as well as any license files that are in the crate route. And so we basically scan the license files to determine the license that it's in the file. And then we basically combine them all together with an AND expression to be maximally covered. But in practice, that's not really accurate because especially for C dependencies, people tend to include C code into the rest crate, link it in with everything else and then kind of completely ignore that the C dependency has a completely different license than the rest of the crate. And yeah, so we have another tool called cargo about which is about kind of doing a similar thing to the notice thing that we heard about earlier. But the basic idea is that it does do full source code scanning of everything and then finds all licenses and make sure as they comply with what the crate says and then otherwise it'll force you to specify the licenses that you found and what the expression is for the crate as a whole. But yeah, cargo denies job is to do that very, very quickly so this takes a millisecond or so. So yeah, there are crates that we don't want. And this is totally fine. Not all crates match the requirements that you have for your project and there's a lot of crates that have different philosophies about how they update or what features they provide versus other crates that kind of operate in the same niche. And so sometimes we find them and we say, yeah, we don't want this and we wanna keep it out for all time. So a particular example that was kind of the motivating reason for creating this tool in the first place was OpenSSL. We despise OpenSSL and unfortunately, basically any time you do TLS and the Rust ecosystem, it's almost always the case that OpenSSL is the default implementation for that, even if they provide a feature to use, for example, RustSSL or something. And kind of the reason that we find this annoying is it does have system dependencies. So if you have different systems, they have different versions of OpenSSL and then particularly for Windows, we have some Windows users who aren't necessarily programmers and it's another dependency that they have to install and keep up to date and it's just tedious. So we have, yeah, this is a very simple example. The reason it's doing the name is you can also have, specify particular versions that you deny instead of just the all versions of the crate. And we do like a quick change here. So that's request and we just turn off on default features by deleting the default features faults and by default request uses OpenSSL and we see that there's an error now. And then basically every time cargo deny finds anything wrong and it puts a warning error that pertains to a particular crate, it's optionally will produce the inverse dependency graph, basically how the crate gets pulled into your crate graph. So the next check would be duplicates, which is a kind of interesting case in Rust. So if you're not aware, dependency resolution is hard and it's actually an MP hard problem. And so some package managers will say you can only have one version of a particular dependency in your project and if you have conflicting versions, you have to figure out how to manually go down to one version. Cargo however does not, it introduces a trade off. So here's a really simple case. So we have a year's crate that depends on both theirs, some other crate as well as log and then the theirs crate also depends on log, but fortunately they both resolve to the same version and so everything's fine, right? You just have one version of log and everything is great. The much more common case in the Rust ecosystem is that you depend on one version of log, you have another dependency has a different version of log and so in this case, like in the classical dependency resolution, this is unsatisfiable and like you have to choose one or the other and you have to somehow get them to both work. But cargo just says why not both and this is great. By saying we can have multiple versions of the same dependency, you can automatically kind of resolve dependencies quite easily and also fast. This is kind of one of the great kind of introductions to Rust like when you're coming especially from like C++ or something and you're adding dependencies and getting functionality and everything just works and it's kind of magical. And it also allows most importantly for the ecosystem as a whole to evolve at differing paces, right? So one crate can decide I wanna use this bleeding edge version of some crate and then the rest of the ecosystem is saying, okay, well actually that one's kind of risky. Maybe I'll wait until it's kind of stabilized or something but they can both use that and you can use all the crates that use any of the versions and it's totally fine. The cons of course are not great. So if you have more versions of more crates, then you download more to compile and then if you compile more, you link more and if you link more, you have larger outputs and that's both the actual final binaries that you ship as well as your local target directories which can get quite large. And then the fun, you expected type X and got type X. Thanks, cargo. No, Rust. So the duplicate handling basically gives you the way to see, look at your crate graph, give a concise kind of inclusion graph for that and then allow you to kind of manage how you deal with duplicates. So basically say, okay, we're gonna deny multiple versions and then we're gonna skip a few and then this is kind of what it looks like. So if we had two versions of base 64, I'll basically give you the inclusion graph for both all of the versions, they have more than two, the two is the typical case and then kind of highlight where they're coming in but also has a different graph output as well optionally and the idea is that the blue lines show the path to the lowest version which is typically the one that you wanna get rid of and then the red path is the path to the one with the fewest number of edges which is typically going to be the one that's the easiest to remove. Obviously this is a contrived case, this is kind of much more typically what the graph will look like. I think this was like X Wayland and Winnet or something but yeah, there's like multiple duplicate versions there that all go to this one and yeah, it can be a mess but the idea is that yeah, it gives you the notice like hey, something is here and then once you find duplicates, then yeah, we have to decide what we wanna do with them. Sometimes you don't care and that's totally fine so then you just skip it and then often you wanna maybe open a PR to bump a version that needs bumping or change your version to point to the same version that it depends he's using to just get rid of the duplicate. There's basically whatever you wanna do, there's a lot of options. To reiterate the point, we don't think duplicates are bad because like I said, it does have a lot of positives. It can, it lets you just do your work without getting in the way but the duplicate detection is there so that you can notice it and actually make a decision about how you wanna deal with it. Next we have advisories. So the advisories are built on top of RASC so if anyone's used Cargo Audit, this is the same core crate that Cargo Audit uses to download, deserialize and inspect your crates with advisories and this is cool because it allows for kind of centralized knowledge base of advisories for all different kinds of things that people can contribute to and kind of help each other with. And then it's not just for vulnerabilities. There's also notices for unmaintained crates so crates that the author is either completely unresponsive or explicitly said like I'm not working on this anymore or for crates that serve to purpose but for example, maybe Navi and the standard library itself have been supplanted by a superior crate. It also can detect yanked versions. This isn't really a problem practice that I've noticed but it's there if you want it. As well as like obviously the possibility of more kind of advisories in the future. So yeah, so you can basically say how you wanna deal with vulnerabilities, how you wanna deal with unmaintained crates, how you wanna deal with yanked crates and then the ability to ignore specific advisories that maybe you don't care about. In this case, the spin is unmaintained but lazy static uses it and everything uses lazy static so it's kind of up to lazy static to remove it at some point. And this kind of, the output it gives you kind of gives you the information that's stored in the database for each advisory. And that'll give you links to alternatives in the case of unmaintained crates or what versions you should update to to get rid of the security vulnerability. And the last thing that we have is the source check. So CoreGuide has multiple sources that it can use as for crates. So there's the local source from a file path, crates.io registries, but then most importantly, Git. So this is the blog post kind of motivated the addition of this check and it's basically talking about MPM lock files but there is some relation to cargo lock files. So we have a typical kind of PR from my boss, updated dependencies and as is typical with Git Hub it'll just hide the diff, looks fine. But if you look in the lock file you would see that actually the version changed but also the source changed, right? So instead of going to crates.io now it's going to get.com definitely not mining bitcoins. So basically the configuration for this is just whether you allow or deny unknown registries and unknown Git sources and basically if you deny unknown Git sources or registries you kind of opt in to them instead of the typical case of just opting to get anything from anywhere. And that's kind of the output of it. Yeah, just as a bonus source that wasn't explicitly allowed and then points to the actual thing. So future, we probably want to add more checks. So one example, maybe the unused dependencies so there is UDEPs but that does actually hook in to Rust C itself. We think it could be faster to just check for unused dependencies just by doing magnetics and so forth. We're also thinking about doing maybe PROC macro, build RS kind of stuff as well because while PROC macros and build RS are great they're also huge security holes and we kind of want to be at least aware when we added dependency on something that uses procedural macro or build RS file for example just so that we can kind of say should we be adding this? And yeah, if anyone else has any ideas of other things that could be added to it would be cool. And then also there's this issue for cargo but the basic idea is that cargo could expose some way to hook into the dependency resolution of cargo itself and this would be really cool because instead of, right now cargo deny just looks at the resolved dependencies after cargo is done with it. If you had this you could add dependency resolution time stop something from getting into your graph in the first place and this would be particularly useful for things like security vulnerabilities. Like I don't want to add a dependency and then have my CI fail. I just want to not have it in there in the first place. And we do have a GitHub action that you can use and here's a few of the users most of them are crates but there's Tonic the DRPC library. And here's links to all the stuff. So the tool itself, spdx expression parser and evaluator creates is like a simple thing that basically takes cargo metadata and marries it to pet graph. There's conflict expert which evaluates configuration expressions and there's cargo audit and rust sec and then cargo about our kind of license attribution tool as well. So yeah. That's it. Did we have time for about one question? Yeah. One question. No one. Okay. Any others? What does cargo about do? So cargo about uses the more like it deep scans the every single file in create source to detect any licenses and then basically make sure that they match the declared licenses and if they don't basically gives a error and then you can configure to say like, okay, actually there's an additional license in this location but basically just takes them all together puts all the attributions and for each crate together and then you can take that information and pass it to a handlebar template and then the handlebar template can be whatever you want. We use like a HTML one and the idea is create something like the Firefox attribution page so that you can list every single crate that's being used, every single license that's used and then the license tax for each of the crates.