Files
acaua/crates/acaua-core/src/update.rs
T
Lucas RayanandClaude Sonnet 5 8a80504c45
Release / Plan (reuse the published image?) (push) Successful in 3s
CI / Docker image (build and smoke test) (push) Skipped
CI / Format and clippy (push) Successful in 4m32s
CI / Dependency audit (push) Successful in 11s
CI / Tests (Linux) (push) Successful in 9m15s
Release / ci (push) Successful in 9m18s
Release / Build image (arm64) (push) Failing after 7m7s
Release / Build image (amd64) (push) Failing after 13m53s
Release / Publish tags (push) Skipped
Release / Gitea release (push) Skipped
refactor: distribute Acaua as a Docker image instead of a desktop app
Acaua is a collective SOC daemon consuming only Zeek log files, not a
single-user tool needing local hardware like its siblings. Drop the
Tauri desktop shell, installers and self-update entirely; the server
and its web dashboard ship as a container, updated by pulling a new
image tag.

Link against the official prebuilt libduckdb instead of compiling it
from source via the bundled feature, cutting image build time from
15+ minutes to about 3. Fix a real bug found along the way: as PID 1
in a container, the daemon ignored SIGTERM and was always killed
after the stop timeout; it now shuts down gracefully.

Also corrects the Pillar 1 beaconing score: the period estimate had a
harmonic alias (a perfectly periodic 4h series resolved to 600s), and
the old score formula flagged pure random traffic as suspicious
(p95 = 0.839 on Poisson noise). The new formula was validated against
300 samples per scenario.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VAyr8d7HuAdUGB6aA5xmDD
2026-10-31 19:54:45 -03:00

69 lines
2.0 KiB
Rust

use crate::error::{AcauaError, Result};
use serde::{Deserialize, Serialize};
use std::process::Command;
const LATEST_RELEASE_URL: &str =
"https://git.lucasrguerra.dev.br/api/v1/repos/ciberfauna/acaua/releases/latest";
#[derive(Debug, Deserialize)]
struct Release {
tag_name: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct UpdateStatus {
pub current_version: String,
pub latest_version: Option<String>,
pub update_available: bool,
}
fn curl_text(url: &str) -> Result<String> {
let output = Command::new("curl")
.args(["-fsSL", "-H", "User-Agent: acaua-updater", url])
.output()
.map_err(|error| AcauaError::CommandFailed {
cmd: format!("curl {url}"),
detail: error.to_string(),
})?;
if !output.status.success() {
return Err(AcauaError::CommandFailed {
cmd: format!("curl {url}"),
detail: String::from_utf8_lossy(&output.stderr).into_owned(),
});
}
Ok(String::from_utf8_lossy(&output.stdout).into_owned())
}
pub fn check(current_version: &str) -> Result<UpdateStatus> {
let body = match curl_text(LATEST_RELEASE_URL) {
Ok(body) => body,
Err(_) => {
return Ok(UpdateStatus {
current_version: current_version.to_string(),
latest_version: None,
update_available: false,
});
}
};
let release: Release = serde_json::from_str(&body)?;
let latest = release.tag_name.trim_start_matches('v').to_string();
let update_available = latest != current_version;
Ok(UpdateStatus {
current_version: current_version.to_string(),
latest_version: Some(latest),
update_available,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_latest_release_tag() {
let json = r#"{"tag_name": "v0.2.0"}"#;
let release: Release = serde_json::from_str(json).unwrap();
assert_eq!(release.tag_name, "v0.2.0");
}
}