cargo-deny icon indicating copy to clipboard operation
cargo-deny copied to clipboard

Check for consistent versioning of direct dependencies in the workspace

Open ahollmann opened this issue 3 years ago • 9 comments

I'm using an allow list for whitelisting dependencies in a big workspace. I have to generate a list of all direct and transitive dependencies.

Adding a depth option like it exists in cargo tree --depth 1 would simplify this use case.

I cannot judge if this option fits with other use cases or breaks features in cargo deny.

Example: deny.toml

[bans]

allow = [
    { name = "anyhow", version = "1.0.58" },
    ... all dependencies in the workspace ... 
]

ahollmann avatar Jul 18 '22 16:07 ahollmann

Maybe I'm misunderstanding, but having a depth of 1 would mean that you'd only be checking direct dependencies and no transitive dependencies at all, which would make the use of cargo-deny fairly pointless?

Jake-Shadle avatar Jul 18 '22 16:07 Jake-Shadle

You are right. For license checks it wouldn't make any sense. So the command line option would be a bad idea.

For the allowed list it would be still useful. A configuration option for the allowed list would be more appropriate? Otherwise you would have to list hundreds of transitive dependencies.

Something like this:

[bans]
allow_list_depth = 1

allow = [
    { name = "anyhow", version = "1.0.58" },
    ... list only direct dependencies here ... 
]

My use case would be a big workspace with multiple developers working on individual crates. This would help keeping used dependencies and versions in sync by the CI.

ahollmann avatar Jul 18 '22 20:07 ahollmann

It feels like you would get a lot more utility from checking in your Cargo.lock file and using a deny list and multiple-versions lint?

FWIW your use case sounds a bit similar to ours, a large monorepo, a dozen or so developers and around 1000 or so crates across the various platforms we target. The allow list was added for symmetry with the deny list, and the specific use case of small library crates that want really strict control over their dependencies, which is why trying to use it in a large workspace is painful.

Jake-Shadle avatar Jul 18 '22 22:07 Jake-Shadle

https://github.com/rust-lang/rfcs/blob/master/text/2906-cargo-workspace-deduplicate.md

Deduplicate common dependency and metadata directives amongst a set of workspace crates in Cargo with extensions to the [workspace] section in Cargo.toml.

This cargo RFC seems to meet my requirements. I hope it gets merged soon into cargo.

My feature request for cargo deny goes into the same direction by enforcing a version with an external tool.

We are already using Cargo.lock, but it is not the place to define common dependencies across the workspace.

Thanks for your valuable input and thanks for the work on cargo deny.

ahollmann avatar Jul 19 '22 10:07 ahollmann

Ok, I think I understand now, you just want all direct dependencies in your workspace to have consistent versioning. We just use the multiple-versions lint to detect that case, but I can understand wanting a separate lint for this scenario since I think some people think the multiple-versions lint is too harsh maybe. I think in this case it would make sense to just have a separate lint that checks that specific case that can be used with or without the regular multiple-versions lint. So if used without, you can have any number of duplicate transitive dependencies, but at least on the workspace level all dependencies are consistent. The lint can then be retired if/when cargo implements the above RFC you linked.

Jake-Shadle avatar Jul 19 '22 11:07 Jake-Shadle

You've summarized it perfectly.

The approach with denying multiple-versions does not work, since we have no control about transitive dependencies which result in multiple versions of the same crate.

ahollmann avatar Jul 19 '22 12:07 ahollmann

multiple-versions works quite well, you just have to use the skip and skip-tree fields to selectively ignore old versions, then cargo-deny warns when you have skips that no longer match anything in the graph so you can keep the configuration relatively clean.

skip = [
    # very common dependency.
    { name = "cfg-if", version = "0.1.10" },

    # Used by core-graphics and core-video-sys
    { name = "core-foundation", version = "<0.9.1" },
    { name = "core-foundation-sys", version = "<0.9.1" },

    # used by core-video-sys 0.1.4 which winit relies on. TODO
    { name = "core-graphics", version = "<0.22.2" },

    # ark-ml -> tract-onnx -> tract-hir -> tranct-core -> tranct-linalg ->
    # liquid -> liquid-core -> pest_derive -> pest_generator -> pest_meta ->
    # sha-1
    { name = "block-buffer", version = "=0.7" },
    { name = "digest", version = "=0.8" },
    { name = "sha-1", version = "=0.8" },

    # ... -> sha-1 -> block-buffer (see above)
    { name = "generic-array", version = "=0.12" },

    # winit, wayland, etc
    { name = "nix", version = "=0.22" },
    { name = "memmap2", version = "=0.3.1" },

    # ash-window using old, PR: https://github.com/MaikKlein/ash/pull/505
    # Several crates have not moved to the recent 0.4.2 version
    { name = "raw-window-handle", version = "0.3.4" },

    # prost, strum, system-deps, wiggle-generate are on older version
    { name = "heck", version = "=0.3" },

    # a lot of crates use the older parking_lot
    { name = "parking_lot", version = "=0.11" },
    { name = "parking_lot_core", version = "=0.8" },

    { name = "tokio-util", version = "=0.6" },

    # minidump-common -> range-map -> num-traits uses an old version, and
    # unfortunately range-map seems unmaintained
    { name = "num-traits", version = "=0.1.43" },

    # metrics-util not upgraded yet
    { name = "ordered-float", version = "=2" },

    # wasmtime uses an older version than backtrace
    { name = "object", version = "=0.27.1" },

    # wasmtime uses a fairly outdated version
    { name = "wasmparser", version = "=0.83.0" },

    # clap -> indexmap -> hashbrown is an older version than that used by dashmap
    { name = "hashbrown", version = "=0.11.2" },

    # several crates still use this older version
    { name = "nix", version = "=0.23.1" },

    # winit not upgraded yet
    { name = "smithay-client-toolkit", version = "=0.15" },

    # we depend on macaw/perchance via Cervo and it's part of this workspace, so we need to add an exception here to allow multiple sources.
    { name = "macaw", version = "0.17.0" },
    { name = "perchance", version = "0.3.1" },
]
skip-tree = [
    # old version transitively used by ndk-glue
    { name = "darling", version = "=0.13.4" },

    # many crates use different versions, lots of churn.
    # our tracking issue discussing that with Microsoft: https://github.com/microsoft/windows-rs/issues/1720
    { name = "windows-sys", version = "=0.36" },
]

Jake-Shadle avatar Jul 19 '22 13:07 Jake-Shadle

Thanks!

multiple-versions works indeed quite well! Somehow I wasn't aware how to use it properly.

The titel got misleading.

I could replace it with: Check for consistent versioning of direct dependencies in the workspace.

ahollmann avatar Jul 20 '22 16:07 ahollmann

Now that cargo supports workspace inheritance I think the addition of this feature becomes much less interesting, I guess it could still be useful in some cases, but not enough to do myself, though PRs are welcome.

Jake-Shadle avatar Oct 24 '22 15:10 Jake-Shadle