Watch
1
0
Fork
You've already forked RedFlag
0
Commit graph

501 commits

Author SHA1 Message Date
Fimeg
7beb0b9478 bump: v0.2.8.1
Version lockstep across server, agent, docker-compose.
2026-06-11 17:47:42 -04:00
Fimeg
7deca9bc25 web: wire FilterBar + useFilterUrl across pages
Agents and History pages now use the primitives FilterBar with
URL-synced filter state via useFilterUrl. Adds test setup infra
(vitest + jsdom) and page-level test shells.
2026-06-11 17:47:39 -04:00
Fimeg
182536a1d1 retain: core retention sweep (RETAIN-001)
Prunes aged rows from append-only history tables on a schedule.
Three operator-tunable horizons (metrics/events/audit), 0 = keep
forever. ctid-based batched DELETE, closed-table whitelist.

Signed-off-by: Fimeg <casey.tunturi@gmail.com>
2026-06-11 17:47:30 -04:00
Fimeg
75346d4c68 sec: encrypt TOTP seed at rest (migration 058)
Store the fleet-join TOTP seed as AES-256-GCM ciphertext instead of
a SHA-256 hash. Hash-only can never verify a time code without the
host disclosing the seed — which made the 2FA a second cleartext
shared secret. Seed crosses the wire once, at token creation over
the admin-authenticated channel; the join request carries only the
6-digit code.
2026-06-11 17:47:23 -04:00
Fimeg
3a8ffe1643 raf: publish — relative links, auth audit section, component tables 2026-06-11 17:47:21 -04:00
Fimeg
a4d585c79c code review: 12-finding fan-out — fixes across server, agent, web
HIGH:
- URL sync race: page useEffect now preserves filter params from useFilterUrl
- useFilterUrl: document two-effect pattern (state→URL and URL→state)
- Fleet-join: store nil (not &"") for absent MachineID/PublicKeyFingerprint
- agents.go: same NULL fix for standard registration path

MEDIUM:
- Test assertions: replace CSS class checks with user-visible element assertions
- Updates vuln toggle: fixed-set like other quick filters (was toggling)
- ConfigureSecrets route: restore to welcome-mode server
- Config upgrade: recursive mergeMissingKeys for nested sub-fields + test

LOW:
- LiveOperations: wire FilterBar pills/clearAll/activeCount
- HashTOTPSeed: remove dead code replaced by encrypted storage (migration 058)
- auditor.go: replace unsafe reflect with Recorder wrapper (AUDIT-002)

History filter panel kept as-is (collapsible pattern intentional).
Agents.tsx duplicate buildFilterPills was a false positive (already resolved).
2026-06-11 17:38:08 -04:00
Fimeg
7c25204bd8 README: fix installer commands to use header-based token auth 2026-06-11 17:24:09 -04:00
Fimeg
d55026aa44 process scan: set Source on AgentCommand to avoid check constraint crash
TriggerProcessScan was building an AgentCommand without Source, which hit
the agent_commands_source_check constraint every time. Every other
command-creation site sets this correctly; this one got missed.

Thanks to QiTechCo for the catch during v0.2.8.0 dev testing.

