feat(api): implement self-update mechanism for Linux agents
Build and Push EvoFirewall Docker Image / build-and-push (push) Successful in 1m45s
Build and Push EvoFirewall Docker Image / create-release (push) Skipped

- Added a `maybe_self_update` function in `evofw-firewall.sh` to allow agents to pull the latest version of the sync script from the server, enhancing the agent's ability to stay updated.
- Updated the `/v1/agent/sync-script` endpoint to return ETag and script SHA256 headers, enabling efficient caching and conditional requests.
- Modified the agent policy response to include `script_sha256`, providing visibility into the current version of the sync script.
- Enhanced tests to verify the self-update functionality and ensure correct behavior of the sync script endpoint.

These changes improve the maintainability and reliability of Linux agents by enabling automatic updates of critical scripts.
This commit is contained in:
Denozordec
2026-08-15 16:56:00 +07:00
parent ef2a333430
commit d552f4f326
9 changed files with 260 additions and 8 deletions
@@ -24,9 +24,81 @@ source "$CONF_FILE"
CLIENT_TOKEN="${CLIENT_TOKEN//$'\r'/}"
CLIENT_TOKEN="${CLIENT_TOKEN//$'\n'/}"
BACKEND="${KERNEL_BACKEND:-auto}"
SYNC_SCRIPT=/usr/local/sbin/evofw-firewall.sh
mkdir -p "$STATE_DIR"
file_sha256() {
local f=$1
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$f" 2>/dev/null | awk '{print $1}'
elif command -v openssl >/dev/null 2>&1; then
openssl dgst -sha256 "$f" 2>/dev/null | awk '{print $NF}'
else
echo ""
fi
}
# Pull a newer sync script from CP before policy (pending agents too).
# Errors must not abort this run — keep the current script.
maybe_self_update() {
if [[ "${EVOFW_SKIP_SELF_UPDATE:-}" == "1" ]]; then
return 0
fi
if [[ ! -f "$SYNC_SCRIPT" ]]; then
return 0
fi
local local_sha tmp code remote_sha
local_sha=$(file_sha256 "$SYNC_SCRIPT")
tmp=$(mktemp "${STATE_DIR}/sync-script.XXXXXX") || return 0
if [[ -n "$local_sha" ]]; then
code=$(curl -sS -o "$tmp" -w '%{http_code}' \
-H "If-None-Match: \"${local_sha}\"" \
"${EVOFW_CP_URL%/}/v1/agent/sync-script") || code="000"
else
code=$(curl -sS -o "$tmp" -w '%{http_code}' \
"${EVOFW_CP_URL%/}/v1/agent/sync-script") || code="000"
fi
if [[ "$code" == "304" ]]; then
rm -f "$tmp"
return 0
fi
if [[ "$code" != "200" ]]; then
log "self-update: sync-script HTTP ${code} — keep current"
rm -f "$tmp"
return 0
fi
if ! head -n1 "$tmp" | grep -q '^#!'; then
log "self-update: sync-script is not a shell script — keep current"
rm -f "$tmp"
return 0
fi
remote_sha=$(file_sha256 "$tmp")
if [[ -z "$remote_sha" ]]; then
log "self-update: cannot hash download — keep current"
rm -f "$tmp"
return 0
fi
if [[ -n "$local_sha" && "$remote_sha" == "$local_sha" ]]; then
rm -f "$tmp"
return 0
fi
if ! install -m 755 "$tmp" "$SYNC_SCRIPT"; then
log "self-update: install failed — keep current"
rm -f "$tmp"
return 0
fi
rm -f "$tmp"
rm -f "$HASH_FILE"
log "self-update: installed script sha256=${remote_sha} — re-exec"
exec env EVOFW_SKIP_SELF_UPDATE=1 "$SYNC_SCRIPT" || {
log "self-update: exec failed — continue current"
return 0
}
}
maybe_self_update
curl_policy() {
local dest="$1"
local code