3.8 KiB
Architecture
Browser .evtx
|
v
ASGI request/body + filename gates -> bounded in-memory bytes
|
v
bounded parse admission -> Rust-backed evtx parser (single thread, time/event/record limits)
|
v
normalized events (bounded strings/fields, explicit timestamp validity/source, stable IDs)
|
v
deterministic correlation rules -> incidents + reasons + evidence IDs
|
v
React workspace shell (Analysis/Timeline/Hunting/Reports/Settings) -> virtualized timeline/filter/inspector -> cloned redacted JSON/Markdown export
Boundaries
backend/app/main.pyowns HTTP, CORS, receive-level request limits, bounded parse admission, privacy headers, upload reading and response contracts.backend/app/parser.pyowns the untrusted EVTX boundary and never emits raw XML to presentation code.backend/app/normalize.pymaps parser-native JSON intoNormalizedEventvalues, with bounded fields, UTC timestamps and explicitevent/record/missing/invalidtimestamp metadata.backend/app/correlate.pyconsumes normalized events only. It never parses raw EVTX, requires provider/channel context for provider-scoped IDs, avoids unknown grouping keys and attaches stable rule/incident/evidence identifiers.backend/app/models.pydefines the API contract.frontend/src/filter.ts,redact.tsandexport.tsare pure browser-side workflow functions.frontend/src/main.tsxis only the React bootstrap.frontend/src/app/App.tsxowns explicit workspace state (active hash workspace, selection, filters, settings and loading/error state); reusable shell/state components live infrontend/src/components/, and Analysis, Timeline, Hunting, Reports and Settings live infrontend/src/workspaces/over the same in-memoryAnalysisobject. The browser UI does not implement parser or correlation rules.
Resource and privacy model
Uploads are bounded while ASGI body messages are received, then read in bounded chunks and parsed from bytes in a worker thread so the FastAPI event loop remains responsive. Each parser record is checked before JSON expansion. Normalized output has a global character budget in addition to per-event limits. The multipart handle is closed after the request and no upload path is retained.
API and health responses are non-cacheable and carry defensive browser headers. The production container runs as an unprivileged user with a read-only root filesystem, dropped capabilities and a bounded temporary filesystem. The browser keeps only the current normalized analysis in memory; large timelines are virtualized and search documents are cached per event.
The deployment broker passes the validated main commit as GITEA_COMMIT_SHA into the Compose build. Docker embeds that exact SHA as EVENTLENS_REVISION; /health exposes it with the product version without running Git in the container. An unlabelled local build reports local.
The browser stores only one validated local-preferences record in localStorage (eventlens.preferences.v1); it never stores events, analysis results or EVTX-derived values. Settings writes that record automatically, exposes an accessible save confirmation and can reset it to validated defaults. A configured default workspace is used only when no URL hash is present, so a hash/deep link always wins. Workspace navigation uses a lightweight URL hash so browser back/forward works without a routing dependency. The static browser-brand package (SVG/ICO/PNG/manifest) is bundled locally, has no service worker and does not add a cache or network dependency. The bundled JSON demo exercises the same normalized, correlation and presentation contracts while deliberately skipping only raw EVTX parsing. The real parser is qualified in CI against a public, hash-verified seven-record EVTX fixture without committing that fixture or its event data to the repository.