Rust Workspace Configuration and Dependency Management#
The DaemonEye project uses a Rust workspace to manage multiple related crates with unified dependency and build configuration. This approach centralizes dependency versions, enforces consistency, and simplifies cross-crate development and testing.
Workspace Structure and Adding collector-core#
The workspace is defined in the root Cargo.toml under the [workspace] section. All member crates are listed in the members array. To add collector-core as a workspace member, its directory name is included in this list:
[workspace]
members = [
"collector-core",
"daemoneye-agent",
"daemoneye-cli",
"daemoneye-lib",
"procmond",
]
This configuration ensures that collector-core is built, tested, and managed as part of the workspace. The crate itself resides in the collector-core/ directory and contains its own Cargo.toml and source files.
Shared Dependencies and Version Management#
Shared dependencies are declared in the root Cargo.toml under [workspace.dependencies]. This centralizes version management and ensures all workspace members use the same versions, reducing duplication and preventing version conflicts. For example:
[workspace.dependencies]
anyhow = "1.0.102"
bitflags = { version = "2.11.0", features = ["serde"] }
proptest = "1.11.0"
# ... other dependencies ...
collector-core = { path = "collector-core" }
daemoneye-lib = { path = "daemoneye-lib" }
The workspace uses resolver version 3 and sets common package metadata (such as version, authors, license, Rust version, repository, homepage, and edition) under [workspace.package]. This metadata is inherited by all member crates, ensuring consistency.
Version Pinning Strategy#
A comment in the root Cargo.toml explains the project's version pinning strategy: "Overpinning the versions is breaking the cross-platform functionality, so we are limiting pinning to minor versions." This means dependencies are pinned to a minor version (e.g., "1.0") rather than an exact patch version, improving compatibility across platforms.
Dependency Rationale#
bitflags#
The bitflags crate is included as a shared dependency (version 2.11.0) and is used for managing capability flags throughout the project. This allows for efficient representation and manipulation of feature sets or permissions using bitwise operations, which is especially useful for capability reporting in monitoring and event source traits.
source
proptest#
The proptest crate is included as a shared dev-dependency (version 1.11.0) and is used for property-based testing. This testing approach generates a wide range of input data to validate code invariants and robustness, which is particularly valuable for testing event sources, IPC mechanisms, and other critical infrastructure.
source
postcard#
The postcard crate is used for efficient serialization with default-features = false and features = ["alloc"]. Disabling default features eliminates the heapless and atomic-polyfill transitive dependencies, which resolves RUSTSEC security advisories while maintaining the serialization functionality needed by the project.
Member Crate Cargo.toml Organization#
Member crates (such as collector-core and daemoneye-lib) keep their Cargo.toml files minimal by deferring most configuration and dependency versions to the workspace. This is done using the workspace = true syntax:
[package]
name = "collector-core"
version.workspace = true
authors.workspace = true
license.workspace = true
rust-version.workspace = true
repository.workspace = true
homepage.workspace = true
edition.workspace = true
[dependencies]
bitflags = { workspace = true }
anyhow = { workspace = true }
# ... other dependencies ...
daemoneye-lib = { path = "../daemoneye-lib" }
This approach ensures that all crates use the same dependency versions and features, and that updates are managed centrally.
Managing Cargo.toml Files and Workspace Organization#
-
Adding a New Workspace Member:
- Create a new directory for the crate (e.g.,
collector-core/). - Add the directory name to the
[workspace].membersarray in the rootCargo.toml. - Create a minimal
Cargo.tomlin the new crate, usingworkspace = truefor shared fields and dependencies.
- Create a new directory for the crate (e.g.,
-
Adding or Updating Shared Dependencies:
- Declare or update the dependency in
[workspace.dependencies]in the rootCargo.toml. - In member crates, reference the dependency with
{ workspace = true }to inherit the version and features.
- Declare or update the dependency in
-
Internal Library Dependencies:
- Use path dependencies for internal crates, e.g.,
collector-core = { path = "collector-core" }.
- Use path dependencies for internal crates, e.g.,
-
Development Dependencies:
- Declare shared dev-dependencies (e.g.,
proptest,assert_cmd,criterion) in the rootCargo.toml. - Reference them in member crates with
{ workspace = true }.
- Declare shared dev-dependencies (e.g.,
-
Linting and Quality Enforcement:
- The workspace enforces linting rules for security, correctness, and style via
[workspace.lints.rust]and[workspace.lints.clippy]in the rootCargo.toml.
- The workspace enforces linting rules for security, correctness, and style via
-
Version Updates:
- Update dependency versions in the root
Cargo.tomlonly. All member crates will automatically use the updated versions.
- Update dependency versions in the root
Example: Minimal Member Cargo.toml#
[package]
name = "collector-core"
version.workspace = true
authors.workspace = true
license.workspace = true
rust-version.workspace = true
repository.workspace = true
homepage.workspace = true
edition.workspace = true
[dependencies]
bitflags = { workspace = true }
anyhow = { workspace = true }
# ... other dependencies ...
Example: Adding a New Shared Dependency#
To add a new shared dependency (e.g., serde):
- Add to root
Cargo.toml:[workspace.dependencies] serde = { version = "1.0", features = ["derive"] } - In member crate
Cargo.toml:[dependencies] serde = { workspace = true }
This structure ensures maintainability, consistency, and ease of updates across the entire workspace.
Note: Version numbers shown in documentation examples are illustrative. Always check the actual Cargo.toml in the repository for current dependency versions.