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

449 commits

Author SHA1 Message Date
Fimeg
a859fabedf nightly: drop the server binary — agent+helper only, server installs via verified channel 2026-06-15 10:26:43 -04:00
Fimeg
eb79af448e v0.2.8.4 — releases publish as prerelease until v0.3.0 (alpha) 2026-06-15 09:58:24 -04:00
Fimeg
d9ba008f67 raf: sync docs to code + relative cross-reference links
Handler/migration counts, calculateBackoff -> calculateDelay, machine-id
binding (cross-platform machineid + fallbacks, not hostname), last-reviewed
dates, and made [[cross-references]] relative so they resolve.
2026-06-15 09:39:34 -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
cc19854941 security: latch /admin group behind RequireAdmin (SEC-026)
The /admin group rode on webAuthMW + audit only; just the securitySettings
sibling checked the role. Inert today (login mints role=admin), live the day
RBAC lands — one group-level gate beats per-route annotations to forget.
2026-06-15 09:07:19 -04:00
Fimeg
7d47b0769d gate: route desktop updates through the helper
Desktop self-updates ran in the agent process with their own replay
file. They now go through the privileged helper like agent and helper
self-updates, so the agent performs no binary mutation and keeps no
replay state of its own. The desktop app is a status surface only.
2026-06-14 14:24:29 -04:00
Fimeg
c35ad89b92 gate(executor): constant-time hash compare in the privileged helper
Compare artifact and closure hashes in constant time via subtle::ConstantTimeEq at the three verify sites, closing a timing oracle on the privileged executor. subtle is added as an explicit dep (was only transitive).
2026-06-14 12:57:04 -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
e0765c29f4 supply-chain: honest self-attestation posture (dep-scan, build provenance, install guard)
dep-scan.sh: capture govulncheck's real exit code and feed the reachability gate only on exit 0 (clean) or 3 (vulns found). Any other exit (crash, timeout, 137) is now INFRA, so a truncated-but-parseable JSON stream can no longer parse clean and yield a falsely attested posture. npm ci / npm audit / cargo audit stderr is captured and surfaced on failure (no more 2>/dev/null).

Dockerfile: the posture-builder stage no longer curl|sh's rustup.rs. The Rust toolchain is COPY --from=rust:1-bookworm (canonical official image, same base as desktop-builder) with RUSTUP_HOME/CARGO_HOME set -- stronger provenance than TLS-TOFU rustup, no pipe-to-shell inside the stage that produces the attestation. docker compose build will validate the new layer.

linux.sh.tmpl: guard the posture check under set -e so an un-attested (exit 3) or blocked (exit 4) verdict degrades honestly instead of aborting the install before POSTURE_RC is captured.

ETHOS #1 (errors are history), #3 (assume failure). CI-002 + CI-003.
2026-06-14 12:56:42 -04:00
Fimeg
8ee6d001f3 desktop: drop tauri.conf.json version field, inherit from the crate
4-octet isn't valid semver, so Tauri's build refused it — cargo build died
before it started. desktop/Cargo.toml is the single source now; the release
gate and bump-version stop touching the field.
2026-06-14 11:48:42 -04:00
Fimeg
e2dab2845a supply-chain: gate our own deps, ship the verdict signed
dep-scan.sh gates go/npm/cargo on push and bakes an attested posture into the
release — embedded in the server, signed into the manifest. Reasoning and the
two Moby exceptions are in SECURITY.md.

