Watch
1
0
Fork
You've already forked RedFlag
0
Commit graph RedFlag/web
Author SHA1 Message Date
Fimeg
ffa7afbb58 desktop: put this computer health first
The Agent now owns one local view of machine health and top processes. RedFlag opens at dashboard scale, names itself plainly, and renders that evidence before updates.\n\nCI now compiles the Tauri bridge before release day.
2026-08-31 21:20:00 -04:00
Fimeg
7427174d99 deps: lift patched public floors
CI found nine reachable Go issues and a high Axios advisory. Move to the published fixed floors and retire three stale Docker exceptions.
2026-08-20 13:14:28 -04:00
Fimeg
1f75bfd23a device-type: layered detection + laptop/vm/container types
Replaces the flat battery x display matrix (which misclassified laptops
as phones) with layered detection: container -> vm -> SMBIOS chassis ->
ARM fallback. Adds laptop, vm, container device types across agent,
migration 062, server validation, web icons/types.
2026-07-12 14:55:04 -04:00
Fimeg
ff2f30f47a v0.2.9.3: device classification + ARM support — Pixel 3 lands
DEVICE-002: ARM machine-ID fallback — device-tree model + /etc/machine-id
combo, then /proc/cpuinfo Serial (all-zero rejected), before the weak
hostname fallback. Hardware-bound IDs on DMI-less devices.

DEVICE-001: agent detects device_type (server/desktop/phone/tablet) from
/sys signals — system battery (scope=Device peripherals excluded, UPS
excluded), DRM connector state, framebuffer min-dimension for phone/tablet
split. Reports device_type/device_model/os_distro in registration and
system-info paths.

SERVER-001: migration 061 — device_type, device_type_manual (operator
override, never agent-written), device_model, os_distro on agents.
effective_device_type computed into every serialized agent.

SERVER-002: PUT /admin/agents/:id/device-type — set/clear override,
enum-validated, journaled.

WEB-001: device-type icons + fleet filter, device model in list, detail
header badge with reclassify dropdown, os_distro surfaced.

INSTALL-003: arm64 install path unblocked — helper (required manifest
component) now cross-built aarch64-unknown-linux-musl via rust-lld in the
server image, signed at boot (helperArches += arm64), listed in the release
manifest. Install template already handled uname -m and pacman.

Plus in-flight: desktop tray wiring, enrollment page polish, CI workflow
updates, RAF session-broker/pacman-scanner docs, native installer scaffold.
2026-07-06 18:21:23 -04:00
Fimeg
bf7930f1fe v0.2.9.1: wire pacman scanner, GATE-006 TODO 2026-06-29 15:11:12 -04:00
Fimeg
865d82ded0 web: wire Agents <-> Enrollment, back on the steel-blue theme
deep-link a chosen key into the install panel, drop the emoji.
2026-06-15 21:12:33 -04:00
Fimeg
99d97a07ee v0.2.9.0 — Windows desktop tray ships; unified Agents & Enrollment page
Desktop:
- Windows tray cross-compiled (cargo-xwin), installed with per-user
  autostart Run key; tray actions trigger_scan/approve_update wired to
  the local API
- Linux tray off the service child-spawn path — XDG autostart only, kills
  the double-launch
- signalDesktopRestart no longer no-ops on Windows (taskkill /F /IM)
- server serves /desktop/:platform/:arch

Web:
- TokenManagement + AgentManagement folded into one Agents & Enrollment
  settings page (useRegistrationTokens hook)

Agent/server:
- platform-aware self-update staging (constants/paths.go), no more
  hardcoded /var/lib/redflag
- consumer helper gated: sudo systemd-run on Linux, child proc elsewhere
- migration 060 drops the never-used token_seats table
- droppage of dead constructors and orphaned windows.go service methods
2026-06-15 20:51:44 -04:00
Fimeg
9e4d59695f upstream: track prereleases per row; rename gitea adapter to forgejo
Most forges hand back a "latest stable" that ignores prereleases. Fine
until something ships only prereleases for a stretch — us, through
alpha, where every tag under v0.3.0 goes out as a prerelease. Against
that, /releases/latest either freezes or returns nothing, and the
dashboard reads like nothing's moving.

