ops-exec: adopt universal clippy/lint baseline; warnings to zero
#[must_use] on the builder setters and CapabilitySet::intersect (return_self_not_must_use); write! instead of push_str+format! in render_shell_line (format_push_string).
clippy --all-targets clean, cargo fmt clean, tests green (47 passed+0 passed+0 passed).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5 files changed,
+45 insertions,
-5 deletions
| 38 |
38 |
|
[dev-dependencies]
|
| 39 |
39 |
|
tempfile = "3.20"
|
| 40 |
40 |
|
tokio = { version = "1.50.0", features = ["macros", "rt-multi-thread", "time"] }
|
|
41 |
+ |
|
|
42 |
+ |
[lints.rust]
|
|
43 |
+ |
unused = "warn"
|
|
44 |
+ |
unreachable_pub = "warn"
|
|
45 |
+ |
|
|
46 |
+ |
[lints.clippy]
|
|
47 |
+ |
pedantic = { level = "warn", priority = -1 }
|
|
48 |
+ |
# Allow-list tuned from a measured breakdown across server/multithreaded/pter
|
|
49 |
+ |
# (2026-07-22). These are the high-churn / low-signal pedantic lints; everything
|
|
50 |
+ |
# else in `pedantic` stays a warning. Keep this block identical across repos.
|
|
51 |
+ |
module_name_repetitions = "allow"
|
|
52 |
+ |
# Doc lints — no docs-completeness push underway.
|
|
53 |
+ |
missing_errors_doc = "allow"
|
|
54 |
+ |
missing_panics_doc = "allow"
|
|
55 |
+ |
doc_markdown = "allow"
|
|
56 |
+ |
# Numeric casts — endemic and mostly intentional in size/byte math.
|
|
57 |
+ |
cast_possible_truncation = "allow"
|
|
58 |
+ |
cast_sign_loss = "allow"
|
|
59 |
+ |
cast_precision_loss = "allow"
|
|
60 |
+ |
cast_possible_wrap = "allow"
|
|
61 |
+ |
cast_lossless = "allow"
|
|
62 |
+ |
# Subjective structure/style nags — high churn, low signal.
|
|
63 |
+ |
must_use_candidate = "allow"
|
|
64 |
+ |
too_many_lines = "allow"
|
|
65 |
+ |
struct_excessive_bools = "allow"
|
|
66 |
+ |
similar_names = "allow"
|
|
67 |
+ |
items_after_statements = "allow"
|
|
68 |
+ |
single_match_else = "allow"
|
|
69 |
+ |
# Frequent false-positives in TUI/router-heavy code — added from the buckets breakdown.
|
|
70 |
+ |
match_same_arms = "allow"
|
|
71 |
+ |
unnecessary_wraps = "allow"
|
|
72 |
+ |
type_complexity = "allow"
|
| 96 |
96 |
|
/// The agent-side enforcement primitive: the effective grant is the
|
| 97 |
97 |
|
/// intersection of what the caller's identity is allowed and what this host
|
| 98 |
98 |
|
/// locally grants. Neither side can widen the other.
|
|
99 |
+ |
#[must_use]
|
| 99 |
100 |
|
pub fn intersect(&self, other: &CapabilitySet) -> CapabilitySet {
|
| 100 |
101 |
|
CapabilitySet {
|
| 101 |
102 |
|
actuate: self.actuate.intersection(&other.actuate).cloned().collect(),
|
| 199 |
199 |
|
let n = COUNTER.fetch_add(1, Ordering::Relaxed);
|
| 200 |
200 |
|
let t = std::time::SystemTime::now()
|
| 201 |
201 |
|
.duration_since(std::time::UNIX_EPOCH)
|
| 202 |
|
- |
.map(|d| d.as_nanos() as u64)
|
| 203 |
|
- |
.unwrap_or(0);
|
|
202 |
+ |
.map_or(0, |d| d.as_nanos() as u64);
|
| 204 |
203 |
|
format!("{t:016x}{:04x}", n & 0xffff)
|
| 205 |
204 |
|
}
|
| 206 |
205 |
|
|
| 304 |
303 |
|
|
| 305 |
304 |
|
/// Reach this host on a non-default SSH port. `None` keeps ssh's default,
|
| 306 |
305 |
|
/// so a caller with an `Option<u16>` can pass it straight through.
|
|
306 |
+ |
#[must_use]
|
| 307 |
307 |
|
pub fn with_port(mut self, port: Option<u16>) -> Self {
|
| 308 |
308 |
|
self.port = port;
|
| 309 |
309 |
|
self
|
| 326 |
326 |
|
/// ([`RemoteHost::command`]) and the sync path (rsync's `-e`), so the two
|
| 327 |
327 |
|
/// cannot drift.
|
| 328 |
328 |
|
pub(crate) fn ssh_args(&self) -> Vec<String> {
|
| 329 |
|
- |
let mut args: Vec<String> = SSH_FLAGS.iter().map(|s| s.to_string()).collect();
|
|
329 |
+ |
let mut args: Vec<String> = SSH_FLAGS
|
|
330 |
+ |
.iter()
|
|
331 |
+ |
.map(std::string::ToString::to_string)
|
|
332 |
+ |
.collect();
|
| 330 |
333 |
|
if let Some(p) = self.port {
|
| 331 |
334 |
|
args.push("-p".into());
|
| 332 |
335 |
|
args.push(p.to_string());
|
| 150 |
150 |
|
}
|
| 151 |
151 |
|
}
|
| 152 |
152 |
|
|
|
153 |
+ |
#[must_use]
|
| 153 |
154 |
|
pub fn with_env(mut self, key: impl Into<String>, val: impl Into<String>) -> Self {
|
| 154 |
155 |
|
self.env.push((key.into(), val.into()));
|
| 155 |
156 |
|
self
|
| 156 |
157 |
|
}
|
| 157 |
158 |
|
|
|
159 |
+ |
#[must_use]
|
| 158 |
160 |
|
pub fn with_cwd(mut self, cwd: impl Into<PathBuf>) -> Self {
|
| 159 |
161 |
|
self.cwd = Some(cwd.into());
|
| 160 |
162 |
|
self
|
| 17 |
17 |
|
use crate::step::Step;
|
| 18 |
18 |
|
use anyhow::{Context, Result};
|
| 19 |
19 |
|
use async_trait::async_trait;
|
|
20 |
+ |
use std::fmt::Write as _;
|
| 20 |
21 |
|
use std::path::Path;
|
| 21 |
22 |
|
use tokio::process::Command;
|
| 22 |
23 |
|
|
| 25 |
26 |
|
fn render_shell_line(step: &Step) -> String {
|
| 26 |
27 |
|
let mut line = String::new();
|
| 27 |
28 |
|
if let Some(cwd) = &step.cwd {
|
| 28 |
|
- |
line.push_str(&format!("cd {} && ", sh_quote(&cwd.to_string_lossy())));
|
|
29 |
+ |
let _ = write!(line, "cd {} && ", sh_quote(&cwd.to_string_lossy()));
|
| 29 |
30 |
|
}
|
| 30 |
31 |
|
for (k, v) in &step.env {
|
| 31 |
|
- |
line.push_str(&format!("{}={} ", k, sh_quote(v)));
|
|
32 |
+ |
let _ = write!(line, "{}={} ", k, sh_quote(v));
|
| 32 |
33 |
|
}
|
| 33 |
34 |
|
match step.shell_script() {
|
| 34 |
35 |
|
Some(script) => line.push_str(script),
|
| 231 |
232 |
|
/// Reach this host on a non-default SSH port. `None` keeps ssh's default,
|
| 232 |
233 |
|
/// so a caller holding an `Option<u16>` can pass it straight through. The
|
| 233 |
234 |
|
/// port applies to both the exec and sync paths (see [`RemoteHost`]).
|
|
235 |
+ |
#[must_use]
|
| 234 |
236 |
|
pub fn with_port(mut self, port: Option<u16>) -> Self {
|
| 235 |
237 |
|
self.host = self.host.with_port(port);
|
| 236 |
238 |
|
self
|