mcpField
R
rust-dependencies

rust-dependencies

github.com/full-stack-skillsDevelopment12111 installsUpdated 5w ago
Repository

About rust-dependencies

rust-dependencies is a Rust dependency-governance skill for developers maintaining Cargo projects. It covers version and source choices, security and policy checks, dependency analysis, and update automation.

Key features

  1. 01Choose Cargo version requirements
  2. 02Evaluate dependency sources
  3. 03Configure cargo-deny policy checks
  4. 04Audit RustSec advisories
  5. 05Analyze dependency trees and duplicates
  6. 06Govern and automate dependency updates

Use cases

  1. 01Set dependency rules for a Rust project
  2. 02Investigate duplicate or cyclic dependencies
  3. 03Review a proposed Cargo.lock update
  4. 04Check dependencies for advisories and license policy

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/full-stack-skills/rust-skills --skill rust-dependencies

After installing, type/rust-dependenciesin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

agents/
openai.yaml
examples/
private-registry.md
examples/golden-deps/
Cargo.lock
Cargo.toml
examples/golden-deps/src/
lib.rs
references/
cargo-deny-cookbook.md
version-requirements.md

Details

From the project README

Rust Dependency Management and Governance

Authority: Cargo — Specifying Dependencies, Cargo — Dependency Resolution, Cargo — Source Replacement, Cargo — Credentials, cargo-deny, cargo-audit, RustSec.

This skill owns the governance of dependencies: how to declare them safely, what they pull in, who is allowed in, and what to do when one goes wrong. It does not own the Cargo.toml field reference (rust-cargo-build), semver (rust-semver), or workspace topology (rust-workspace).

Capability Boundaries

✅ Strengths
  1. Choosing the right version requirement ("1" vs "1.2" vs "=1.2.3")
  2. Evaluating dependency sources (crates.io / git / path / private registry)
  3. Setting up source replacement for vendored or mirrored registries
  4. Configuring cargo-deny (4 tables: advisories, licenses, bans, sources)
  5. Running cargo-audit and responding to RustSec advisories
  6. Diagnosing dependency cycles and duplicate-version problems via cargo tree
  7. Setting MSRV-aware resolver behavior
  8. Automating dependency updates with Renovate / Dependabot
  9. Establishing supply-chain policy for an organization
⚠️ Prerequisites
  1. Cargo manifest basics — see rust-cargo-build
  2. Semver vocabulary — see rust-semver
❌ Out of Scope
  1. Cargo.toml field-by-field reference → rust-cargo-build
  2. Workspace layout → rust-workspace
  3. Clippy / lint policy → rust-style-clippy
  4. Testing dependency injection → rust-testing

Data Privacy

This skill does not collect, store, or transmit user data. Private registry access and credential use are user-authorized actions; never log credentials or expose tokens in build artifacts.


Part 1: Version Requirement Syntax

Cargo uses SemVer version requirements (not exact versions) by default.

SyntaxMeaningCompatibility
"1" or "^1">=1.0.0, <2.0.0Default — auto-update within major
"1.2" or "^1.2">=1.2.0, <2.0.0At least 1.2.x
"1.2.3" or "^1.2.3">=1.2.3, <2.0.0At least 1.2.3, may pull 1.5.0
"=1.2.3"Exactly 1.2.3Pin — for reproducibility
"~1.2">=1.2.0, <1.3.0Within minor only
"~1.2.3">=1.2.3, <1.3.0Within minor only
">=1.0, <2.0"RangeExplicit bounds
"*"AnyForbidden on crates.io — too loose
"0.1" or "^0.1">=0.1.0, <0.2.0Pre-1.0: minor treated as major
"0.0.1">=0.0.1, <0.0.2Pre-0.1: patch treated as major

The default is caret (^)

[dependencies]
serde = "1"              # caret by default
serde = { version = "1" }   # same

This is usually right. You get bug fixes and non-breaking features automatically.

When to deviate

NeedUseExample
Pin for reproducibility="=1.2.3"
Restrict to minor only~"~1.2" (no 1.3.x)
Bounded range>=, <">=1.0, <1.5"
Pre-1.0 with breaking minorsminor pin"0.7.3" (Cargo treats as <0.8)
Git headgit{ git = "..." }

Caret rule for pre-1.0

# These are equivalent and both mean <0.2:
my-crate = "0.1"
my-crate = "^0.1"

# 0.0.x is even more restrictive:
my-crate = "0.0.3"      # means >=0.0.3, <0.0.4 — almost a pin

