ci: enforce clippy -D warnings and cargo audit as hard gates
All checks were successful
Build and Test / Build Agent (Windows) (push) Successful in 12m18s
Build and Test / Build Server (Linux) (push) Successful in 14m11s
Build and Test / Security Audit (push) Successful in 5m32s
Build and Test / Build Summary (push) Successful in 9s

Flip both CI gates from informational to hard-fail (SPEC-001 quality gates):
- clippy: `-- -D warnings` on the server crate. Cleared the debt via clippy --fix
  (unused imports/style), targeted #[allow(dead_code)] on native-remote-control
  future API, and #[allow(clippy::too_many_arguments)] on 3 protocol-mirroring fns.
- cargo audit: hard-fail with documented per-ID --ignore flags (rsa RUSTSEC-2023-0071
  unfixable/unreachable in active tree; gtk-rs + glib Linux-only tray backend not
  compiled into the Windows agent; proc-macro-error build-time). New advisories fail.
- Move [profile.release] to the workspace root (it was silently ignored in the server
  member), activating lto/codegen-units/strip.

No behavioral changes. Reviewed and gates verified passing on the build host.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-30 00:18:50 +00:00
parent 6e7e7c0ccb
commit ccc6ba9c02
21 changed files with 92 additions and 55 deletions

View File

@@ -57,11 +57,10 @@ jobs:
- name: Check formatting
run: cd server && cargo fmt --all -- --check
# Informational (warn-only) for now. The pre-spec codebase has ~65 lint warnings,
# mostly dead-code for API the integration spec (native-remote-control) will wire.
# Re-tighten to `-- -D warnings` during the GC re-spec once that API is in use.
- name: Run Clippy (informational)
run: cd server && cargo clippy --all-targets --all-features
# Hard gate: clippy must pass with zero warnings (-D warnings). Dead-code that is
# future API surface for native-remote-control carries targeted #[allow(dead_code)].
- name: Run Clippy
run: cd server && cargo clippy --all-targets --all-features -- -D warnings
- name: Build server
run: |
@@ -143,12 +142,18 @@ jobs:
- name: Install cargo-audit
run: cargo install cargo-audit
# Informational (warn-only) for now, like clippy. GuruConnect is a single Cargo workspace,
# so one `cargo audit` at the root covers all members (agent + server) via the shared
# Cargo.lock. The pre-spec dependency tree has known advisories; re-tighten to a hard gate
# during the GC re-spec after a dependency refresh.
- name: Run security audit (informational)
run: cargo audit || echo "[WARNING] cargo audit reported advisories (informational; address in GC re-spec)"
# Hard gate: cargo audit must pass. GuruConnect is a single Cargo workspace, so one
# `cargo audit` at the root covers all members (agent + server) via the shared Cargo.lock.
# The advisories below are explicitly ignored with documented justifications; any NEW
# advisory fails the build.
# RUSTSEC-2023-0071 (rsa) ............. no fixed upgrade; optional/unreachable in active tree
# RUSTSEC-2024-0413/-0416/-0412/-0418/
# -0415/-0420/-0419 (gtk-rs GTK3) ..... Linux-only tray-icon backend, not compiled into shipping Windows agent
# RUSTSEC-2024-0429 (glib) ............ Linux-only tray-icon backend, not compiled into shipping Windows agent
# RUSTSEC-2024-0370 (proc-macro-error) build-time proc-macro dependency, no runtime impact
- name: Run security audit
run: |
cargo audit --ignore RUSTSEC-2023-0071 --ignore RUSTSEC-2024-0413 --ignore RUSTSEC-2024-0416 --ignore RUSTSEC-2024-0412 --ignore RUSTSEC-2024-0418 --ignore RUSTSEC-2024-0415 --ignore RUSTSEC-2024-0420 --ignore RUSTSEC-2024-0419 --ignore RUSTSEC-2024-0429 --ignore RUSTSEC-2024-0370
build-summary:
name: Build Summary

View File

@@ -25,3 +25,8 @@ anyhow = "1"
thiserror = "1"
uuid = { version = "1", features = ["v4", "serde"] }
chrono = { version = "0.4", features = ["serde"] }
[profile.release]
lto = true
codegen-units = 1
strip = true

View File

@@ -60,8 +60,3 @@ prometheus-client = "0.22"
[build-dependencies]
prost-build = "0.13"
[profile.release]
lto = true
codegen-units = 1
strip = true

View File

