cargo-deny
cargo-deny is a cargo plugin that lets you lint your project's dependency graph to ensure all your dependencies conform to your expectations and requirements.
Quickstart
Installs cargo-deny, initializes your project with a default configuration, then runs all of the checks against your project.
cargo install --locked cargo-deny && cargo deny init && cargo deny check
Command Line Interface
cargo-deny is intended to be used as a Command Line Tool, see the link for the available commands and options.
Checks
cargo-deny supports several classes of checks, see Checks for the available checks and their configuration options.
API
cargo-deny is primarily meant to be used as a cargo plugin, but a majority of its functionality is within a library whose docs you may view on docs.rs
GitHub Action
For GitHub projects, one can run cargo-deny automatically as part of continuous integration using a GitHub Action:
name: CI
on: [push, pull_request]
jobs:
cargo-deny:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: EmbarkStudios/cargo-deny-action@v1
For more information, see cargo-deny-action
repository.
Command Line Tool
cargo-deny can be used either as a command line tool or as a Rust crate. Let's focus on the command line tool capabilities first.
Install From Binaries
Precompiled binaries are provided for major platforms on a best-effort basis. Visit the releases page to download the appropriate version for your platform.
Installation on Arch Linux
cargo-deny is available in the Arch Linux community repository, you can install it via pacman as shown below:
pacman -S cargo-deny
Install From Source
cargo-deny can also be installed from source.
Pre-requisites
cargo-deny is written in Rust and therefore needs to be compiled with Cargo. If you haven't already installed Rust, please go ahead and install it now.
cargo-deny depends on some crates that use C code, so you will also need to have a C toolchain available on your machine, such as gcc, clang, or msvc.
Install Crates.io version
Installing cargo-deny is relatively easy if you already have Rust and Cargo installed. You just have to type this snippet in your terminal:
cargo install --locked cargo-deny
This will fetch the source code for the latest release from Crates.io and compile it. You will have to add Cargo's bin
directory to your PATH
if you have not done so already.
Run cargo deny help
in your terminal to verify if it works. Congratulations, you have installed cargo-deny!
Install Git version
The git version contains all the latest bug-fixes and features, that will be released in the next version on Crates.io, if you can't wait until the next release. You can build the git version yourself.
cargo install --locked --git https://github.com/EmbarkStudios/cargo-deny cargo-deny
Run cargo deny help
in your terminal to verify if it works. Congratulations, you have installed cargo-deny!
CI Usage
We now have a Github Action for running cargo-deny on your Github repositories, check it out here.
If you don't want to use the action, you can manually download (or install) cargo-deny as described above, but here's an example script that you can copy to get you started.
#!/bin/bash
set -eu
NAME="cargo-deny"
VS="0.8.5"
DIR="/tmp/$NAME"
mkdir $DIR
# Download the tarball
curl -L -o $DIR/archive.tar.gz https://github.com/EmbarkStudios/$NAME/releases/download/$VS/$NAME-$VS-x86_64-unknown-linux-musl.tar.gz
# Unpack the tarball into the temp directory
tar -xzvf $DIR/archive.tar.gz --strip-components=1 -C $DIR
# Run cargo deny check in our current directory
$DIR/$NAME --context . -L debug check bans licenses advisories
Common options
The subcommands share some common options that can be used before the subcommand.
--manifest-path
The path to a Cargo.toml
file which is used as the context for operations.
--all-features
(single crate or workspace)
Enables all features when determining which crates to consider. Works for both single crates and workspaces.
--no-default-features
(single crate only)
Disables the default
feature for a crate when determing which crates to consider.
--features
(single crate only)
Space-separated list of features to enable when determining which crates to consider.
--workspace
Forces all workspace crates to be used as roots in the crate graph that we operate on, unless they are excluded by other means. By default, if you specify a virtual manifest, all crates in the workspace will be used as roots. However, if you specify a normal package manifest somewhere inside a workspace, only that crate will be used as a graph root, and only other workspaces crates it depends on will be included in the graph. If you want to specify a sub-crate in a workspace, but still include all other crates in the workspace, you can use this flag.
--exclude
Exclude the specified package(s) from the crate graph. Unlike other cargo subcommands, it doesn't have to be used in conjunction with the --workspace
flag. This flag may be specified multiple times.
This uses a similar (though slightly more strict) Package ID specification to other cargo subcommands.
Packages can also be excluded in your configuration files, specifying this on the command line will append the package ID to the list that may exist in your configuration.
-L, --log-level
The log level for messages, only log messages at or above the level will be emitted.
Possible values:
off
- No output will be emittederror
warn
(default)info
debug
trace
--format
The format of the output of both log and diagnostic messages.
Possible values:
human
(default) - Output for the pesky humansjson
- Each log message/diagnostic is outputted as a single line JSON object
--color
Whether coloring is applied to human-formatted output, using it on JSON output has no effect.
Possible values:
auto
(default) - Coloring is applied if the output stream is a TTYalways
- Coloring is always appliednever
- No coloring is applied for any output
-t, --target
One or more platforms to filter crates with. If a dependency is target specific, it will be ignored if it does not match at least 1 of the specified targets. This overrides the top-level targets = []
configuration value.
The init command
cargo-deny's configuration is a little bit complicated, so we provide the init
command to create a configuration file from a template for you to give you a starting point for configuring how you want cargo-deny to lint your project.
The init
command is used like this:
cargo deny init
Specify a path
The init
command can take a path as an argument to use as path of the config instead of the default which is <cwd>/deny.toml
.
cargo deny init path/to/config.toml
Template
A deny.toml
file will be created in the current working directory that is a direct copy of this template.
# This template contains all of the possible sections and their default values
# Note that all fields that take a lint level have these possible values:
# * deny - An error will be produced and the check will fail
# * warn - A warning will be produced, but the check will not fail
# * allow - No warning or error will be produced, though in some cases a note
# will be
# The values provided in this template are the default values that will be used
# when any section or field is not specified in your own configuration
# Root options
# If 1 or more target triples (and optionally, target_features) are specified,
# only the specified targets will be checked when running `cargo deny check`.
# This means, if a particular package is only ever used as a target specific
# dependency, such as, for example, the `nix` crate only being used via the
# `target_family = "unix"` configuration, that only having windows targets in
# this list would mean the nix crate, as well as any of its exclusive
# dependencies not shared by any other crates, would be ignored, as the target
# list here is effectively saying which targets you are building for.
targets = [
# The triple can be any string, but only the target triples built in to
# rustc (as of 1.40) can be checked against actual config expressions
#{ triple = "x86_64-unknown-linux-musl" },
# You can also specify which target_features you promise are enabled for a
# particular target. target_features are currently not validated against
# the actual valid features supported by the target architecture.
#{ triple = "wasm32-unknown-unknown", features = ["atomics"] },
]
# When creating the dependency graph used as the source of truth when checks are
# executed, this field can be used to prune crates from the graph, removing them
# from the view of cargo-deny. This is an extremely heavy hammer, as if a crate
# is pruned from the graph, all of its dependencies will also be pruned unless
# they are connected to another crate in the graph that hasn't been pruned,
# so it should be used with care. The identifiers are [Package ID Specifications]
# (https://doc.rust-lang.org/cargo/reference/pkgid-spec.html)
#exclude = []
# If true, metadata will be collected with `--all-features`. Note that this can't
# be toggled off if true, if you want to conditionally enable `--all-features` it
# is recommended to pass `--all-features` on the cmd line instead
all-features = false
# If true, metadata will be collected with `--no-default-features`. The same
# caveat with `all-features` applies
no-default-features = false
# If set, these feature will be enabled when collecting metadata. If `--features`
# is specified on the cmd line they will take precedence over this option.
#features = []
# When outputting inclusion graphs in diagnostics that include features, this
# option can be used to specify the depth at which feature edges will be added.
# This option is included since the graphs can be quite large and the addition
# of features from the crate(s) to all of the graph roots can be far too verbose.
# This option can be overridden via `--feature-depth` on the cmd line
feature-depth = 1
# This section is considered when running `cargo deny check advisories`
# More documentation for the advisories section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html
[advisories]
# The path where the advisory database is cloned/fetched into
db-path = "~/.cargo/advisory-db"
# The url(s) of the advisory databases to use
db-urls = ["https://github.com/rustsec/advisory-db"]
# The lint level for security vulnerabilities
vulnerability = "deny"
# The lint level for unmaintained crates
unmaintained = "warn"
# The lint level for crates that have been yanked from their source registry
yanked = "warn"
# The lint level for crates with security notices. Note that as of
# 2019-12-17 there are no security notice advisories in
# https://github.com/rustsec/advisory-db
notice = "warn"
# A list of advisory IDs to ignore. Note that ignored advisories will still
# output a note when they are encountered.
ignore = [
#"RUSTSEC-0000-0000",
]
# Threshold for security vulnerabilities, any vulnerability with a CVSS score
# lower than the range specified will be ignored. Note that ignored advisories
# will still output a note when they are encountered.
# * None - CVSS Score 0.0
# * Low - CVSS Score 0.1 - 3.9
# * Medium - CVSS Score 4.0 - 6.9
# * High - CVSS Score 7.0 - 8.9
# * Critical - CVSS Score 9.0 - 10.0
#severity-threshold =
# If this is true, then cargo deny will use the git executable to fetch advisory database.
# If this is false, then it uses a built-in git library.
# Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support.
# See Git Authentication for more information about setting up git authentication.
#git-fetch-with-cli = true
# This section is considered when running `cargo deny check licenses`
# More documentation for the licenses section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html
[licenses]
# The lint level for crates which do not have a detectable license
unlicensed = "deny"
# List of explicitly allowed licenses
# See https://spdx.org/licenses/ for list of possible licenses
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
allow = [
#"MIT",
#"Apache-2.0",
#"Apache-2.0 WITH LLVM-exception",
]
# List of explicitly disallowed licenses
# See https://spdx.org/licenses/ for list of possible licenses
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
deny = [
#"Nokia",
]
# Lint level for licenses considered copyleft
copyleft = "warn"
# Blanket approval or denial for OSI-approved or FSF Free/Libre licenses
# * both - The license will be approved if it is both OSI-approved *AND* FSF
# * either - The license will be approved if it is either OSI-approved *OR* FSF
# * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF
# * fsf-only - The license will be approved if is FSF *AND NOT* OSI-approved
# * neither - This predicate is ignored and the default lint level is used
allow-osi-fsf-free = "neither"
# Lint level used when no other predicates are matched
# 1. License isn't in the allow or deny lists
# 2. License isn't copyleft
# 3. License isn't OSI/FSF, or allow-osi-fsf-free = "neither"
default = "deny"
# The confidence threshold for detecting a license from license text.
# The higher the value, the more closely the license text must be to the
# canonical license text of a valid SPDX license file.
# [possible values: any between 0.0 and 1.0].
confidence-threshold = 0.8
# Allow 1 or more licenses on a per-crate basis, so that particular licenses
# aren't accepted for every possible crate as with the normal allow list
exceptions = [
# Each entry is the crate and version constraint, and its specific allow
# list
#{ allow = ["Zlib"], name = "adler32", version = "*" },
]
# Some crates don't have (easily) machine readable licensing information,
# adding a clarification entry for it allows you to manually specify the
# licensing information
#[[licenses.clarify]]
# The name of the crate the clarification applies to
#name = "ring"
# The optional version constraint for the crate
#version = "*"
# The SPDX expression for the license requirements of the crate
#expression = "MIT AND ISC AND OpenSSL"
# One or more files in the crate's source used as the "source of truth" for
# the license expression. If the contents match, the clarification will be used
# when running the license check, otherwise the clarification will be ignored
# and the crate will be checked normally, which may produce warnings or errors
# depending on the rest of your configuration
#license-files = [
# Each entry is a crate relative path, and the (opaque) hash of its contents
#{ path = "LICENSE", hash = 0xbd0eed23 }
#]
[licenses.private]
# If true, ignores workspace crates that aren't published, or are only
# published to private registries.
# To see how to mark a crate as unpublished (to the official registry),
# visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field.
ignore = false
# One or more private registries that you might publish crates to, if a crate
# is only published to private registries, and ignore is true, the crate will
# not have its license(s) checked
registries = [
#"https://sekretz.com/registry
]
# This section is considered when running `cargo deny check bans`.
# More documentation about the 'bans' section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html
[bans]
# Lint level for when multiple versions of the same crate are detected
multiple-versions = "warn"
# Lint level for when a crate version requirement is `*`
wildcards = "allow"
# The graph highlighting used when creating dotgraphs for crates
# with multiple versions
# * lowest-version - The path to the lowest versioned duplicate is highlighted
# * simplest-path - The path to the version with the fewest edges is highlighted
# * all - Both lowest-version and simplest-path are used
highlight = "all"
# The default lint level for `default` features for crates that are members of
# the workspace that is being checked. This can be overriden by allowing/denying
# `default` on a crate-by-crate basis if desired.
workspace-default-features = "allow"
# The default lint level for `default` features for external crates that are not
# members of the workspace. This can be overriden by allowing/denying `default`
# on a crate-by-crate basis if desired.
external-default-features = "allow"
# List of crates that are allowed. Use with care!
allow = [
#{ name = "ansi_term", version = "=0.11.0" },
]
# List of crates to deny
deny = [
# Each entry the name of a crate and a version range. If version is
# not specified, all versions will be matched.
#{ name = "ansi_term", version = "=0.11.0" },
#
# Wrapper crates can optionally be specified to allow the crate when it
# is a direct dependency of the otherwise banned crate
#{ name = "ansi_term", version = "=0.11.0", wrappers = [] },
]
# List of features to allow/deny
# Each entry the name of a crate and a version range. If version is
# not specified, all versions will be matched.
#[[bans.features]]
#name = "reqwest"
# Features to not allow
#deny = ["json"]
# Features to allow
#allow = [
# "rustls",
# "__rustls",
# "__tls",
# "hyper-rustls",
# "rustls",
# "rustls-pemfile",
# "rustls-tls-webpki-roots",
# "tokio-rustls",
# "webpki-roots",
#]
# If true, the allowed features must exactly match the enabled feature set. If
# this is set there is no point setting `deny`
#exact = true
# Certain crates/versions that will be skipped when doing duplicate detection.
skip = [
#{ name = "ansi_term", version = "=0.11.0" },
]
# Similarly to `skip` allows you to skip certain crates during duplicate
# detection. Unlike skip, it also includes the entire tree of transitive
# dependencies starting at the specified crate, up to a certain depth, which is
# by default infinite.
skip-tree = [
#{ name = "ansi_term", version = "=0.11.0", depth = 20 },
]
# This section is considered when running `cargo deny check sources`.
# More documentation about the 'sources' section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html
[sources]
# Lint level for what to happen when a crate from a crate registry that is not
# in the allow list is encountered
unknown-registry = "warn"
# Lint level for what to happen when a crate from a git repository that is not
# in the allow list is encountered
unknown-git = "warn"
# List of URLs for allowed crate registries. Defaults to the crates.io index
# if not specified. If it is specified but empty, no registries are allowed.
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
# List of URLs for allowed Git repositories
allow-git = []
[sources.allow-org]
# 1 or more github.com organizations to allow git sources for
github = [""]
# 1 or more gitlab.com organizations to allow git sources for
gitlab = [""]
# 1 or more bitbucket.org organizations to allow git sources for
bitbucket = [""]
The check
command
The check command is the primary subcommand of cargo-deny as it is what actually runs through all of the crates in your project and checks them against your configuration.
Args
<which>
The check(s) to perform. By default, all checks will be performed, unless one or more checks are specified here.
See checks for the list of available checks.
Options
-A, --allow <ALLOW>
Set lint allowed
--audit-compatible-output
To ease transition from cargo-audit to cargo-deny, this flag will tell cargo-deny to output the exact same output as cargo-audit would, to stdout
instead of stderr
, just as with cargo-audit.
Note that this flag only applies when the output format is JSON, and note that since cargo-deny supports multiple advisory databases, instead of a single JSON object, there will be 1 for each unique advisory database.
-c, --config <CONFIG>
Path to the config to use
Defaults to <cwd>/deny.toml
if not specified
-d, --disable-fetch
Disable fetching of the advisory database
When running the advisories
check, the configured advisory database will be fetched and opened. If this flag is passed, the database won't be fetched, but an error will occur if it doesn't already exist locally.
-D, --deny <DENY>
Set lint denied
--feature-depth <FEATURE_DEPTH>
Specifies the depth at which feature edges are added in inclusion graphs
-g, --graph <GRAPH>
Path to graph_output root directory
If set, a dotviz graph will be created for whenever multiple versions of the same crate are detected.
Each file will be created at <dir>/graph_output/<crate_name>.dot
. <dir>/graph_output/*
is deleted and recreated each run.
--hide-inclusion-graph
Hides the inclusion graph when printing out info for a crate
By default, if a diagnostic message pertains to a specific crate, cargo-deny will append an inverse dependency graph to the diagnostic to show you how that crate was pulled into your project.
some diagnostic message
the-crate
├── a-crate
└── b-crate
└── c-crate
-s, --show-stats
Show stats for all the checks, regardless of the log-level
-W, --warn <WARN>
Set lint warnings
The list
command
Similarly to cargo-license, list
prints out the license information for each crate.
Options
-f, --format
The format of the output
human
(default) - Simple format where each crate or license is its own linejson
tsv
--color
Output coloring, only applies to the human
format.
auto
(default) - Only colors if stdout is a TTYalways
- Always emits colorsnever
- Never emits colors
Colors:
- SPDX identifier -
- Crate with 1 license -
- Crate with 2 or more licenses -
- Crate with 0 licenses -
-l, --layout
The layout of the output. Does not apply to the tsv
format.
license
(default) - Each license acts as the key, and the values are all of the crates that use that licensecrate
- Each crate is a key, and the values are the list of licenses it uses.
-t, --threshold
The confidence threshold required for assigning a license identifier to a license text file. See the license configuration for more information.
layout = license, format = human
(default)
layout = crate, format = human
layout = license, format = json
layout = license, format = tsv
Checks
cargo-deny supports several different classes of checks that can be performed on your project's crate graph. By default, cargo deny check
will execute all of the supported checks, falling back to the default configuration for that check if one is not explicitly specified.
licenses
Checks the license information for each crate.
bans
Checks for specific crates in your graph, as well as duplicates.
advisories
Checks advisory databases for crates with security vulnerabilities, or that have been marked as Unmaintained
, or which have been yanked from their source registry.
sources
Checks the source location for each crate.
config
The top level config for cargo-deny, by default called deny.toml
.
Example - cargo-deny's own configuration
# cargo-deny is really only ever intended to run on the "normal" tier-1 targets
targets = [
{ triple = "x86_64-unknown-linux-gnu" },
{ triple = "aarch64-unknown-linux-gnu" },
{ triple = "x86_64-unknown-linux-musl" },
{ triple = "aarch64-apple-darwin" },
{ triple = "x86_64-apple-darwin" },
{ triple = "x86_64-pc-windows-msvc" },
]
[advisories]
vulnerability = "deny"
unmaintained = "deny"
notice = "deny"
unsound = "deny"
ignore = [
# rmp-serde used by askalono for the cache files, these are always utf-8 so
# the advisory is not relevant
"RUSTSEC-2022-0092",
# This is kind of relevant since cargo-deny can do git operations via SSH
# from cargo, but cargo needs to update before we can
"RUSTSEC-2023-0003",
]
[bans]
multiple-versions = "deny"
deny = []
skip = [
# cargo depends on two versions of these crates
{ name = "hex", version = "=0.3.2" },
# cargo-lock uses this older version
{ name = "toml", version = "=0.5.11" },
]
skip-tree = [
# Sigh
{ name = "windows-sys", version = "=0.42" },
# cargo uses an old version
{ name = "toml_edit", version = "=0.15" },
]
[sources]
unknown-registry = "deny"
unknown-git = "deny"
[sources.allow-org]
github = ["EmbarkStudios"]
[licenses]
unlicensed = "deny"
allow-osi-fsf-free = "neither"
copyleft = "deny"
# We want really high confidence when inferring licenses from text
confidence-threshold = 0.93
allow = ["Apache-2.0", "Apache-2.0 WITH LLVM-exception", "MIT", "MPL-2.0"]
exceptions = [
{ allow = ["Zlib"], name = "tinyvec" },
{ allow = ["Unicode-DFS-2016"], name = "unicode-ident" },
{ allow = ["BSD-3-Clause"], name = "subtle" },
]
The targets
field (optional)
By default, cargo-deny will consider every single crate that is resolved by cargo, including target specific dependencies eg
[target.x86_64-pc-windows-msvc.dependencies]
winapi = "0.3.8"
[target.'cfg(target_os = "fuchsia")'.dependencies]
fuchsia-cprng = "0.1.1"
But unless you are actually targeting x86_64-fuchsia
or aarch64-fuchsia
, the fuchsia-cprng
is never actually going to be compiled or linked into your project, so checking it is pointless for you.
The targets
field allows you to specify one or more targets which you actually build for. Every dependency link to a crate is checked against this list, and if none of the listed targets satisfy the target constraint, the dependency link is ignored. If a crate has no dependency links to it, it is not included into the crate graph that the checks are executed against.
The triple
field
The target triple for the target you wish to filter target specific dependencies with. If the target triple specified is not one of the targets builtin to rustc
, the configuration check for that target will be limited to only the raw [target.<target-triple>.dependencies]
style of target configuration, as cfg()
expressions require us to know the details about the target.
The exclude
field (optional)
Just as with the --exclude
command line option, this field allows you to specify one or more Package ID specifications that will cause the crate(s) in question to be excluded from the crate graph that is used for the operation you are performing.
Note that excluding a crate is recursive, if any of its transitive dependencies are only referenced via the excluded crate, they will also be excluded from the crate graph.
The features
field (optional)
Rust cfg()
expressions support the target_feature = "feature-name"
predicate, but at the moment, the only way to actually pass them when compiling is to use the RUSTFLAGS
environment variable. The features
field allows you to specify 1 or more target_feature
s you plan to build with, for a particular target triple. At the time of this writing, cargo-deny does not attempt to validate that the features you specify are actually valid for the target triple, but this is planned.
The all-features
field (optional)
If set to true
, --all-features
will be used when collecting metadata.
The no-default-features
field (optional)
If set to true
, --no-default-features
will be used when collecting metadata.
The features
field (optional)
If set, and --features
is not specified on the cmd line, these features will be used when collecting metadata.
The feature-depth
field (optional)
The maximum depth that features will be displayed when inclusion graphs are included in diagnostics, unless specified via --feature-depth
on the command line. Only applies to diagnostics that actually print features. If not specified defaults to 1
.
The [licenses]
section
See the licenses config for more info.
The [bans]
section
See the bans config for more info.
The [advisories]
section
See the advisories config for more info.
The [sources]
section
See the sources config for more info.
advisories
The advisories check is used to detect issues for crates by looking in an advisory database.
cargo deny check advisories
Use Case - Detecting security vulnerabilities
Security vulnerabilities are generally considered "not great" by most people, luckily, Rust has a great advisory database which cargo-deny can use to check that you don't have any crates with (known) security vulnerabilities.
You can also use your own advisory databases instead of, or in addition to, the above default, as long as it follows the same format.
Use Case - Detecting unmaintained crates
The advisory database also contains advisories for unmaintained crates, which in most cases users will want to avoid in favor of more actively maintained crates.
Example output
The [advisories]
section
Contains all of the configuration for cargo deny check advisories
Example Config
[advisories]
db-path = "~/.cargo/advisory-dbs"
db-url = "https://github.com/RustSec/advisory-db"
vulnerability = "deny"
unmaintained = "warn"
unsound = "warn"
yanked = "warn"
notice = "warn"
ignore = [
"RUSTSEC-0000-0000",
]
severity-threshold = "medium"
The db-urls
field (optional)
URLs to one or more advisory databases.
Default: RustSec Advisory DB
The db-path
field (optional)
Path to the root directory into which one or more advisory databases are cloned into
Default: ~/.cargo/advisory-db
The vulnerability
field (optional)
Determines what happens when a crate with a security vulnerability is encountered.
deny
(default) - Will emit an error with details about each vulnerability, and fail the check.warn
- Prints a warning for each vulnerability, but does not fail the check.allow
- Prints a note about the security vulnerability, but does not fail the check.
The unmaintained
field (optional)
Determines what happens when a crate with an unmaintained
advisory is encountered.
deny
- Will emit an error with details about the unmaintained advisory, and fail the check.warn
(default) - Prints a warning for each unmaintained advisory, but does not fail the check.allow
- Prints a note about the unmaintained advisory, but does not fail the check.
The unsound
field (optional)
Determines what happens when a crate with an unsound
advisory is encountered.
deny
- Will emit an error with details about the unsound advisory, and fail the check.warn
(default) - Prints a warning for each unsound advisory, but does not fail the check.allow
- Prints a note about the unsound advisory, but does not fail the check.
The yanked
field (optional)
Determines what happens when a crate with a version that has been yanked from its source registry is encountered.
deny
- Will emit an error with the crate name and version that was yanked, and fail the check.warn
(default) - Prints a warning with the crate name and version that was yanked, but does not fail the check.allow
- Prints a note about the yanked crate, but does not fail the check.
The notice
field (optional)
Determines what happens when a crate with a notice
advisory is encountered.
NOTE: As of 2019-12-17 there are no notice
advisories in the RustSec Advisory DB
deny
- Will emit an error with details about the notice advisory, and fail the check.warn
(default) - Prints a warning for each notice advisory, but does not fail the check.allow
- Prints a note about the notice advisory, but does not fail the check.
The ignore
field (optional)
Every advisory in the advisory database contains a unique identifier, eg. RUSTSEC-2019-0001
. Putting an identifier in this array will cause the advisory to be treated as a note, rather than a warning or error.
The severity-threshold
field (optional)
The threshold for security vulnerabilities to be turned into notes instead of warnings or errors, depending upon its CVSS score. So having a high threshold means some vulnerabilities might not fail the check, but having a log level >= info
will mean that a note will be printed instead of a warning or error, depending on [advisories.vulnerability]
.
None
(default) - CVSS Score 0.0Low
- CVSS Score 0.1 - 3.9Medium
- CVSS Score 4.0 - 6.9High
- CVSS Score 7.0 - 8.9Critical
- CVSS Score 9.0 - 10.0
The git-fetch-with-cli
field (optional)
Similar to cargo's net.git-fetch-with-cli, this field allows you to opt-in to fetching advisory databases with the git CLI rather than using git2
, for example if you are using SSH authentication.
false
(default) - Fetches advisory databases viagit2
true
- Fetches advisory databases usinggit
. Git must be installed and inPATH
.
Advisories Diagnostics
vulnerability
A vulnerability
advisory was detected for a crate.
notice
A notice
advisory was detected for a crate.
unmaintained
An unmaintained
advisory was detected for a crate.
unsound
An unsound
advisory was detected for a crate.
yanked
A crate using a version that has been yanked from the registry index was detected.
index-failure
An error occurred trying to read or update the registry index (typically crates.io) so cargo-deny was unable to check the current yanked status for any crate.
advisory-not-detected
An advisory in advisories.ignore
didn't apply to any crate. This could happen if the advisory was withdrawn, or the version of the crate no longer falls within the range of affected versions the advisory applies to.
unknown-advisory
An advisory in advisories.ignore
wasn't found in any of the configured advisory databases, usually indicating a typo, as advisories, at the moment, are never deleted from the database, at least the canonical advisory-db.
bans
The bans check is used to deny (or allow) specific crates, as well as detect and handle multiple versions of the same crate.
cargo deny check bans
Use Case - Denying specific crates
Sometimes, certain crates just don't fit in your project, so you have to remove them. However, nothing really stops them from sneaking back in due to innocuous changes like doing a cargo update
and getting it transitively, or even forgetting to set default-features = false, features = ["feature-without-the-thing"]
when the crate is pulled in via the default features of a crate you already depend on, in your entire workspace.
For example, we previously depended on OpenSSL as it is the "default" for many crates that provide TLS. This was extremely annoying as it required us to have OpenSSL development libraries installed on Windows, for both individuals and CI. We moved all of our dependencies to use the much more streamlined native-tls
or ring
crates instead, and now we can make sure that OpenSSL doesn't return from the grave by accident.
Use Case - Duplicate version detection
The larger your project and number of external dependencies, the likelihood that you will have multiple versions of the same crate rises. This is due to two fundamental aspects of the Rust ecosystem.
- Cargo's dependency resolution tries to solve all the version constraints to a crate to the same version, but is totally ok with using multiple versions if it is unable to.
- Rust has a huge (ever growing) number of crates. Every maintainer has different amounts of time and energy they can spend on their crate, not to mention different philosophies on dependencies and how often (or not) they should be updated, so it is inevitable that crates will not always agree on which version of another crate they want to use.
This tradeoff of allowing multiple version of the same crate is one of the reasons that cargo is such a pleasant experience for many people new to Rust, but as with all tradeoffs, it does come with costs.
- More packages must be fetched, which especially impacts CI, as well as devs.
- Compile times increase, which impacts CI and devs.
- Target directory size increases, which can impact devs, or static CI environments.
- Final binary size will also tend to increase, which can impact users.
Normally, you will not really notice that you have multiple versions of the same crate unless you constantly watch your build log, but as mentioned above, it does introduce paper cuts into your workflows.
The intention of duplicate detection in cargo-deny is not to "correct" cargo's behavior, but rather to draw your attention to duplicates so that you can make an informed decision about how to handle the situation.
- Maybe you want to open up a PR on a crate to use a version of the duplicate that is aligned with the rest of the ecosystem.
- Maybe the crate has actually already been updated, but the maintainer hasn't published a new version yet, and you can ask if they can publish a new one.
- Maybe, even though the versions are supposedly incompatible according to semver, they actually aren't, and you can temporarily introduce a
[patch]
to force the crate to use a particular version for your entire workspace. - Sometimes having the "latest and greatest" is not really that important for every version, and you can just specify a lower version in your own project that matches the transitive constraint(s).
- And finally, you don't care about a particular case of multiple versions, so you just tell cargo-deny to ignore one or more of the specific versions, and the situation will eventually resolve itself.
Example output
The [bans]
section
Contains all of the configuration for cargo deny check bans
Example Config
[bans]
multiple-versions = "deny"
wildcards = "deny"
allow-wildcard-paths = true
highlight = "simplest-path"
workspace-default-features = "warn"
external-default-features = "deny"
allow = [
{ name = "all-versionsa" },
{ name = "specific-versiona", version = "<0.1.1" },
]
skip-tree = [{ name = "blah", depth = 20 }]
[[bans.deny]]
name = "all-versionsd"
wrappers = ["specific-versiona"]
[[bans.deny]]
name = "specific-versiond"
version = "=0.1.9"
[[bans.skip]]
name = "rand"
version = "=0.6.5"
[[bans.features]]
name = "featured-krate"
version = "1.0"
deny = ["bad-feature"]
allow = ["good-feature"]
exact = true
The multiple-versions
field (optional)
Determines what happens when multiple versions of the same crate are encountered.
deny
- Will emit an error for each crate with duplicates and fail the check.warn
(default) - Prints a warning for each crate with duplicates, but does not fail the check.allow
- Ignores duplicate versions of the same crate.
The wildcards
field (optional)
Determines what happens when a dependency is specified with the *
(wildcard) version.
deny
- Will emit an error for each crate specified with a wildcard version.warn
(default) - Prints a warning for each crate with a wildcard version, but does not fail the check.allow
- Ignores all wildcard version specifications.
The allow-wildcard-paths
field (optional)
If specified, alters how the wildcard
field behaves:
- path
dependencies
in private crates will no longer emit a warning or error. - path
dev-dependencies
in both public and private crates will no longer emit a warning or error. - path
dependencies
andbuild-dependencies
in public crates will continue to produce warnings and errors.
Being limited to private crates is due to crates.io not allowing packages to be published with path
dependencies except for dev-dependencies
.
The highlight
field (optional)
When multiple versions of the same crate are encountered and multiple-versions
is set to warn
or deny
, using the -g <dir>
option will print out a dotgraph of each of the versions and how they were included into the graph. This field determines how the graph is colored to help you quickly spot good candidates for removal or updating.
lowest-version
- Highlights the path to the lowest duplicate version. Highlighted insimplest-path
- Highlights the path to the duplicate version with the fewest number of total edges to the root of the graph, which will often be the best candidate for removal and/or upgrading. Highlighted in.
all
- Highlights both thelowest-version
andsimplest-path
. If they are the same, they are only highlighted in.
Crate specifier
The allow
, deny
, features
, skip
, and skip-tree
fields all use a crate identifier to specify what crate(s) they want to match against.
{ name = "some-crate-name-here", version = "<= 0.7.0" }
The name
field
The name of the crate.
The version
field (optional)
An optional version constraint specifying the range of crate versions that will match. Defaults to any version.
The deny
field (optional)
deny = [{ name = "crate-you-don't-want", version = "<= 0.7.0" }]
Determines specific crates that are denied.
The wrappers
field (optional)
deny = [{ name = "crate-you-don't-want", version = "<= 0.7.0", wrappers = ["this-can-use-it"] }]
This field allows specific crates to have a direct dependency on the banned crate but denies all transitive dependencies on it.
The deny-multiple-versions
field (optional)
multiple-versions = 'allow'
deny = [{ name = "crate-you-want-only-one-version-of", deny-multiple-versions = true }]
This field allows specific crates to deny multiple versions of themselves, but allowing or warning on multiple versions for all other crates. This field cannot be set simultaneously with wrappers
.
The allow
field (optional)
Determines specific crates that are allowed. If the allow
list has one or more entries, then any crate not in that list will be denied, so use with care.
The external-default-features
field (optional)
Determines the lint level used for when the default
feature is enabled on a crate not in the workspace. This lint level will can then be overridden on a per-crate basis if desired.
For example, if an-external-crate
had the default
feature enabled it could be explicitly allowed.
[bans]
external-default-features = "deny"
[[bans.features]]
name = "an-external-crate"
allow = ["default"]
The workspace-default-features
field (optional)
The workspace version of external-default-features
.
[bans]
external-default-features = "allow"
[[bans.features]]
name = "a-workspace-crate"
deny = ["default"]
The features
field (optional)
[[bans.features]]
name = "featured-krate"
version = "1.0"
deny = ["bad-feature"]
allow = ["good-feature"]
exact = true
Allows specification of crate specific allow/deny lists of features.
The features.deny
field (optional)
Denies specific features for the crate.
The features.allow
field (optional)
Allows specific features for the crate, enabled features not in this list are denied.
The features.exact
field (optional)
If specified, requires that the features in allow
exactly match the features enabled on the crate, and will fail if features are allowed that are not enabled.
The skip
field (optional)
When denying duplicate versions, it's often the case that there is a window of time where you must wait for, for example, PRs to be accepted and new version published, before 1 or more duplicates are gone. The skip
field allows you to temporarily ignore a crate during duplicate detection so that no errors are emitted, until it is no longer need.
It is recommended to use specific version constraints for crates in the skip
list, as cargo-deny will emit warnings when any entry in the skip
list no longer matches a crate in your graph so that you can cleanup your configuration.
The skip-tree
field (optional)
When dealing with duplicate versions, it's often the case that a particular crate acts as a nexus point for a cascade effect, by either using bleeding edge versions of certain crates while in alpha or beta, or on the opposite end of the spectrum, a crate is using severely outdated dependencies while much of the rest of the ecosystem has moved to more recent versions. In both cases, it can be quite tedious to explicitly skip
each transitive dependency pulled in by that crate that clashes with your other dependencies, which is where skip-tree
comes in.
skip-tree
entries are similar to skip
in that they are used to specify a crate name and version range that will be skipped, but they also have an additional depth
field used to specify how many levels from the crate will also be skipped. A depth of 0
would be the same as specifying the crate in the skip
field.
Note that by default, the depth
is infinite.
NOTE: skip-tree
is a very big hammer at the moment, and should be used with care.
The allow-build-scripts
field (optional)
Specifies all the crates that are allowed to have a build script. If this option is omitted, all crates are allowed to have a build script, and if this option is set to an empty list, no crate is allowed to have a build script.
Bans diagnostics
banned
A crate which is explicitly banned was detected.
allowed
A crate which is explicitly allowed was detected.
not-allowed
When using bans.allow
, a crate was detected that wasn't in that list.
duplicate
One or more duplicate versions of the same crate were detected.
skipped
A crate version that matched an entry in bans.skip
was encountered.
wildcard
A crate was included via a wildcard dependency by one or more crates.
unmatched-skip
A crate version in bans.skip
was not encountered.
allowed-by-wrapper
A crate in bans.deny
was allowed since it was directly depended on by a wrappers
crate.
unmatched-wrapper
A crate in bans.deny
had one or more wrappers
crates, but a crate not in that list had a direct dependency on the banned crate.
skipped-by-root
A crate was skipped from being checked as a duplicate due to being transitively referenced by a crate version in bans.skip-tree
.
unmatched-root
A crate version in bans.skip-tree
was not encountered.
build-script-not-allowed
A crate which has been denied because it has a build script but is not part of the bans.allow-build-script
list.
exact-features-mismatch
A crate's features do not exactly match the configured feature set, and bans.features.exact
is true
.
feature-banned
An enabled crate feature is present in the bans.features.deny
list.
unknown-feature
A feature in either bans.features.deny
or bans.features.allow
does not exist for the crate.
default-feature-enabled
The default
feature was enabled on a crate, and the bans.external-default-features
or bans.workspace-default-features
was configured.
licenses
The licenses check is used to verify that every crate you use has license terms you find acceptable. cargo-deny does this by evaluating the license requirements specified by each crate against the configuration you've specified, to determine if your project meets that crate's license requirements.
cargo deny check licenses
SPDX
cargo-deny uses SPDX license expressions as the source of truth for the license requirements of a crate. Note however, that cargo-deny does not (currently)exhaustively search the entirety of the source code of every crate to find every possible license that could be attributed to the crate, as there are a ton of edge cases to that approach.
cargo-deny rather assumes that each crate correctly defines its license requirements, but it provides a mechanism for manually specifying the license requirements for crates in the, from our experience, rare circumstance that they cannot be gathered automatically.
Expression Source Precedence
The source of the SPDX expression used to evaluate the crate by is obtained in the following order.
- If the crate in question has a Clarification applied to it, and the source file(s) in the crate's source still match, the expression from the clarification will be used.
- The
license
field from the crate's Cargo.toml manifest will be used if it exists. - The
license-file
field, as well as all otherLICENSE(-*)?
files will be parsed to determine the SPDX license identifier, and then all of those identifiers will be joined with theAND
operator, meaning that you must accept all of the licenses detected.
Evaluation Precedence
Currently, the precedence for determining whether a particular license is accepted or rejected is as follows:
- A license specified in the
deny
list is always rejected. - A license specified in the
allow
list is always accepted. - If the license is considered copyleft, the
[licenses.copyleft]
configuration determines its status - If the license is OSI Approved or FSF Free/Libre, the
[licenses.allow-osi-fsf-free]
configuration determines its status, if it isneither
the check continues - If the license does not match any of the above criteria, the
[licenses.default]
configuration determines its status
Example output
The [licenses]
section
Contains all of the configuration for cargo deny check license
.
Example
[licenses]
unlicensed = "warn"
allow-osi-fsf-free = "both"
copyleft = "deny"
default = "warn"
unused-allowed-license = "warn"
confidence-threshold = 0.95
deny = [
"Nokia",
"BSD-2-Clause",
]
allow = [
"EUPL-1.2",
"Apache-2.0 WITH LLVM-exception",
]
[licenses.private]
ignore = true
registries = ["sekrets"]
[[licenses.exceptions]]
allow = ["Zlib"]
name = "adler32"
version = "0.1.1"
[[licenses.clarify]]
name = "ring"
expression = "MIT AND ISC AND OpenSSL"
license-files = [
{ path = "LICENSE", hash = 0xbd0eed23 }
]
SPDX Identifiers
All identifiers used in the license configuration section are expected to be valid SPDX v2.1 short identifiers, either from version 3.11 of the SPDX License List, or use a custom identifier by prefixing it with LicenseRef-
.
allow = [
# The Apache license identifier
"Apache-2.0",
# A custom license identifier
"LicenseRef-Embark-Custom",
]
# Custom license refs can be specified for crates which don't use a license
# in the SPDX list
[[licenses.clarify]]
name = "a-crate"
expression = "LicenseRef-Embark-Custom"
license-files = [
{ path = "LICENSE", hash = 0x001c7e6c },
]
License identifiers can also be coupled with an optional exception by appending WITH <exception-id>
to the license identifier. Licenses coupled with exceptions are considered distinct from the same license without the exception.
allow = [
# The Apache license identifier
"Apache-2.0",
# The Apache license + LLVM-exception
"Apache-2.0 WITH LLVM-exception",
]
The unlicensed
field (optional)
Determines what happens when a crate has not explicitly specified its license terms, and no license information could be confidently detected via LICENSE*
files in the crate's source.
deny
(default) - All unlicensed crates will emit an error and fail the license checkallow
- All unlicensed crates will show a note, but will not fail the license checkwarn
- All unlicensed crates will show a warning, but will not fail the license check
The allow
and deny
fields (optional)
The licenses that should be allowed or denied, note that the same license cannot
appear in both the allow
and deny
lists.
Note on GNU licenses
- GPL
- AGPL
- LGPL
- GFDL
The GNU licenses are, of course, different from all the other licenses in the SPDX list which makes them annoying to deal with. When supplying one of the above licenses, to either allow
or deny
, you must not use the suffixes -only
or -or-later
, as they can only be used by the license holder themselves to decide under which terms to license their code.
So, for example, if you wanted to disallow GPL-2.0
licenses, but allow GPL-3.0
licenses, you could use the following configuration.
[licenses]
allow = [ "GPL-3.0" ]
deny = [ "GPL-2.0" ]
This gets worse with the GFDL licenses, which also have an invariants
modifier. Before licenses are checked they are normalized to make them consistent for all licenses.
Let's use GFDL-1.2
to show how license requirements are normalized.
GFDL-1.2-invariants-only
=>GFDL-1.2-invariants
GFDL-1.2-invariants-or-later
=>GFDL-1.2-invariants+
GFDL-1.2-no-invariants-only
=>GFDL-1.2
GFDL-1.2-no-invariants-or-later
=>GFDL-1.2+
GFDL-1.2-only
=>GFDL-1.2
GFDL-1.2-or-later
=>GFDL-1.2+
So, for example, if you wanted to allow all version (1.1, 1.2, and 1.3), but only invariants for 1.3 you could use the following configuration.
[licenses]
allow = [ "GFDL-1.1", "GFDL-1.2", "GFDL-1.3", "GFDL-1.3-variants"]
The exceptions
field (optional)
The license configuration generally applies to the entire crate graph, but this means that allowing any one license applies to all possible crates, even if only 1 crate actually uses that license. The exceptions
field is meant to allow additional licenses only for particular crates, to make a clear distinction between licenses which you are fine with everywhere, versus ones which you want to be more selective about, and not have implicitly allowed in the future.
The exceptions.name
field
The name of the crate that you are adding an exception for
The exceptions.version
field (optional)
An optional version constraint specifying the range of crate versions you are excepting. Defaults to any version.
The allow
field
This is the exact same as the general allow
field.
[licenses]
allow = [
"Apache-2.0",
"MIT",
]
exceptions = [
# This is the only crate that cannot be licensed with either Apache-2.0
# or MIT, so we just add an exception for it, meaning we'll get a warning
# if we add another crate that also requires this license
{ name = "cloudabi", allow = ["BSD-2-Clause"] },
]
The copyleft
field (optional)
Determines what happens when a license that is considered copyleft is encountered.
warn
(default) - Will emit a warning that a copyleft license was detected, but will not fail the license checkdeny
- The license is not accepted if it is copyleft, but the license check might not fail if the expression still evaluates to trueallow
- The license is accepted if it is copyleft
The allow-osi-fsf-free
field (optional)
Determines what happens when licenses aren't explicitly allowed or denied, but are marked as OSI Approved or FSF Free/Libre in version 3.11 of the SPDX License List.
both
- The license is accepted if it is both OSI approved and FSF Freeeither
- The license is accepted if it is either OSI approved or FSF Freeosi-only
- The license is accepted if it is OSI approved and not FSF Freefsf-only
- The license is accepted if it is FSF Free and not OSI approvedneither
(default) - No special consideration is given the license
The default
field (optional)
Determines what happens when a license is encountered that:
- Isn't in the
allow
ordeny
lists - Isn't
copyleft
- Isn't OSI Approved nor FSF Free/Libre, or
allow-osi-fsf-free = "neither"
warn
- Will emit a warning that the license was detected, but will not fail the license checkdeny
(default) - The license is not accepted, but the license check might not fail if the expression still evaluates to trueallow
- The license is accepted
The confidence-threshold
field (optional)
cargo-deny
uses askalono to determine the license of a LICENSE file. Due to variability in license texts because of things like authors, copyright year, and so forth, askalano assigns a confidence score to its determination, from 0.0
(no confidence) to 1.0
(perfect match). The confidence threshold value is used to reject the license determination if the score does not match or exceed the threshold.
0.0
- 1.0
(default 0.8
)
The clarify
field (optional)
In some exceptional cases, a crate will not have easily machine readable license information, and would by default be considered "unlicensed" by cargo-deny. As a (hopefully) temporary patch for using the crate, you can specify a clarification for the crate by manually assigning its SPDX expression, based on one or more files in the crate's source. cargo-deny will use that expression for as long as the source files in the crate exactly match the clarification's hashes.
[[licenses.clarify]]
name = "webpki"
expression = "ISC"
license-files = [
{ path = "LICENSE", hash = 0x001c7e6c },
]
The name
field
The name of the crate that you are clarifying
The version
field (optional)
An optional version constraint specifying the range of crate versions you are clarifying. Defaults to any version.
The expression
field
The SPDX license expression you are specifying as the license requirements for the crate.
The license-files
field
Contains one or more files that will be checked to ensure the license expression still applies to a version of the crate.
The path
field
The crate relative path to a file to be used as a source of truth.
The hash
field
An opaque hash calculated from the file contents. This hash can be obtained from the output of the license check when cargo-deny can't determine the license of the file in question.
The private
field (optional)
It's often not useful or wanted to check for licenses in your own private workspace crates. So the private field allows you to do so.
The ignore
field
If true
, workspace members will not have their license expression checked if they are not published.
# Cargo.toml
[package]
name = "sekret"
license = "¯\_(ツ)_/¯"
publish = false # "private"!
# deny.toml
[licenses]
# The sekret package would be ignored now
private = { ignore = true }
The registries
field
A list of private registries you may publish your workspace crates to. If a workspace member only publishes to private registries, it will also be ignored if private.ignore = true
# Cargo.toml
[package]
name = "sekret"
license = "¯\_(ツ)_/¯"
publish = ["sauce"]
# deny.toml
[licenses]
# Still ignored!
private = { ignore = true, registries = ["sauce"] }
The ignore-sources
field
A list of registries that crates can be sourced from that will not have their licenses checked.
# deny.toml
[licenses.private]
ignore = true
ignore-sources = ["https://sekretz.com/super/secret-index"]
The unused-allowed-license
field (optional)
Determines what happens when one of the licenses that appears in the allow
list is not encountered in the dependency graph.
warn
(default) - A warning is emitted for each license that appears inlicense.allow
but which is not used in any crate.allow
- Unused licenses in thelicenses.allow
list are ignored.deny
- An unused license in thelicenses.allow
list triggers an error, and cause the license check to fail.
Licenses Diagnostics
rejected
One or more licenses for a crate were rejected because they were not configured to be allowed.
accepted
The license expression for a crate was allowed, though there may be warnings.
unlicensed
No license expression could be found for a crate and it is considered unlicensed.
skipped-private-workspace-crate
A workspace member is publish = false
and was skipped.
license-not-encountered
A license in licenses.allow
was not found in any crate.
This diagnostic can be silenced by configuring the licenses.unused-allowed-license
field to "allow".
license-exception-not-encountered
A licenses.exception
was not used as the crate it applied to was not encountered.
sources
The sources check ensures crates only come from sources you trust.
cargo deny check sources
Use Case - Only allowing known/trusted sources
Cargo can retrieve crates from a variety of sources, namely registries, git repositories, or local file paths. This is great in general and very flexible for development. But, especially when re-routing dependencies to git repositories, increasing the amount of sources that a project has to trust may be something a repository wants to explicitly opt-in to.
See Why npm lockfiles can be a security blindspot for injecting malicious modules for the motivating reason for why this check was added.
Use Case - Only using vendored file dependencies
A project may want to only support local file dependencies, such as having all dependencies vendored into the repository for full control and offline building. This can be achieved by disallowing all git and registry sources to ensure that every dependency is added into your source control rather than via an external source.
Example output
The [sources]
section
Contains all of the configuration for cargo deny check sources
Example Config
[sources]
unknown-registry = "allow"
unknown-git = "deny"
required-git-spec = "tag"
allow-registry = [
"https://sekretz.com/registry/index",
"sparse+https://fake.sparse.com",
]
allow-git = [
"https://notgithub.com/orgname/reponame.git",
]
private = [
"https://internal-host/repos",
]
[sources.allow-org]
github = [
"yourghid",
"YourOrg",
]
gitlab = [
"gitlab-org",
]
bitbucket = [
"atlassian",
]
The unknown-registry
field (optional)
Determines what happens when a crate from a crate registry that is not in the allow-registry
list is encountered.
deny
- Will emit an error with the URL of the source, and fail the check.warn
(default) - Prints a warning for each crate, but does not fail the check.allow
- Prints a note for each crate, but does not fail the check.
The unknown-git
field (optional)
Determines what happens when a crate from a git repository not in the allow-git
list is encountered.
deny
- Will emit an error with the URL of the repository, and fail the check.warn
(default) - Prints a warning for each crate, but does not fail the check.allow
- Prints a note for each crate, but does not fail the check.
The required-git-spec
(optional)
Determines which specifiers are required for git sources. Git sources are a convenient way to use patched code temporarily, but they have downsides for long term maintenance, as the specifier you use for the source determines what happens when you do a cargo update
, and in the default case, this means you essentially have a wildcard dependency on the repository.
This configuration value allows you to control what specifiers you want to allow for your git sources to reduce surprises. The following values are listed in order from least to most specific, and using a less specific specifier will also allow all of the more specific ones.
any
(default) - Allows all git specs, including the default of not having any specifier, which tracks the latest commit on themaster
branch of the repobranch
- Allows thebranch = "<branch_name>"
specifier.tag
- Allows thetag = "<tag_name>"
specifier.rev
- Allows therev = "<commit_sha>"
specifier.
The allow-git
field (optional)
Configure which git urls are allowed for crate sources. If a crate's source is not in one of the listed urls, then the unknown-git
setting will determine how it is handled. Note that the url must match exactly, though .git
is stripped if it exists to match the logic of cargo.
[sources]
allow-git = [
"https://github.com/EmbarkStudios/cargo-deny",
]
The private
field (optional)
Similarly to allow-git
, allows you to configure urls, however, unlike allow-git
which is meant for a single, exact, url, private
urls actually allow any git repo url which matches the host and begins with the same path. This field is primarily meant to support the use of internal/private git hosts (usually on a VPN) without needing to specify each individual repo. Of course, this can be used to also just allow every repo on Github, but this is not recommended. 😉
[sources]
private = [
"https://super-duper-sekret",
]
The allow-registry
field (optional)
The list of registries that are allowed. If a crate is not found in one of the listed registries, then the unknown-registry
setting will determine how it is handled.
If not specified, this list will by default contain the crates.io registry, equivalent to this:
[sources]
allow-registry = [
"https://github.com/rust-lang/crates.io-index",
]
To not allow any crates registries, set it to empty:
[sources]
unknown-registry = "deny"
allow-registry = []
The allow-org
field (optional)
Generally, I think most projects in the Rust space probably follow a similar procedure as we do when they want to fix a bug or add a feature to one of their dependencies, which is basically.
- Fork the crate to make your changes
- Hack away locally, probably just patching your project(s) to use a
path
dependency to the cloned fork - Push changes to your fork, and once you're happy, change the
path
dependency to agit
dependency and point it to your fork for others/CI to be able to use the same changes easily - Eventually (hopefully!) make a PR to the original repo with your changes
- Hopefully get your changes merged to the original repo
- Wait until a release is made that incorporates your changes, possibly changing the
git
source to point to the original repo - Remove the
git
source and instead point at the new version of the crate with your changes - Profit!
When working in a company or organization, it is often the case that all crates will be forked to a shared organization account rather than a personal Github account. However, if you lint your git sources, every new and deleted fork needs to keep that list updated, which is tedious, even if all the forks fall under the same organization (in Github terminology), even though presumably only people you trust have permission to create forks there, and you would like to just blanket trust any repo under that org.
The allow-org
object allows you to specify 1 or more organizations or users in several VCS providers to more easily configure git sources for your projects.
The github
field (optional)
Allows you to specify one or more github.com
organizations to allow as git sources.
[sources.allow-org]
github = ["YourCoolOrgGoesHere"]
The gitlab
field (optional)
Allows you to specify one or more gitlab.com
organizations to allow as git sources.
[sources.allow-org]
gitlab = ["YourCoolOrgGoesHere"]
The bitbucket
field (optional)
Allows you to specify one or more bitbucket.org
organizations to allow as git sources.
[sources.allow-org]
bitbucket = ["YourCoolOrgGoesHere"]
Sources diagnostics
git-source-underspecified
A git
source uses a specification that doesn't meet the minimum specifier required by sources.required-git-spec
.
allowed-source
A crate source is explicitly allowed by sources.allow-git
or sources.allow-registry
.
allowed-by-organization
A crate source was explicitly allowed by an entry in sources.allow-org
.
source-not-allowed
A crate's source was not explicitly allowed.
unmatched-source
An allowed source in sources.allow-git
or sources.allow-registry
was not encountered.
unmatched-organization
An allowed source in sources.allow-org
was not encountered.