The pre-1.0 rules exist because the SemVer spec treats 0.x as "anything goes." Cargo encodes community convention: minor bump in 0.x = breaking.


Part 2: Dependency Sources

crates.io (default)

[dependencies]
serde = "1"

Public, immutable, audited via crates.io. This is what 99% of dependencies should use.

Git

[dependencies]
# Branch / tag / rev / default
my-crate = { git = "https://github.com/user/repo", branch = "dev" }
my-crate = { git = "https://github.com/user/repo", tag = "v1.0.0" }
my-crate = { git = "https://github.com/user/repo", rev = "abc1234" }
my-crate = { git = "https://github.com/user/repo" }

Use sparingly: git deps make Cargo.lock non-portable, slow down CI, and cannot be published to crates.io unless the git dep is also published. Prefer crates.io, a fork published under a different name, or cargo vendor.

Path (local / workspace)

[dependencies]
my-core = { path = "../core", version = "0.1" }

Required for workspace internal deps. Always pair with a version for publishing (otherwise cargo publish fails).

Private registry

# .cargo/config.toml
[registries.my-registry]
index = "sparse+https://my-registry.example.com/index/"

[registry]
default = "my-registry"   # optional: make this the default
# Cargo.toml
[dependencies]
my-private-crate = { version = "1.0", registry = "my-registry" }

Source replacement (transparent)

Cargo Source Replacement lets you replace crates.io with a mirror — without editing each Cargo.toml:

# .cargo/config.toml
[source.my-mirror]
registry = "sparse+https://mirrors.example.com/crates.io-index"

[source.crates-io]
replace-with = "my-mirror"

Use cases: enterprise proxy, China mirrors (RsProxy, tuna), vendored offline builds.

Vendored

cargo vendor vendor/   # downloads all deps to vendor/
# .cargo/config.toml
[source.crates-io]
replace-with = "vendored-sources"

[source.vendored-sources]
directory = "vendor"

