Skip to content

Dependency Updates

Runbook for managing Cargo and GitHub Actions dependencies in rust-template.


Dependabot is configured in .github/dependabot.yml with two ecosystems:

SettingValue
ScheduleWeekly, Mondays at 09:00 America/Chicago
PR limit10 open PRs
Commit prefixchore(deps)
Labelsdependencies, rust
Reviewerzircote

Grouped updates (minor + patch combined into single PRs):

GroupPackages
dev-dependenciesproptest*, test-*, criterion*
async-runtimetokio*, async-*
serde-ecosystemserde*
SettingValue
ScheduleWeekly, Mondays at 09:00 America/Chicago
PR limit5 open PRs
Commit prefixchore(deps)
Labelsdependencies, github-actions
Reviewerzircote

Grouped updates: All actions grouped together for minor + patch updates.


The dependabot-automerge.yml workflow automatically squash-merges Dependabot PRs that meet these criteria:

Update typeAuto-merge?Rationale
Patch (0.0.x)YesBug fixes, low risk
Minor (0.x.0)YesBackward-compatible features
Major (x.0.0)No — manual reviewPotentially breaking changes

Auto-merge is enabled but the PR still must pass all CI checks before merging. The flow is:

  1. Dependabot opens a PR
  2. dependabot-automerge.yml runs and enables auto-merge (squash) for patch/minor
  3. CI (ci.yml) runs: fmt, clippy, test, doc, deny, msrv
  4. Only after all CI checks pass does the PR actually merge
  • Major version bumps — always review the changelog for breaking changes
  • PRs that fail CI — investigate the failure; the dependency update may be incompatible
  • Security advisories — expedite the merge; do not wait for the weekly cycle
  • Grouped PRs with many changes — scan the diff for unexpected changes
Terminal window
# Review the PR
gh pr view <number>
gh pr diff <number>
# Approve and merge
gh pr review <number> --approve
gh pr merge <number> --squash

cargo-deny runs in CI as part of the deny job. It checks four categories defined in deny.toml:

CheckWhat it doesFailure mode
advisoriesKnown vulnerabilities (RustSec DB)Deny all advisory types
licensesOnly allow listed SPDX licensesDeny anything not in the allow-list
bansBlock specific cratesopenssl (use rustls), atty (use std)
sourcesOnly allow crates.ioDeny unknown registries and git sources

Run locally:

Terminal window
# Install
cargo install cargo-deny
# Run all checks
cargo deny check
# Run a specific check
cargo deny check advisories
cargo deny check licenses
cargo deny check bans
cargo deny check sources
# Generate a report
cargo deny list

The security-audit.yml workflow runs cargo-audit:

  • Daily at 00:00 UTC (cron schedule)
  • On every push that changes Cargo.toml or Cargo.lock
  • Can be triggered manually via workflow_dispatch

Run locally:

Terminal window
# Install
cargo install cargo-audit
# Run audit
cargo audit
# Run with deny on warnings
cargo audit --deny warnings
# Generate JSON output for tooling
cargo audit --json
Terminal window
# 1. Update the advisory database
cargo audit fetch
# 2. Run cargo-audit
cargo audit --deny warnings
# 3. Run cargo-deny (broader checks)
cargo deny check
# 4. Check for outdated dependencies
cargo outdated
# 5. Inspect dependency tree
cargo tree
cargo tree --duplicates # find duplicate crates

When cargo-audit or Dependabot flags a security advisory:

Terminal window
# Check the advisory details
cargo audit
# Check if the vulnerable code path is reachable
cargo tree -i <affected-crate>
Terminal window
# Update a specific dependency
cargo update -p <crate-name>
# Update all dependencies
cargo update
# Verify the update resolves the advisory
cargo audit

Options in order of preference:

  1. Pin to an unaffected version in Cargo.toml
  2. Add to the ignore list in deny.toml (temporary, with comment explaining why):
    [advisories]
    ignore = [
    "RUSTSEC-2024-XXXX", # No fix available; unexploitable in our usage. Revisit by YYYY-MM-DD.
    ]
  3. Replace the dependency with an alternative crate
  4. Fork and patch the dependency
Terminal window
cargo deny check advisories
cargo test --all-features
git add Cargo.toml Cargo.lock
git commit -m "fix(deps): address RUSTSEC-XXXX-YYYY in <crate>"
git push

All GitHub Actions in this repository are pinned to full commit SHAs for supply chain security (not tags). When updating:

Terminal window
# Look up the commit SHA for a new release tag
gh api repos/<owner>/<action>/git/refs/tags/<tag> --jq '.object.sha'

Or visit the action’s releases page and copy the full commit SHA from the tag.

Replace the SHA and update the comment with the new version:

# Before
uses: actions/checkout@OLD_SHA # v6.0.2
# After
uses: actions/checkout@NEW_SHA # v6.1.0

The same action may appear in multiple workflow files. Search across all of them:

Terminal window
grep -r "actions/checkout@" .github/workflows/

Update every occurrence to the same SHA.

Dependabot is configured to update GitHub Actions weekly. For minor and patch updates, these are grouped and auto-merged. For major updates, review manually.


Before adding a new dependency, evaluate:

  • Necessity — Can this be done with std or existing dependencies?
  • Maintenance — Is the crate actively maintained? Check last commit date, open issues
  • License — Must be in the deny.toml allow-list: MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, Zlib, MPL-2.0, Unicode-DFS-2016, Unicode-3.0, CC0-1.0, BSL-1.0, 0BSD
  • Security — Run cargo audit after adding; check RustSec for known advisories
  • Size — Check transitive dependency count with cargo tree -p <crate>
  • Quality — Does it have tests? Documentation? Is it widely used?
  • Banned crates — Ensure it does not pull in openssl or atty (banned in deny.toml)
  • MSRV — Does the crate support Rust 1.92 (this project’s MSRV)?
Terminal window
# Add the dependency
cargo add <crate-name>
# Or for dev-only
cargo add --dev <crate-name>
# Verify it passes all checks
cargo deny check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features
# Check the dependency tree impact
cargo tree -p <crate-name>
  1. Evaluate whether the license is acceptable for your project
  2. Add it to deny.toml:
    [licenses]
    allow = [
    # ...existing licenses...
    "NEW-LICENSE-SPDX",
    ]
  3. Document why the license was added in the commit message

Terminal window
# Install cargo-machete
cargo install cargo-machete
# Find unused dependencies
cargo machete
Terminal window
# Remove from Cargo.toml
cargo remove <crate-name>
# Update the lock file
cargo update
# Verify nothing broke
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features
cargo deny check

Edit .github/dependabot.yml:

groups:
new-group-name:
patterns:
- "crate-prefix*"
update-types:
- "minor"
- "patch"
schedule:
interval: "daily" # or "weekly" or "monthly"
day: "monday" # for weekly
time: "09:00"
timezone: "America/Chicago"
ignore:
- dependency-name: "crate-to-ignore"
versions: [">=2.0.0"] # ignore major updates only

TaskCommand
Run all supply chain checkscargo deny check
Audit for security advisoriescargo audit --deny warnings
Update all dependenciescargo update
Update one dependencycargo update -p <crate>
List outdated dependenciescargo outdated
Show dependency treecargo tree
Find duplicatescargo tree --duplicates
Find unused dependenciescargo machete
Add a dependencycargo add <crate>
Remove a dependencycargo remove <crate>
Check Dependabot PRsgh pr list --label dependencies