chore(lints): enforce per-crate lint policy and add build profiles
Give every member crate its own `[lints.clippy]` (`pedantic`, `todo`, `unwrap_used`) and `[lints.rust]` block, add explicit `release` and `production` profiles to the workspace manifest, and fix the code so that `just clippy` -- `cargo clippy --workspace --all-targets --all-features -- -D warnings` -- passes with zero warnings. Declaring the lints is the easy half and on its own it was actively harmful: `unsafe_code = "forbid"` cannot be overridden from source, so it broke `lanparty-gateway`, `lanparty-client-tap`, and `lanparty-client-route`, which all need OS FFI, and the workspace no longer compiled on Linux at all. The rest of the workspace produced roughly 120 denied lints. A lint policy nobody can satisfy is worse than no policy, so this commit makes the tree actually clean. Unsafe policy: the three FFI crates use `unsafe_code = "deny"`, and the one module in each that holds the FFI (`gateway::packet`, `client_tap::windows`, `client_route::windows`) opts back in with a documented `#![allow(unsafe_code)]`. Every other crate keeps `"forbid"`. `deny` was chosen over dropping the lint so that `unsafe` outside those modules is still a hard error, and over per-block allows because the FFI is dense enough that per-block attributes would drown the code. Build profiles: `release` stays optimized but debuggable (debug info, debug assertions, overflow checks, no LTO, incremental) so that a bug reproduced at close-to-real speed still panics loudly and gives a usable backtrace. `production` inherits from it and turns all of that off, adding fat LTO and a single codegen unit, and is what ships. Note the consequence: `cargo build --release` binaries are now slower than before this commit and must not be shipped; use `just build-production`. Code changes made to satisfy the lints, grouped by kind: - `# Errors` sections on every public fallible function, and `# Panics` on `RoomRegistry::new`. The Windows-only implementations and their non-Windows `bail!` stubs are documented in parallel so the crates stay clean when built for Windows too, which CI on Linux cannot check. - Panicking paths removed rather than documented where the panic was only an unreachable invariant: `OverlayHeader::decode` and `declared_payload_len` take a fixed-size prefix via `first_chunk` instead of `try_into().expect(...)`, and `RoomRegistry::join` returns an `InternalError` reject instead of `expect`ing the room it just inserted. - Tests keep using `unwrap`/`unwrap_err`: each crate root carries `#![cfg_attr(test, allow(clippy::unwrap_used))]`. The lint is about production code; an `expect` message per assertion buys nothing. - Lossy casts replaced with `try_from` where a real conversion was happening (datagram-size negotiation, control-frame length prefix, MTU clamping). In `gateway::packet` the cast lints are allowed module-wide instead: those casts move values between libc's C types and ours after the value is already known to fit, so fallible conversions would only add unreachable branches. - Signature changes, all on private or crate-internal items except one: `RoomRegistry::join` now takes `&EndpointHello` (public, it never consumed the hello), `Room::join` and `reject_control_error` likewise. `Room`'s `room_id` field is now `id`. - `#[allow(clippy::too_many_lines)]` with a reason on three end-to-end test scenarios and on `bridge_until_shutdown`, whose `select!` loop mutates state shared by every arm; splitting it would hide that. - Mechanical fixes from `cargo clippy --fix`: `map_or_else`, `let...else`, inline format args, backticks in doc comments, `Duration::from_mins`. No runtime behavior changes: the only observable differences are the error text when a relay room lookup fails immediately after insertion (previously a panic) and the profile rename described above. Also documents the lint policy and the profile table in README.md, whose build section now points at the `just` recipes it should have used all along. Test Plan: - `just clippy` -- passes, zero warnings - `just test` -- 186 tests pass, 0 failed - `cargo check --profile production --workspace --all-features` -- passes - `just fmt` -- clean - Not verified: the Windows-only code paths and their doc comments, which need a Windows target to compile. Refs: https://doc.rust-lang.org/cargo/reference/profiles.html Refs: https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc Refs: https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes
This commit is contained in:
@@ -16,3 +16,11 @@ tokio.workspace = true
|
||||
|
||||
[target."cfg(windows)".dependencies]
|
||||
lanparty-client-route = { path = "../lanparty-client-route" }
|
||||
|
||||
[lints.clippy]
|
||||
pedantic = { level = "warn", priority = -1 }
|
||||
todo = "warn"
|
||||
unwrap_used = "warn"
|
||||
|
||||
[lints.rust]
|
||||
unsafe_code = "forbid"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#![cfg_attr(test, allow(clippy::unwrap_used))]
|
||||
#[cfg(any(windows, test))]
|
||||
use std::collections::BTreeMap;
|
||||
#[cfg(any(windows, test))]
|
||||
@@ -384,6 +385,8 @@ async fn run_client(
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
// Mirrors the Windows signature so the call site needs no `cfg`.
|
||||
#[allow(clippy::unused_async)]
|
||||
async fn run_client(_session: &ClientSession) -> Result<()> {
|
||||
unreachable!("ensure_supported_platform rejects non-Windows before tunnel setup")
|
||||
}
|
||||
@@ -756,24 +759,19 @@ fn client_frame_log_line(
|
||||
};
|
||||
let source_mac = log
|
||||
.source_mac()
|
||||
.map(|mac| mac.to_string())
|
||||
.unwrap_or_else(|| "-".to_owned());
|
||||
.map_or_else(|| "-".to_owned(), |mac| mac.to_string());
|
||||
let destination_mac = log
|
||||
.destination_mac()
|
||||
.map(|mac| mac.to_string())
|
||||
.unwrap_or_else(|| "-".to_owned());
|
||||
.map_or_else(|| "-".to_owned(), |mac| mac.to_string());
|
||||
let ethertype_or_len = log
|
||||
.ethertype_or_len()
|
||||
.map(|value| format!("0x{value:04x}"))
|
||||
.unwrap_or_else(|| "-".to_owned());
|
||||
.map_or_else(|| "-".to_owned(), |value| format!("0x{value:04x}"));
|
||||
let peer_id = log
|
||||
.peer_id()
|
||||
.map(|peer_id| peer_id.to_string())
|
||||
.unwrap_or_else(|| "-".to_owned());
|
||||
.map_or_else(|| "-".to_owned(), |peer_id| peer_id.to_string());
|
||||
let drop_reason = log
|
||||
.drop_reason()
|
||||
.map(|reason| format!("{reason:?}"))
|
||||
.unwrap_or_else(|| "-".to_owned());
|
||||
.map_or_else(|| "-".to_owned(), |reason| format!("{reason:?}"));
|
||||
|
||||
format!(
|
||||
"client frame direction={:?} peer_id={} src={} dst={} ethertype_or_len={} len={} action={:?} drop_reason={}",
|
||||
@@ -934,8 +932,7 @@ impl ControlEventFormatter {
|
||||
Role::Client => {
|
||||
let mac = peer
|
||||
.mac()
|
||||
.map(|mac| mac.to_string())
|
||||
.unwrap_or_else(|| "unknown".to_string());
|
||||
.map_or_else(|| "unknown".to_string(), |mac| mac.to_string());
|
||||
format!(
|
||||
"relay event: client peer {} with MAC {} left ({reason:?})",
|
||||
peer.peer_id(),
|
||||
@@ -961,8 +958,7 @@ fn format_peer_joined(peer: &PeerInfo) -> String {
|
||||
Role::Client => {
|
||||
let mac = peer
|
||||
.mac()
|
||||
.map(|mac| mac.to_string())
|
||||
.unwrap_or_else(|| "unknown".to_string());
|
||||
.map_or_else(|| "unknown".to_string(), |mac| mac.to_string());
|
||||
format!(
|
||||
"relay event: client peer {} joined with MAC {}",
|
||||
peer.peer_id(),
|
||||
|
||||
Reference in New Issue
Block a user