# cargo-crev: signed code reviews for Rust dependencies

> cargo-crev is a Rust command line tool that implements the Crev distributed code review system for cargo, letting reviewers publish signed findings about suspicious crates and consumers build a web of trust. It is tri-licensed in Cargo.toml while the repository-level field names only one, its two newest tags are 37 seconds apart in the wrong order, and seven crypto crates are pinned to opt-level 2 because unoptimised builds are unusable.

**crev-dev/cargo-crev** — A cryptographically verifiable code review system for the cargo (Rust) package manager.

- Repository: https://github.com/crev-dev/cargo-crev
- Stars: 2,337 · Forks: 97
- Language: Rust
- License: Apache-2.0
- Published: 2026-09-30 · Updated: 2026-09-30 · Language: en
- Canonical page: https://hysenlabs.com/projects/crev-dev-cargo-crev

## Three licence files, an OR expression, and one licence in the metadata

The repository metadata for cargo-crev records the licence as Apache-2.0. The Cargo.toml records something different:

```toml
[workspace.package]
authors = [
	"Dawid Ciężarkiewicz <dpc@dpc.pw>",
	"Kornel Lesiński <kornel@geekhood.net>",
]
edition = "2024"
license = "MPL-2.0 OR MIT OR Apache-2.0"
repository = "https://github.com/crev-dev/cargo-crev"
rust-version = "1.92"
version = "0.27.1"
```

And the repository listing backs up the manifest rather than the metadata: LICENSE-APACHE, LICENSE-MIT and LICENSE-MPL2 are all at the root.

So the actual licence position is a three-way disjunction, and the disjunction is the generous choice. Under MPL-2.0 OR MIT OR Apache-2.0 you may take the terms you prefer, and for most consumers that means MIT, which is the least restrictive of the three. This is the conventional arrangement for a Rust project of this size and it is the position any lawyer would want.

The mismatch is with the repository-level metadata, and it is worth naming because that field is what automated tooling reads. A dependency scanner that queries the GitHub API for a licence identifier gets Apache-2.0 and stops. It does not read Cargo.toml, and even a tool that does read Cargo.toml has to evaluate the OR rather than take the first alternative. So the most accurate summary of this project's licensing is the one in the manifest, and the one most tools will act on is the one in the metadata.

The same block contains two other things an evaluator needs. edition is 2024, which is a recent Rust edition and the first to change the default behaviour of several things. rust-version is 1.92, a specific toolchain floor well above what a lot of build infrastructure still pins. Between them they mean cargo-crev will refuse to build on anything older than a current stable Rust, which is a real constraint for a security tool that people might expect to drop into an older CI image.

The workspace resolves with the version 2 resolver and five members, cargo-crev, crev-common, crev-data, crev-wot and crev-lib, with crevette excluded. Those five names are the architecture: crev-lib is the library interface, crev-wot is the web of trust, crev-data is the signed data model, crev-common is shared types, and cargo-crev is the CLI. The project is a workspace with a real internal structure, not a single crate.

## v0.27.0 was tagged 37 seconds after v0.27.1

The two most recent releases in this repository are v0.27.1 at 18:52:15 and v0.27.0 at 18:52:52 on the same afternoon, 2026-04-12.

The patch was tagged first and the minor 37 seconds later. That is almost certainly an accident of release automation rather than an intent, and it has one concrete consequence worth stating: a version sort on the tag list, or any tool that reads releases in timestamp order and takes the last one, sees v0.27.0 as the newest release of the two. The Cargo.toml says version 0.27.1, and crates.io publishes 0.27.1, so the artefact you get from a dependency line is the right one. The confusion is confined to anything that navigates the release list rather than the registry.

The wider timeline is more interesting than the ordering. The release before those two is v0.26.5, tagged 2025-07-25. So the pattern is a nine-month gap, two releases in the same afternoon, and then the last push on 2026-07-21 with no release since. Five months of commits past the newest tag.

The version number tells its own story. v0.27.1 means this is a pre-1.0 project by its own numbering, which in the Rust ecosystem conventionally means the public API is not yet stable and the author is not promising it will be. That is consistent with the README's own assessment, which says cargo-crev is a work in progress but should be usable at all times. That sentence is unusual candour: it claims usability without claiming stability, and it is the sentence an evaluator should hold the tool to.

The MIT licence in the disjunction applies here, incidentally. Pre-1.0 with a permissive licence is a combination that favours experimentation, which is exactly what a distributed trust system for a package ecosystem is.