@@ -1,13 +1,9 @@
//! Authentication API endpoints
use axum::{
extract::{Request, State},
http::StatusCode,
Json,
};
use axum::{extract::State, http::StatusCode, Json};
use serde::{Deserialize, Serialize};
use crate::auth::{verify_password, AuthenticatedUser, JwtConfig};
use crate::auth::{verify_password, AuthenticatedUser};
use crate::db;
use crate::AppState;

View File

@@ -1,7 +1,7 @@
//! Logout and token revocation endpoints
use axum::{
extract::{Path, Request, State},
extract::{Request, State},
http::{HeaderMap, StatusCode},
Json,
};
@@ -97,7 +97,7 @@ pub struct RevokeUserRequest {
///
/// For MVP, we're implementing the foundation but not the full user tracking.
pub async fn revoke_user_tokens(
State(state): State<AppState>,
State(_state): State<AppState>,
admin: AuthenticatedUser,
Json(req): Json<RevokeUserRequest>,
) -> Result<Json<LogoutResponse>, (StatusCode, Json<ErrorResponse>)> {

View File

@@ -7,13 +7,13 @@
use axum::{
body::Body,
extract::{Path, Query, State},
extract::Query,
http::{header, StatusCode},
response::{IntoResponse, Response},
};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use tracing::{error, info, warn};
use tracing::{error, info};
/// Magic marker for embedded configuration (must match agent)
const MAGIC_MARKER: &[u8] = b"GURUCONFIG";

View File

@@ -8,7 +8,7 @@ pub mod releases;
pub mod users;
use axum::{
extract::{Path, Query, State},
extract::{Path, State},
Json,
};
use serde::{Deserialize, Serialize};
@@ -78,12 +78,14 @@ impl From<crate::session::Session> for SessionInfo {
}
/// List all active sessions
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn list_sessions(State(sessions): State<SessionManager>) -> Json<Vec<SessionInfo>> {
let sessions = sessions.list_sessions().await;
Json(sessions.into_iter().map(SessionInfo::from).collect())
}
/// Get a specific session by ID
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn get_session(
State(sessions): State<SessionManager>,
Path(id): Path<String>,

View File

@@ -23,11 +23,14 @@ pub struct AuthenticatedUser {
pub user_id: String,
pub username: String,
pub role: String,
#[allow(dead_code)]
// TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub permissions: Vec<String>,
}
impl AuthenticatedUser {
/// Check if user has a specific permission
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub fn has_permission(&self, permission: &str) -> bool {
if self.role == "admin" {
return true;
@@ -54,6 +57,7 @@ impl From<Claims> for AuthenticatedUser {
/// Authenticated agent from API key
#[derive(Debug, Clone)]
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub struct AuthenticatedAgent {
pub agent_id: String,
pub org_id: String,
@@ -61,11 +65,13 @@ pub struct AuthenticatedAgent {
/// JWT configuration stored in app state
#[derive(Clone)]
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub struct AuthState {
pub jwt_config: Arc<JwtConfig>,
}
impl AuthState {
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub fn new(jwt_secret: String, expiry_hours: i64) -> Self {
Self {
jwt_config: Arc::new(JwtConfig::new(jwt_secret, expiry_hours)),
@@ -122,6 +128,7 @@ where
/// Optional authenticated user (doesn't reject if not authenticated)
#[derive(Debug, Clone)]
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub struct OptionalUser(pub Option<AuthenticatedUser>);
#[axum::async_trait]
@@ -161,6 +168,7 @@ where
}
/// Validate an agent API key (placeholder for MVP)
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub fn validate_agent_key(_api_key: &str) -> Option<AuthenticatedAgent> {
// TODO: Implement actual API key validation against database
// For now, accept any key for agent connections

View File

@@ -5,6 +5,7 @@ use serde::Deserialize;
use std::env;
#[derive(Debug, Clone, Deserialize)]
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub struct Config {
/// Address to listen on (e.g., "0.0.0.0:8080")
pub listen_addr: String,

View File

@@ -26,10 +26,13 @@ pub struct EventTypes;
impl EventTypes {
pub const SESSION_STARTED: &'static str = "session_started";
pub const SESSION_ENDED: &'static str = "session_ended";
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub const SESSION_TIMEOUT: &'static str = "session_timeout";
pub const VIEWER_JOINED: &'static str = "viewer_joined";
pub const VIEWER_LEFT: &'static str = "viewer_left";
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub const STREAMING_STARTED: &'static str = "streaming_started";
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub const STREAMING_STOPPED: &'static str = "streaming_stopped";
// Failed connection events (security audit trail)
@@ -75,6 +78,7 @@ pub async fn log_event(
}
/// Get events for a session
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn get_session_events(
pool: &PgPool,
session_id: Uuid,
@@ -88,6 +92,7 @@ pub async fn get_session_events(
}
/// Get recent events (for dashboard)
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn get_recent_events(
pool: &PgPool,
limit: i64,
@@ -101,6 +106,7 @@ pub async fn get_recent_events(
}
/// Get events by type
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn get_events_by_type(
pool: &PgPool,
event_type: &str,

View File

@@ -48,6 +48,7 @@ pub async fn upsert_machine(
}
/// Update machine status and info
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn update_machine_status(
pool: &PgPool,
agent_id: &str,

View File

@@ -15,11 +15,7 @@ use sqlx::postgres::PgPoolOptions;
use sqlx::PgPool;
use tracing::info;
pub use events::*;
pub use machines::*;
pub use releases::*;
pub use sessions::*;
pub use support_codes::*;
pub use users::*;
/// Database connection pool wrapper

View File

@@ -20,6 +20,7 @@ pub struct Release {
}
/// Create a new release
#[allow(clippy::too_many_arguments)] // signature mirrors the relay/session protocol contract; refactor into a params struct tracked in docs/specs/native-remote-control/
pub async fn create_release(
pool: &PgPool,
version: &str,
@@ -157,6 +158,7 @@ pub async fn update_machine_update_status(
}
/// Get machines that need updates (version < latest stable)
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn get_machines_needing_update(
pool: &PgPool,
latest_version: &str,

View File

@@ -64,6 +64,7 @@ pub async fn end_session(
}
/// Get session by ID
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn get_session(
pool: &PgPool,
session_id: Uuid,
@@ -75,6 +76,7 @@ pub async fn get_session(
}
/// Get active sessions for a machine
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn get_active_sessions_for_machine(
pool: &PgPool,
machine_id: Uuid,
@@ -88,6 +90,7 @@ pub async fn get_active_sessions_for_machine(
}
/// Get recent sessions (for dashboard)
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn get_recent_sessions(pool: &PgPool, limit: i64) -> Result<Vec<DbSession>, sqlx::Error> {
sqlx::query_as::<_, DbSession>(
"SELECT * FROM connect_sessions ORDER BY started_at DESC LIMIT $1",

View File

@@ -7,6 +7,7 @@ use uuid::Uuid;
/// Support code record from database
#[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)]
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub struct DbSupportCode {
pub id: Uuid,
pub code: String,
@@ -21,6 +22,7 @@ pub struct DbSupportCode {
}
/// Create a new support code
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn create_support_code(
pool: &PgPool,
code: &str,
@@ -40,6 +42,7 @@ pub async fn create_support_code(
}
/// Get support code by code string
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn get_support_code(
pool: &PgPool,
code: &str,
@@ -88,6 +91,7 @@ pub async fn mark_code_completed(pool: &PgPool, code: &str) -> Result<(), sqlx::
}
/// Mark support code as cancelled
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn mark_code_cancelled(pool: &PgPool, code: &str) -> Result<(), sqlx::Error> {
sqlx::query("UPDATE connect_support_codes SET status = 'cancelled' WHERE code = $1")
.bind(code)
@@ -97,6 +101,7 @@ pub async fn mark_code_cancelled(pool: &PgPool, code: &str) -> Result<(), sqlx::
}
/// Get active support codes (pending or connected)
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn get_active_support_codes(pool: &PgPool) -> Result<Vec<DbSupportCode>, sqlx::Error> {
sqlx::query_as::<_, DbSupportCode>(
"SELECT * FROM connect_support_codes WHERE status IN ('pending', 'connected') ORDER BY created_at DESC"
@@ -106,6 +111,7 @@ pub async fn get_active_support_codes(pool: &PgPool) -> Result<Vec<DbSupportCode
}
/// Check if code exists and is valid for connection
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn is_code_valid(pool: &PgPool, code: &str) -> Result<bool, sqlx::Error> {
let result = sqlx::query_scalar::<_, bool>(
"SELECT EXISTS(SELECT 1 FROM connect_support_codes WHERE code = $1 AND status = 'pending')",
@@ -117,6 +123,7 @@ pub async fn is_code_valid(pool: &PgPool, code: &str) -> Result<bool, sqlx::Erro
}
/// Check if code is cancelled
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn is_code_cancelled(pool: &PgPool, code: &str) -> Result<bool, sqlx::Error> {
let result = sqlx::query_scalar::<_, bool>(
"SELECT EXISTS(SELECT 1 FROM connect_support_codes WHERE code = $1 AND status = 'cancelled')"
@@ -128,6 +135,7 @@ pub async fn is_code_cancelled(pool: &PgPool, code: &str) -> Result<bool, sqlx::
}
/// Link session to support code
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn link_session_to_code(
pool: &PgPool,
code: &str,

View File

@@ -15,12 +15,15 @@ pub struct User {
pub role: String,
pub enabled: bool,
pub created_at: DateTime<Utc>,
#[allow(dead_code)]
// TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub updated_at: DateTime<Utc>,
pub last_login: Option<DateTime<Utc>>,
}
/// User without password hash (for API responses)
#[derive(Debug, Clone, serde::Serialize)]
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub struct UserInfo {
pub id: Uuid,
pub username: String,
@@ -193,6 +196,7 @@ pub async fn set_user_permissions(
}
/// Get user's accessible client IDs (empty = all access)
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn get_user_client_access(pool: &PgPool, user_id: Uuid) -> Result<Vec<Uuid>> {
let clients: Vec<(Uuid,)> =
sqlx::query_as("SELECT client_id FROM user_client_access WHERE user_id = $1")
@@ -226,6 +230,7 @@ pub async fn set_user_client_access(
}
/// Check if user has access to a specific client
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn user_has_client_access(pool: &PgPool, user_id: Uuid, client_id: Uuid) -> Result<bool> {
// Admins have access to all
let user = get_user_by_id(pool, user_id).await?;

View File

@@ -31,7 +31,7 @@ use axum::{
use serde::Deserialize;
use std::net::SocketAddr;
use std::sync::Arc;
use tower_http::cors::{AllowOrigin, Any, CorsLayer};
use tower_http::cors::CorsLayer;
use tower_http::services::ServeDir;
use tower_http::trace::TraceLayer;
use tracing::{info, Level};
@@ -76,7 +76,7 @@ async fn auth_layer(
#[tokio::main]
async fn main() -> Result<()> {
// Initialize logging
let _subscriber = FmtSubscriber::builder()
FmtSubscriber::builder()
.with_max_level(Level::INFO)
.with_target(true)
.init();
@@ -359,7 +359,7 @@ async fn main() -> Result<()> {
.layer(TraceLayer::new_for_http())
// SEC-11: Restricted CORS configuration
.layer({
let cors = CorsLayer::new()
CorsLayer::new()
// Allow requests from the production domain and localhost (for development)
.allow_origin([
"https://connect.azcomputerguru.com"
@@ -383,8 +383,7 @@ async fn main() -> Result<()> {
axum::http::header::ACCEPT,
])
// Allow credentials (cookies, auth headers)
.allow_credentials(true);
cors
.allow_credentials(true)
});
// Start server
@@ -437,6 +436,7 @@ async fn list_codes(
}
#[derive(Deserialize)]
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
struct ValidateParams {
code: String,
}

View File

@@ -288,6 +288,7 @@ pub async fn viewer_ws_handler(
}
/// Handle an agent WebSocket connection
#[allow(clippy::too_many_arguments)] // signature mirrors the relay/session protocol contract; refactor into a params struct tracked in docs/specs/native-remote-control/
async fn handle_agent_connection(
socket: WebSocket,
sessions: SessionManager,
@@ -318,7 +319,7 @@ async fn handle_agent_connection(
};
let mut buf = Vec::new();
if prost::Message::encode(&disconnect_msg, &mut buf).is_ok() {
let _ = ws_sender.send(Message::Binary(buf.into())).await;
let _ = ws_sender.send(Message::Binary(buf)).await;
}
let _ = ws_sender.close().await;
return;
@@ -335,7 +336,7 @@ async fn handle_agent_connection(
info!("Session created: {} (agent in idle mode)", session_id);
// Database: upsert machine and create session record
let machine_id = if let Some(ref db) = db {
let _machine_id = if let Some(ref db) = db {
match db::machines::upsert_machine(db.pool(), &agent_id, &agent_name, is_persistent).await {
Ok(machine) => {
// Create session record
@@ -401,11 +402,7 @@ async fn handle_agent_connection(
let input_forward = tokio::spawn(async move {
while let Some(input_data) = input_rx.recv().await {
let mut sender = ws_sender_input.lock().await;
if sender
.send(Message::Binary(input_data.into()))
.await
.is_err()
{
if sender.send(Message::Binary(input_data)).await.is_err() {
break;
}
}
@@ -435,7 +432,7 @@ async fn handle_agent_connection(
let mut buf = Vec::new();
if prost::Message::encode(&disconnect_msg, &mut buf).is_ok() {
let mut sender = ws_sender_cancel.lock().await;
let _ = sender.send(Message::Binary(buf.into())).await;
let _ = sender.send(Message::Binary(buf)).await;
let _ = sender.close().await;
}
break;
@@ -651,11 +648,7 @@ async fn handle_viewer_connection(
// Task to forward frames from agent to this viewer
let frame_forward = tokio::spawn(async move {
while let Ok(frame_data) = frame_rx.recv().await {
if ws_sender
.send(Message::Binary(frame_data.into()))
.await
.is_err()
{
if ws_sender.send(Message::Binary(frame_data)).await.is_err() {
break;
}
}

View File

@@ -27,6 +27,7 @@ pub struct ViewerInfo {
}
/// Heartbeat timeout (90 seconds - 3x the agent's 30 second interval)
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
const HEARTBEAT_TIMEOUT_SECS: u64 = 90;
/// Session state
@@ -68,6 +69,8 @@ struct SessionData {
frame_tx: FrameSender,
/// Channel for input events (viewer -> agent)
input_tx: InputSender,
#[allow(dead_code)]
// TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
input_rx: Option<InputReceiver>,
/// Map of connected viewers (id -> info)
viewers: HashMap<ViewerId, ViewerInfo>,
@@ -176,6 +179,7 @@ impl SessionManager {
}
/// Update agent status from heartbeat or status message
#[allow(clippy::too_many_arguments)] // signature mirrors the relay/session protocol contract; refactor into a params struct tracked in docs/specs/native-remote-control/
pub async fn update_agent_status(
&self,
session_id: SessionId,
@@ -225,6 +229,7 @@ impl SessionManager {
}
/// Check if a session has timed out (no heartbeat for too long)
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn is_session_timed_out(&self, session_id: SessionId) -> bool {
let sessions = self.sessions.read().await;
if let Some(session_data) = sessions.get(&session_id) {
@@ -235,6 +240,7 @@ impl SessionManager {
}
/// Get sessions that have timed out
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn get_timed_out_sessions(&self) -> Vec<SessionId> {
let sessions = self.sessions.read().await;
sessions
@@ -471,11 +477,9 @@ impl SessionManager {
};
let mut buf = Vec::new();
if admin_cmd.encode(&mut buf).is_ok() {
if session_data.input_tx.send(buf).await.is_ok() {
tracing::info!("Sent admin command {:?} to session {}", command, session_id);
return true;
}
if admin_cmd.encode(&mut buf).is_ok() && session_data.input_tx.send(buf).await.is_ok() {
tracing::info!("Sent admin command {:?} to session {}", command, session_id);
return true;
}
}
false

View File

@@ -36,6 +36,8 @@ pub enum CodeStatus {
/// Request to create a new support code
#[derive(Debug, Deserialize)]
pub struct CreateCodeRequest {
#[allow(dead_code)]
// TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub technician_id: Option<String>,
pub technician_name: Option<String>,
}
@@ -172,6 +174,7 @@ impl SupportCodeManager {
}
/// Get code by its code string
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn get_code(&self, code: &str) -> Option<SupportCode> {
let codes = self.codes.read().await;
codes.get(code).cloned()
@@ -209,6 +212,7 @@ impl SupportCodeManager {
}
/// Check if a code is valid for connection (exists and is pending)
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn is_valid_for_connection(&self, code: &str) -> bool {
let codes = self.codes.read().await;
codes
@@ -218,6 +222,7 @@ impl SupportCodeManager {
}
/// List all codes (for dashboard)
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn list_codes(&self) -> Vec<SupportCode> {
let codes = self.codes.read().await;
codes.values().cloned().collect()
@@ -234,6 +239,7 @@ impl SupportCodeManager {
}
/// Get code by session ID
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub async fn get_by_session(&self, session_id: Uuid) -> Option<SupportCode> {
let session_to_code = self.session_to_code.read().await;
let code = session_to_code.get(&session_id)?;

View File

@@ -1,6 +1,5 @@
//! IP address extraction from WebSocket connections
use axum::extract::ConnectInfo;
use std::net::{IpAddr, SocketAddr};
/// Extract IP address from Axum ConnectInfo
@@ -12,11 +11,13 @@ use std::net::{IpAddr, SocketAddr};
/// // Use ip for logging
/// }
/// ```
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub fn extract_ip(addr: &SocketAddr) -> IpAddr {
addr.ip()
}
/// Extract IP address as string
#[allow(dead_code)] // TODO(native-remote-control): consumed by the integration API; see docs/specs/native-remote-control/
pub fn extract_ip_string(addr: &SocketAddr) -> String {
addr.ip().to_string()
}