(posture-builder runs rustup; bookworm's cargo is too old for cargo-audit.)
2026-06-14 11:43:23 -04:00
Fimeg
938a8f6dbb desktop: version 0.1.0 -> 0.2.8.2, into the lockstep
desktop sat at the 0.1.0 stub while everything else moved to 0.2.8.2, so the
release gate's version lockstep would reject any tag. bump-version.sh already
covers desktop (steps 5/6) — this is the one-time catch-up it couldn't do as a
no-op. Cargo.toml 3-part (0.2.8), tauri.conf.json 4-octet (0.2.8.2).
2026-06-13 20:10:47 -04:00
Fimeg
27fe605d78 ci: versioned releases publish to codeberg; drop orphaned gitea image push
Codeberg is the public distribution endpoint, so the release job now creates
the release there too — same artifacts as gitea, server image excluded (server
ships as docker-compose build from source). The docker job that built and pushed
redflag-server to the private gitea registry is gone: nothing pulled it once the
install checkoff started reading the running container, and as a publish gate it
could block a public release on a private-registry hiccup.

README clone URL -> codeberg; Dockerfile builds ./cmd/server/ as a package.
2026-06-13 19:58:35 -04:00
Fimeg
23e9c37953 fix(install): server checkoff reads running container, never pulls a registry
The docker-component checkoff ran 'docker run 10.10.20.120:4455/fimeg/redflag'
to read a version string — reaching the private Gitea registry from every
install, and 'grep redflag' matched unrelated containers. Verify the running
redflag-server container's --version locally instead; agent-only hosts skip
cleanly. (INSTALL-001)
2026-06-13 16:17:55 -04:00
Fimeg
e5f8444482 ci: validate wiuf-docker runner (gitea official image) 2026-06-13 10:13:11 -04:00
Fimeg
ada246764c ci: validate wiuf-docker runner 2026-06-13 09:43:52 -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
b8cdb91a21 ci: nightly alpha channel + hand profile readme to profile-engine 2026-06-12 19:48:54 -04:00
Fimeg
0e1a375af6 ci: fix codeberg secret name typo, escape badge date, guard profile step 2026-06-12 18:57:48 -04:00
Fimeg
8c7e6a4d76 ci: sync-codeberg also stamps .profile README with badges + activity 2026-06-12 16:49:40 -04:00
Fimeg
6a59d46631 fix: escape docker container check from Go template parser
docker ps --format '{{.Names}}' gets eaten by text/template before
Docker sees it. Use docker container ls + grep instead.
2026-06-12 15:38:38 -04:00
Fimeg
0dbf4432dd ci: sync-codeberg job — auto-push public to codeberg when CI passes 2026-06-12 15:23:46 -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
8d54fec8eb raf: desktop component + local trust boundary + fleet-join maintainability
- components/05-desktop.md: the tray as credential-less localapi client; no-token surface marked as open decision (peer identity unanswered), not doctrine
- trust-boundaries: Local boundary section — the kernel is the middleware, group stamping at login is the sharp edge
- standalone-authority: fleet join must stay idempotent, single-source gated, and tested in both directions
2026-06-12 13:26:54 -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
070148f1f5 test: set issuer claim in auth verify test tokens
Now mandatory after the JWT issuer grace period closed.
2026-06-11 20:58:28 -04:00
Fimeg
7670594ac3 sec: issuer claim mandatory — grace period closed
Grace shipped 2026-05-21 for pre-issuer tokens; forward-only removal.
Empty issuer now rejects like a wrong one.
2026-06-11 20:50:27 -04:00
Fimeg
2b1189aaa2 sec: hash failure now blocks approval — fail closed
Hash registry is the tamper gate; approving without it was fail-open.
Empty hash with no error (no artifact) still passes.
2026-06-11 20:48:05 -04:00
Fimeg
6a4be4d12f refactor: timeout + reconciler tickers onto bgRunner
Last two raw tickers; now they get shutdown, panic isolation,
and /health/tasks like everything else.
2026-06-11 20:48:04 -04:00
Fimeg
1af5a9a184 test: guard test learns the bgRunner.Every pattern
Ticker consolidation moved refresh_token_cleanup into the taskrunner;
the source-grep guard only knew go func/ticker.
2026-06-11 20:39:32 -04:00
Fimeg
6cec9aa8ac test: atomic counter in notifier countingSink
Dispatch fires sinks in goroutines; the plain-int counter tripped
go test -race. CI red since the notification bell landed.
2026-06-11 20:27:28 -04:00
Fimeg
dee6149c06 bump: v0.2.8.2
Version lockstep across server, agent, docker-compose, helper.
2026-06-11 20:25:08 -04:00
Fimeg
a944479085 changelog: backfill v0.2.8.1, add v0.2.8.2 2026-06-11 20:24:33 -04:00
Fimeg
413211c657 fix: idempotent Stop() + surface discarded errors
sync.Once on TimeoutService/Reconciler/Syncer stop channels.
syncOne returns its error so admin SyncNow reports real failures.
OSV vuln unmarshal failure now logged, still fails closed.
2026-06-11 20:23:35 -04:00
Fimeg
32c195ef2f sec: stop trusting Host header for agent-facing URLs
resolveServerURL: operator-configured REDFLAG_PUBLIC_URL wins;
request Host only as fallback with a [WARN]. Applied to install
scripts, registration responses, and fleet-join. Host header is
attacker-controllable on pre-auth endpoints.
2026-06-11 20:23:35 -04:00
Fimeg
43ddaab262 cleanup: remove unwired lifecycle/build services
AgentLifecycleService, ConfigService, BuildService, ArtifactService,
AgentBuildHandler — added as a unification pass (e56888e6), never
instantiated by any commit since. ~600 lines.
2026-06-11 20:17:26 -04:00
Fimeg
c6e430225c setup: read bootstrap DB password from environment
Server container shares the bootstrap .env with postgres, so the
current password is already in our environment. Hardcoded literal
kept only as fallback for the shipped default.
2026-06-11 20:17:26 -04:00
Fimeg
230b2f9ab9 fix: comma-ok guards on agent-supplied metadata and gin context
Malformed agent metadata could panic the server (rapid_polling
fields, buffered event metadata, timeout params). scanner_config
asserted uuid.UUID on a user_id the middleware stores as string —
guaranteed panic on both admin endpoints.
2026-06-11 20:17:26 -04:00
Fimeg
86b0944551 wire: auth audit registration + background task consolidation
AUDIT-002: webAuth/agentAuth/metricsAuth registered with the route
auditor before AuditAndExit. RETAIN-001: retention sweep on bgRunner.
Offline-agent and refresh-token tickers migrated to bgRunner.Every;
upstream syncer + reconciler now stopped on shutdown.
2026-06-11 20:17:26 -04:00
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