For air-gapped / reproducible builds. Check vendor/ into git (it's large but stable).


Part 3: Dependency Tree Analysis

cargo tree

cargo tree                        # full tree
cargo tree --depth 2              # limit
cargo tree --invert --package X   # what depends on X?
cargo tree -e features            # show feature unification
cargo tree -e no-dev              # exclude dev-deps
cargo tree -e no-build            # exclude build-deps

Finding duplicates

cargo tree --duplicates           # show crates with multiple versions

If you see serde at both 1.0.180 and 1.0.195, that's two versions in the tree. Common causes:

  • An old transitive dep requires an old version
  • A git dep pulled in a specific version
  • Your own version requirement is too tight

Resolving duplicates

cargo update -p serde             # bump to latest matching req
cargo update -p serde --precise 1.0.200

If a transitive dep pins an old version, you can either:

  1. Update the transitive dep (cargo update -p that-crate)
  2. Live with the duplicate (usually fine)
  3. Replace the transitive with a fork

Detecting cycles

Cargo forbids cycles in the dependency graph. If you see:

error: cyclic package dependency: package `a` depends on `b`. package `b` depends on `a`.

You have a real design bug — restructure (often by extracting a shared crate c that both depend on).


Part 4: Dependency Update Governance

Use rust-cargo-build for current Cargo.lock version-control guidance and the exact behavior of --locked, --offline, and --frozen. The current Cargo Guide recommends committing Cargo.lock when in doubt; do not apply an application-versus-library prohibition here.

This skill owns how resolved dependency changes are proposed, reviewed, and approved:

cargo update                      # bump all to latest within reqs
cargo update --precise 1.0.200 -p serde   # pin a specific version
cargo update --dry-run            # see what would change
  • Prefer package-scoped updates over unrelated graph churn.
  • Review lockfile source, checksum, version, feature, and duplicate-version changes.
  • Run advisories, licenses, bans, and source-policy checks on the proposed graph.
  • Keep automated update pull requests bounded and observable.
  • Use a separate scheduled compatibility lane when libraries need to test newly resolved dependency ranges.
  • Never add an unconditional cargo update to required CI merely to make a stale lockfile pass.

Part 5: cargo-deny (Supply-Chain Governance)

cargo-deny is the de-facto tool for dependency policy. Four checks:

5.1 advisories — RustSec

# deny.toml
[advisories]
db-urls = ["https://github.com/rustsec/advisory-db"]
yanked = "deny"
ignore = [
    # "RUSTSEC-2024-0001",  # ignore specific advisory with justification
]
cargo deny check advisories

5.2 licenses — policy

# deny.toml
[licenses]
allow = [
    "MIT",
    "Apache-2.0",
    "BSD-3-Clause",
    "ISC",
    "Unicode-DFS-2016",
]
confidence-threshold = 0.93

[[licenses.exceptions]]
allow = ["Zlib"]
name = "some-zlib-crate"
version = "1.0"
cargo deny check licenses

Default is permissive; tighten to your org's policy.

5.3 bans — forbidden crates

# deny.toml
[bans]
multiple-versions = "warn"
wildcards = "deny"        # don't allow "2.*" requirements

[[bans.deny]]
name = "openssl"          # prefer rustls
version = "*"

[[bans.deny]]
name = "chrono"
version = "<0.5"          # only old versions

[bans.workspace-dependencies]
duplicates = "deny"       # require [workspace.dependencies]
cargo deny check bans

5.4 sources — where deps come from

# deny.toml
[sources]
unknown-registry = "deny"   # disallow non-crates.io registries
unknown-git = "deny"        # disallow non-allowlisted git sources
allow-registry = ["crates-io"]
allow-git = []
cargo deny check sources

All-in-one

cargo deny check               # runs all four

CI integration:

- uses: EmbarkStudios/cargo-deny-action@v2
  with:
    command: check

Part 6: cargo-audit

cargo-audit scans Cargo.lock against the RustSec advisory database.

cargo install cargo-audit --locked
cargo audit                           # scan
cargo audit --deny warnings           # fail CI on warnings
cargo audit --ignore RUSTSEC-XXXX     # ignore specific advisory

Difference from cargo-deny:

  • cargo-audit is advisory-only (security focus)
  • cargo-deny covers advisories + licenses + bans + sources

Most projects use cargo-deny as a superset. Some use both (defense in depth).

Responding to an advisory

  1. Run cargo audit to identify the vulnerable crate + version
  2. Check RustSec for the fixed version
  3. cargo update -p vulnerable-crate --precise X.Y.Z
  4. If no fix exists: switch to a maintained fork, remove the dependency, or disable the affected feature
  5. File an issue upstream if it's a new vulnerability

Part 7: Automation

Renovate

Renovate auto-opens PRs when deps update. Supports Cargo out of the box:

// .renovaterc.json
{
  "extends": ["config:recommended", ":semanticCommits"],
  "schedule": ["before 6am on Monday"]
}

Dependabot

Dependabot is GitHub-native:

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "cargo"
    directory: "/"
    schedule:
      interval: "weekly"

Cargo's own auto-update

There's no built-in "cargo update PR" tool, but you can script it:

cargo update
git diff Cargo.lock
# Commit + push to a branch

Part 8: Feature Minimization

[dependencies]
serde = { version = "1", features = ["derive"] }     # only what you use
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }

Each enabled feature increases compile time, binary size, and attack surface. Disable defaults when you only need a subset:

[dependencies]
tokio = { version = "1", default-features = false, features = ["rt", "net"] }

Inspecting features

cargo tree -e features              # which features are enabled, where
cargo tree -e features -p tokio     # just tokio's features

If tokio shows up with [full] from a transitive dep, you're paying for more than you use.

Workspace dep governance

# root Cargo.toml
[workspace.dependencies]
serde = { version = "1", features = ["derive"] }   # pin features once

# crates/abc/Cargo.toml
[dependencies]
serde.workspace = true    # inherits feature set

Prevents feature drift across members.


Workflow

  1. Inventory — cargo tree -e features, cargo tree --duplicates
  2. Audit — cargo audit (advisories) + cargo deny check (full policy)
  3. Tighten versions — replace "*" with "1"; pin exact only when reproducible
  4. Minimize features — default-features = false, list only what you use
  5. Decide sources — prefer crates.io; reserve git/path for legitimate cases
  6. Configure CI — cargo build --locked, cargo deny check, scheduled cargo audit
  7. Automate updates — Renovate or Dependabot with semantic commits

Decision Shortcuts

QuestionAnswer
Pin or caret?Caret ("1") by default; pin ("=1.2.3") for reproducibility only
crates.io or git?crates.io unless you have a specific reason
Use latest or wait?Wait 1-2 weeks for new majors; auto-patch for patches
Allow "*" requirements?No — crates.io rejects them, and they hide upgrades
How many versions of serde?One. If duplicates, trace via cargo tree --duplicates
Commit Cargo.lock for a library?No — downstream owns the lock
CI: --locked or --frozen?--locked for normal CI; --frozen for air-gapped

Resources

Upstream Sources

Comments

Markdown supported