From e3640ebe2acf0997e7f69e46b202fdacd8536d13 Mon Sep 17 00:00:00 2001 From: Pavlos Rontidis Date: Tue, 23 Jun 2026 16:06:18 -0400 Subject: [PATCH 1/2] chore(clippy): add workspace lints string_slice, await_holding_lock, let_underscore_must_use Adds three opt-in clippy lints to [workspace.lints.clippy] so they apply across all workspace crates: - string_slice: catches &str[n..] byte-index slicing that can panic on multi-byte UTF-8 boundaries (the direct cause of the bug fixed in #25582) - await_holding_lock: catches .await while holding a MutexGuard (potential deadlock) - let_underscore_must_use: catches let _ = expr where expr has a #[must_use] type or return value All existing violations are resolved: real fixes preferred (strip_prefix, split_once, split_at, .ok()), with targeted #[expect] or #![allow] reserved for provably-safe patterns (regex/find() indices, Derivative macro false positives) and one genuine unavoidable case (kinesis partition_key truncation via floor_char_boundary). Also fixes a latent panic in aws_kinesis sink: partition_key[..256] could panic on multi-byte keys; replaced with floor_char_boundary(256). --- Cargo.toml | 13 +++- lib/codecs/Cargo.toml | 3 + lib/codecs/src/encoding/format/parquet.rs | 3 + lib/codecs/src/encoding/format/syslog.rs | 15 ++-- lib/dnsmsg-parser/Cargo.toml | 3 + lib/docs-renderer/Cargo.toml | 3 + lib/fakedata/Cargo.toml | 3 + lib/file-source-common/Cargo.toml | 3 + lib/file-source/Cargo.toml | 3 + lib/k8s-e2e-tests/Cargo.toml | 3 + lib/k8s-test-framework/Cargo.toml | 3 + lib/loki-logproto/Cargo.toml | 3 + lib/opentelemetry-proto/Cargo.toml | 3 + lib/prometheus-parser/Cargo.toml | 3 + lib/prometheus-parser/src/lib.rs | 26 +++++-- lib/tracing-limit/Cargo.toml | 3 + lib/vector-api-client/Cargo.toml | 3 + lib/vector-buffers/Cargo.toml | 4 +- .../src/topology/channel/sender.rs | 3 + lib/vector-common-macros/Cargo.toml | 3 + lib/vector-common/Cargo.toml | 3 + lib/vector-common/src/event_test_util.rs | 4 +- lib/vector-config-common/Cargo.toml | 3 + .../src/schema/generator.rs | 9 +-- lib/vector-config-macros/Cargo.toml | 3 + lib/vector-config/Cargo.toml | 3 + lib/vector-config/tests/integration/smoke.rs | 4 +- lib/vector-core/Cargo.toml | 4 +- .../src/event/util/log/all_fields.rs | 6 +- lib/vector-core/src/event/vrl_target.rs | 2 +- lib/vector-core/src/fanout.rs | 2 +- lib/vector-lib/Cargo.toml | 3 + lib/vector-lookup/Cargo.toml | 3 + lib/vector-stream/Cargo.toml | 3 + lib/vector-tap/Cargo.toml | 3 + lib/vector-top/Cargo.toml | 3 + lib/vector-top/src/input.rs | 78 +++++++++++-------- lib/vector-vrl/category/Cargo.toml | 3 + lib/vector-vrl/cli/Cargo.toml | 3 + lib/vector-vrl/dnstap-parser/Cargo.toml | 3 + lib/vector-vrl/doc-builder/Cargo.toml | 3 + lib/vector-vrl/enrichment/Cargo.toml | 3 + lib/vector-vrl/functions/Cargo.toml | 3 + lib/vector-vrl/metrics/Cargo.toml | 3 + lib/vector-vrl/metrics/src/common.rs | 5 +- lib/vector-vrl/tests/Cargo.toml | 3 + lib/vector-vrl/web-playground/Cargo.toml | 3 + src/cli.rs | 2 +- src/components/validation/resources/http.rs | 2 +- src/config/unit_test/unit_test_components.rs | 3 + src/dns.rs | 2 +- src/encoding_transcode.rs | 4 + src/internal_events/parser.rs | 6 +- src/sinks/aws_cloudwatch_logs/config.rs | 2 +- src/sinks/aws_kinesis/sink.rs | 7 +- src/sinks/azure_common/shared_key_policy.rs | 4 +- src/sinks/databend/config.rs | 4 +- src/sinks/doris/client.rs | 2 +- src/sinks/elasticsearch/common.rs | 2 +- src/sinks/elasticsearch/integration_tests.rs | 2 +- src/sinks/elasticsearch/service.rs | 2 +- src/sinks/influxdb/logs.rs | 2 +- src/sinks/influxdb/mod.rs | 4 + src/sinks/kafka/sink.rs | 2 +- src/sinks/prometheus/collector.rs | 16 ++-- src/sinks/prometheus/exporter.rs | 2 +- .../splunk_hec/logs/integration_tests.rs | 2 +- src/sinks/util/service/net/mod.rs | 4 +- src/sinks/websocket_server/sink.rs | 2 +- src/sources/apache_metrics/mod.rs | 9 +-- src/sources/datadog_agent/tests.rs | 34 ++++---- src/sources/file.rs | 2 +- .../file_descriptors/file_descriptor.rs | 2 +- src/sources/host_metrics/mod.rs | 7 +- src/sources/journald.rs | 5 +- src/sources/kafka.rs | 32 ++++---- src/sources/kubernetes_logs/parser/cri.rs | 3 + src/sources/mongodb_metrics/mod.rs | 8 +- src/sources/splunk_hec/mod.rs | 6 +- src/sources/statsd/parser.rs | 6 +- src/sources/util/net/mod.rs | 4 +- src/sources/websocket/source.rs | 2 +- src/template.rs | 12 ++- src/test_util/mock/sinks/completion.rs | 4 +- src/transforms/lua/v1/mod.rs | 3 + src/transforms/remap.rs | 5 +- src/utilization.rs | 2 +- tests/antithesis/harness/Cargo.toml | 3 + vdev/Cargo.toml | 3 + vdev/src/app.rs | 7 +- vdev/src/commands/check/events.rs | 16 ++++ vdev/src/commands/compose_tests/test.rs | 4 +- vdev/src/utils/deprecation.rs | 11 +-- 93 files changed, 382 insertions(+), 160 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 324843447172d..5fd2f21a29761 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,8 +47,8 @@ lto = "fat" [profile.bench] debug = true -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tokio_unstable)'] } +[lints] +workspace = true [package.metadata.deb] name = "vector" @@ -136,6 +136,15 @@ members = [ "vdev", ] +[workspace.lints.rust] +# 'cfg(tokio_unstable)' used in vector; 'cfg(ddsketch_extended)' used in vector-core +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tokio_unstable)', 'cfg(ddsketch_extended)'] } + +[workspace.lints.clippy] +string_slice = "warn" +await_holding_lock = "warn" +let_underscore_must_use = "warn" + [workspace.dependencies] antithesis-instrumentation = { version = "0.1", default-features = false, features = [] } antithesis_sdk = { version = "0.2", default-features = false, features = [] } diff --git a/lib/codecs/Cargo.toml b/lib/codecs/Cargo.toml index c2bd34dc81d3d..9408098279201 100644 --- a/lib/codecs/Cargo.toml +++ b/lib/codecs/Cargo.toml @@ -7,6 +7,9 @@ publish = false [lints.clippy] unwrap-used = "deny" +string_slice = "warn" +await_holding_lock = "warn" +let_underscore_must_use = "warn" [[bin]] name = "generate-avro-fixtures" diff --git a/lib/codecs/src/encoding/format/parquet.rs b/lib/codecs/src/encoding/format/parquet.rs index b8874d9b1de90..d954340b890e0 100644 --- a/lib/codecs/src/encoding/format/parquet.rs +++ b/lib/codecs/src/encoding/format/parquet.rs @@ -1,3 +1,6 @@ +// Derivative's Debug impl generates 'let _ = field.fmt(f)' which triggers this lint. +#![allow(clippy::let_underscore_must_use)] + //! Parquet batch format codec for batched event encoding //! //! Provides Apache Parquet format encoding with schema file support and auto-inference. diff --git a/lib/codecs/src/encoding/format/syslog.rs b/lib/codecs/src/encoding/format/syslog.rs index 188ecb0d4cb52..94e920f5eb686 100644 --- a/lib/codecs/src/encoding/format/syslog.rs +++ b/lib/codecs/src/encoding/format/syslog.rs @@ -235,8 +235,9 @@ where None => Cow::Borrowed(s), // All valid, zero allocation Some((first_invalid_idx, _)) => { let mut result = String::with_capacity(s.len()); - result.push_str(&s[..first_invalid_idx]); // Copy valid prefix - for c in s[first_invalid_idx..].chars() { + let (valid_prefix, remainder) = s.split_at(first_invalid_idx); + result.push_str(valid_prefix); + for c in remainder.chars() { result.push(if is_valid(c) { c } else { '_' }); } @@ -320,7 +321,7 @@ impl SyslogMessage { fn encode(&self, rfc: &SyslogRFC) -> String { let mut result = String::with_capacity(256); - let _ = write!(result, "{}", self.pri.encode()); + write!(result, "{}", self.pri.encode()).ok(); if *rfc == SyslogRFC::Rfc5424 { result.push_str(SYSLOG_V1); @@ -329,7 +330,7 @@ impl SyslogMessage { match rfc { SyslogRFC::Rfc3164 => { - let _ = write!(result, "{} ", self.timestamp.format("%b %e %H:%M:%S")); + write!(result, "{} ", self.timestamp.format("%b %e %H:%M:%S")).ok(); } SyslogRFC::Rfc5424 => { result.push_str( @@ -435,12 +436,12 @@ impl StructuredData { self.elements .iter() .fold(String::new(), |mut acc, (sd_id, sd_params)| { - let _ = write!(acc, "[{sd_id}"); + write!(acc, "[{sd_id}").ok(); for (key, value) in sd_params { let esc_val = escape_sd_value(value); - let _ = write!(acc, " {key}=\"{esc_val}\""); + write!(acc, " {key}=\"{esc_val}\"").ok(); } - let _ = write!(acc, "]"); + write!(acc, "]").ok(); acc }) } diff --git a/lib/dnsmsg-parser/Cargo.toml b/lib/dnsmsg-parser/Cargo.toml index b392579014ef1..4e1e0098033ae 100644 --- a/lib/dnsmsg-parser/Cargo.toml +++ b/lib/dnsmsg-parser/Cargo.toml @@ -8,6 +8,9 @@ license = "MIT" [lints.clippy] unwrap-used = "forbid" +string_slice = "warn" +await_holding_lock = "warn" +let_underscore_must_use = "warn" [dependencies] data-encoding = "2.10" diff --git a/lib/docs-renderer/Cargo.toml b/lib/docs-renderer/Cargo.toml index 3f25b0600c401..be24cbf656ccb 100644 --- a/lib/docs-renderer/Cargo.toml +++ b/lib/docs-renderer/Cargo.toml @@ -5,6 +5,9 @@ authors = ["Vector Contributors "] edition = "2024" publish = false +[lints] +workspace = true + [dependencies] anyhow.workspace = true serde.workspace = true diff --git a/lib/fakedata/Cargo.toml b/lib/fakedata/Cargo.toml index 52ba22387ef89..a6fa99197b776 100644 --- a/lib/fakedata/Cargo.toml +++ b/lib/fakedata/Cargo.toml @@ -6,6 +6,9 @@ edition = "2024" publish = false license = "MPL-2.0" +[lints] +workspace = true + [dependencies] chrono.workspace = true rand.workspace = true diff --git a/lib/file-source-common/Cargo.toml b/lib/file-source-common/Cargo.toml index 1fcc808ec5c72..59afec8e452e0 100644 --- a/lib/file-source-common/Cargo.toml +++ b/lib/file-source-common/Cargo.toml @@ -6,6 +6,9 @@ edition = "2024" publish = false license = "MIT" +[lints] +workspace = true + [target.'cfg(windows)'.dependencies] libc.workspace = true winapi = { version = "0.3", features = ["winioctl"] } diff --git a/lib/file-source/Cargo.toml b/lib/file-source/Cargo.toml index 03d6860e5c659..75ba3d6299dbe 100644 --- a/lib/file-source/Cargo.toml +++ b/lib/file-source/Cargo.toml @@ -6,6 +6,9 @@ edition = "2024" publish = false license = "MIT" +[lints] +workspace = true + [target.'cfg(windows)'.dependencies] libc.workspace = true winapi = { version = "0.3", features = ["winioctl"] } diff --git a/lib/k8s-e2e-tests/Cargo.toml b/lib/k8s-e2e-tests/Cargo.toml index e7e7a49175c28..f85cf12f5d0f9 100644 --- a/lib/k8s-e2e-tests/Cargo.toml +++ b/lib/k8s-e2e-tests/Cargo.toml @@ -7,6 +7,9 @@ description = "End-to-end tests of Vector in the Kubernetes environment" publish = false license = "MPL-2.0" +[lints] +workspace = true + [dependencies] futures.workspace = true k8s-openapi = { version = "0.27.0", default-features = false, features = ["v1_31"] } diff --git a/lib/k8s-test-framework/Cargo.toml b/lib/k8s-test-framework/Cargo.toml index 06fb275de9a42..9d252bc9f3ac8 100644 --- a/lib/k8s-test-framework/Cargo.toml +++ b/lib/k8s-test-framework/Cargo.toml @@ -7,6 +7,9 @@ description = "Kubernetes Test Framework used to test Vector in Kubernetes" publish = false license = "MPL-2.0" +[lints] +workspace = true + [dependencies] k8s-openapi = { version = "0.27.0", default-features = false, features = ["v1_31"] } serde_json.workspace = true diff --git a/lib/loki-logproto/Cargo.toml b/lib/loki-logproto/Cargo.toml index 4547fc83eb719..1fe52ed882a8b 100644 --- a/lib/loki-logproto/Cargo.toml +++ b/lib/loki-logproto/Cargo.toml @@ -7,6 +7,9 @@ publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lints] +workspace = true + [dependencies] prost.workspace = true prost-types.workspace = true diff --git a/lib/opentelemetry-proto/Cargo.toml b/lib/opentelemetry-proto/Cargo.toml index 1467a171129ca..db965e3976567 100644 --- a/lib/opentelemetry-proto/Cargo.toml +++ b/lib/opentelemetry-proto/Cargo.toml @@ -5,6 +5,9 @@ authors = ["Vector Contributors "] edition = "2024" publish = false +[lints] +workspace = true + [build-dependencies] prost-build.workspace = true tonic-build.workspace = true diff --git a/lib/prometheus-parser/Cargo.toml b/lib/prometheus-parser/Cargo.toml index 3947771f85a09..d31d436b7e895 100644 --- a/lib/prometheus-parser/Cargo.toml +++ b/lib/prometheus-parser/Cargo.toml @@ -8,6 +8,9 @@ license = "MPL-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lints] +workspace = true + [dependencies] indexmap.workspace = true nom.workspace = true diff --git a/lib/prometheus-parser/src/lib.rs b/lib/prometheus-parser/src/lib.rs index 218319b8ea4b8..c588c70888977 100644 --- a/lib/prometheus-parser/src/lib.rs +++ b/lib/prometheus-parser/src/lib.rs @@ -157,6 +157,10 @@ impl GroupKind { prefix_len: usize, metric: Metric, ) -> Result, ParserError> { + #[expect( + clippy::string_slice, + reason = "prefix_len is always self.name.len(), a valid UTF-8 boundary" + )] let suffix = &metric.name[prefix_len..]; let mut key = GroupKey { timestamp: metric.timestamp, @@ -328,15 +332,23 @@ struct MetricGroupSet(IndexMap); impl MetricGroupSet { fn get_group<'a>(&'a mut self, name: &str) -> (usize, &'a String, &'a mut GroupKind) { - let len = name.len(); let name = if self.0.contains_key(name) { name - } else if name.ends_with("_bucket") && self.0.contains_key(&name[..len - 7]) { - &name[..len - 7] - } else if name.ends_with("_sum") && self.0.contains_key(&name[..len - 4]) { - &name[..len - 4] - } else if name.ends_with("_count") && self.0.contains_key(&name[..len - 6]) { - &name[..len - 6] + } else if let Some(base) = name + .strip_suffix("_bucket") + .filter(|b| self.0.contains_key(*b)) + { + base + } else if let Some(base) = name + .strip_suffix("_sum") + .filter(|b| self.0.contains_key(*b)) + { + base + } else if let Some(base) = name + .strip_suffix("_count") + .filter(|b| self.0.contains_key(*b)) + { + base } else { self.0 .insert(name.into(), GroupKind::new(MetricKind::Untyped)); diff --git a/lib/tracing-limit/Cargo.toml b/lib/tracing-limit/Cargo.toml index ba52c12fdea99..2cd826ec85785 100644 --- a/lib/tracing-limit/Cargo.toml +++ b/lib/tracing-limit/Cargo.toml @@ -8,6 +8,9 @@ license = "MPL-2.0" [lints.clippy] unwrap-used = "forbid" +string_slice = "warn" +await_holding_lock = "warn" +let_underscore_must_use = "warn" [dependencies] tracing-core = { version = "0.1", default-features = false } diff --git a/lib/vector-api-client/Cargo.toml b/lib/vector-api-client/Cargo.toml index 260a84a927e76..ffe7557670a71 100644 --- a/lib/vector-api-client/Cargo.toml +++ b/lib/vector-api-client/Cargo.toml @@ -6,6 +6,9 @@ edition = "2024" publish = false license = "MPL-2.0" +[lints] +workspace = true + [dependencies] # gRPC tonic.workspace = true diff --git a/lib/vector-buffers/Cargo.toml b/lib/vector-buffers/Cargo.toml index c8d57a8e50862..0c8f6004a7333 100644 --- a/lib/vector-buffers/Cargo.toml +++ b/lib/vector-buffers/Cargo.toml @@ -5,8 +5,8 @@ authors = ["Vector Contributors "] edition = "2024" publish = false -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tokio_unstable)'] } +[lints] +workspace = true [dependencies] async-recursion = "1.1.1" diff --git a/lib/vector-buffers/src/topology/channel/sender.rs b/lib/vector-buffers/src/topology/channel/sender.rs index c3eb22c3c952e..3c2f833bdc1f0 100644 --- a/lib/vector-buffers/src/topology/channel/sender.rs +++ b/lib/vector-buffers/src/topology/channel/sender.rs @@ -1,3 +1,6 @@ +// Derivative's Debug impl generates 'let _ = field.fmt(f)' which triggers this lint. +#![allow(clippy::let_underscore_must_use)] + use std::{sync::Arc, time::Instant}; use async_recursion::async_recursion; diff --git a/lib/vector-common-macros/Cargo.toml b/lib/vector-common-macros/Cargo.toml index 64ea946ecf3c1..5a8b6d638c431 100644 --- a/lib/vector-common-macros/Cargo.toml +++ b/lib/vector-common-macros/Cargo.toml @@ -4,6 +4,9 @@ version = "0.1.0" edition = "2024" license = "MPL-2.0" +[lints] +workspace = true + [lib] proc-macro = true diff --git a/lib/vector-common/Cargo.toml b/lib/vector-common/Cargo.toml index 75241fb602f22..cf64890def3cd 100644 --- a/lib/vector-common/Cargo.toml +++ b/lib/vector-common/Cargo.toml @@ -6,6 +6,9 @@ edition = "2024" publish = false license = "MPL-2.0" +[lints] +workspace = true + [features] default = [ "btreemap", diff --git a/lib/vector-common/src/event_test_util.rs b/lib/vector-common/src/event_test_util.rs index 4e2e9e728b440..ef95dcac5e646 100644 --- a/lib/vector-common/src/event_test_util.rs +++ b/lib/vector-common/src/event_test_util.rs @@ -73,9 +73,9 @@ pub fn record_internal_event(event: &str) { // Remove leading '&' let event = event.strip_prefix('&').unwrap_or(event); // Remove trailing '{fields…}' - let event = event.find('{').map_or(event, |par| &event[..par]); + let event = event.split_once('{').map_or(event, |(before, _)| before); // Remove trailing '::from…' - let event = event.find(':').map_or(event, |colon| &event[..colon]); + let event = event.split_once(':').map_or(event, |(before, _)| before); EVENTS_RECORDED.with(|er| er.borrow_mut().insert(event.trim().into())); } diff --git a/lib/vector-config-common/Cargo.toml b/lib/vector-config-common/Cargo.toml index 946bc48e17e70..b15a36cf28e7c 100644 --- a/lib/vector-config-common/Cargo.toml +++ b/lib/vector-config-common/Cargo.toml @@ -4,6 +4,9 @@ version = "0.1.0" edition = "2024" license = "MPL-2.0" +[lints] +workspace = true + [dependencies] convert_case.workspace = true darling.workspace = true diff --git a/lib/vector-config-common/src/schema/generator.rs b/lib/vector-config-common/src/schema/generator.rs index 0b71abc2e099d..d0a2d5e44f910 100644 --- a/lib/vector-config-common/src/schema/generator.rs +++ b/lib/vector-config-common/src/schema/generator.rs @@ -117,12 +117,9 @@ impl SchemaGenerator { .. }) => { let definitions_path = &self.settings().definitions_path; - if schema_ref.starts_with(definitions_path) { - let name = &schema_ref[definitions_path.len()..]; - self.definitions.get(name) - } else { - None - } + schema_ref + .strip_prefix(definitions_path.as_str()) + .and_then(|name| self.definitions.get(name)) } _ => None, } diff --git a/lib/vector-config-macros/Cargo.toml b/lib/vector-config-macros/Cargo.toml index 386dbca03f4f7..2cd6f28a3faa4 100644 --- a/lib/vector-config-macros/Cargo.toml +++ b/lib/vector-config-macros/Cargo.toml @@ -4,6 +4,9 @@ version = "0.1.0" edition = "2024" license = "MPL-2.0" +[lints] +workspace = true + [lib] proc-macro = true diff --git a/lib/vector-config/Cargo.toml b/lib/vector-config/Cargo.toml index 5f4cfdbdcf1b2..cc71a55036d6e 100644 --- a/lib/vector-config/Cargo.toml +++ b/lib/vector-config/Cargo.toml @@ -6,6 +6,9 @@ edition = "2024" publish = false license = "MPL-2.0" +[lints] +workspace = true + [[test]] name = "integration" path = "tests/integration/lib.rs" diff --git a/lib/vector-config/tests/integration/smoke.rs b/lib/vector-config/tests/integration/smoke.rs index 12c1f2dd5d430..51471a2fbfd65 100644 --- a/lib/vector-config/tests/integration/smoke.rs +++ b/lib/vector-config/tests/integration/smoke.rs @@ -288,7 +288,9 @@ impl TryFrom for SocketListenAddr { Err(_) => { let fd: usize = match input.as_str() { "systemd" => Ok(0), - s if s.starts_with("systemd#") => s[8..] + s if s.starts_with("systemd#") => s + .strip_prefix("systemd#") + .unwrap() .parse::() .map_err(|_| "failed to parse usize".to_string())? .checked_sub(1) diff --git a/lib/vector-core/Cargo.toml b/lib/vector-core/Cargo.toml index 7cd2bd653642a..7ed7c20aa0d6b 100644 --- a/lib/vector-core/Cargo.toml +++ b/lib/vector-core/Cargo.toml @@ -5,8 +5,8 @@ authors = ["Vector Contributors "] edition = "2024" publish = false -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(ddsketch_extended)'] } +[lints] +workspace = true [dependencies] async-trait.workspace = true diff --git a/lib/vector-core/src/event/util/log/all_fields.rs b/lib/vector-core/src/event/util/log/all_fields.rs index 2e1511c124e42..172365abf8c8e 100644 --- a/lib/vector-core/src/event/util/log/all_fields.rs +++ b/lib/vector-core/src/event/util/log/all_fields.rs @@ -259,7 +259,11 @@ mod test { .map(|(k, v)| (k.into(), v)) .collect(); // Compare without the leading `"` char so that the order is the same as the collected fields. - expected.sort_by(|(a, _), (b, _)| a[1..].cmp(&b[1..])); + expected.sort_by(|(a, _), (b, _)| { + a.strip_prefix('"') + .unwrap_or(a) + .cmp(b.strip_prefix('"').unwrap_or(b)) + }); assert_eq!(collected, expected); } diff --git a/lib/vector-core/src/event/vrl_target.rs b/lib/vector-core/src/event/vrl_target.rs index 64e81b2281331..b2ead7fe0de71 100644 --- a/lib/vector-core/src/event/vrl_target.rs +++ b/lib/vector-core/src/event/vrl_target.rs @@ -303,7 +303,7 @@ impl Target for VrlTarget { metric.remove_tags(); for (field, value) in &value { set_metric_tag_values( - field[..].into(), + field.as_str().into(), value, metric, *multi_value_tags, diff --git a/lib/vector-core/src/fanout.rs b/lib/vector-core/src/fanout.rs index 2d680b22949e9..ac48fd4609ff4 100644 --- a/lib/vector-core/src/fanout.rs +++ b/lib/vector-core/src/fanout.rs @@ -877,7 +877,7 @@ mod tests { let (mut fanout, _, _receivers) = fanout_from_senders(&[2, 2]); let empty: EventArray = Vec::::new().into(); - let _ = fanout.send(empty, None).await; + _ = fanout.send(empty, None).await; } #[tokio::test] diff --git a/lib/vector-lib/Cargo.toml b/lib/vector-lib/Cargo.toml index 4975cd884bf2e..67181e59e2ef9 100644 --- a/lib/vector-lib/Cargo.toml +++ b/lib/vector-lib/Cargo.toml @@ -5,6 +5,9 @@ authors = ["Vector Contributors "] edition = "2024" publish = false +[lints] +workspace = true + [dependencies] codecs = { path = "../codecs", default-features = false } enrichment = { path = "../vector-vrl/enrichment" } diff --git a/lib/vector-lookup/Cargo.toml b/lib/vector-lookup/Cargo.toml index e588f6f1089c5..24957f84b0afb 100644 --- a/lib/vector-lookup/Cargo.toml +++ b/lib/vector-lookup/Cargo.toml @@ -6,6 +6,9 @@ edition = "2024" publish = false license = "MPL-2.0" +[lints] +workspace = true + [dependencies] proptest = { workspace = true, optional = true } proptest-derive = { workspace = true, optional = true } diff --git a/lib/vector-stream/Cargo.toml b/lib/vector-stream/Cargo.toml index 21b9f1a9a2d7b..440c960695cb1 100644 --- a/lib/vector-stream/Cargo.toml +++ b/lib/vector-stream/Cargo.toml @@ -5,6 +5,9 @@ authors = ["Vector Contributors "] edition = "2024" publish = false +[lints] +workspace = true + [dependencies] async-stream.workspace = true futures.workspace = true diff --git a/lib/vector-tap/Cargo.toml b/lib/vector-tap/Cargo.toml index 127c2e1ea32bd..fb6ba1a549616 100644 --- a/lib/vector-tap/Cargo.toml +++ b/lib/vector-tap/Cargo.toml @@ -6,6 +6,9 @@ edition = "2024" publish = false license = "MPL-2.0" +[lints] +workspace = true + [features] api = [ "dep:bytes", diff --git a/lib/vector-top/Cargo.toml b/lib/vector-top/Cargo.toml index 869fec71484f1..057f05a75f4d4 100644 --- a/lib/vector-top/Cargo.toml +++ b/lib/vector-top/Cargo.toml @@ -5,6 +5,9 @@ authors = ["Vector Contributors "] edition = "2024" publish = false +[lints] +workspace = true + [dependencies] clap.workspace = true chrono.workspace = true diff --git a/lib/vector-top/src/input.rs b/lib/vector-top/src/input.rs index c0fd4810e0d48..7e0d648b7ae1e 100644 --- a/lib/vector-top/src/input.rs +++ b/lib/vector-top/src/input.rs @@ -38,71 +38,79 @@ async fn handle_top_input( return true; } KeyCode::Up | KeyCode::Char('k') => { - let _ = event_tx + event_tx .send(UiEventType::Scroll(-1, terminal.size().unwrap_or_default())) - .await; + .await + .ok(); } KeyCode::Down | KeyCode::Char('j') => { - let _ = event_tx + event_tx .send(UiEventType::Scroll(1, terminal.size().unwrap_or_default())) - .await; + .await + .ok(); } KeyCode::End | KeyCode::Char('G') => { - let _ = event_tx + event_tx .send(UiEventType::Scroll( isize::MAX, terminal.size().unwrap_or_default(), )) - .await; + .await + .ok(); } KeyCode::Home | KeyCode::Char('g') => { - let _ = event_tx + event_tx .send(UiEventType::Scroll( isize::MIN, terminal.size().unwrap_or_default(), )) - .await; + .await + .ok(); } KeyCode::Left | KeyCode::PageUp => { - let _ = event_tx + event_tx .send(UiEventType::ScrollPage( -1, terminal.size().unwrap_or_default(), )) - .await; + .await + .ok(); } KeyCode::Char('b') if key_event.modifiers.intersects(KeyModifiers::CONTROL) => { - let _ = event_tx + event_tx .send(UiEventType::ScrollPage( -1, terminal.size().unwrap_or_default(), )) - .await; + .await + .ok(); } KeyCode::Right | KeyCode::PageDown => { - let _ = event_tx + event_tx .send(UiEventType::ScrollPage( 1, terminal.size().unwrap_or_default(), )) - .await; + .await + .ok(); } KeyCode::Char('f') if key_event.modifiers.intersects(KeyModifiers::CONTROL) => { - let _ = event_tx + event_tx .send(UiEventType::ScrollPage( 1, terminal.size().unwrap_or_default(), )) - .await; + .await + .ok(); } KeyCode::Char('?') | KeyCode::F(1) => { - let _ = event_tx.send(UiEventType::ToggleHelp).await; + event_tx.send(UiEventType::ToggleHelp).await.ok(); } KeyCode::Char('s') | KeyCode::F(6) => { - let _ = event_tx.send(UiEventType::ToggleSortMenu).await; + event_tx.send(UiEventType::ToggleSortMenu).await.ok(); } KeyCode::Char('r') | KeyCode::F(7) => { - let _ = event_tx.send(UiEventType::ToggleSortDirection).await; + event_tx.send(UiEventType::ToggleSortDirection).await.ok(); } KeyCode::Char(d) if d.is_ascii_digit() => { let col = match d { @@ -118,10 +126,10 @@ async fn handle_top_input( '0' => SortColumn::MemoryUsed, _ => return false, }; - let _ = event_tx.send(UiEventType::SortByColumn(col)).await; + event_tx.send(UiEventType::SortByColumn(col)).await.ok(); } KeyCode::F(4) | KeyCode::Char('f') | KeyCode::Char('/') => { - let _ = event_tx.send(UiEventType::ToggleFilterMenu).await; + event_tx.send(UiEventType::ToggleFilterMenu).await.ok(); } _ => (), } @@ -135,7 +143,7 @@ async fn handle_help_input( ) -> bool { match key_event.code { KeyCode::Esc => { - let _ = event_tx.send(UiEventType::ToggleHelp).await; + event_tx.send(UiEventType::ToggleHelp).await.ok(); } _ => return handle_top_input(key_event, event_tx, terminal).await, } @@ -149,16 +157,16 @@ async fn handle_sort_input( ) -> bool { match key_event.code { KeyCode::Esc => { - let _ = event_tx.send(UiEventType::ToggleSortMenu).await; + event_tx.send(UiEventType::ToggleSortMenu).await.ok(); } KeyCode::Up | KeyCode::BackTab | KeyCode::Char('k') => { - let _ = event_tx.send(UiEventType::SortSelection(-1)).await; + event_tx.send(UiEventType::SortSelection(-1)).await.ok(); } KeyCode::Down | KeyCode::Tab | KeyCode::Char('j') => { - let _ = event_tx.send(UiEventType::SortSelection(1)).await; + event_tx.send(UiEventType::SortSelection(1)).await.ok(); } KeyCode::Enter => { - let _ = event_tx.send(UiEventType::SortConfirmation).await; + event_tx.send(UiEventType::SortConfirmation).await.ok(); } _ => return handle_top_input(key_event, event_tx, terminal).await, } @@ -172,22 +180,28 @@ async fn handle_filter_input( ) -> bool { match key_event.code { KeyCode::Esc => { - let _ = event_tx.send(UiEventType::ToggleFilterMenu).await; + event_tx.send(UiEventType::ToggleFilterMenu).await.ok(); } KeyCode::BackTab | KeyCode::Up => { - let _ = event_tx.send(UiEventType::FilterColumnSelection(-1)).await; + event_tx + .send(UiEventType::FilterColumnSelection(-1)) + .await + .ok(); } KeyCode::Tab | KeyCode::Down => { - let _ = event_tx.send(UiEventType::FilterColumnSelection(1)).await; + event_tx + .send(UiEventType::FilterColumnSelection(1)) + .await + .ok(); } KeyCode::Backspace => { - let _ = event_tx.send(UiEventType::FilterBackspace).await; + event_tx.send(UiEventType::FilterBackspace).await.ok(); } KeyCode::Enter => { - let _ = event_tx.send(UiEventType::FilterConfirmation).await; + event_tx.send(UiEventType::FilterConfirmation).await.ok(); } KeyCode::Char(any) => { - let _ = event_tx.send(UiEventType::FilterInput(any)).await; + event_tx.send(UiEventType::FilterInput(any)).await.ok(); } _ => return handle_top_input(key_event, event_tx, terminal).await, } diff --git a/lib/vector-vrl/category/Cargo.toml b/lib/vector-vrl/category/Cargo.toml index 886b7dce5e72f..eb2d1f0c89a75 100644 --- a/lib/vector-vrl/category/Cargo.toml +++ b/lib/vector-vrl/category/Cargo.toml @@ -6,5 +6,8 @@ edition = "2024" publish = false license = "MPL-2.0" +[lints] +workspace = true + [dependencies] strum.workspace = true diff --git a/lib/vector-vrl/cli/Cargo.toml b/lib/vector-vrl/cli/Cargo.toml index 8e3c78597de8b..ee4b08761306a 100644 --- a/lib/vector-vrl/cli/Cargo.toml +++ b/lib/vector-vrl/cli/Cargo.toml @@ -6,6 +6,9 @@ edition = "2024" publish = false license = "MPL-2.0" +[lints] +workspace = true + [features] # Enable the full VRL stdlib, which includes all available VRL functions. default = ["vrl/stdlib"] diff --git a/lib/vector-vrl/dnstap-parser/Cargo.toml b/lib/vector-vrl/dnstap-parser/Cargo.toml index 6e30f22732fd9..f608c8f53141e 100644 --- a/lib/vector-vrl/dnstap-parser/Cargo.toml +++ b/lib/vector-vrl/dnstap-parser/Cargo.toml @@ -6,6 +6,9 @@ edition = "2024" publish = false license = "MIT" +[lints] +workspace = true + [dependencies] base64 = { workspace = true, features = ["alloc"] } bytes = { workspace = true, features = ["serde"] } diff --git a/lib/vector-vrl/doc-builder/Cargo.toml b/lib/vector-vrl/doc-builder/Cargo.toml index 75a1d262f4708..7121d35d2bb6c 100644 --- a/lib/vector-vrl/doc-builder/Cargo.toml +++ b/lib/vector-vrl/doc-builder/Cargo.toml @@ -6,6 +6,9 @@ edition = "2024" publish = false license = "MPL-2.0" +[lints] +workspace = true + [dependencies] anyhow.workspace = true clap.workspace = true diff --git a/lib/vector-vrl/enrichment/Cargo.toml b/lib/vector-vrl/enrichment/Cargo.toml index 2f69588f51f60..c3465b1fd1d58 100644 --- a/lib/vector-vrl/enrichment/Cargo.toml +++ b/lib/vector-vrl/enrichment/Cargo.toml @@ -5,6 +5,9 @@ authors = ["Vector Contributors "] edition = "2024" publish = false +[lints] +workspace = true + [dependencies] arc-swap.workspace = true chrono.workspace = true diff --git a/lib/vector-vrl/functions/Cargo.toml b/lib/vector-vrl/functions/Cargo.toml index 874ffbd759ad6..3fa914782c42b 100644 --- a/lib/vector-vrl/functions/Cargo.toml +++ b/lib/vector-vrl/functions/Cargo.toml @@ -6,6 +6,9 @@ edition = "2024" publish = false license = "MPL-2.0" +[lints] +workspace = true + [dependencies] indoc.workspace = true vrl.workspace = true diff --git a/lib/vector-vrl/metrics/Cargo.toml b/lib/vector-vrl/metrics/Cargo.toml index 38c29ceaf8ceb..b223cad73ce8a 100644 --- a/lib/vector-vrl/metrics/Cargo.toml +++ b/lib/vector-vrl/metrics/Cargo.toml @@ -6,6 +6,9 @@ edition = "2021" publish = false license = "MPL-2.0" +[lints] +workspace = true + [dependencies] arc-swap.workspace = true const-str.workspace = true diff --git a/lib/vector-vrl/metrics/src/common.rs b/lib/vector-vrl/metrics/src/common.rs index 8f765c486d193..f73329499eca8 100644 --- a/lib/vector-vrl/metrics/src/common.rs +++ b/lib/vector-vrl/metrics/src/common.rs @@ -100,13 +100,12 @@ impl MetricsStorage { /// Checks if the tag matches - also considers wildcards fn tag_matches(metric: &Metric, (tag_key, tag_value): (&String, &String)) -> bool { - if let Some(wildcard_index) = tag_value.find('*') { + if let Some((prefix, suffix)) = tag_value.split_once('*') { let Some(metric_tag_value) = metric.tag_value(tag_key) else { return false; }; - metric_tag_value.starts_with(&tag_value[0..wildcard_index]) - && metric_tag_value.ends_with(&tag_value[(wildcard_index + 1)..]) + metric_tag_value.starts_with(prefix) && metric_tag_value.ends_with(suffix) } else { metric.tag_matches(tag_key, tag_value) } diff --git a/lib/vector-vrl/tests/Cargo.toml b/lib/vector-vrl/tests/Cargo.toml index 791c51f24c77e..2407faa2a3397 100644 --- a/lib/vector-vrl/tests/Cargo.toml +++ b/lib/vector-vrl/tests/Cargo.toml @@ -5,6 +5,9 @@ authors = ["Vector Contributors "] edition = "2024" publish = false +[lints] +workspace = true + [dependencies] chrono-tz.workspace = true vector-vrl-functions = { workspace = true, features = ["dnstap", "vrl-metrics"] } diff --git a/lib/vector-vrl/web-playground/Cargo.toml b/lib/vector-vrl/web-playground/Cargo.toml index 59db0427b3698..448fee1e23d5c 100644 --- a/lib/vector-vrl/web-playground/Cargo.toml +++ b/lib/vector-vrl/web-playground/Cargo.toml @@ -8,6 +8,9 @@ license = "MPL-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lints] +workspace = true + [lib] crate-type = ["cdylib"] diff --git a/src/cli.rs b/src/cli.rs index f44f3677ac26f..01e3c5c7f618d 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -589,7 +589,7 @@ mod tests { if setrlimit(Resource::RLIMIT_NOFILE, hard, hard).is_err() { #[cfg(target_os = "macos")] if let Some(maxfiles) = super::macos_maxfilesperproc() { - let _ = setrlimit(Resource::RLIMIT_NOFILE, maxfiles, hard); + setrlimit(Resource::RLIMIT_NOFILE, maxfiles, hard).ok(); } } diff --git a/src/components/validation/resources/http.rs b/src/components/validation/resources/http.rs index ff7de67ffc1dc..9bc91e42b1304 100644 --- a/src/components/validation/resources/http.rs +++ b/src/components/validation/resources/http.rs @@ -427,7 +427,7 @@ impl HttpResourceOutputContext<'_> { resource_shutdown_rx.wait().await; // signal the server to shutdown - let _ = http_server_shutdown_tx.send(()); + http_server_shutdown_tx.send(()).ok(); // mark ourselves as done resource_completed.mark_as_done(); diff --git a/src/config/unit_test/unit_test_components.rs b/src/config/unit_test/unit_test_components.rs index b3f09098237da..ecf587515fc36 100644 --- a/src/config/unit_test/unit_test_components.rs +++ b/src/config/unit_test/unit_test_components.rs @@ -1,3 +1,6 @@ +// Derivative's Debug impl generates `let _ = field.fmt(f)` which triggers this lint. +#![allow(clippy::let_underscore_must_use)] + use std::sync::Arc; use futures::{Sink, Stream, stream}; diff --git a/src/dns.rs b/src/dns.rs index 0d6aa3eeae8a9..5eaa7888fb516 100644 --- a/src/dns.rs +++ b/src/dns.rs @@ -35,7 +35,7 @@ impl Resolver { let name_ref = match name.as_str() { // strip IPv6 prefix and suffix name if name.starts_with('[') && name.ends_with(']') => { - &name[1..name.len() - 1] + name.strip_prefix('[').unwrap().strip_suffix(']').unwrap() } name => name, }; diff --git a/src/encoding_transcode.rs b/src/encoding_transcode.rs index 986c8657b8cdd..e3e89a3c5b8a9 100644 --- a/src/encoding_transcode.rs +++ b/src/encoding_transcode.rs @@ -154,6 +154,10 @@ impl Encoder { let mut total_had_errors = false; loop { + #[expect( + clippy::string_slice, + reason = "total_read_from_input is a byte offset returned by the encoder, always a char boundary" + )] let (result, read, written, had_errors) = self.inner.encode_from_utf8( &input[total_read_from_input..], &mut self.buffer, diff --git a/src/internal_events/parser.rs b/src/internal_events/parser.rs index 2610ae5458958..5224b4db9bc17 100644 --- a/src/internal_events/parser.rs +++ b/src/internal_events/parser.rs @@ -16,6 +16,10 @@ fn truncate_string_at(s: &str, maxlen: usize) -> Cow<'_, str> { while !s.is_char_boundary(len) { len -= 1; } + #[expect( + clippy::string_slice, + reason = "len is adjusted to a char boundary in the loop above" + )] format!("{}{}", &s[..len], ellipsis).into() } else { s.into() @@ -34,7 +38,7 @@ impl InternalEvent for ParserMatchError<'_> { error_code = "no_match_found", error_type = error_type::CONDITION_FAILED, stage = error_stage::PROCESSING, - field = &truncate_string_at(&String::from_utf8_lossy(self.value), 60)[..] + field = truncate_string_at(&String::from_utf8_lossy(self.value), 60).as_ref() ); counter!( CounterName::ComponentErrorsTotal, diff --git a/src/sinks/aws_cloudwatch_logs/config.rs b/src/sinks/aws_cloudwatch_logs/config.rs index 6ec24d7e093e2..d1fd5b7f49fbf 100644 --- a/src/sinks/aws_cloudwatch_logs/config.rs +++ b/src/sinks/aws_cloudwatch_logs/config.rs @@ -68,7 +68,7 @@ where Ok(days) } else { let msg = format!("one of allowed values: {ALLOWED_VALUES:?}").to_owned(); - let expected: &str = &msg[..]; + let expected: &str = msg.as_str(); Err(de::Error::invalid_value( de::Unexpected::Signed(days.into()), &expected, diff --git a/src/sinks/aws_kinesis/sink.rs b/src/sinks/aws_kinesis/sink.rs index 52e0de5d6f596..dabda85bd86d6 100644 --- a/src/sinks/aws_kinesis/sink.rs +++ b/src/sinks/aws_kinesis/sink.rs @@ -114,7 +114,12 @@ pub(crate) fn process_log( Cow::Owned(gen_partition_key()) }; let partition_key = if partition_key.len() >= 256 { - partition_key[..256].to_string() + #[expect( + clippy::string_slice, + reason = "floor_char_boundary guarantees a valid char boundary" + )] + let s = &partition_key[..partition_key.floor_char_boundary(256)]; + s.to_string() } else { partition_key.into_owned() }; diff --git a/src/sinks/azure_common/shared_key_policy.rs b/src/sinks/azure_common/shared_key_policy.rs index f684f19a00a65..38bd98aa27956 100644 --- a/src/sinks/azure_common/shared_key_policy.rs +++ b/src/sinks/azure_common/shared_key_policy.rs @@ -192,7 +192,7 @@ impl SharedKeyAuthorizationPolicy { vals.sort(); vals.dedup(); let joined = vals.join(","); - let _ = writeln!(s, "{}:{}", k, joined); + writeln!(s, "{}:{}", k, joined).ok(); } // CanonicalizedResource @@ -280,7 +280,7 @@ fn append_canonicalized_resource(s: &mut String, account: &str, url: &Url) -> Az for (k, mut vals) in qp_map { vals.sort(); let mut line = String::new(); - let _ = write!(&mut line, "\n{}:", k); + write!(&mut line, "\n{}:", k).ok(); let joined = vals.join(","); line.push_str(&joined); s.push_str(&line); diff --git a/src/sinks/databend/config.rs b/src/sinks/databend/config.rs index c00e4dd514f72..945d312b50e51 100644 --- a/src/sinks/databend/config.rs +++ b/src/sinks/databend/config.rs @@ -125,8 +125,8 @@ impl SinkConfig for DatabendConfig { let mut endpoint = url::Url::parse(&endpoint)?; match auth { Some(Auth::Basic { user, password }) => { - let _ = endpoint.set_username(&user); - let _ = endpoint.set_password(Some(password.inner())); + endpoint.set_username(&user).ok(); + endpoint.set_password(Some(password.inner())).ok(); } Some(Auth::Bearer { .. }) => { return Err("Bearer authentication is not supported currently".into()); diff --git a/src/sinks/doris/client.rs b/src/sinks/doris/client.rs index 85bf9092829ba..91c17b3d400d6 100644 --- a/src/sinks/doris/client.rs +++ b/src/sinks/doris/client.rs @@ -177,7 +177,7 @@ impl DorisSinkClient { // Add custom headers for (header, value) in self.headers.as_ref() { - builder = builder.header(&header[..], &value[..]); + builder = builder.header(header.as_str(), value.as_str()); } let body = Body::from(payload.clone()); diff --git a/src/sinks/elasticsearch/common.rs b/src/sinks/elasticsearch/common.rs index c279a202cf841..91e78e80f2b76 100644 --- a/src/sinks/elasticsearch/common.rs +++ b/src/sinks/elasticsearch/common.rs @@ -429,7 +429,7 @@ async fn get( let mut builder = Request::get(format!("{base_url}{path}")); for (header, value) in &request.headers { - builder = builder.header(&header[..], &value[..]); + builder = builder.header(header.as_str(), value.as_str()); } let mut request = builder.body(Bytes::new())?; diff --git a/src/sinks/elasticsearch/integration_tests.rs b/src/sinks/elasticsearch/integration_tests.rs index 68095e8d9d3e6..d93e463ef41b4 100644 --- a/src/sinks/elasticsearch/integration_tests.rs +++ b/src/sinks/elasticsearch/integration_tests.rs @@ -55,7 +55,7 @@ impl ElasticsearchCommon { } for (header, value) in &self.request.headers { - builder = builder.header(&header[..], &value[..]); + builder = builder.header(header.as_str(), value.as_str()); } let mut request = builder.body(Bytes::new())?; diff --git a/src/sinks/elasticsearch/service.rs b/src/sinks/elasticsearch/service.rs index b0a39038c5df1..71ef1b2c0544c 100644 --- a/src/sinks/elasticsearch/service.rs +++ b/src/sinks/elasticsearch/service.rs @@ -131,7 +131,7 @@ impl HttpRequestBuilder { } for (header, value) in &self.http_request_config.headers { - builder = builder.header(&header[..], &value[..]); + builder = builder.header(header.as_str(), value.as_str()); } let mut request = builder diff --git a/src/sinks/influxdb/logs.rs b/src/sinks/influxdb/logs.rs index 0c7f9a115a96b..f6b58efe9767c 100644 --- a/src/sinks/influxdb/logs.rs +++ b/src/sinks/influxdb/logs.rs @@ -291,7 +291,7 @@ impl HttpEventEncoder for InfluxDbLogsEncoder { let mut tags = MetricTags::default(); let mut fields: HashMap = HashMap::new(); log.convert_to_fields().for_each(|(key, value)| { - if self.tags.contains(&key[..]) { + if self.tags.contains(key.as_str()) { tags.replace(key.into(), value.to_string_lossy().into_owned()); } else { fields.insert(key, to_field(value)); diff --git a/src/sinks/influxdb/mod.rs b/src/sinks/influxdb/mod.rs index d386dfae8fa99..afdf6bfff119b 100644 --- a/src/sinks/influxdb/mod.rs +++ b/src/sinks/influxdb/mod.rs @@ -553,6 +553,10 @@ pub mod test_util { // InfluxDB strips off trailing zeros in timestamps in metrics fn strip_timestamp(timestamp: String) -> String { + #[expect( + clippy::string_slice, + reason = "last two bytes are always ASCII ('0Z' or '.Z'), guaranteed char boundaries" + )] let strip_one = || format!("{}Z", ×tamp[..timestamp.len() - 2]); match timestamp { _ if timestamp.ends_with("0Z") => strip_timestamp(strip_one()), diff --git a/src/sinks/kafka/sink.rs b/src/sinks/kafka/sink.rs index 016f569bb726d..9b930fd4abecd 100644 --- a/src/sinks/kafka/sink.rs +++ b/src/sinks/kafka/sink.rs @@ -134,7 +134,7 @@ pub(crate) async fn healthcheck( tokio::task::spawn_blocking(move || { let producer: BaseProducer = client_config.create().unwrap(); - let topic = topic.as_ref().map(|topic| &topic[..]); + let topic = topic.as_deref(); producer .client() diff --git a/src/sinks/prometheus/collector.rs b/src/sinks/prometheus/collector.rs index 794badf96de2e..7ae08b2d5566a 100644 --- a/src/sinks/prometheus/collector.rs +++ b/src/sinks/prometheus/collector.rs @@ -301,11 +301,17 @@ impl StringCollector { result.push_str(key); result.push_str("=\""); while let Some(i) = value.find(['\\', '"']) { - result.push_str(&value[..i]); - result.push('\\'); - // Ugly but works because we know the character at `i` is ASCII - result.push(value.as_bytes()[i] as char); - value = &value[i + 1..]; + #[expect( + clippy::string_slice, + reason = "i comes from find() on ASCII chars, i and i+1 are char boundaries" + )] + { + result.push_str(&value[..i]); + result.push('\\'); + // Ugly but works because we know the character at `i` is ASCII + result.push(value.as_bytes()[i] as char); + value = &value[i + 1..]; + } } result.push_str(value); result.push('"'); diff --git a/src/sinks/prometheus/exporter.rs b/src/sinks/prometheus/exporter.rs index 8ed514b638fa0..c297c8754896b 100644 --- a/src/sinks/prometheus/exporter.rs +++ b/src/sinks/prometheus/exporter.rs @@ -811,7 +811,7 @@ mod tests { let mut gz = GzDecoder::new(&body_raw[..]); let mut body_decoded = String::new(); - let _ = gz.read_to_string(&mut body_decoded); + gz.read_to_string(&mut body_decoded).ok(); assert!(body_raw.len() < expected.len()); assert_eq!(body_decoded, expected); diff --git a/src/sinks/splunk_hec/logs/integration_tests.rs b/src/sinks/splunk_hec/logs/integration_tests.rs index 4980e74569dfb..01efefe1482aa 100644 --- a/src/sinks/splunk_hec/logs/integration_tests.rs +++ b/src/sinks/splunk_hec/logs/integration_tests.rs @@ -59,7 +59,7 @@ async fn recent_entries(index: Option<&str>) -> Vec { splunk_api_address() )) .form(&vec![ - ("search", &search_query[..]), + ("search", search_query.as_str()), ("exec_mode", "oneshot"), ("f", "*"), ]) diff --git a/src/sinks/util/service/net/mod.rs b/src/sinks/util/service/net/mod.rs index 8af2e3aa29a58..b2e6a6dff4c6c 100644 --- a/src/sinks/util/service/net/mod.rs +++ b/src/sinks/util/service/net/mod.rs @@ -343,14 +343,14 @@ impl Service> for NetworkService { // Send the socket back to the service, since theoretically it's still valid to // reuse given that we may have simply overrun the OS socket buffers, etc. - let _ = tx.send(Some(socket)); + tx.send(Some(socket)).ok(); Ok(sent) } Err(e) => { // We need to signal back to the service that it needs to create a fresh socket // since this one could be tainted. - let _ = tx.send(None); + tx.send(None).ok(); Err(e) } diff --git a/src/sinks/websocket_server/sink.rs b/src/sinks/websocket_server/sink.rs index ea38d88fdac7f..7a47b23a79699 100644 --- a/src/sinks/websocket_server/sink.rs +++ b/src/sinks/websocket_server/sink.rs @@ -888,7 +888,7 @@ mod tests { } } - let _ = tx.close().await; + tx.close().await.ok(); }) } diff --git a/src/sources/apache_metrics/mod.rs b/src/sources/apache_metrics/mod.rs index d9cfb1b1ec387..2b30b896987fe 100644 --- a/src/sources/apache_metrics/mod.rs +++ b/src/sources/apache_metrics/mod.rs @@ -382,11 +382,10 @@ Scoreboard: ____S_____I______R____I_______KK___D__C__G_L____________W___________ match m.tags() { Some(tags) => { - assert_eq!( - tags.get("endpoint"), - Some(&format!("http://{in_addr}/metrics")[..]) - ); - assert_eq!(tags.get("host"), Some(&in_addr.to_string()[..])); + let endpoint = format!("http://{in_addr}/metrics"); + let host = in_addr.to_string(); + assert_eq!(tags.get("endpoint"), Some(endpoint.as_str())); + assert_eq!(tags.get("host"), Some(host.as_str())); } None => error!(message = "No tags for metric.", metric = ?m), } diff --git a/src/sources/datadog_agent/tests.rs b/src/sources/datadog_agent/tests.rs index dc7c414722150..d7e9468e35fee 100644 --- a/src/sources/datadog_agent/tests.rs +++ b/src/sources/datadog_agent/tests.rs @@ -574,7 +574,7 @@ async fn api_key_in_url() { assert_eq!(log["ddtags"], "one,two,three".into()); assert_eq!(*log.get_source_type().unwrap(), "datadog_agent".into()); assert_eq!( - &event.metadata().datadog_api_key().as_ref().unwrap()[..], + event.metadata().datadog_api_key().as_deref().unwrap(), DD_API_KEY ); assert_eq!( @@ -632,7 +632,7 @@ async fn api_key_in_query_params() { assert_eq!(log["ddtags"], "one,two,three".into()); assert_eq!(*log.get_source_type().unwrap(), "datadog_agent".into()); assert_eq!( - &event.metadata().datadog_api_key().as_ref().unwrap()[..], + event.metadata().datadog_api_key().as_deref().unwrap(), DD_API_KEY ); assert_eq!( @@ -690,7 +690,7 @@ async fn api_key_in_header() { assert_eq!(log["ddtags"], "one,two,three".into()); assert_eq!(*log.get_source_type().unwrap(), "datadog_agent".into()); assert_eq!( - &event.metadata().datadog_api_key().as_ref().unwrap()[..], + event.metadata().datadog_api_key().as_deref().unwrap(), DD_API_KEY ); assert_eq!( @@ -989,7 +989,7 @@ async fn decode_series_endpoint_v1() { ); assert_eq!( - &events[0].metadata().datadog_api_key().as_ref().unwrap()[..], + events[0].metadata().datadog_api_key().as_deref().unwrap(), DD_API_KEY ); @@ -1015,7 +1015,7 @@ async fn decode_series_endpoint_v1() { ); assert_eq!( - &events[1].metadata().datadog_api_key().as_ref().unwrap()[..], + events[1].metadata().datadog_api_key().as_deref().unwrap(), DD_API_KEY ); @@ -1046,7 +1046,7 @@ async fn decode_series_endpoint_v1() { ); assert_eq!( - &events[2].metadata().datadog_api_key().as_ref().unwrap()[..], + events[2].metadata().datadog_api_key().as_deref().unwrap(), DD_API_KEY ); @@ -1084,7 +1084,7 @@ async fn decode_series_endpoint_v1() { assert_eq!(metric.namespace(), Some("system")); assert_eq!( - &events[3].metadata().datadog_api_key().as_ref().unwrap()[..], + events[3].metadata().datadog_api_key().as_deref().unwrap(), DD_API_KEY ); } @@ -1180,7 +1180,7 @@ async fn decode_sketches() { } assert_eq!( - &events[0].metadata().datadog_api_key().as_ref().unwrap()[..], + events[0].metadata().datadog_api_key().as_deref().unwrap(), DD_API_KEY ); @@ -1343,7 +1343,7 @@ async fn decode_traces() { 0.577.into() ); assert_eq!( - &events[0].metadata().datadog_api_key().as_ref().unwrap()[..], + events[0].metadata().datadog_api_key().as_deref().unwrap(), DD_API_KEY ); @@ -1361,7 +1361,7 @@ async fn decode_traces() { assert_eq!(span_from_apm_event["resource"], "a_resource".into()); assert_eq!( - &events[1].metadata().datadog_api_key().as_ref().unwrap()[..], + events[1].metadata().datadog_api_key().as_deref().unwrap(), DD_API_KEY ); @@ -1423,7 +1423,7 @@ async fn decode_traces() { 0.577.into() ); assert_eq!( - &events[2].metadata().datadog_api_key().as_ref().unwrap()[..], + events[2].metadata().datadog_api_key().as_deref().unwrap(), DD_API_KEY ); } @@ -1512,7 +1512,7 @@ async fn split_outputs() { ), ); assert_eq!( - &event.metadata().datadog_api_key().as_ref().unwrap()[..], + event.metadata().datadog_api_key().as_deref().unwrap(), "abcdefgh12345678abcdefgh12345678" ); } @@ -1535,7 +1535,7 @@ async fn split_outputs() { assert_eq!(log["ddtags"], "one,two,three".into()); assert_eq!(*log.get_source_type().unwrap(), "datadog_agent".into()); assert_eq!( - &event.metadata().datadog_api_key().as_ref().unwrap()[..], + event.metadata().datadog_api_key().as_deref().unwrap(), DD_API_KEY ); assert_eq!( @@ -2201,7 +2201,7 @@ async fn decode_series_endpoint_v2() { assert_eq!(metric.namespace(), Some("namespace")); assert_eq!( - &events[0].metadata().datadog_api_key().as_ref().unwrap()[..], + events[0].metadata().datadog_api_key().as_deref().unwrap(), DD_API_KEY ); @@ -2231,7 +2231,7 @@ async fn decode_series_endpoint_v2() { assert_eq!(metric.namespace(), Some("namespace")); assert_eq!( - &events[1].metadata().datadog_api_key().as_ref().unwrap()[..], + events[1].metadata().datadog_api_key().as_deref().unwrap(), DD_API_KEY ); @@ -2264,7 +2264,7 @@ async fn decode_series_endpoint_v2() { assert_eq!(metric.namespace(), Some("another_namespace")); assert_eq!( - &events[2].metadata().datadog_api_key().as_ref().unwrap()[..], + events[2].metadata().datadog_api_key().as_deref().unwrap(), DD_API_KEY ); @@ -2296,7 +2296,7 @@ async fn decode_series_endpoint_v2() { assert_eq!(metric.namespace(), None); assert_eq!( - &events[3].metadata().datadog_api_key().as_ref().unwrap()[..], + events[3].metadata().datadog_api_key().as_deref().unwrap(), DD_API_KEY ); diff --git a/src/sources/file.rs b/src/sources/file.rs index d485c6ad6b4b6..cba66b1a59f0a 100644 --- a/src/sources/file.rs +++ b/src/sources/file.rs @@ -2571,7 +2571,7 @@ mod tests { let mut rx = rx; while let Some(event) = rx.next().await { counter.fetch_add(1, Ordering::SeqCst); - let _ = relay_tx.send(event); + relay_tx.send(event).ok(); } }); diff --git a/src/sources/file_descriptors/file_descriptor.rs b/src/sources/file_descriptors/file_descriptor.rs index 45ab828cedbb7..2442b0387c6c2 100644 --- a/src/sources/file_descriptors/file_descriptor.rs +++ b/src/sources/file_descriptors/file_descriptor.rs @@ -249,7 +249,7 @@ mod tests { write(&write_fd, b"hello world\nhello world again\n").unwrap(); // Consume the OwnedFd without closing it to avoid double-close // with the File created in build(). - let _ = write_fd.into_raw_fd(); + _ = write_fd.into_raw_fd(); let context = SourceContext::new_test(tx, None); config.build(context).await.unwrap().await.unwrap(); diff --git a/src/sources/host_metrics/mod.rs b/src/sources/host_metrics/mod.rs index 0052d0d0b8b98..3ca124f2ea2f7 100644 --- a/src/sources/host_metrics/mod.rs +++ b/src/sources/host_metrics/mod.rs @@ -913,7 +913,12 @@ mod tests { let keys = collect_tag_values(&all_metrics, tag); // Pick an arbitrary key value if let Some(key) = keys.into_iter().next() { - let key_prefix = &key[..key.len() - 1].to_string(); + #[expect( + clippy::string_slice, + reason = "index from char_indices, always a char boundary" + )] + let key_prefix = + &key[..key.char_indices().next_back().map_or(0, |(i, _)| i)].to_string(); let key_prefix_pattern = PatternWrapper::try_from(format!("{key_prefix}*")).unwrap(); let key_pattern = PatternWrapper::try_from(key.clone()).unwrap(); diff --git a/src/sources/journald.rs b/src/sources/journald.rs index 177ee5e91663c..eb8f8cd438ca1 100644 --- a/src/sources/journald.rs +++ b/src/sources/journald.rs @@ -1110,10 +1110,7 @@ impl Checkpointer { 0 => Ok(None), _ => { let text = String::from_utf8_lossy(&buf); - match text.find('\n') { - Some(nl) => Ok(Some(String::from(&text[..nl]))), - None => Ok(None), // Maybe return an error? - } + Ok(text.split_once('\n').map(|(line, _)| line.to_string())) } } } diff --git a/src/sources/kafka.rs b/src/sources/kafka.rs index f5927b365157b..1a14680bc4ee6 100644 --- a/src/sources/kafka.rs +++ b/src/sources/kafka.rs @@ -1309,13 +1309,15 @@ impl KafkaSourceContext { return; } let (send, rendezvous) = sync_channel(0); - let _ = self.callbacks.send(KafkaCallback::PartitionsAssigned( - tpl.elements() - .iter() - .map(|tp| (tp.topic().into(), tp.partition())) - .collect(), - send, - )); + self.callbacks + .send(KafkaCallback::PartitionsAssigned( + tpl.elements() + .iter() + .map(|tp| (tp.topic().into(), tp.partition())) + .collect(), + send, + )) + .ok(); while rendezvous.recv().is_ok() { // no-op: wait for partition assignment handler to complete @@ -1329,13 +1331,15 @@ impl KafkaSourceContext { /// sender is dropped by the callback handler. fn revoke_partitions(&self, tpl: &TopicPartitionList) { let (send, rendezvous) = sync_channel(0); - let _ = self.callbacks.send(KafkaCallback::PartitionsRevoked( - tpl.elements() - .iter() - .map(|tp| (tp.topic().into(), tp.partition())) - .collect(), - send, - )); + self.callbacks + .send(KafkaCallback::PartitionsRevoked( + tpl.elements() + .iter() + .map(|tp| (tp.topic().into(), tp.partition())) + .collect(), + send, + )) + .ok(); while rendezvous.recv().is_ok() { self.commit_consumer_state(); diff --git a/src/sources/kubernetes_logs/parser/cri.rs b/src/sources/kubernetes_logs/parser/cri.rs index 2d9741dd46c30..de0f965662c6c 100644 --- a/src/sources/kubernetes_logs/parser/cri.rs +++ b/src/sources/kubernetes_logs/parser/cri.rs @@ -1,3 +1,6 @@ +// Derivative's Debug impl generates `let _ = field.fmt(f)` which triggers this lint. +#![allow(clippy::let_underscore_must_use)] + use chrono::{DateTime, Utc}; use derivative::Derivative; use vector_lib::{ diff --git a/src/sources/mongodb_metrics/mod.rs b/src/sources/mongodb_metrics/mod.rs index 7fd3047b57016..2043d642adf60 100644 --- a/src/sources/mongodb_metrics/mod.rs +++ b/src/sources/mongodb_metrics/mod.rs @@ -1009,6 +1009,10 @@ fn document_size(doc: &Document) -> usize { /// `endpoint` argument would not be required, but field `original_uri` in `ClientOptions` is private. /// `.unwrap()` in function is safe because endpoint was already verified by `ClientOptions`. /// Based on ClientOptions::parse_uri -- +#[expect( + clippy::string_slice, + reason = "all indices come from find() on ASCII chars ('/', '?', '=', '@', ':'), guaranteed char boundaries" +)] fn sanitize_endpoint(endpoint: &str, options: &ClientOptions) -> String { let mut endpoint = endpoint.to_owned(); if options.credential.is_some() { @@ -1164,8 +1168,8 @@ mod integration_tests { assert!((timestamp - Utc::now()).num_seconds() < 1); // validate basic tags let tags = metric.tags().expect("existed tags"); - assert_eq!(tags.get("endpoint"), Some(&clean_endpoint[..])); - assert_eq!(tags.get("host"), Some(&host[..])); + assert_eq!(tags.get("endpoint"), Some(clean_endpoint.as_str())); + assert_eq!(tags.get("host"), Some(host.as_str())); } }) .await; diff --git a/src/sources/splunk_hec/mod.rs b/src/sources/splunk_hec/mod.rs index 2a04b14d68d33..ac6943f91a0fd 100644 --- a/src/sources/splunk_hec/mod.rs +++ b/src/sources/splunk_hec/mod.rs @@ -2714,7 +2714,7 @@ mod tests { message.into() ); assert_eq!( - &event.metadata().splunk_hec_token().as_ref().unwrap()[..], + event.metadata().splunk_hec_token().as_deref().unwrap(), TOKEN ); }) @@ -2741,7 +2741,7 @@ mod tests { "splunk_hec".into() ); assert_eq!( - &event.metadata().splunk_hec_token().as_ref().unwrap()[..], + event.metadata().splunk_hec_token().as_deref().unwrap(), TOKEN ); }) @@ -2792,7 +2792,7 @@ mod tests { message.into() ); assert_eq!( - &event.metadata().splunk_hec_token().as_ref().unwrap()[..], + event.metadata().splunk_hec_token().as_deref().unwrap(), TOKEN ); }) diff --git a/src/sources/statsd/parser.rs b/src/sources/statsd/parser.rs index ca98eb25ef23b..2afe0499fd86c 100644 --- a/src/sources/statsd/parser.rs +++ b/src/sources/statsd/parser.rs @@ -145,7 +145,7 @@ fn parse_sampling(input: &str) -> Result { )); } - let num: f64 = input[1..].parse()?; + let num: f64 = input.strip_prefix('@').unwrap().parse()?; if num.is_sign_positive() { Ok(num) } else { @@ -161,7 +161,9 @@ fn parse_tags(input: &&str) -> Result { )); } - Ok(input[1..] + Ok(input + .strip_prefix('#') + .unwrap() .split(',') .map(extract_tag_key_and_value) .collect()) diff --git a/src/sources/util/net/mod.rs b/src/sources/util/net/mod.rs index 000b5136bc0a7..3e134792008a4 100644 --- a/src/sources/util/net/mod.rs +++ b/src/sources/util/net/mod.rs @@ -112,7 +112,9 @@ impl TryFrom for SocketListenAddr { Err(_) => { let fd: usize = match input.as_str() { "systemd" => Ok(0), - s if s.starts_with("systemd#") => s[8..] + s if s.starts_with("systemd#") => s + .strip_prefix("systemd#") + .unwrap() .parse::() .map_err(|_| Self::Error::UsizeParse)? .checked_sub(1) diff --git a/src/sources/websocket/source.rs b/src/sources/websocket/source.rs index 42038387ef21a..2ce6ad552963f 100644 --- a/src/sources/websocket/source.rs +++ b/src/sources/websocket/source.rs @@ -649,7 +649,7 @@ mod tests { code: CloseCode::Error, reason: Cow::from("Simulated Internal Server Error"), }; - let _ = websocket.close(Some(close_frame)).await; + websocket.close(Some(close_frame)).await.ok(); } }); diff --git a/src/template.rs b/src/template.rs index 980586fdeef19..e21afa02bb41c 100644 --- a/src/template.rs +++ b/src/template.rs @@ -551,6 +551,10 @@ fn parse_template(src: &str) -> Result, TemplateParseError> { for cap in RE.captures_iter(src) { let all = cap.get(0).expect("Capture 0 is always defined"); if all.start() > last_end { + #[expect( + clippy::string_slice, + reason = "indices come from regex match positions, always char boundaries" + )] parts.push(parse_literal(&src[last_end..all.start()])?); } @@ -566,6 +570,10 @@ fn parse_template(src: &str) -> Result, TemplateParseError> { last_end = all.end(); } if src.len() > last_end { + #[expect( + clippy::string_slice, + reason = "last_end comes from a regex match end position, always a char boundary" + )] parts.push(parse_literal(&src[last_end..])?); } @@ -576,7 +584,9 @@ fn render_metric_field<'a>(key: &str, metric: &'a Metric) -> Option<&'a str> { match key { "name" => Some(metric.name()), "namespace" => metric.namespace(), - _ if key.starts_with("tags.") => metric.tags().and_then(|tags| tags.get(&key[5..])), + _ if key.starts_with("tags.") => metric + .tags() + .and_then(|tags| tags.get(key.strip_prefix("tags.").unwrap())), _ => None, } } diff --git a/src/test_util/mock/sinks/completion.rs b/src/test_util/mock/sinks/completion.rs index a390f33c9828b..f9dfa2f2287db 100644 --- a/src/test_util/mock/sinks/completion.rs +++ b/src/test_util/mock/sinks/completion.rs @@ -81,13 +81,13 @@ impl StreamSink for CompletionSink { if self.remaining == 0 && let Some(tx) = self.completion_tx.take() { - let _ = tx.send(true); + tx.send(true).ok(); } } } if let Some(tx) = self.completion_tx.take() { - let _ = tx.send(self.remaining == 0); + tx.send(self.remaining == 0).ok(); } Ok(()) diff --git a/src/transforms/lua/v1/mod.rs b/src/transforms/lua/v1/mod.rs index 05f1c059cbc3a..af0918b428ab2 100644 --- a/src/transforms/lua/v1/mod.rs +++ b/src/transforms/lua/v1/mod.rs @@ -1,3 +1,6 @@ +// Derivative's Debug impl generates `let _ = field.fmt(f)` which triggers this lint. +#![allow(clippy::let_underscore_must_use)] + use std::{future::ready, pin::Pin}; use futures::{Stream, StreamExt, stream}; diff --git a/src/transforms/remap.rs b/src/transforms/remap.rs index c08fa35961c9d..13ef05663f096 100644 --- a/src/transforms/remap.rs +++ b/src/transforms/remap.rs @@ -1,3 +1,6 @@ +// Derivative's Debug impl generates `let _ = field.fmt(f)` which triggers this lint. +#![allow(clippy::let_underscore_must_use)] + use std::{ collections::{BTreeMap, HashMap}, fs::File, @@ -321,7 +324,7 @@ impl TransformConfig for RemapConfig { // Attempt to copy over the meanings from the input definition. // The function will fail if the meaning that now points to a field that no longer exists, // this is fine since we will no longer want that meaning in the output definition. - let _ = new_type_def.try_with_meaning(path.clone(), id); + new_type_def.try_with_meaning(path.clone(), id).ok(); } // Apply any semantic meanings set in the VRL program diff --git a/src/utilization.rs b/src/utilization.rs index 21d5f670bf1d9..5c4c717af8778 100644 --- a/src/utilization.rs +++ b/src/utilization.rs @@ -81,7 +81,7 @@ where // all the timers and emits utilization value periodically let this = self.project(); this.timer_tx.try_send_start_wait(); - let _ = this.intervals.poll_next_unpin(cx); + _ = this.intervals.poll_next_unpin(cx); let result = ready!(this.inner.poll_next_unpin(cx)); this.timer_tx.try_send_stop_wait(); Poll::Ready(result) diff --git a/tests/antithesis/harness/Cargo.toml b/tests/antithesis/harness/Cargo.toml index 3120ca061b94c..b7d19f95fab7f 100644 --- a/tests/antithesis/harness/Cargo.toml +++ b/tests/antithesis/harness/Cargo.toml @@ -8,6 +8,9 @@ publish = false # and the eventually-phase conservation/liveness judge. They are buffer-agnostic, # so each scenario builds them with `-p antithesis-harness` and points them at its own # topology through environment variables. +[lints] +workspace = true + [dependencies] antithesis_sdk = { workspace = true, features = ["full"] } axum = { workspace = true, features = ["http1", "tokio"] } diff --git a/vdev/Cargo.toml b/vdev/Cargo.toml index d5bdcfb6fb804..e8b4d3b2254dc 100644 --- a/vdev/Cargo.toml +++ b/vdev/Cargo.toml @@ -16,6 +16,9 @@ include = [ "src/**", ] +[lints] +workspace = true + [dependencies] anyhow.workspace = true chrono.workspace = true diff --git a/vdev/src/app.rs b/vdev/src/app.rs index e5360a639844f..9a38769a3d345 100644 --- a/vdev/src/app.rs +++ b/vdev/src/app.rs @@ -207,14 +207,15 @@ fn format_command_error( } if let Some(description) = command_description { - let _ = writeln!(error_msg, "{description}"); + writeln!(error_msg, "{description}").ok(); } - let _ = write!( + write!( error_msg, "failed with exit code: {}", output.status.code().unwrap() - ); + ) + .ok(); error_msg } diff --git a/vdev/src/commands/check/events.rs b/vdev/src/commands/check/events.rs index 44ac06d9f03da..2651771a892ad 100644 --- a/vdev/src/commands/check/events.rs +++ b/vdev/src/commands/check/events.rs @@ -426,6 +426,10 @@ fn normalize_value(s: &str) -> String { /// fragment a `registered_event!` field. `>` only decrements when there is a /// matching `<`, so the `>` in `key => value` tag pairs (used by `counter!` /// args) doesn't underflow. +#[expect( + clippy::string_slice, + reason = "indices from byte-iterator over ASCII delimiters, always char boundaries" +)] fn split_comma_args(s: &str) -> Vec { let mut out = Vec::new(); let mut depth: i32 = 0; @@ -786,6 +790,10 @@ impl<'ast> Visit<'ast> for Scanner<'_> { impl Scanner<'_> { /// Parse a `registered_event!` invocation's tokens to extract the event /// name, members, handle metrics, and emit-block log calls. + #[expect( + clippy::string_slice, + reason = "indices from find() on ASCII patterns or match_paren_end(), always char boundaries" + )] fn handle_registered_event(&mut self, mac: &syn::Macro) { let raw = mac.tokens.to_string(); // Event name: first ident. @@ -911,6 +919,10 @@ impl Scanner<'_> { /// Operates on the raw source rather than via the AST so that log calls /// nested inside opaque outer macros (`tokio::select!`, `cfg_if!`, …) are /// also covered — those bodies are not visited by `syn`. +#[expect( + clippy::string_slice, + reason = "indices from regex .end() and match_paren_end(), always char boundaries" +)] fn format_check_log_messages(text: &str, path_str: &str) -> Vec { let mut reports = Vec::new(); for caps in RE_LOG_CALL_OPEN.captures_iter(text) { @@ -1017,6 +1029,10 @@ fn match_paren_end(s: &str) -> Option { } /// Split a `{ ... }` block off the front of `s`, returning `(inside, rest)`. +#[expect( + clippy::string_slice, + reason = "indices from byte-iterator over ASCII '{' '}', always char boundaries" +)] fn split_brace_block(s: &str) -> (&str, &str) { if !s.starts_with('{') { return ("", s); diff --git a/vdev/src/commands/compose_tests/test.rs b/vdev/src/commands/compose_tests/test.rs index e78b4c3413a03..ecf617a10c551 100644 --- a/vdev/src/commands/compose_tests/test.rs +++ b/vdev/src/commands/compose_tests/test.rs @@ -51,14 +51,14 @@ pub fn exec( let merged_path = coverage_dir.join(coverage_filename(None)); // Remove any stale lcov.info from a previous run so callers never pick // up outdated data if the merge below fails to read a per-env file. - let _ = std::fs::remove_file(&merged_path); + std::fs::remove_file(&merged_path).ok(); let mut merged = String::new(); for env_name in &ran_environments { let env_file = coverage_dir.join(coverage_filename(Some(env_name))); match std::fs::read_to_string(&env_file) { Ok(contents) => { merged.push_str(&contents); - let _ = std::fs::remove_file(&env_file); + std::fs::remove_file(&env_file).ok(); } Err(e) => { warn!("Could not read coverage file {}: {e}", env_file.display()); diff --git a/vdev/src/utils/deprecation.rs b/vdev/src/utils/deprecation.rs index eed6d5c6d2fd5..2c5b4b92a0093 100644 --- a/vdev/src/utils/deprecation.rs +++ b/vdev/src/utils/deprecation.rs @@ -204,18 +204,19 @@ fn split_frontmatter<'a>(content: &'a str, path: &Path) -> Result<(&'a str, &'a } // Advance past the opening `---` (and optional trailing whitespace on that line) - let after_open = content[3..].trim_start_matches([' ', '\t']); + let after_open = content + .strip_prefix("---") + .unwrap() + .trim_start_matches([' ', '\t']); let after_open = after_open.trim_start_matches('\n'); - let close_pos = after_open.find("\n---").ok_or_else(|| { + let (frontmatter, rest) = after_open.split_once("\n---").ok_or_else(|| { anyhow!( "Deprecation fragment {} has unclosed frontmatter", path.display() ) })?; - - let frontmatter = &after_open[..close_pos]; - let rest = &after_open[close_pos + 4..]; // skip `\n---` + let rest = rest.trim_start_matches(['\r', '\n']); let body = rest.trim_start_matches(['\r', '\n']); Ok((frontmatter, body)) From ccd384c85e9b34808f700c25a49fd988fe5103a8 Mon Sep 17 00:00:00 2001 From: Pavlos Rontidis Date: Tue, 23 Jun 2026 16:24:44 -0400 Subject: [PATCH 2/2] fix(clippy): resolve string_slice in cgroups.rs macro --- src/sources/host_metrics/cgroups.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sources/host_metrics/cgroups.rs b/src/sources/host_metrics/cgroups.rs index 7d53950f56d88..f95e072d3ea6b 100644 --- a/src/sources/host_metrics/cgroups.rs +++ b/src/sources/host_metrics/cgroups.rs @@ -389,8 +389,8 @@ macro_rules! define_stat_struct { for line in text.lines(){ if false {} $( - else if line.starts_with(concat!(stringify!($field), ' ')) { - result.$field = line[stringify!($field).len()+1..].parse()?; + else if let Some(rest) = line.strip_prefix(concat!(stringify!($field), ' ')) { + result.$field = rest.parse()?; } )* }