Files
EvoFirewall/apps/api/src/services/sync-script.ts
T
Denozordec d552f4f326
Build and Push EvoFirewall Docker Image / build-and-push (push) Successful in 1m45s
Build and Push EvoFirewall Docker Image / create-release (push) Skipped
feat(api): implement self-update mechanism for Linux agents
- 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.
2026-08-15 16:56:00 +07:00

40 lines
1.2 KiB
TypeScript

import { readFileSync } from 'node:fs'
import { createHash } from 'node:crypto'
import { join } from 'node:path'
import { resolveAgentScriptsDir } from './agent-scripts-path.js'
export type SyncScriptMeta = {
body: Buffer
sha256: string
etag: string
}
let cache: SyncScriptMeta | null = null
/** Linux sync agent script + sha256 of file bytes (process-lifetime cache). */
export function getSyncScriptMeta(): SyncScriptMeta {
if (cache) return cache
const dir = resolveAgentScriptsDir()
const body = readFileSync(join(dir, 'evofw-firewall.sh'))
const sha256 = createHash('sha256').update(body).digest('hex')
cache = { body, sha256, etag: `"${sha256}"` }
return cache
}
/** Compare If-None-Match with our ETag (`"<sha256>"`). */
export function ifNoneMatchHits(
header: string | string[] | undefined,
etag: string,
): boolean {
if (!header) return false
const raw = Array.isArray(header) ? header.join(',') : header
const want = etag.replaceAll('"', '').toLowerCase()
for (const part of raw.split(',')) {
let token = part.trim()
if (token.startsWith('W/')) token = token.slice(2).trim()
token = token.replaceAll('"', '')
if (token === '*' || token.toLowerCase() === want) return true
}
return false
}