The homepage is declared as none, so the canonical surfaces are the crates.io listing, the GitHub discussions board the README points at for help and feedback, docs.rs for the API documentation, and a getting started guide kept in the repository at cargo-crev/src/doc/getting_started.md. Static binaries are available from the releases page, which matters for anyone who does not want to compile it.

## Seven crypto crates forced to opt-level 2, for a stated reason

One block in Cargo.toml is the most operationally interesting thing in the repository, and the comment above it explains why.

```toml
# Crypto crates are unusably slow without optimizations
[profile.dev.package]
blake2 = { opt-level = 2 }
ed25519-dalek = { opt-level = 2 }
curve25519-dalek = { opt-level = 2 }
sha2 = { opt-level = 2 }
rust-argon2 = { opt-level = 2 }
blake2b_simd = { opt-level = 2 }
constant_time_eq = { opt-level = 2 }
```

Seven overrides, all of them cryptography, all raised to optimisation level 2 even in a development build where dependencies normally compile unoptimised. The reason is given in the comment rather than left to be inferred, and it is the right reason: an unoptimised implementation of curve25519 or argon2 is not slightly slower, it is slow enough that the tool stops being usable.

The cost of that decision is specific and worth naming. opt-level 2 is not free. These seven crates will compile slowly, they will be larger, and they will take real time in a cold build. In exchange, signature verification and hashing run at a speed a developer can wait for. For a tool whose entire loop is verifying signed review data, that is the correct trade, and the fact that it was made explicitly in a profile override rather than left to a user flag is the difference between a project that has been used and one that has been reasoned about.

The dependency set around it explains what the tool actually does cryptographically. blake2 and blake2b_simd for hashing, ed25519-dalek and curve25519-dalek for signing and verification, sha2 for the digests you would expect, rust-argon2 for password hashing, and constant_time_eq for comparisons that should not leak timing. There is no TLS stack in that list and no network client, which is a meaningful shape: the cryptography is for signing and verifying review records, not for talking to a server. That matches the project's description of itself as distributed and peer to peer.

The rest of the workspace dependencies are ordinary application libraries: cargo at version 0.95, which is the library form of the package manager rather than a shell-out, git2 for repository access, rayon for parallelism, itertools, semver, serde with derive, serde_json, serde_yaml, thiserror and log. chrono is pinned with default-features turned off and only the std and clock features enabled, which is a careful default for a project that runs in CI. Using cargo as a library rather than a subprocess is the design decision that makes cargo-crev able to do things a wrapper script around cargo cannot, including dependency-bloat analysis.

## A Nix flake generates the justfile, and direnv opens the shell

The developer environment here is not a Makefile and it is not a shell script, and the reason is written into the file that automates it.

The justfile opens with a comment saying it is autogenerated from Flakebox configuration, and then imports justfile.custom.just. That is a two-file arrangement where the generated file is committed so it can be read and the custom file holds whatever a contributor adds. The commands themselves are aliases for the common cases, b for build, c for check and t for test, and the default recipe is just --list, which means running just with no arguments tells you what you can run rather than doing something.

The build commands are more interesting than they look. Every recipe starts with a shebang line and set -euo pipefail, so the strict shell options are on, and then most of them check whether Cargo.toml exists in the current directory and cd to the invocation directory if not. That guard is what lets just recipes work from a subdirectory. build defaults to cargo build --workspace --all-targets, check to the same with cargo check, and test depends on build and then runs cargo test. final-check is declared as lint clippy and additionally runs just test, so one command covers the full pre-PR sequence.

Underneath all of that is Nix. There is a flake.nix, a flake.lock, a default.nix and a shell.nix, plus an .envrc at the root, which is the direnv file that loads the flake's development shell the moment you cd into the repository. flake.lock is committed, so the Nix inputs are pinned and the development environment is reproducible to the same standard as the Cargo.lock.

Windows is covered separately, by appveyor.yml, and .github holds the GitHub Actions workflow the README badges. So there are three CI and environment systems, one per platform, and the Linux and macOS contributors get a reproducible shell while Windows contributors get a traditional CI configuration. That is a deliberate split rather than an oversight, and it costs a little duplication in exchange for a pinned toolchain on the two platforms where most Rust development happens.

Two smaller files complete the setup. .rustfmt.toml and .treefmt.toml together with the format recipe running treefmt mean formatting is not a per-language concern, and .pre-commit-config.yaml is what the lint target ultimately invokes.

## just lint runs your installed hook, so a fresh clone checks nothing