Co-Authored-By: Xzaviar <user@QiTechCo.qitc.io>
2026-06-11 17:24:06 -04:00
Fimeg
44d7e3dd66 global events: notification bell feed + exclude client_error from operator alerts 2026-06-11 13:38:31 -04:00
Fimeg
34d4a02826 install template integrity test — render, config keys, scriptlet syntax 2026-06-11 13:38:17 -04:00
Fimeg
76fd491849 agent config: persist new default keys on upgrade 2026-06-11 13:38:16 -04:00
Fimeg
88adf90420 agent: post-upgrade healthcheck + kernel enforcer wired to tee logger 2026-06-11 13:38:16 -04:00
Fimeg
db63095e03 CI: installer integrity test job 2026-06-11 13:38:15 -04:00
Fimeg
ea9fbc1d7b supply chain consumer: refinements + test coverage 2026-06-11 13:37:58 -04:00
Fimeg
c99d0a1815 security logger: structured event output + test coverage 2026-06-11 13:37:57 -04:00
Fimeg
4ec8afcbfd kernel: eBPF consumer refinements 2026-06-11 13:37:56 -04:00
Fimeg
5e710f597b notifier: ntfy + SMTP event dispatch, wired through SystemEventLogger 2026-06-11 13:37:53 -04:00
Fimeg
4c1da83d8d SEC-025: wire fleet-join endpoint + notifier dispatcher (main.go) 2026-06-11 13:37:41 -04:00
Fimeg
9c43698b00 SEC-025: fleet-join 2FA — TOTP validation, host-generated seed, migration 057 2026-06-11 13:37:17 -04:00
Fimeg
47fe315e8f RAF: convert [[wiki-links]] to standard markdown for GitHub rendering 2026-06-11 11:47:44 -04:00
Fimeg
6debe1f729 global events query + handler — fleet-wide notification bell feed 2026-06-11 11:33:07 -04:00
Fimeg
7d1ad50399 wire agent + global event endpoints (LIFECYCLE-006 groundwork) 2026-06-11 11:32:51 -04:00
Fimeg
5845709f86 dnf scanner: tighten EVRA comparison + test coverage 2026-06-11 11:32:25 -04:00
Fimeg
2064a5035f supply chain vuln UI — backend endpoints + frontend rendering for CVE/advisory detail 2026-06-11 11:32:24 -04:00
Fimeg
a19dcf4f14 RAF: full docs pass — components, flows, security, scanners, reference, testing, verification, overview 2026-06-11 11:32:21 -04:00
Fimeg
565baa0819 AUTHOR.md + SECURITY.md split out; README restructured for public eyes 2026-06-11 11:32:19 -04:00
Fimeg
da455b77a5 fix: severity stats scoped to non-terminal statuses + consistent type icons (UI-DASHBOARD-AUDIT #2, #4) 2026-06-11 08:45:27 -04:00
Fimeg
937b3a5b6d fix: desktop-self token missing ArtifactPath — stageClosureArtifact requires it 2026-06-11 08:30:11 -04:00
Fimeg
b2319e15ed feat: mint desktop-self tokens on agent update (UPDATE-002) 2026-06-11 08:24:46 -04:00
Fimeg
f6bb28e9cd fix: tracker save failures tee inward; drop restorecon stderr suppression (ETHOS #1)
Delivery-tracker persistence failures (ack/receipt/confirmed Save) were
local-only log lines; a tracker that cannot persist risks double-delivery
or replay-rejection after a crash, so they now tee to the server event
buffer via TeeLogger. The untagged 'Command rejected' line gains ETHOS
tags. install.sh restorecon calls lose their 2>/dev/null — SELinux
relabel failures now print a tagged warning instead of vanishing.
2026-06-11 08:10:04 -04:00
Fimeg
aee87c476d refactor: StatusBadge + SeverityBadge primitives — one way to render state
Extract the repeated cn('badge', getStatusColor/getSeverityColor) span
into primitives; port Updates, Agents, Docker, LiveOperations,
PackageDetail, AgentUpdatesEnhanced. Docker's local colour maps deleted —
its image-lifecycle statuses join the central getStatusColor map, and its
severity palette aligns with the app-wide one. AgentUpdatesEnhanced's
divergent local severity palette replaced by the shared map.
2026-06-11 08:05:58 -04:00
Fimeg
7269d25823 fix: route audit misclassified inlined AuthMiddleware — server refused boot
The compiler inlines middleware.AuthMiddleware across packages, renaming
its closure to "<caller>.AuthMiddleware.func1" — the package-qualified
match ("middleware.AuthMiddleware") never hit, every agent-JWT route
was flagged as naked, and AuditAndExit refused boot (122 container
restarts overnight). Classify on bare names, web before agent since
WebAuthMiddleware contains AuthMiddleware. Regression test now uses the
real production middleware instead of a same-package fake.
2026-06-11 07:59:13 -04:00
Fimeg
e4afe1f605 feat: helper trust-file self-validation (SEC-021)
The privileged executor no longer trusts its keyring, agent_id, or
replay-guard state by content alone. Before any read, each trust input
and its immediate parent must be root-owned, not group/other-writable,
and not a symlink — otherwise deny with EXIT_TRUST_PATH (26), fail
closed. This makes the gate self-defending: a packaging or installer
mistake that leaves a trust path writable can no longer be parlayed
into key injection, token rebinding, or replay-record clearing.

An agent_id file that exists but fails validation is a denial, never a
fall-through to the next location. The replay dir is validated after
ensure-exists so a pre-planted attacker-owned dir is refused, not
adopted.
2026-06-11 07:55:34 -04:00
Fimeg
6c3461cdf9 feat: rate limiter startup grace penalty (SEC-004)
The limiter is in-memory; a restart clears all counters, so an attacker
who can force one gets a fresh budget. For 60s after boot every limit
runs at half its configured budget (min 1), making a restart strictly
worse for the attacker while per-key limits keep reconnecting agents
comfortable. Restart semantics documented in OPERATIONS.md §6.
2026-06-11 04:29:50 -04:00
Fimeg
6ac937bfe5 refactor: unified backoff policy with failure classes (BUG-014)
classifyFailure is now the single source of truth for which polling
failures are terminal (ErrRefreshTokenInvalid, ErrMachineMismatch —
wrapped or bare) vs transient. delayForFailure picks the curve: flat
10-minute delay for terminal states awaiting operator intervention,
jittered exponential (calculateBackoff) for everything else. The
terminalBackoff bool is gone from the polling loop. Task file said
to delete itself when this landed — done.
2026-06-11 04:27:44 -04:00
Fimeg
1c4b363375 fix: registration token moves from install URL to X-Registration-Token header (SEC-002)
A token in the query string leaks to shell history, process lists, and
server access logs. The install endpoint now reads X-Registration-Token;
a query-string token is refused with guidance and is never echoed back
or logged. Server-built and web-UI install commands updated (curl -H,
irm -Headers).
2026-06-11 04:25:32 -04:00
Fimeg
0abff08a9d fix: clear selected_version on transition to installed
A version pinned at approval (selected_version) survived the install,
so the next scan compared against the stale pin and plain Approve became
a no-op after the first install. Clear the pin and its metadata source
marker inside the transition tx once the package reaches installed;
subsequent scans track latest available again.
2026-06-11 04:20:20 -04:00
Fimeg
d223c4608a fix: docker/winget VerifyHash fail closed — no silent skip when a hash is registered
Both previously logged hash_verification_skipped and returned nil when the
server had registered an expected hash the installer cannot verify. Now:
empty expected hash errors (consistent with dnf/apt), and a registered hash
without an implemented verifier blocks the install instead of pretending.
No behavior change today — the server only registers hashes for npm/pypi,
and handlers skip VerifyHash on empty hash — this closes the latent path.
2026-06-11 04:20:20 -04:00
Fimeg
c33b62489e feat: boot-time route audit — ETHOS #2 enforced structurally
Walk every Gin radix tree at startup, classify each route's handler chain
(agent JWT / web JWT / metrics token), and refuse to boot if any route
lacks auth and is not on the explicit public allowlist. Adding a path to
PublicPathSet is a reviewable act.

Covers param routes, nested groups, and per-method trees (tested).
2026-06-11 04:20:08 -04:00
Fimeg
71cf60b66c refactor: unify Docker container images + runtime state into single table 2026-06-11 02:28:24 -04:00
Fimeg
f07e4be94c fix: docker ports — replace 0.0.0.0 with * (standard docker ps notation) 2026-06-11 02:18:13 -04:00
Fimeg
175d3dfd90 refactor: port Docker page to SortableTable — unify two container tables
Container images table (per-agent-group) and runtime container state table
both use SortableTable with shared sort state. ~120 lines of raw table markup
removed. Stacks grid unchanged — card layout is the right shape for that.
2026-06-11 02:13:53 -04:00
Fimeg
5a284f1370 fix: show View Update link when package name is empty; cross-link Agent+Update in command history
ChatTimeline: when updateLink exists but packageName is falsy, show 'View Update'
instead of hiding the link entirely. Updates: clickable Agent/Update links in
command history rows (UI-AGENT-UPDATE-CROSSLINKING).
2026-06-11 02:01:44 -04:00
Fimeg
8811ec9100 refactor: centralize polling intervals — replace hardcoded ms with POLL.* constants
Every hook that polled had its own magic number. POLL tiers (LIVE/DASHBOARD/
DETAIL/OVERVIEW/STATIC/HEALTH) declared once in polling.ts, consumed everywhere.
Mechanical change, no behavior shift.
2026-06-11 02:01:44 -04:00
Fimeg
488cca2dd5 refactor: extract SortableTable primitive from Agents page
Column-driven table component under primitives/ — sortable headers, checkbox
selection, empty/loading states, pagination slot. Agents.tsx rewired as
proof-of-integration; ~220 lines of raw table markup collapsed into column
definitions + <SortableTable />. Same output, same behavior.
2026-06-11 02:01:43 -04:00
Fimeg
c71fc093db refactor: vulnerability → security advisory terminology
Rename CVE/vulnerability language to advisory/threat/fix across the stack:
- Dashboard: installed_cve_count→open_threat_count, security_update_count→available_fix_count
- Update detail: Known Vulnerabilities→Security Advisories
- AdvisoryType() helper for human-readable advisory ID prefixes
- clearVulnsOnInstall on installed transition with per-advisory security event logging
- StatsHandler takes checkInInterval for online/offline threshold
- AttentionPanel re-keyed on open-threats / available-fixes
2026-06-11 02:01:43 -04:00
Fimeg
5683bc15a4 feat: Wazuh queue-socket event emitter (INTEG-001)
Outbound-only: no listener, no control surface — RedFlag's journal is
authoritative, Wazuh is a best-effort mirror. DGRAM to the local agent's
queue socket, ECS-formatted, rule IDs mapped from security event types.
Opt-in via REDFLAG_WAZUH_ENABLED=true; disabled = socket never opened.

- Sink interface on SecurityLogger (mirror after journal write)
- Write deadline + one reconnect, then drop-count with rate-limited log
- 3 tests: frame/ECS shape, absent-socket non-blocking, unknown→generic
2026-06-11 02:01:43 -04:00
Fimeg
aff48376b9 v0.2.8.0 — changelog + version lockstep bump 2026-06-11 02:01:43 -04:00
Fimeg
8b1884eadc fix: nil logger on Windows scan path, rpmEVRAhead equal-version false positive, desktop-self replay token burned before install
- NewOrchestrator initialises a log-only TeeLogger (nil buffer) so the
  Windows service path never carries a nil logger into executeScan
- rpmEVRAhead returns false when all epoch/version/release components
  compare equal; adds test cases for "0:2.0-1" vs "2.0-1" normalisation
- processDesktopSelfToken splits replayCheckAndRecordAgent into
  replayCheckAgent (before install) + recordAgentTokenConsumed (after
  successful install) so a transient install failure does not permanently
  consume the token
- Comments on helperSelfStagingPath (Go) and DEFAULT_HELPER_SELF_SOURCE
  (Rust) name each other as the cross-language counterpart
2026-06-11 02:01:43 -04:00
Fimeg
2da1e92fe9 feat: setup accepts operator-supplied signing keypair + validation
Extract serverSetupRequest type and resolveSetupSigningKeys(): when no keys
are provided the server generates a fresh Ed25519 pair (existing behaviour);
when a private key is provided it is validated and the public key derived from
it (public key may be omitted or supplied for cross-check). Mismatched pairs
are rejected 400. Remove configure-secrets route from welcome-mode router
(was only usable with Docker socket mounted, unreachable in that mode).
Add inferPublicURL() helper to fill publicURL from X-Forwarded-* headers when
the operator omits it. pq.QuoteLiteral() used for password in ALTER USER.
Tests: generate-when-missing, use-provided-pair, reject-mismatched-pair.
2026-06-11 02:01:43 -04:00