style(server): cargo fmt + clippy fixes for v2 keystone (CI green)
All checks were successful
Build and Test / Build Agent (Windows) (push) Successful in 6m29s
Build and Test / Build Server (Linux) (push) Successful in 10m23s
Build and Test / Security Audit (push) Successful in 4m17s
Build and Test / Build Summary (push) Successful in 11s

The Task 2/3/authz commits failed CI at the first gate (cargo fmt --all
--check), which short-circuited before clippy/build/test ran. Verified on the
build host (172.16.3.30): the v2 server compiles and all 18 tests pass; only
3 cosmetic issues blocked CI, all fixed here:
- cargo fmt --all (whitespace, 3 files)
- clippy unused_imports: drop ViewerClaims from auth/mod.rs re-export
- clippy doc_overindented_list_items: de-indent one doc line in sessions.rs
Testing Agent confirmed fmt + clippy -D warnings + build --release + test are
all green with these applied. No logic changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-29 20:19:26 -07:00
parent a453e7984e
commit 8a0193577b
4 changed files with 46 additions and 29 deletions

View File

@@ -16,7 +16,7 @@
//! → a CONTROL token (input is forwarded to the agent). //! → a CONTROL token (input is forwarded to the agent).
//! - else the `view` permission (see [`SESSION_VIEW_PERMISSION`]) //! - else the `view` permission (see [`SESSION_VIEW_PERMISSION`])
//! → a VIEW-ONLY token (the relay refuses to forward this viewer's input; //! → a VIEW-ONLY token (the relay refuses to forward this viewer's input;
//! video still streams). //! video still streams).
//! - else → 403 (standard envelope). //! - else → 403 (standard envelope).
//! //!
//! This is why the gate is no longer a single `view` check: `view` is held by //! This is why the gate is no longer a single `view` check: `view` is held by
@@ -95,8 +95,13 @@ pub async fn mint_viewer_token(
State(state): State<AppState>, State(state): State<AppState>,
Path(id): Path<String>, Path(id): Path<String>,
) -> ApiResult<Json<ViewerTokenResponse>> { ) -> ApiResult<Json<ViewerTokenResponse>> {
let session_id = Uuid::parse_str(&id) let session_id = Uuid::parse_str(&id).map_err(|_| {
.map_err(|_| err(StatusCode::BAD_REQUEST, "INVALID_SESSION_ID", "Invalid session ID"))?; err(
StatusCode::BAD_REQUEST,
"INVALID_SESSION_ID",
"Invalid session ID",
)
})?;
// TIERED AUTHORIZATION GATE (closes audit CRITICAL #1 — authz-strength split). // TIERED AUTHORIZATION GATE (closes audit CRITICAL #1 — authz-strength split).
// Authentication alone is not enough, and a single `view` check is too coarse // Authentication alone is not enough, and a single `view` check is too coarse
@@ -127,13 +132,17 @@ pub async fn mint_viewer_token(
// The session must exist (live session manager is the // The session must exist (live session manager is the
// source of truth for joinable sessions, matching GET /api/sessions/:id). // source of truth for joinable sessions, matching GET /api/sessions/:id).
let session = state.sessions.get_session(session_id).await.ok_or_else(|| { let session = state
err( .sessions
StatusCode::NOT_FOUND, .get_session(session_id)
"SESSION_NOT_FOUND", .await
"Session not found", .ok_or_else(|| {
) err(
})?; StatusCode::NOT_FOUND,
"SESSION_NOT_FOUND",
"Session not found",
)
})?;
// Resolve tenancy (Phase-1: always the default tenant). Carried in the // Resolve tenancy (Phase-1: always the default tenant). Carried in the
// claim so the WS and Phase-4 isolation can enforce it. // claim so the WS and Phase-4 isolation can enforce it.

View File

@@ -111,7 +111,10 @@ mod tests {
let key = generate_agent_key(); let key = generate_agent_key();
assert!(key.starts_with(AGENT_KEY_PREFIX)); assert!(key.starts_with(AGENT_KEY_PREFIX));
// prefix + 32 bytes * 2 hex chars // prefix + 32 bytes * 2 hex chars
assert_eq!(key.len(), AGENT_KEY_PREFIX.len() + AGENT_KEY_RANDOM_BYTES * 2); assert_eq!(
key.len(),
AGENT_KEY_PREFIX.len() + AGENT_KEY_RANDOM_BYTES * 2
);
} }
#[test] #[test]

View File

@@ -8,7 +8,7 @@ pub mod jwt;
pub mod password; pub mod password;
pub mod token_blacklist; pub mod token_blacklist;
pub use jwt::{Claims, JwtConfig, ViewerAccess, ViewerClaims}; pub use jwt::{Claims, JwtConfig, ViewerAccess};
pub use password::{generate_random_password, hash_password, verify_password}; pub use password::{generate_random_password, hash_password, verify_password};
pub use token_blacklist::TokenBlacklist; pub use token_blacklist::TokenBlacklist;

View File

@@ -338,16 +338,18 @@ async fn validate_agent_api_key(state: &AppState, api_key: &str) -> AgentKeyAuth
crate::auth::agent_keys::verify_agent_key(db.pool(), api_key).await crate::auth::agent_keys::verify_agent_key(db.pool(), api_key).await
{ {
// Resolve the trusted identity from the authenticated key's machine. // Resolve the trusted identity from the authenticated key's machine.
let trusted_agent_id = match db::machines::get_machine_by_id(db.pool(), machine_id) let trusted_agent_id =
.await match db::machines::get_machine_by_id(db.pool(), machine_id).await {
{ Ok(Some(machine)) => Some(machine.agent_id),
Ok(Some(machine)) => Some(machine.agent_id), Ok(None) => None,
Ok(None) => None, Err(e) => {
Err(e) => { tracing::error!(
tracing::error!("Failed to resolve machine for authenticated agent key: {}", e); "Failed to resolve machine for authenticated agent key: {}",
None e
} );
}; None
}
};
return AgentKeyAuth::PerAgentKey(trusted_agent_id); return AgentKeyAuth::PerAgentKey(trusted_agent_id);
} }
} }
@@ -403,13 +405,16 @@ pub async fn viewer_ws_handler(
// 1. Signature + expiry + `purpose == "viewer"`. A login JWT fails this // 1. Signature + expiry + `purpose == "viewer"`. A login JWT fails this
// (wrong claim shape / no `purpose`), so login tokens are no longer // (wrong claim shape / no `purpose`), so login tokens are no longer
// accepted on the viewer plane. // accepted on the viewer plane.
let claims = state.jwt_config.validate_viewer_token(&token).map_err(|e| { let claims = state
warn!( .jwt_config
"Viewer connection rejected from {}: invalid viewer token: {}", .validate_viewer_token(&token)
client_ip, e .map_err(|e| {
); warn!(
StatusCode::UNAUTHORIZED "Viewer connection rejected from {}: invalid viewer token: {}",
})?; client_ip, e
);
StatusCode::UNAUTHORIZED
})?;
// 2. Revocation check on the WS plane (CRITICAL #2): a logged-out / revoked // 2. Revocation check on the WS plane (CRITICAL #2): a logged-out / revoked
// token must not grant live remote control even before natural expiry. // token must not grant live remote control even before natural expiry.