refactor: distribute Acaua as a Docker image instead of a desktop app
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

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
This commit is contained in:
Lucas RayanandClaude Sonnet 5 committed 2026-10-31 19:54:45 -03:00
1 parent 1b974bb90d
commit 8a80504c45
72 files changed
+2524 -6384

No files matched your search

+39 -17
View File
@@ -17,6 +17,10 @@ step() { # step "name" command...
if "$@"; then printf '\033[32mok\033[0m %s\n' "$name"; else printf '\033[31mFAILED\033[0m %s\n' "$name"; failures+=("$name"); fi
}
duckdb_dir="${XDG_CACHE_HOME:-$HOME/.cache}/acaua/duckdb"
scripts/fetch-libduckdb.sh "$duckdb_dir" >/dev/null || { echo "could not install libduckdb" >&2; exit 1; }
export DUCKDB_LIB_DIR="$duckdb_dir" DUCKDB_INCLUDE_DIR="$duckdb_dir" LD_LIBRARY_PATH="$duckdb_dir${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
step "formatting (cargo fmt)" cargo fmt --all -- --check
# Same flags as CI: warnings are treated as errors across all targets, including tests
step "clippy (workspace, all targets)" env RUSTFLAGS="-D warnings" cargo clippy --workspace --all-targets
@@ -32,9 +36,16 @@ terms = [
'updater' + '.pubkey',
'createUpdater' + 'Artifacts',
'plugin' + '-updater',
'Tau' + 'ri',
'App' + 'Image',
]
skip_dirs = {'.git', 'target', '.wolf', '.claude', 'dist-gui'}
allowed = {Path('docs/architecture.md')}
skip_dirs = {'.git', 'target', '.wolf', '.claude'}
allowed = {
Path('docs/architecture.md'),
Path('docs/pt-BR/arquitetura.md'),
Path('CHANGELOG.md'),
Path('CHANGELOG.pt-BR.md'),
}
hits = []
for path in Path('.').rglob('*'):
if not path.is_file() or any(part in skip_dirs for part in path.parts):
@@ -61,9 +72,9 @@ import glob, yaml
for f in glob.glob('.gitea/**/*.yml', recursive=True):
yaml.safe_load(open(f))
"
step "brand assets" test -s logo.png -a -s apps/gui/src-tauri/icons/source.png -a -s apps/gui/src-tauri/icons/icon.ico
step "brand assets" test -s logo.png
step "consistent Semantic Versioning 2.0.0" python3 -c "
import json, re, sys
import re, sys
from pathlib import Path
semver_re = re.compile(
@@ -78,22 +89,33 @@ def cargo_version(path):
sys.exit(f'version not found in {path}')
return m.group(1)
versions = [
cargo_version('Cargo.toml'),
cargo_version('apps/gui/src-tauri/Cargo.toml'),
json.load(open('apps/gui/src-tauri/tauri.conf.json'))['version'],
]
if len(set(versions)) != 1:
sys.exit(f'version mismatch: Cargo.toml={versions[0]}, src-tauri={versions[1]}, tauri.conf={versions[2]}')
if not semver_re.match(versions[0]):
sys.exit(f'invalid SemVer 2.0.0 version: {versions[0]}')
print(versions[0])
version = cargo_version('Cargo.toml')
if not semver_re.match(version):
sys.exit(f'invalid SemVer 2.0.0 version: {version}')
print(version)
"
step "DuckDB pin matches the duckdb crate" python3 -c "
import re, sys
from pathlib import Path
lock = Path('Cargo.lock').read_text()
m = re.search(r'^name = \"duckdb\"\nversion = \"1\.(\d+)\.\d+\"', lock, re.M)
if not m:
sys.exit('duckdb crate not found in Cargo.lock')
enc = int(m.group(1))
crate = f'{enc // 10000}.{enc // 100 % 100}.{enc % 100}'
pin = re.search(r'^DUCKDB_VERSION=(\S+)$', Path('scripts/fetch-libduckdb.sh').read_text(), re.M).group(1)
if crate != pin:
sys.exit(f'DuckDB mismatch: duckdb crate targets {crate}, scripts/fetch-libduckdb.sh pins {pin}')
print(f'DuckDB {pin}')
"
step "forbidden stack terms" check_forbidden_terms
if [ -f apps/gui/src-tauri/Cargo.toml ] && pkg-config --exists webkit2gtk-4.1 2>/dev/null; then
step "desktop app (cargo check)" env RUSTFLAGS="" cargo check --manifest-path apps/gui/src-tauri/Cargo.toml
if command -v docker >/dev/null && docker compose version >/dev/null 2>&1; then
step "docker compose config" docker compose config --quiet
else
printf '\n(desktop app: skipped, WebKitGTK development libraries not installed; built in CI)\n'
printf '\n(docker compose config: skipped, docker compose not available)\n'
fi
if [ "$full" = 1 ]; then