diff --git a/Cargo.toml b/Cargo.toml index a49ae129..b743b349 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,16 @@ version = "0.1.0" edition = "2024" publish = false +[workspace.lints.rust] +warnings = "deny" + +[workspace.lints.clippy] +all = "deny" +pedantic = "deny" +nursery = "deny" +cargo = "deny" +multiple_crate_versions = "allow" + [workspace.dependencies] anyhow = "1" askama = { version = "0.16.0", default-features = false } diff --git a/lib/rust.nix b/lib/rust.nix index 17e75c62..f6e5793f 100644 --- a/lib/rust.nix +++ b/lib/rust.nix @@ -12,18 +12,6 @@ writePythonApplication, }: let - defaultClippyDeniedLints = [ - "warnings" - "clippy::all" - "clippy::pedantic" - "clippy::nursery" - "clippy::cargo" - ]; - - defaultClippyAllowedLints = [ - "clippy::multiple_crate_versions" - ]; - defaultRustToolchain = rustToolchain; defaultRustsecAdvisoryDb = pkgs.fetchFromGitHub { @@ -49,8 +37,8 @@ let enable = true; package = clippyPackage; cargoArgs = [ "--all-targets" ]; - deniedLints = defaultClippyDeniedLints; - allowedLints = defaultClippyAllowedLints; + deniedLints = [ ]; + allowedLints = [ ]; }; tests = { enable = true; diff --git a/modules/services/resource-monitor/stats-writer/Cargo.toml b/modules/services/resource-monitor/stats-writer/Cargo.toml index 7b3cf8bb..87d5919c 100644 --- a/modules/services/resource-monitor/stats-writer/Cargo.toml +++ b/modules/services/resource-monitor/stats-writer/Cargo.toml @@ -4,4 +4,7 @@ version.workspace = true edition.workspace = true publish.workspace = true +[lints] +workspace = true + [dependencies] diff --git a/packages/agents-md/Cargo.toml b/packages/agents-md/Cargo.toml index 57a210cf..574f6467 100644 --- a/packages/agents-md/Cargo.toml +++ b/packages/agents-md/Cargo.toml @@ -4,6 +4,9 @@ version.workspace = true edition.workspace = true publish.workspace = true +[lints] +workspace = true + [dependencies] anyhow.workspace = true clap = { workspace = true, features = ["derive"] } diff --git a/packages/code-tokenizer/Cargo.toml b/packages/code-tokenizer/Cargo.toml index be1b6334..29dcb525 100644 --- a/packages/code-tokenizer/Cargo.toml +++ b/packages/code-tokenizer/Cargo.toml @@ -5,6 +5,9 @@ edition.workspace = true publish.workspace = true description = "Tantivy tokenizer that splits identifiers on camelCase, snake_case, and kebab-case boundaries" +[lints] +workspace = true + [dependencies] strip-ansi-escapes.workspace = true tantivy.workspace = true diff --git a/packages/dag-runner/Cargo.toml b/packages/dag-runner/Cargo.toml index 02485f23..c1af7846 100644 --- a/packages/dag-runner/Cargo.toml +++ b/packages/dag-runner/Cargo.toml @@ -4,6 +4,9 @@ version.workspace = true edition.workspace = true publish.workspace = true +[lints] +workspace = true + [dependencies] anyhow.workspace = true clap = { workspace = true, features = ["derive"] } diff --git a/packages/file-search/Cargo.toml b/packages/file-search/Cargo.toml index 7e3cb2fc..87238e48 100644 --- a/packages/file-search/Cargo.toml +++ b/packages/file-search/Cargo.toml @@ -5,6 +5,9 @@ edition.workspace = true publish.workspace = true description = "BM25 file indexer and searcher built on Tantivy" +[lints] +workspace = true + [lib] name = "file_search" path = "src/lib.rs" diff --git a/packages/ix-dev-diagnose/Cargo.toml b/packages/ix-dev-diagnose/Cargo.toml index 0111f4dc..1d8c31e4 100644 --- a/packages/ix-dev-diagnose/Cargo.toml +++ b/packages/ix-dev-diagnose/Cargo.toml @@ -6,6 +6,9 @@ publish.workspace = true description = "Collect JSON diagnostics for ix.dev HTTPS reachability" license = "MIT" +[lints] +workspace = true + [dependencies] anyhow.workspace = true base64.workspace = true diff --git a/packages/mcp/Cargo.toml b/packages/mcp/Cargo.toml index ac75d3d1..5f6e0868 100644 --- a/packages/mcp/Cargo.toml +++ b/packages/mcp/Cargo.toml @@ -4,6 +4,9 @@ version.workspace = true edition.workspace = true publish.workspace = true +[lints] +workspace = true + [dependencies] anyhow.workspace = true clap = { workspace = true, features = ["derive"] } diff --git a/packages/minecraft/nbt/Cargo.toml b/packages/minecraft/nbt/Cargo.toml index d5970a61..4b081be2 100644 --- a/packages/minecraft/nbt/Cargo.toml +++ b/packages/minecraft/nbt/Cargo.toml @@ -4,6 +4,9 @@ version.workspace = true edition.workspace = true publish.workspace = true +[lints] +workspace = true + [dependencies] anyhow.workspace = true clap = { workspace = true, features = ["derive"] } diff --git a/packages/minecraft/sync-managed/Cargo.toml b/packages/minecraft/sync-managed/Cargo.toml index 05e8b6cf..e42dcc8e 100644 --- a/packages/minecraft/sync-managed/Cargo.toml +++ b/packages/minecraft/sync-managed/Cargo.toml @@ -4,6 +4,9 @@ version.workspace = true edition.workspace = true publish.workspace = true +[lints] +workspace = true + [dependencies] anyhow.workspace = true clap = { workspace = true, features = ["derive"] } diff --git a/packages/nix-cargo-unit/Cargo.toml b/packages/nix-cargo-unit/Cargo.toml index 4a53f96f..9c27fbbd 100644 --- a/packages/nix-cargo-unit/Cargo.toml +++ b/packages/nix-cargo-unit/Cargo.toml @@ -6,6 +6,9 @@ description = "Render Cargo unit graphs as composable Nix derivations" license = "MIT" publish.workspace = true +[lints] +workspace = true + [dependencies] askama = { workspace = true, default-features = false, features = ["derive", "std"] } clap = { workspace = true, features = ["derive"] } diff --git a/packages/nix-cargo-unit/src/model.rs b/packages/nix-cargo-unit/src/model.rs index a3e4ab29..797ed3ee 100644 --- a/packages/nix-cargo-unit/src/model.rs +++ b/packages/nix-cargo-unit/src/model.rs @@ -23,6 +23,10 @@ pub struct Unit { pub profile: Profile, #[serde(default)] pub features: Vec, + #[serde(default)] + pub lint_rustflags: Vec, + #[serde(default)] + pub check_cfg_args: Vec, pub mode: UnitMode, #[serde(default)] pub dependencies: Vec, @@ -679,6 +683,14 @@ fn write_unit_identity(hasher: &mut sha2::Sha256, unit: &Unit) { hasher.update(flag.as_bytes()); hasher.update(b"\0"); } + for flag in &unit.lint_rustflags { + hasher.update(flag.as_bytes()); + hasher.update(b"\0"); + } + for arg in &unit.check_cfg_args { + hasher.update(arg.as_bytes()); + hasher.update(b"\0"); + } hasher.update(unit.mode.as_str().as_bytes()); hasher.update(b"\0"); if let Some(platform) = &unit.platform { diff --git a/packages/nix-cargo-unit/src/render.rs b/packages/nix-cargo-unit/src/render.rs index 6cd144e7..d2db6c43 100644 --- a/packages/nix-cargo-unit/src/render.rs +++ b/packages/nix-cargo-unit/src/render.rs @@ -695,7 +695,7 @@ fn render_rustc_build_phase( append_build_script_flag_reader(&mut script, &run_ref, unit); } - push_rustc_args(&mut script, unit, &prepared.hashes[index]); + push_rustc_args(&mut script, unit, &prepared.hashes[index])?; append_target_linker_arg(&mut script, unit); append_extra_rustc_args(&mut script, unit); @@ -814,7 +814,7 @@ fn collects_unused_crate_dependencies(unit: &Unit, options: &RenderOptions) -> b options.deny_unused_crate_dependencies && !unit.is_external() } -fn push_rustc_args(script: &mut String, unit: &Unit, hash: &str) { +fn push_rustc_args(script: &mut String, unit: &Unit, hash: &str) -> Result<()> { push_arg(script, "--crate-name"); push_arg(script, &unit.target.name.replace('-', "_")); push_arg(script, "--edition"); @@ -878,6 +878,12 @@ fn push_rustc_args(script: &mut String, unit: &Unit, hash: &str) { for rustflag in &unit.profile.rustflags { push_arg(script, rustflag); } + for rustflag in &unit.lint_rustflags { + push_arg(script, rustflag); + } + for arg in &unit.check_cfg_args { + push_arg(script, arg); + } for feature in &unit.features { push_arg(script, "--cfg"); push_arg(script, &format!("feature=\"{feature}\"")); @@ -896,6 +902,8 @@ fn push_rustc_args(script: &mut String, unit: &Unit, hash: &str) { push_arg(script, "--cap-lints"); push_arg(script, "warn"); } + + Ok(()) } fn lto_for_unit(unit: &Unit) -> Option<&'static str> { @@ -2280,6 +2288,12 @@ fn render_doctest_command( push_rustdoc_arg(&mut script, &unit.target.name.replace('-', "_")); push_rustdoc_arg(&mut script, "--edition"); push_rustdoc_arg(&mut script, &unit.target.edition); + for rustflag in &unit.lint_rustflags { + push_rustdoc_arg(&mut script, rustflag); + } + for arg in &unit.check_cfg_args { + push_rustdoc_arg(&mut script, arg); + } for feature in &unit.features { push_rustdoc_arg(&mut script, "--cfg"); push_rustdoc_arg(&mut script, &format!("feature=\"{feature}\"")); @@ -3246,6 +3260,8 @@ version = "0.1.0" "edition": "2024" }, "profile": { "name": "release", "opt_level": "3", "rustflags": ["-C", "target-feature=+sse2"] }, + "lint_rustflags": ["--deny=warnings", "--warn=unexpected_cfgs"], + "check_cfg_args": ["--check-cfg", "cfg(docsrs,test)"], "features": [], "mode": "build", "dependencies": [ @@ -3280,6 +3296,10 @@ version = "0.1.0" assert!(rendered.contains("doctest_runtime_library_paths=()")); assert!(rendered.contains("rustdoc_args+=( \"''${build_script_rustdoc_args[@]}\" )")); assert!(rendered.contains("doctest_build_args+=( '-C' )")); + assert!(rendered.contains("rustdoc_args+=( '--deny=warnings' )")); + assert!(rendered.contains("rustdoc_args+=( '--warn=unexpected_cfgs' )")); + assert!(rendered.contains("rustdoc_args+=( '--check-cfg' )")); + assert!(rendered.contains("rustdoc_args+=( 'cfg(docsrs,test)' )")); assert!(rendered.contains("rustdoc_args+=( --doctest-build-arg \"$doctest_build_arg\" )")); assert!(rendered.contains("case \"$link_search_path\" in")); assert!(rendered.contains( @@ -4491,4 +4511,75 @@ version = "0.1.0" assert!(rendered.contains("export \"$cargo_metadata_env=$cargo_metadata_value\"")); fs::remove_dir_all(workspace).unwrap(); } + + #[test] + fn unit_graph_lint_flags_render_as_rustc_args() { + let workspace = std::env::temp_dir().join(format!( + "nix-cargo-unit-lint-flags-test-{}", + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map_or(0, |duration| duration.as_nanos()) + )); + let _ = fs::remove_dir_all(&workspace); + fs::create_dir_all(workspace.join("src")).unwrap(); + fs::write(workspace.join("src/lib.rs"), "pub fn marker() {}\n").unwrap(); + + let src_path = workspace.join("src/lib.rs"); + let pkg_id = format!("path+file://{}#linted@0.1.0", workspace.display()); + let graph: UnitGraph = serde_json::from_value(serde_json::json!({ + "version": 1, + "units": [{ + "pkg_id": pkg_id, + "target": { + "kind": ["lib"], + "crate_types": ["lib"], + "name": "linted", + "src_path": src_path, + "edition": "2024" + }, + "profile": { "name": "dev", "opt_level": "0" }, + "lint_rustflags": [ + "--deny=clippy::all", + "--forbid=unsafe_code", + "--warn=unexpected_cfgs", + "--warn=clippy::pedantic", + "--check-cfg", + "cfg(ix_test)" + ], + "check_cfg_args": [ + "--check-cfg", + "cfg(docsrs,test)", + "--check-cfg", + "cfg(feature, values(\"alpha\", \"beta\"))" + ], + "mode": "build", + "dependencies": [] + }], + "roots": [0] + })) + .unwrap(); + + let rendered = render_units_nix( + &graph, + &RenderOptions { + workspace_root: workspace.clone(), + vendor_root: None, + cargo_lock_sources: CargoLockSources::default(), + content_addressed: false, + toolchain_id: None, + deny_unused_crate_dependencies: false, + }, + ) + .unwrap(); + + assert!(rendered.contains("rustc_args+=( '--deny=clippy::all' )")); + assert!(rendered.contains("rustc_args+=( '--forbid=unsafe_code' )")); + assert!(rendered.contains("rustc_args+=( '--warn=clippy::pedantic' )")); + assert!(rendered.contains("rustc_args+=( '--warn=unexpected_cfgs' )")); + assert!(rendered.contains("rustc_args+=( '--check-cfg' )")); + assert!(rendered.contains("rustc_args+=( 'cfg(docsrs,test)' )")); + assert!(rendered.contains("rustc_args+=( 'cfg(feature, values(\"alpha\", \"beta\"))' )")); + assert!(rendered.contains("rustc_args+=( 'cfg(ix_test)' )")); + fs::remove_dir_all(workspace).unwrap(); + } } diff --git a/packages/oci-image-builder/Cargo.toml b/packages/oci-image-builder/Cargo.toml index 32f3d7e2..9f42973a 100644 --- a/packages/oci-image-builder/Cargo.toml +++ b/packages/oci-image-builder/Cargo.toml @@ -4,6 +4,9 @@ version.workspace = true edition.workspace = true publish.workspace = true +[lints] +workspace = true + [dependencies] chrono = { workspace = true, default-features = false, features = ["clock", "std"] } serde = { workspace = true, features = ["derive"] } diff --git a/packages/repo-walker/Cargo.toml b/packages/repo-walker/Cargo.toml index c063b025..697195ed 100644 --- a/packages/repo-walker/Cargo.toml +++ b/packages/repo-walker/Cargo.toml @@ -5,6 +5,9 @@ edition.workspace = true publish.workspace = true description = "Iterator over text files in a directory tree, honoring .gitignore and skipping known binary extensions" +[lints] +workspace = true + [dependencies] ignore.workspace = true diff --git a/tests/default.nix b/tests/default.nix index a36b1d65..3c6378c3 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -2946,14 +2946,8 @@ let let denied = cargoUnitWorkspace.policy.clippy.deniedLints; in - builtins.all (lint: builtins.elem lint denied) [ - "warnings" - "clippy::all" - "clippy::pedantic" - "clippy::nursery" - "clippy::cargo" - ]; - message = "cargo-unit clippy checks should deny the shared strict lint set by default"; + denied == [ ]; + message = "cargo-unit clippy policy should defer default lint levels to Cargo.toml"; } { assertion = cargoUnitWorkspace.policyChecks ? cargoMachete;