One recipe in the justfile is worth reading closely, because it is a good idea with a sharp edge.

```bash
# run lints (git pre-commit hook)
lint:
  #!/usr/bin/env bash
  set -euo pipefail
  env NO_STASH=true $(git rev-parse --git-common-dir)/hooks/pre-commit
```

The idea is sound. Rather than duplicating a list of checks in the justfile and in the pre-commit configuration, the lint target runs the hook itself, so there is one definition of what linting means and the developer gets the same result whether they commit or they run just lint. The path is resolved through git rev-parse --git-common-dir rather than a hard-coded .git/hooks, which is the correct way to find it and also means the recipe works in a worktree.

The edge is that the hook has to exist. A fresh clone does not install pre-commit hooks, and git's core.hooksPath is not something a repository can set from the working tree in a way every contributor will pick up. So on a new machine, just lint runs a file that is not there. With set -euo pipefail in effect, the failure depends on what the shell does with a missing script, and either way the developer learns that they need to install hooks rather than that their code is clean.

That is arguably a feature. The pre-commit configuration is the source of truth, installing it is a deliberate step, and a contributor who has not installed hooks has not yet opted into the project's checks. The alternative, a lint target that runs the tools directly and the hook that runs the same tools, risks the two drifting apart.

NO_STASH=true is the other detail. Many pre-commit frameworks stash your unstaged changes before running so that the checks see a clean tree, and restore them afterwards. Setting that off means the checks run against your actual working tree, including unstaged edits. For a formatting check that is what you want, because it tells you whether the files on disk are formatted. For a lint that examines staged content it changes the semantics. The project has chosen disk state, and the recipes around it, with the clippy invocation below, are consistent with that choice.

For completeness, the clippy recipes are the strictest thing in the file: cargo clippy with --locked --offline --workspace --all-targets and then -- --deny warnings --allow deprecated. Warnings are errors, deprecation is exempted, and the lockfile is required and the network is off. That is a high bar for a project of this size.

## The README asks you to advertise it in your own project

There is a section in this README that has no place in a technical document, and it is the section that tells you most about how the project expects to grow.

It is headed Raise awareness. It says that if you are supportive of the cause, help raise awareness of the project, and asks you to consider putting a specific note in the README of your Rust projects. The note recommends always using cargo-crev to verify the trustworthiness of each of your dependencies, including this one.

The request is explicit and the wording is worked out. The phrase including this one is doing real work, because it means the endorsement is self-referential: a crate that recommends cargo-crev creates a second reason to trust the endorsement, which is the actual growth mechanism of a trust network. It is a sensible design and it is also a request for advertising.

For an evaluator, that is a consideration rather than a defect. Adopting the tool does not require pasting the note, and nothing in the software depends on it. But a project whose README shows up in yours is a public association, and some teams will not want their crate to appear in a web of trust graph alongside crates they have not audited, particularly while the tool is at version 0.27.1 and describes itself as a work in progress. Others will read the request as a sign of a project that needs users to reach viability, which is a reasonable thing to support.

The rest of the README follows the same candid register. The feature list is written in the present tense with can already, covering warnings about untrustworthy crates and security vulnerabilities, dependency metrics, dependency-bloat identification, the ability to review suspicious dependencies and publish findings, the ability to use reviews produced by other users, increasing the trustworthiness of your own code, and building a web of trust of reputable users. Then there is the line that should probably be the first line of the README: cargo-crev is a work in progress, but it should be usable at all times.

And at the top there is a meme image captioned jesus, that's a lot of dependencies, with a link crediting the artist. The project whose feature list includes identify dependency-bloat opens with a joke about having too many dependencies. That is a fair summary of the situation cargo-crev exists to address, and putting it above the fold is the kind of self-awareness that makes the rest of the project's claims easier to evaluate.

## What the signed data is actually for, and where the trust boundary sits

The architecture is worth reconstructing, because the security properties of this tool depend on what is signed and what is not.

Crev itself is a separate project, described in the README as a language and ecosystem agnostic, distributed code review system. cargo-crev is one implementation of it, integrated as a cargo subcommand, and the parent repository is crev-dev/crev. That separation is the right one: the trust model is a specification, and cargo-crev is a client for it. The topics list carries code, code-review, decentralized, p2p, review, scalable, security and trust, which is the vocabulary of a system with no central authority.

Now the boundary. The cryptography in the dependency list, ed25519 for signing and curve25519 for verification with blake2 and sha2 for hashing and argon2 for password hashing, is there to make a review record attributable and tamper-evident. A reviewer signs a set of findings about a crate version, the signature travels with the review, and a consumer can check that the review came from the key it expects. That is the part that is genuinely verifiable and it does not depend on trusting any server.

