refactor: comprehensive audit — fix bugs, harden security, deduplicate providers, add CI/Docker
Some checks failed
CI / Check (push) Has been cancelled
CI / Clippy (push) Has been cancelled
CI / Formatting (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Release Build (push) Has been cancelled

Phase 1: Fix compilation (config_path Option<PathBuf>, streaming test, stale test cleanup)
Phase 2: Fix critical bugs (remove block_on deadlocks in 4 providers, fix broken SQL query builder)
Phase 3: Security hardening (session manager, real auth, token masking, Gemini key to header, password policy)
Phase 4: Implement stubs (real provider test, /proc health metrics, client/provider/backup endpoints, has_images)
Phase 5: Code quality (shared provider helpers, explicit re-exports, all Clippy warnings fixed, unwrap removal, 6 unused deps removed, dashboard split into 7 sub-modules)
Phase 6: Infrastructure (GitHub Actions CI, multi-stage Dockerfile, rustfmt.toml, clippy.toml, script fixes)
This commit is contained in:
2026-03-02 00:35:45 -05:00
parent ba643dd2b0
commit 2cdc49d7f2
42 changed files with 2800 additions and 2747 deletions

View File

@@ -1,8 +1,8 @@
use chrono::{DateTime, Utc};
use serde::Serialize;
use sqlx::SqlitePool;
use tokio::sync::broadcast;
use tracing::warn;
use serde::Serialize;
use crate::errors::AppError;
@@ -38,7 +38,7 @@ impl RequestLogger {
pub fn log_request(&self, log: RequestLog) {
let pool = self.db_pool.clone();
let tx = self.dashboard_tx.clone();
// Spawn async task to log without blocking response
tokio::spawn(async move {
// Broadcast to dashboard
@@ -77,20 +77,18 @@ impl RequestLogger {
.bind(log.status)
.bind(log.error_message)
.bind(log.duration_ms as i64)
.bind(None::<String>) // request_body - TODO: store serialized request
.bind(None::<String>) // response_body - TODO: store serialized response or error
.bind(None::<String>) // request_body - optional, not stored to save disk space
.bind(None::<String>) // response_body - optional, not stored to save disk space
.execute(&mut *tx)
.await?;
// Deduct from provider balance if successful
if log.cost > 0.0 {
sqlx::query(
"UPDATE provider_configs SET credit_balance = credit_balance - ? WHERE id = ?"
)
.bind(log.cost)
.bind(&log.provider)
.execute(&mut *tx)
.await?;
sqlx::query("UPDATE provider_configs SET credit_balance = credit_balance - ? WHERE id = ?")
.bind(log.cost)
.bind(&log.provider)
.execute(&mut *tx)
.await?;
}
tx.commit().await?;
@@ -108,32 +106,32 @@ impl RequestLogger {
// next: Next,
// ) -> Response {
// let start_time = std::time::Instant::now();
//
//
// // Extract client_id from auth or use "unknown"
// let client_id = match auth_result {
// Ok(auth) => auth.client_id,
// Err(_) => "unknown".to_string(),
// };
//
//
// // Try to extract request details
// let (request_parts, request_body) = request.into_parts();
//
//
// // Clone request parts for logging
// let path = request_parts.uri.path().to_string();
//
//
// // Check if this is a chat completion request
// let is_chat_completion = path == "/v1/chat/completions";
//
//
// // Reconstruct request for downstream handlers
// let request = Request::from_parts(request_parts, request_body);
//
//
// // Process request and get response
// let response = next.run(request).await;
//
//
// // Calculate duration
// let duration = start_time.elapsed();
// let duration_ms = duration.as_millis() as u64;
//
//
// // Log basic request info
// info!(
// "Request from {} to {} - Status: {} - Duration: {}ms",
@@ -142,10 +140,10 @@ impl RequestLogger {
// response.status().as_u16(),
// duration_ms
// );
//
//
// // TODO: Extract more details from request/response for logging
// // For now, we'll need to modify the server handler to pass additional context
//
//
// response
// }
@@ -177,26 +175,26 @@ impl LoggingContext {
error: None,
}
}
pub fn with_token_counts(mut self, prompt_tokens: u32, completion_tokens: u32) -> Self {
self.prompt_tokens = prompt_tokens;
self.completion_tokens = completion_tokens;
self.total_tokens = prompt_tokens + completion_tokens;
self
}
pub fn with_cost(mut self, cost: f64) -> Self {
self.cost = cost;
self
}
pub fn with_images(mut self, has_images: bool) -> Self {
self.has_images = has_images;
self
}
pub fn with_error(mut self, error: AppError) -> Self {
self.error = Some(error);
self
}
}
}