Add a per-row track_prereleases flag. When it's on, the forgejo adapter
walks the full release list and considers prereleases when picking the
highest version; off (the default) keeps stable-only behavior, so the
other adapters don't change. Seed our own self-row on so we stop
looking frozen.

Renamed gitea_releases to forgejo_releases while in there — the wire
format is Forgejo's, Codeberg runs it, and the old name was a misnomer.
Legacy source="gitea" rows still resolve through an alias.
2026-06-15 12:10:12 -04:00
Fimeg
1d84fd46a7 web: primary -> steel blue, split from danger (C5)
primary was byte-identical to danger (both red), so every focus ring, toggle,
tab and link read as an error. primary is now steel #336699 (red lives on as
danger). Walked the stray hard-coded interactives onto the token — StackDriftPanel,
software-binding buttons/links, retry CTA — and left the destructive reds alone.
2026-06-15 09:37:48 -04:00
Fimeg
f340c0d084 web: log errors at the boundary, ditch the toast-logging wrapper (C6)
API errors already log via the axios interceptor — wrapping 78 toast calls
would just double-log and turn validation prompts into noise. Wrapper gone;
ErrorBoundary + window error/rejection handlers log to clientErrorLogger,
skipping axios errors so the log POST can't loop. setupApiInstance logs now too.
2026-06-15 09:28:31 -04:00
Fimeg
f04fbe8b1f web: fix 13 dashboard criticals from the UI/UX audit
- confirm-deps used a raw fetch with no auth headers -> API layer
- retry/cancel had two copies with divergent invalidation (one hit a dead
  ['active'] key); unified in useCommands, bulk-approve now refreshes counts
- Docker stat-card filter was sent server-side where it mapped to the severity
  column and matched nothing; moved client-side with two distinct values
- wired dead Quick Actions buttons, notification deep-links, ws reconnect+backoff
- useMemo side-effect -> useEffect, agent-events dedup, stale-closure toast
- dropped dead agent memory block, labeled security health as fleet-wide
- maintenance banner claimed installs are "blocked"; they wait for the window
2026-06-15 09:07:19 -04:00
Fimeg
0b1b8124b0 crypto: forward-only key-path ceiling + OSV resilience + token serialization
SEC-028 -- a rotated-out server signing key must stop being trusted even when the agent cannot phone home. pubkey.go: bounded stale-cache window on public-key fetch failure; past the window (or when cache age is unknown) it fails closed instead of trusting the cached key indefinitely. Window length is operator policy (command_signing.stale_key_max_age_hours, default 168h/7d) delivered fleet-wide via GET /agents/:id/config; the [1h, 30d] clamp and the existence of the ceiling are doctrine, not knobs. verification.go: CheckKeyRotation refuses when the named key_id is not in the server active set (no primary fallback), and applies the same bounded-stale ceiling to the active-set fetch-failure path so key_id'd commands are no weaker than keyless ones. Server carries the default + 1-720h validation; web surfaces it in Security Settings.

SEC-029 -- the standalone OSV.dev client retries transient transport/5xx/429 with exponential backoff and trips a process-wide circuit breaker after a run of failures, fast-failing to 'unreachable'. Verdict semantics unchanged and still fail-closed; the resilience only stops a transient scanner blip from forcing an operator override.

GATE-004 #4 -- Consumer.ProcessToken holds a mutex so the replay-state guards are never raced by a concurrent caller. Today's single caller (the poll loop) never overlaps; this enforces the one-token-at-a-time invariant for future callers (local-API trigger, retry worker).

RAF/verification/03 and RAF/security/05 document the key-path and OSV changes. ETHOS #3, #4; forward-only doctrine.
2026-06-14 12:57:04 -04:00
Fimeg
9be8aba073 fix: dashboard populates Updates-by-Type and gives honest severity bars
The stats handler initialized updates_by_type but never filled it, so the
"Updates by Type" card always rendered empty (Codeberg #10). Add
UpdateQueries.GetUpdatesByType (grouped by package_type, non-terminal scope)
and wire it into GetDashboardStats.

Severity bars were sized against total_updates (all statuses) while the
severity counts are scoped to non-terminal rows — a scope mismatch. Bars now
size against the sum of the scoped severity values, so they form a true
breakdown that always sums to 100% and never overflows.

Also closed the silent error-swallows in GetDashboardStats: each sub-count
failure is now logged [ERROR] [server] [stats] instead of vanishing.
2026-06-13 08:23:20 -04:00
Fimeg
88b612c77e feat: component manifest drives installs, checkoff, and desktop lockstep
INSTALL-001: manifest schema with components+artifacts, CI generation
in release gate, manifest-driven install template with --guided and
--checkoff modes, post-install provisioning checks, desktop joins
version lockstep (bump-version.sh + CI build + gate enforcement).

Setup.tsx reduced to primitives (FormSection, TextField, Alert).
2026-06-12 15:23:15 -04:00
Fimeg
0669b4d6b1 web: completed is green everywhere; typed-confirmation actually gates
CommandStatusBadge joins the inline timelines (Casey ruling). SecuritySettings CONFIRM/RESET input was theater — border colors changed, Confirm worked regardless. Now controlled state, button disabled until the phrase matches.
2026-06-12 14:35:27 -04:00
Fimeg
6fb7e7c81f web: shared timestamp formatters + PageState adoption; Agents test gets ConfirmProvider
formatUnixTime/formatTimeOnly into utils (ProcessDetailModal's formatTime was never a duration). RateLimiting loading state onto PageState; six candidate sites correctly left alone as section/inline loaders. Agents.test.tsx wraps in ConfirmProvider — the 31c4ae74 conversion broke it and nobody ran the full suite.
2026-06-12 14:25:32 -04:00
Fimeg
8c396c1f7a web: hand-rolled modal overlays onto the Modal primitive
Five sites converted (LiveOperations, AgentUpdatesEnhanced x2, SecurityEvents, ProcessDetailModal, SecuritySettings); Layout's sidebar backdrop is a drawer, not a modal — left alone. Modal grows maxHeight + Body scrollable.
2026-06-12 14:18:52 -04:00
Fimeg
31c4ae74e5 web: ConfirmDialog primitive — window.confirm is gone
ConfirmProvider + useConfirm, 11 call sites converted (4 more than expected). Danger variant: red button, Enter inert, cancel takes focus — a stray Enter can never destroy. Modal now yields focus to autoFocus children.
2026-06-12 14:11:16 -04:00
Fimeg
d75939cb6a web: status/severity colors get one truth table
statusColors.ts in primitives — 9 domains, kept distinct on purpose. Eight files stop hand-rolling switches. Known discrepancy documented in place: CommandStatusBadge paints completed gray, both inline command timelines paint it green.
2026-06-12 14:01:00 -04:00
Fimeg
e0f2dd8b07 tests: drop unused React imports breaking tsc 2026-06-12 13:41:11 -04:00
Fimeg
415f229b8f web: server status awareness — version header, disconnect overlay, update banner
X-RedFlag-Version on every response; axios interceptor tracks connection state, no dedicated health poll. Recovered from stash — never meant to be parked.
2026-06-12 13:41:11 -04:00
Fimeg
71fe075f65 desktop: fix tray icon depth, entry routing, socket error UX
- icon.png 16-bit -> 8-bit RGBA (tray panicked on data size)
- devUrl + dist rename so the desktop entry actually loads (release served 404, dev served the fleet login)
- permission denied on the localapi socket now explains group membership / re-login instead of os error 13
2026-06-12 13:19:51 -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
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
44d7e3dd66 global events: notification bell feed + exclude client_error from operator alerts 2026-06-11 13:38:31 -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
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
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
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
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
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
Fimeg
244d9091ee feat: process explorer — on-demand /proc scanning with full osquery parity
Agent-side: reads /proc for all PIDs with 25+ fields (identity, resources,
state, disk I/O, elevation) plus related data on drill-down (open files,
sockets, pipes, env keys, memory map, namespaces, listening ports). Pure
/proc reads, no subprocess spawns.

Server-side: dedicated tables (agent_process_snapshots, agent_processes,
agent_process_related) with JSONB for related data. On-demand scan via
scan_processes command, last-10-snapshot retention. Four endpoints:
report, get latest, get detail, trigger scan.

UI: new Processes tab in agent detail with sortable/filterable table,
search by name/cmdline, state/user filters, and ProcessDetailModal with
tabs for Overview, Network, Files, Environment, Memory, Namespaces.
2026-06-11 02:01:43 -04:00
Fimeg
469d61c0dc ui: command primitives extracted; agent page split-button sizing restored
CommandCard and CommandStatusBadge pulled out of Agents.tsx; restart
host split button back to flush edges with stretched trigger.
2026-06-11 02:01:43 -04:00
Fimeg
2f3363cbce feat: post-upgrade attestation — new binary proves the swap took
Old binary drops a marker (command_id, from/to) once the swap is
committed, on both the helper path and the legacy path. New binary
checks it at startup: running >= target just clears the marker
(check-in confirm still owns success); short of target means the swap
failed or rolled back, so it files a failed update_agent report under
the original command_id and the server clears is_updating right away
instead of sitting out the stuck-update timeout. Marker survives
failed reports for retry, drops on 409 or after 24h.
2026-06-11 02:01:42 -04:00
Fimeg
1fa76bf665 feat: System Information grid primitives — auto-placing 2-column grid 2026-06-11 02:01:42 -04:00
Fimeg
2084019be7 fix: grant CAP_SYS_PTRACE on agent binary for display/process discovery
The agent runs as redflag-agent user and cannot read /proc/[pid]/environ
from the logged-in user's session processes (owner-only permissions).
Without this, discoverSessionDisplay() finds nothing — screenshot fails
on Wayland because XDG_RUNTIME_DIR/WAYLAND_DISPLAY are never discovered.

- Installer: setcap cap_sys_ptrace=eip after placing the binary
- Helper (agent self-update): restore setcap after atomic replace,
  since rename() creates a new inode and strips file capabilities

Non-fatal if setcap is unavailable — agent degrades gracefully,
just loses screenshot and per-process telemetry.
2026-06-11 02:01:42 -04:00
Fimeg
411f25b1b7 v0.2.7.0 2026-06-11 02:01:42 -04:00
Fimeg
73c1e0ef21 fix: build errors + move platform info under screenshot card
- Fix premature </div> in Docker.tsx and History.tsx (TS1005/TS1128)
- Fix unused imports/vars (noUnusedLocals): AgentStorage, AgentUpdatesModal,
  ErrorBoundary, useAgentUpdate, useHeartbeat, Dashboard, Updates
- Move Platform/Distribution/Architecture under screenshot card in Agents page
- Move Top Processes into right stats column
2026-06-08 22:37:31 -04:00
Fimeg
c3d84ec7f9 feat: UI primitives + agent version bump
- PageState, Modal, Pagination, StatCard primitives
- Migrated Dashboard, Updates, LiveOperations, Agents, Docker, TokenManagement
- AgentUpdate, AgentUpdatesModal now use Modal primitive
- Version bump to 0.2.6.9
2026-06-08 19:40:06 -04:00
Fimeg
7cbf174652 feat: unified event timeline, desktop bundling, UI primitives
Unified timeline:
- client_errors bridge to system_events (component='client')
- Admin action audit middleware on /admin/* routes
- History page filters: type, severity dropdowns
- ChatTimeline accepts externalType/externalSeverity props

Desktop app bundling:
- Docker: Tauri builder stage (Rust + Node + webkit2gtk)
- Server signs desktop binary at startup, serves via /api/v1/desktop/:arch
- Install script downloads + verifies desktop binary (Step 7c)
- Agent spawns desktop as child process, monitors + restarts on crash
- Desktop config: enabled, max_restarts, restart_delay_sec
- Session detection: /proc environ scan (Linux), query session (Windows)
- Desktop health: POST /v1/desktop every 30s from tray app
- /v1/status includes desktop running/pid/enabled state

UI primitives:
- Modal, PageState, Pagination, StatCard components
- Dashboard, Updates, Agents pages refactored to use primitives
- Novell aesthetic preserved throughout
2026-06-08 19:09:58 -04:00
Fimeg
c0a717ab26 fix: README, .env.example, ErrorBoundary, client-logger, HEALTHCHECK, Docker hygiene
- README: version v0.2.6.8, corrected stale gate claim, updated changelog
- .env.example: merged two competing files into one, deleted bootstrap duplicate
- ErrorBoundary: new component wrapping app, prevents white-screen crashes
- Layout sidebar: version display from /api/health, Docs link to GitHub
- client-logger: debug/trace logger gated behind localStorage.redflag_debug=1,
  routes through existing /logs/client-error server endpoint (ETHOS #1)
- All web console.log calls rerouted through client-logger instead of deleted
- Server health endpoint returns version field
- Server accepts client_debug/client_trace in error_type validation
- Dockerfiles: pinned alpine:latest->3.21, nginx:alpine->1.27-alpine,
  added HEALTHCHECK directives
- docker-compose: healthcheck blocks for server and web services
- .dockerignore: created to slim Docker build context
2026-06-08 18:23:39 -04:00
Fimeg
80e719acc9 fix: screenshot square inside System Information card; display discovery
UI: move screenshot/Sunshine square into the System Information card
header (top-right, w-48 aspect-video) instead of a standalone block
above the card. Same click logic, smaller size to fit the header row.

Agent: captureScreenLinux now discovers DISPLAY/WAYLAND_DISPLAY/
XDG_RUNTIME_DIR from /proc environ entries so the service (which
doesn't inherit display vars from systemd) can reach the session.
Tool priority: scrot → grim → magick import → import.
Adds bytes/strconv/strings imports for discoverSessionDisplayEnv.
2026-06-08 18:02:33 -04:00
Fimeg
ab6fc48925 feat: v0.2.6.8 — dark/light tray app theme, version bump
LocalAgentApp: dark default with ☀/☾ toggle; palette-driven inline
styles (DARK/LIGHT objects) so both modes work without Tailwind dark
mode configuration. Dense Novell-style layout: status strip, section
headers with red accent bar, monospace identifiers, dot indicators per
scanner status. No Tailwind class changes — web/package-lock.json
untouched.

Version bump 0.2.6.7 → 0.2.6.8.
2026-06-08 17:22:01 -04:00
Fimeg
ffffe9b956 feat: FEAT-002 local agent API, desktop tray spine, screenshot handler
Slices 1-3 of the local agent IPC surface:
- Read model (local_status.go, loop wired): update counts, scanner status,
  check-in state, token receipt counts — no token material exposed
- Local IPC (localapi/): Unix socket (group=redflag-local, 0660) + Windows
  named pipe (SDDL: LocalSystem/Admins/RedFlagLocal); five read-only endpoints
- `redflag-agent -local-status` CLI probe of the local API surface
- Screenshot capture handler (screenshot.go, dispatch wired)
- Tauri desktop spine (desktop/): tray icon, left-click window, local IPC reader
- Desktop React entry (web/src/desktop/LocalAgentApp.tsx, index.desktop.html,
  vite.desktop.config.ts)
- Installer group provisioning: linux.sh creates redflag-local, sets
  SupplementaryGroups; windows.ps1 creates RedFlagLocal security group
- Server-side: screenshot receipt handler on agents, updates handler additions
- web/package.json: @tauri-apps/api + tauri CLI dev dep added
2026-06-08 17:08:58 -04:00