What is not verifiable is the review itself. A signature proves who said something, not that it was correct, not that it was thorough, and not that the reviewer was competent. That is precisely why the feature list includes building a web of trust of reputable users, and why the tool can also increase the trustworthiness of your own code, which is the publish-your-own-credibility half of the system. A trust network is a social structure with a cryptographic wrapper, and the wrapper prevents forgery while the social structure determines whether the contents mean anything.

The consequence for an evaluator is that cargo-crev does not replace the tools it sits alongside. It is not a vulnerability database, though it warns about crates it considers untrustworthy. It is not a supply-chain attestation system, because a review is an opinion rather than a build provenance record. It is not a substitute for cargo audit. What it is, and what it is genuinely unusual in offering, is a way for a review to be signed, distributed without a central server, and consulted by people who have decided whose judgement to weight.

That is a real gap in the Rust ecosystem and the project's pre-1.0 version, its nine-month-then-two-releases-in-an-afternoon cadence, and its own work in progress label are all consistent with a system that is being built rather than finished. The README's guidance, use discussions to get help, more information and report feedback, is the right instruction for a project at that stage.

## Conclusion

Adopt cargo-crev if you publish Rust crates and want your downstream users to be able to verify that you reviewed their dependencies, because that is the half of the system the project implements well and the half where the signed data has lasting value. Do not adopt it as your only supply-chain control, because the tool is a social trust layer over a registry you do not control, and the README itself calls it a work in progress. Do not paste its recommended note into your own README without deciding you want that association, since the project asks for it explicitly and adoption is visible. Verify five things. Read Cargo.toml rather than the repository-level field for the licence, because the manifest says MPL-2.0 OR MIT OR Apache-2.0 and three LICENSE files exist while the repository-level field says Apache-2.0. Confirm your toolchain is Rust 1.92 or newer on edition 2024. Build with the pinned Cargo.lock rather than updating it, since the clippy target runs with --locked and --offline for a reason. Install the pre-commit hook before trusting just lint, or the lint target silently does nothing on a fresh clone. And check the static binary on the releases page against your platform before assuming a cargo install is the only route. The deciding fact is that cargo-crev gives you cryptographic verifiability for an opinion, which is worth exactly as much as the reputation behind the key.

## FAQ

### What does cargo-crev do?

It is a cargo subcommand implementing the Crev distributed code review system. It warns about untrustworthy crates and security vulnerabilities, reports metrics about your dependencies, helps identify dependency bloat, lets you review suspicious dependencies and publish signed findings, lets you use reviews produced by other users, and builds a web of trust of users whose judgement you can weight.

### What licence is cargo-crev released under?

Cargo.toml declares license = "MPL-2.0 OR MIT OR Apache-2.0" and the repository contains LICENSE-APACHE, LICENSE-MIT and LICENSE-MPL2 at the root, so you may take whichever of the three terms you prefer. Note that the repository-level licence metadata says Apache-2.0, which is why the manifest is the more accurate source.

### What Rust version does cargo-crev need?

The workspace declares edition = "2024" and rust-version = "1.92", so it needs a current stable Rust toolchain. The workspace also pins resolver = "2" and uses the cargo library at version 0.95 rather than shelling out to the cargo binary.

### How do I build and test cargo-crev?

Static binaries are published on the releases page. To build from source the justfile provides just build, just check, just test, just format which runs treefmt, just clippy and just lint, with just final-check running lint, clippy and the tests together. The justfile is autogenerated from Flakebox configuration, and a Nix flake plus an .envrc file provide a reproducible development shell.

### Is cargo-crev ready to depend on?

The version is 0.27.1, which is pre-1.0, and the README states that cargo-crev is a work in progress but should be usable at all times. It is tri-licensed so you can take the terms you prefer, but the signed review data it produces is verifiable in origin rather than in correctness, so it complements cargo audit and dependency review rather than replacing them.

## Sources

- [crev-dev/cargo-crev on GitHub](https://github.com/crev-dev/cargo-crev)
- [Issues](https://github.com/crev-dev/cargo-crev/issues)
- [License: Apache-2.0](https://github.com/crev-dev/cargo-crev/blob/main/LICENSE)
- [README](https://github.com/crev-dev/cargo-crev/blob/main/README.md)
- [Releases](https://github.com/crev-dev/cargo-crev/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/crev-dev-cargo-crev
