safety: add clippy deny(unwrap_used, expect_used) to api_gateway, backtesting_service
Add #![deny(clippy::unwrap_used, clippy::expect_used)] to api_gateway and backtesting_service crate roots. The ml and common crates already had these deny attributes. Production code fixes: - api_gateway: replace expect with unwrap_or for cache stats and LRU eviction - api_gateway: add #[allow] on NonZeroU32 constants and Prometheus metrics - backtesting_service: replace expect/unwrap with ok_or_else/? for OHLCV bar bounds checks and chrono timestamp resampling - backtesting_service: add #[allow] on Prometheus Lazy metric statics Test code: cfg_attr(test, allow) at crate root for both crates. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -204,7 +204,7 @@ impl LocalRevocationCache {
|
||||
let misses = self.misses.load(std::sync::atomic::Ordering::Relaxed);
|
||||
let total = hits
|
||||
.checked_add(misses)
|
||||
.expect("Cache stats overflow: hits + misses exceeds u64");
|
||||
.unwrap_or(u64::MAX);
|
||||
let hit_rate = if total > 0 {
|
||||
let rate = (hits as f64 / total as f64) * 100.0;
|
||||
// f64 multiplication is safe, check for valid result
|
||||
|
||||
@@ -25,13 +25,19 @@ use x509_parser::{
|
||||
};
|
||||
|
||||
// --- Prometheus Metrics ---
|
||||
// SAFETY: Prometheus metric registration panics only if duplicate names exist,
|
||||
// which is a fatal misconfiguration that should crash at startup.
|
||||
#[allow(clippy::unwrap_used)]
|
||||
static OCSP_REQUESTS_TOTAL: Lazy<IntCounter> =
|
||||
Lazy::new(|| register_int_counter!("ocsp_requests_total", "Total OCSP requests sent").unwrap());
|
||||
#[allow(clippy::unwrap_used)]
|
||||
static OCSP_CACHE_HITS: Lazy<IntCounter> =
|
||||
Lazy::new(|| register_int_counter!("ocsp_cache_hits_total", "Total OCSP cache hits").unwrap());
|
||||
#[allow(clippy::unwrap_used)]
|
||||
static OCSP_CACHE_MISSES: Lazy<IntCounter> = Lazy::new(|| {
|
||||
register_int_counter!("ocsp_cache_misses_total", "Total OCSP cache misses").unwrap()
|
||||
});
|
||||
#[allow(clippy::unwrap_used)]
|
||||
static OCSP_REVOKED_TOTAL: Lazy<IntCounter> = Lazy::new(|| {
|
||||
register_int_counter!(
|
||||
"ocsp_revoked_certs_total",
|
||||
@@ -39,9 +45,11 @@ static OCSP_REVOKED_TOTAL: Lazy<IntCounter> = Lazy::new(|| {
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
#[allow(clippy::unwrap_used)]
|
||||
static OCSP_REQUEST_FAILURES: Lazy<IntCounter> = Lazy::new(|| {
|
||||
register_int_counter!("ocsp_request_failures_total", "Total failed OCSP requests").unwrap()
|
||||
});
|
||||
#[allow(clippy::unwrap_used)]
|
||||
static OCSP_RESPONSE_VALIDATION_FAILURES: Lazy<IntCounter> = Lazy::new(|| {
|
||||
register_int_counter!(
|
||||
"ocsp_response_validation_failures_total",
|
||||
@@ -49,6 +57,7 @@ static OCSP_RESPONSE_VALIDATION_FAILURES: Lazy<IntCounter> = Lazy::new(|| {
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
#[allow(clippy::unwrap_used)]
|
||||
static OCSP_REQUEST_LATENCY: Lazy<Histogram> = Lazy::new(|| {
|
||||
register_histogram!("ocsp_request_latency_seconds", "Latency of OCSP requests").unwrap()
|
||||
});
|
||||
|
||||
@@ -75,10 +75,14 @@ impl MlTradingProxy {
|
||||
/// - Connection pooling managed by tonic::transport::Channel
|
||||
pub fn new(client: TradingServiceClient<tonic::transport::Channel>) -> Self {
|
||||
// Create rate limiter for predictions: 100 requests per minute per user
|
||||
// SAFETY: NonZeroU32::new on positive constants always returns Some
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let quota_predictions = Quota::per_minute(NonZeroU32::new(100).unwrap());
|
||||
let rate_limiter_predictions = Arc::new(GovernorRateLimiter::keyed(quota_predictions));
|
||||
|
||||
// Create rate limiter for performance queries: 20 requests per minute per user (expensive)
|
||||
// SAFETY: NonZeroU32::new on positive constants always returns Some
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let quota_performance = Quota::per_minute(NonZeroU32::new(20).unwrap());
|
||||
let rate_limiter_performance = Arc::new(GovernorRateLimiter::keyed(quota_performance));
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
//! - Performance monitoring
|
||||
//! - Token bucket rate limiting with <50ns cache hits
|
||||
|
||||
#![deny(clippy::unwrap_used, clippy::expect_used)]
|
||||
#![cfg_attr(test, allow(clippy::unwrap_used, clippy::expect_used))]
|
||||
|
||||
// Include generated protobuf code FIRST (needed by other modules)
|
||||
pub mod foxhunt {
|
||||
pub mod tli {
|
||||
|
||||
@@ -344,7 +344,7 @@ impl RateLimiter {
|
||||
let num_to_evict = self
|
||||
.max_cache_size
|
||||
.checked_div(10)
|
||||
.expect("Division by zero in LRU eviction");
|
||||
.unwrap_or(1);
|
||||
|
||||
// Collect entries with their last access time (lock-free iteration)
|
||||
let mut entries: Vec<_> = self
|
||||
|
||||
@@ -330,13 +330,14 @@ impl DbnMarketDataRepository {
|
||||
return Err(anyhow::anyhow!("No data found for symbol: {}", symbol));
|
||||
}
|
||||
|
||||
// SAFETY: bars is non-empty (validated by is_empty check above)
|
||||
let first = bars
|
||||
.first()
|
||||
.expect("INVARIANT: bars is non-empty (validated above)")
|
||||
.ok_or_else(|| anyhow::anyhow!("INVARIANT violated: bars is empty after check"))?
|
||||
.timestamp;
|
||||
let last = bars
|
||||
.last()
|
||||
.expect("INVARIANT: bars is non-empty (validated above)")
|
||||
.ok_or_else(|| anyhow::anyhow!("INVARIANT violated: bars is empty after check"))?
|
||||
.timestamp;
|
||||
|
||||
debug!("Date range for {}: {} to {}", symbol, first, last);
|
||||
@@ -372,11 +373,11 @@ impl DbnMarketDataRepository {
|
||||
let bucket_start = bar
|
||||
.timestamp
|
||||
.with_minute((bar.timestamp.minute() / target_minutes) * target_minutes)
|
||||
.unwrap()
|
||||
.ok_or_else(|| anyhow::anyhow!("Invalid minute in timestamp resampling"))?
|
||||
.with_second(0)
|
||||
.unwrap()
|
||||
.ok_or_else(|| anyhow::anyhow!("Invalid second in timestamp resampling"))?
|
||||
.with_nanosecond(0)
|
||||
.unwrap();
|
||||
.ok_or_else(|| anyhow::anyhow!("Invalid nanosecond in timestamp resampling"))?;
|
||||
|
||||
// Start new bucket or add to existing
|
||||
match &mut current_bucket {
|
||||
@@ -391,11 +392,11 @@ impl DbnMarketDataRepository {
|
||||
.with_minute(
|
||||
(first_bar.timestamp.minute() / target_minutes) * target_minutes,
|
||||
)
|
||||
.unwrap()
|
||||
.ok_or_else(|| anyhow::anyhow!("Invalid minute in timestamp resampling"))?
|
||||
.with_second(0)
|
||||
.unwrap()
|
||||
.ok_or_else(|| anyhow::anyhow!("Invalid second in timestamp resampling"))?
|
||||
.with_nanosecond(0)
|
||||
.unwrap();
|
||||
.ok_or_else(|| anyhow::anyhow!("Invalid nanosecond in timestamp resampling"))?;
|
||||
|
||||
if bucket_start == first_bucket_start {
|
||||
// Same bucket
|
||||
@@ -436,9 +437,10 @@ impl DbnMarketDataRepository {
|
||||
|
||||
#[allow(clippy::indexing_slicing)] // Bounds checked above: !is_empty()
|
||||
let first = &bucket[0];
|
||||
// SAFETY: bucket is non-empty (validated by is_empty check above)
|
||||
let last = bucket
|
||||
.last()
|
||||
.expect("INVARIANT: bucket is non-empty (validated above)");
|
||||
.ok_or_else(|| anyhow::anyhow!("INVARIANT violated: bucket is empty after check"))?;
|
||||
|
||||
// Calculate OHLCV
|
||||
let open = first.open;
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
//! for testing purposes.
|
||||
|
||||
#![warn(missing_docs)]
|
||||
#![allow(clippy::unwrap_used)]
|
||||
#![allow(clippy::expect_used)]
|
||||
#![deny(clippy::unwrap_used, clippy::expect_used)]
|
||||
#![cfg_attr(test, allow(clippy::unwrap_used, clippy::expect_used))]
|
||||
|
||||
/// Performance analysis and metrics
|
||||
pub mod performance;
|
||||
|
||||
@@ -5,7 +5,11 @@
|
||||
use once_cell::sync::Lazy;
|
||||
use prometheus::{register_counter, register_gauge, Counter, Gauge};
|
||||
|
||||
// SAFETY: Prometheus metric registration panics only if duplicate names exist,
|
||||
// which is a fatal misconfiguration that should crash at startup.
|
||||
|
||||
/// Service uptime in seconds
|
||||
#[allow(clippy::expect_used)]
|
||||
pub static SERVICE_UPTIME: Lazy<Gauge> = Lazy::new(|| {
|
||||
register_gauge!(
|
||||
"backtesting_service_uptime_seconds",
|
||||
@@ -15,6 +19,7 @@ pub static SERVICE_UPTIME: Lazy<Gauge> = Lazy::new(|| {
|
||||
});
|
||||
|
||||
/// Total number of backtests started
|
||||
#[allow(clippy::expect_used)]
|
||||
pub static BACKTESTS_STARTED: Lazy<Counter> = Lazy::new(|| {
|
||||
register_counter!(
|
||||
"backtesting_backtests_started_total",
|
||||
@@ -24,6 +29,7 @@ pub static BACKTESTS_STARTED: Lazy<Counter> = Lazy::new(|| {
|
||||
});
|
||||
|
||||
/// Total number of backtests completed
|
||||
#[allow(clippy::expect_used)]
|
||||
pub static BACKTESTS_COMPLETED: Lazy<Counter> = Lazy::new(|| {
|
||||
register_counter!(
|
||||
"backtesting_backtests_completed_total",
|
||||
@@ -35,6 +41,7 @@ pub static BACKTESTS_COMPLETED: Lazy<Counter> = Lazy::new(|| {
|
||||
});
|
||||
|
||||
/// Total number of backtest errors
|
||||
#[allow(clippy::expect_used)]
|
||||
pub static BACKTEST_ERRORS: Lazy<Counter> = Lazy::new(|| {
|
||||
register_counter!(
|
||||
"backtesting_errors_total",
|
||||
|
||||
Reference in New Issue
Block a user