Fix USB policy reporting and improve agent reliability
- Fix Zod schema to accept null values (nullable) for error/currentPolicy - Add robust logging system writing to raven-agent.log file - Rewrite auto-start using winreg with validation - Auto-start agent on app setup if credentials exist - Reduce retry attempts to 2 (1 + 1 retry after 2s) - Replace provider's remote access on ID change (prevents duplicates) - Update agent to v0.2.0 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
b60255fe03
commit
20b63f4ad6
5 changed files with 290 additions and 62 deletions
|
|
@ -1185,12 +1185,17 @@ struct UsbPolicyStatusReport {
|
|||
}
|
||||
|
||||
async fn check_and_apply_usb_policy(base_url: &str, token: &str) {
|
||||
crate::log_info!("Verificando politica USB pendente...");
|
||||
|
||||
let url = format!("{}/api/machines/usb-policy?machineToken={}", base_url, token);
|
||||
|
||||
let response = match HTTP_CLIENT.get(&url).send().await {
|
||||
Ok(resp) => resp,
|
||||
Ok(resp) => {
|
||||
crate::log_info!("Resposta da verificacao de politica USB: status={}", resp.status());
|
||||
resp
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("[agent] Falha ao verificar politica USB: {e}");
|
||||
crate::log_error!("Falha ao verificar politica USB: {e}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
|
@ -1198,23 +1203,26 @@ async fn check_and_apply_usb_policy(base_url: &str, token: &str) {
|
|||
let policy_response: UsbPolicyResponse = match response.json().await {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
eprintln!("[agent] Falha ao parsear resposta de politica USB: {e}");
|
||||
crate::log_error!("Falha ao parsear resposta de politica USB: {e}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if !policy_response.pending {
|
||||
crate::log_info!("Nenhuma politica USB pendente");
|
||||
return;
|
||||
}
|
||||
|
||||
let policy_str = match policy_response.policy {
|
||||
Some(p) => p,
|
||||
None => {
|
||||
eprintln!("[agent] Politica USB pendente mas sem valor de policy");
|
||||
crate::log_warn!("Politica USB pendente mas sem valor de policy");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
crate::log_info!("Politica USB pendente encontrada: {}", policy_str);
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
use crate::usb_control::{apply_usb_policy, get_current_policy, UsbPolicy};
|
||||
|
|
@ -1222,7 +1230,7 @@ async fn check_and_apply_usb_policy(base_url: &str, token: &str) {
|
|||
let policy = match UsbPolicy::from_str(&policy_str) {
|
||||
Some(p) => p,
|
||||
None => {
|
||||
eprintln!("[agent] Politica USB invalida: {}", policy_str);
|
||||
crate::log_error!("Politica USB invalida: {}", policy_str);
|
||||
report_usb_policy_status(base_url, token, "FAILED", Some(format!("Politica invalida: {}", policy_str)), None).await;
|
||||
return;
|
||||
}
|
||||
|
|
@ -1231,30 +1239,44 @@ async fn check_and_apply_usb_policy(base_url: &str, token: &str) {
|
|||
// Verifica se a politica ja esta aplicada localmente
|
||||
match get_current_policy() {
|
||||
Ok(current) if current == policy => {
|
||||
eprintln!("[agent] Politica USB ja esta aplicada localmente: {}", policy_str);
|
||||
report_usb_policy_status(base_url, token, "APPLIED", None, Some(policy_str)).await;
|
||||
crate::log_info!("Politica USB ja esta aplicada localmente: {}", policy_str);
|
||||
let reported = report_usb_policy_status(base_url, token, "APPLIED", None, Some(policy_str.clone())).await;
|
||||
if !reported {
|
||||
crate::log_error!("Falha ao reportar politica ja aplicada");
|
||||
}
|
||||
return;
|
||||
}
|
||||
Ok(current) => {
|
||||
eprintln!("[agent] Politica atual: {:?}, esperada: {:?}", current, policy);
|
||||
crate::log_info!("Politica atual: {:?}, esperada: {:?}", current, policy);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("[agent] Nao foi possivel ler politica atual: {e}");
|
||||
crate::log_warn!("Nao foi possivel ler politica atual: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
eprintln!("[agent] Aplicando politica USB: {}", policy_str);
|
||||
crate::log_info!("Aplicando politica USB: {}", policy_str);
|
||||
|
||||
// Reporta APPLYING para progress bar real no frontend
|
||||
report_usb_policy_status(base_url, token, "APPLYING", None, None).await;
|
||||
let _ = report_usb_policy_status(base_url, token, "APPLYING", None, None).await;
|
||||
|
||||
match apply_usb_policy(policy) {
|
||||
Ok(result) => {
|
||||
eprintln!("[agent] Politica USB aplicada com sucesso: {:?}", result);
|
||||
report_usb_policy_status(base_url, token, "APPLIED", None, Some(policy_str)).await;
|
||||
crate::log_info!("Politica USB aplicada com sucesso: {:?}", result);
|
||||
let reported = report_usb_policy_status(base_url, token, "APPLIED", None, Some(policy_str.clone())).await;
|
||||
if !reported {
|
||||
crate::log_error!("CRITICO: Politica aplicada mas falha ao reportar ao servidor!");
|
||||
// Agenda retry em background
|
||||
let base_url = base_url.to_string();
|
||||
let token = token.to_string();
|
||||
tokio::spawn(async move {
|
||||
tokio::time::sleep(Duration::from_secs(60)).await;
|
||||
crate::log_info!("Retry agendado: reportando politica USB...");
|
||||
let _ = report_usb_policy_status(&base_url, &token, "APPLIED", None, Some(policy_str)).await;
|
||||
});
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("[agent] Falha ao aplicar politica USB: {e}");
|
||||
crate::log_error!("Falha ao aplicar politica USB: {e}");
|
||||
report_usb_policy_status(base_url, token, "FAILED", Some(e.to_string()), None).await;
|
||||
}
|
||||
}
|
||||
|
|
@ -1262,7 +1284,7 @@ async fn check_and_apply_usb_policy(base_url: &str, token: &str) {
|
|||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
eprintln!("[agent] Controle de USB nao suportado neste sistema operacional");
|
||||
crate::log_warn!("Controle de USB nao suportado neste sistema operacional");
|
||||
report_usb_policy_status(base_url, token, "FAILED", Some("Sistema operacional nao suportado".to_string()), None).await;
|
||||
}
|
||||
}
|
||||
|
|
@ -1273,7 +1295,7 @@ async fn report_usb_policy_status(
|
|||
status: &str,
|
||||
error: Option<String>,
|
||||
current_policy: Option<String>,
|
||||
) {
|
||||
) -> bool {
|
||||
let url = format!("{}/api/machines/usb-policy", base_url);
|
||||
|
||||
let report = UsbPolicyStatusReport {
|
||||
|
|
@ -1283,39 +1305,56 @@ async fn report_usb_policy_status(
|
|||
current_policy,
|
||||
};
|
||||
|
||||
// Retry com backoff exponencial: 2s, 4s, 8s
|
||||
let delays = [2, 4, 8];
|
||||
crate::log_info!("Reportando status de politica USB: status={}", status);
|
||||
|
||||
// Retry simples: 1 tentativa imediata + 1 retry após 2s
|
||||
let delays = [2];
|
||||
let mut last_error = None;
|
||||
|
||||
for (attempt, delay_secs) in delays.iter().enumerate() {
|
||||
match HTTP_CLIENT.post(&url).json(&report).send().await {
|
||||
Ok(response) if response.status().is_success() => {
|
||||
if attempt > 0 {
|
||||
eprintln!("[agent] Report de politica USB enviado na tentativa {}", attempt + 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
Ok(response) => {
|
||||
last_error = Some(format!("HTTP {}", response.status()));
|
||||
let status_code = response.status();
|
||||
if status_code.is_success() {
|
||||
crate::log_info!(
|
||||
"Report de politica USB enviado com sucesso na tentativa {}",
|
||||
attempt + 1
|
||||
);
|
||||
return true;
|
||||
} else {
|
||||
let body = response.text().await.unwrap_or_default();
|
||||
last_error = Some(format!("HTTP {} - {}", status_code, body));
|
||||
crate::log_warn!(
|
||||
"Report de politica USB falhou (tentativa {}): HTTP {}",
|
||||
attempt + 1,
|
||||
status_code
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
last_error = Some(e.to_string());
|
||||
crate::log_warn!(
|
||||
"Report de politica USB falhou (tentativa {}): {}",
|
||||
attempt + 1,
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if attempt < delays.len() - 1 {
|
||||
eprintln!(
|
||||
"[agent] Falha ao reportar politica USB (tentativa {}), retentando em {}s...",
|
||||
attempt + 1,
|
||||
delay_secs
|
||||
);
|
||||
crate::log_info!("Retentando report de politica USB em {}s...", delay_secs);
|
||||
tokio::time::sleep(Duration::from_secs(*delay_secs)).await;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(err) = last_error {
|
||||
eprintln!("[agent] Falha ao reportar status de politica USB apos 3 tentativas: {err}");
|
||||
crate::log_error!(
|
||||
"Falha ao reportar status de politica USB apos {} tentativas: {err}",
|
||||
delays.len()
|
||||
);
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
struct HeartbeatHandle {
|
||||
|
|
@ -1332,9 +1371,9 @@ impl HeartbeatHandle {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Clone)]
|
||||
pub struct AgentRuntime {
|
||||
inner: Mutex<Option<HeartbeatHandle>>,
|
||||
inner: Arc<Mutex<Option<HeartbeatHandle>>>,
|
||||
}
|
||||
|
||||
fn sanitize_base_url(input: &str) -> Result<String, AgentError> {
|
||||
|
|
@ -1348,7 +1387,7 @@ fn sanitize_base_url(input: &str) -> Result<String, AgentError> {
|
|||
impl AgentRuntime {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inner: Mutex::new(None),
|
||||
inner: Arc::new(Mutex::new(None)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1381,24 +1420,29 @@ impl AgentRuntime {
|
|||
let status_clone = status.clone();
|
||||
|
||||
let join_handle = async_runtime::spawn(async move {
|
||||
crate::log_info!("Loop de agente iniciado");
|
||||
|
||||
if let Err(error) =
|
||||
post_heartbeat(&base_clone, &token_clone, status_clone.clone()).await
|
||||
{
|
||||
eprintln!("[agent] Falha inicial ao enviar heartbeat: {error}");
|
||||
crate::log_error!("Falha inicial ao enviar heartbeat: {error}");
|
||||
} else {
|
||||
crate::log_info!("Heartbeat inicial enviado com sucesso");
|
||||
}
|
||||
|
||||
// Verifica politica USB apos heartbeat inicial
|
||||
check_and_apply_usb_policy(&base_clone, &token_clone).await;
|
||||
|
||||
let mut heartbeat_ticker = tokio::time::interval(Duration::from_secs(interval));
|
||||
heartbeat_ticker.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
|
||||
let mut usb_ticker = tokio::time::interval(Duration::from_secs(15));
|
||||
usb_ticker.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
|
||||
let mut heartbeat_ticker = tokio::time::interval(Duration::from_secs(interval));
|
||||
heartbeat_ticker.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
|
||||
let mut usb_ticker = tokio::time::interval(Duration::from_secs(15));
|
||||
usb_ticker.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
|
||||
|
||||
loop {
|
||||
// Wait interval
|
||||
tokio::select! {
|
||||
_ = stop_signal_clone.notified() => {
|
||||
crate::log_info!("Loop de agente encerrado por sinal de parada");
|
||||
break;
|
||||
}
|
||||
_ = heartbeat_ticker.tick() => {}
|
||||
|
|
@ -1411,7 +1455,7 @@ impl AgentRuntime {
|
|||
if let Err(error) =
|
||||
post_heartbeat(&base_clone, &token_clone, status_clone.clone()).await
|
||||
{
|
||||
eprintln!("[agent] Falha ao enviar heartbeat: {error}");
|
||||
crate::log_error!("Falha ao enviar heartbeat: {error}");
|
||||
}
|
||||
|
||||
// Verifica politica USB apos cada heartbeat
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue