fix: validation hardening — agent import prompt limit, relay retry tracking, heartbeat validation
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
- agent_import: add system_prompt length validation (max 50K chars) to prevent excessive token consumption from imported configs - relay retry_task: wrap JoinHandle to log abort on server shutdown - device_heartbeat: validate device_id length (1-64 chars) matching register endpoint constraints
This commit is contained in:
@@ -283,6 +283,11 @@ pub async fn device_heartbeat(
|
|||||||
.and_then(|v| v.as_str())
|
.and_then(|v| v.as_str())
|
||||||
.ok_or_else(|| SaasError::InvalidInput("缺少 device_id".into()))?;
|
.ok_or_else(|| SaasError::InvalidInput("缺少 device_id".into()))?;
|
||||||
|
|
||||||
|
// Validate device_id length (must match register endpoint constraints)
|
||||||
|
if device_id.is_empty() || device_id.len() > 64 {
|
||||||
|
return Err(SaasError::InvalidInput("device_id 长度必须在 1-64 个字符之间".into()));
|
||||||
|
}
|
||||||
|
|
||||||
let now = chrono::Utc::now();
|
let now = chrono::Utc::now();
|
||||||
|
|
||||||
// Also update platform/app_version if provided (supports client upgrades)
|
// Also update platform/app_version if provided (supports client upgrades)
|
||||||
|
|||||||
@@ -550,7 +550,7 @@ pub async fn retry_task(
|
|||||||
// 异步执行重试 — 根据解析结果选择执行路径
|
// 异步执行重试 — 根据解析结果选择执行路径
|
||||||
let db = state.db.clone();
|
let db = state.db.clone();
|
||||||
let task_id = id.clone();
|
let task_id = id.clone();
|
||||||
tokio::spawn(async move {
|
let handle = tokio::spawn(async move {
|
||||||
let result = match model_resolution {
|
let result = match model_resolution {
|
||||||
ModelResolution::Direct(ref candidate) => {
|
ModelResolution::Direct(ref candidate) => {
|
||||||
service::execute_relay(
|
service::execute_relay(
|
||||||
@@ -575,6 +575,13 @@ pub async fn retry_task(
|
|||||||
Err(e) => tracing::warn!("Relay task {} 重试失败: {}", task_id, e),
|
Err(e) => tracing::warn!("Relay task {} 重试失败: {}", task_id, e),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// Detach with warning — if server shuts down mid-retry, the task is lost.
|
||||||
|
// The DB status is already reset to 'queued', so a future restart can pick it up.
|
||||||
|
tokio::spawn(async move {
|
||||||
|
if let Err(e) = handle.await {
|
||||||
|
tracing::warn!("Relay retry task aborted (server shutdown?): {}", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 异步派发操作日志
|
// 异步派发操作日志
|
||||||
state.dispatch_log_operation(
|
state.dispatch_log_operation(
|
||||||
|
|||||||
@@ -295,6 +295,18 @@ pub async fn agent_import(
|
|||||||
let mut config: AgentConfig = serde_json::from_str(&config_json)
|
let mut config: AgentConfig = serde_json::from_str(&config_json)
|
||||||
.map_err(|e| format!("Invalid agent config JSON: {}", e))?;
|
.map_err(|e| format!("Invalid agent config JSON: {}", e))?;
|
||||||
|
|
||||||
|
// Validate system_prompt length to prevent excessive token consumption
|
||||||
|
const MAX_SYSTEM_PROMPT_LEN: usize = 50_000;
|
||||||
|
if let Some(ref prompt) = config.system_prompt {
|
||||||
|
if prompt.len() > MAX_SYSTEM_PROMPT_LEN {
|
||||||
|
return Err(format!(
|
||||||
|
"system_prompt too long: {} chars (max {})",
|
||||||
|
prompt.len(),
|
||||||
|
MAX_SYSTEM_PROMPT_LEN
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Regenerate ID to avoid collisions
|
// Regenerate ID to avoid collisions
|
||||||
config.id = AgentId::new();
|
config.id = AgentId::new();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user