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

479 commits

Author SHA1 Message Date
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
Fimeg
b0e2a77528 fix: pin installed version instead of clearing on install
After successful install (confirm_dependencies or capability receipt),
pin the installed version as selected_version instead of clearing it.
This prevents subsequent scans from silently advancing to a newer
unapproved version. The pin is the enforcement mechanism.
2026-06-08 16:07:33 -04:00
Fimeg
7d089ab5d2 v0.2.6.7 — GATE-006 D, version row OSV check
- evaluateSupplyChainHold checks version row osv_status for target
  version, closing hole where we OSV-check one version but install
  another.
- confirm_dependencies uses TransitionByPackageFrom with source-state
  guard (StatusInstalling → Installed/Failed).
- Clears pinned version on successful install.
- Version bump to v0.2.6.7.
2026-06-08 16:01:05 -04:00
Fimeg
14cd0884b4 fix: consolidate heartbeat, lower dashboard polling
- useHeartbeatStatus reads from agent metadata (single source of
  truth) instead of separate endpoint (eliminated split-brain).
- Online/offline threshold fixed to 10min to match server (was 15min).
- Dashboard polling lowered from 30s to 15s.
- Toggle feedback: invalidate agent queries immediately, clear
  loading state after 2s.
- Removed command-table fallback from GetHeartbeatStatus endpoint,
  dead helper functions, and unused GetRecentHeartbeatCommands.
2026-06-08 16:01:01 -04:00
Fimeg
9c8e08e079 fix: migration loop caused by phantom config_v5_migration
Three layered causes:
1. config_v5_migration had no executor phase — structurally impossible
   to mark complete.
2. StateManager.loadConfig unmarshaled into typed config.Config, but
   install template writes version as JSON number while Config types
   it as string — migration completion never persisted to disk.
3. readConfigVersion only parsed float64, so normalized string read 0
   and re-triggered.

Fix: StateManager is map-based (immune to field-type drift). Executor
has real config_v5 phase (bump + mark complete). parseConfigVersion
accepts both number and string. validateMigration uses MkdirAll then
stat (fixes false 'state dir not found' on Windows).
2026-06-08 16:00:56 -04:00
Fimeg
c2d683d63b fix: Windows agent — service, logging, local state, CPU parse
Service:
- Build complete LoopContext in Windows service runAgent (was missing
  ReceiptTracker, ConfirmedTracker, scanners, circuit breakers,
  kernel enforcer — nil ReceiptTracker caused immediate panic).
- Wire process logger so log.Printf writes to agent.log on Windows.
- Parse CPU info JSON from PowerShell fallback (wmic absent on
  modern Windows; old code tried CSV parse on JSON output).

Local state cache:
- Agent writes status, scan results, capability token state to
  local disk cache. Enables local observability without a server
  round-trip. Handlers expose /local/state, /local/status endpoints.
- Record agent status (online/backoff) and capability token metrics
  to local cache during polling loop.
2026-06-08 16:00:47 -04:00
Fimeg
f83f5a0960 fix: Windows install path — ACL repair, host/port, CRLF
- Install script repairs config ACL before detection (unreadable
  config.json caused false 'not installed' and 409 re-registration).
- Config permissions use stable SIDs (SYSTEM, LOCAL SERVICE,
  Administrators) instead of localized account names.
- Install URL preserves port for non-localhost hosts.
- Server bind address vs reachable host distinction fixed.
- Windows install script served as CRLF.
- Installer tolerates missing Ed25519 verifier.
2026-06-08 16:00:01 -04:00
Fimeg
8ced1d5a47 fix: make Windows installer tolerate missing Ed25519 verifier 2026-06-08 10:47:07 -04:00
Fimeg
4dc750b687 fix: agent install URL preserves port for non-localhost hosts
getServerUrl() was stripping the port when hostname != localhost,
generating install commands on port 80. Now uses window.location.port
directly — the browser's host:port is always reachable by the agent.
2026-06-08 09:25:46 -04:00
Fimeg
7ae7429878 fix: bake reachable host into install script, not server bind addr
getServerURL returned localhost:31337 (the server's own bind address), so
a remote agent's binary/manifest/config fetches pointed at itself and
failed with "Unable to connect". Prefer the host the client actually
reached us on (Host + X-Forwarded-Proto, which nginx forwards), falling
back to PublicURL then the configured bind addr. Also set charset=utf-8 so
irm stops mangling the ✓/⚠ glyphs.
2026-06-08 09:15:26 -04:00
Fimeg
495d5fb3a7 fix: serve Windows install script as CRLF
Windows PowerShell 5.1's parser chokes on here-strings in LF-only .ps1
files — the embedded config template blew up with a cascade of
"Unexpected token ':'". Convert the windows script to CRLF at serve time
(parses clean in 5.1 and 7; .ps1 should be CRLF anyway). Linux stays LF.
2026-06-08 09:07:43 -04:00
Fimeg
f811b47e0b fix: Windows one-liner self-authenticates again (irm | iex)
The Windows installer relied on a Mandatory=$true -Token param, but the
one-liner ran the script with no -Token -> PowerShell dropped to an
interactive prompt and the install looked hung.

Bake the token/server into the rendered script like the Linux template
already does, drop param() and #Requires (both no-op under iex; runtime
admin check still enforces elevation), and switch the command to
'irm ... | iex' so the body actually pipes. -Token/-Server/-Skip become
RF_TOKEN/RF_SERVER/RF_SKIP_SERVICE_INSTALL env overrides.
2026-06-08 08:44:27 -04:00
Fimeg
40f57edefc v0.2.6.4 2026-06-08 08:14:24 -04:00
Fimeg
b09453e849 install the version that cleared the soak window, not the bleeding edge
the supply-chain check was judging available_version while the gate could
install a different one. re-run OSV against the version we actually install
(operator-pinned, else gated), and auto-pin the newest soak-aged clean
version when the gate's enforced — forward-only, operator force-pin wins.
2026-06-08 08:14:20 -04:00
Fimeg
ae3db516c0 let the agent spot sunshine and give the overview tab a face for it
observe-only: the agent folds detected integrations into its system-info
report under metadata.integrations; the dashboard renders what it reports.
nothing reaches into the host — an integration can be watched, not commanded.
2026-06-08 08:14:13 -04:00
Fimeg
f136c12902 shed agent writes when the db pool runs dry
last half of S8. the pool bump and bounded background took most of the pressure
off, but a full fleet can still pin every connection. now there's a valve:

- middleware reads db.DB.Stats(); at the saturation threshold it answers 503 +
  retry-after instead of letting writes queue into a deadlock
- fails open — unlimited pool never sheds, default only trips at 100% in-use.
  tunable via REDFLAG_DB_SHED_UTILIZATION and _RETRY_AFTER_SECONDS
- wired to the agent write group only. health, metrics, auth, register/renew
  and the dashboard stay reachable so you can still watch it and log in while
  it's hot

table-driven test across the branches, race clean.
2026-06-07 21:16:53 -04:00
Fimeg
cf061a13a1 seal the settings path so secrets land encrypted
the encrypt/decrypt hooks existed but the write path wrote values straight to
the column, so a sensitive setting would have gone in as plaintext. closed it:

- sensitive values serialize + encrypt before they persist (base64 aes-gcm over
  the json), and updates now carry the is_encrypted flag through
- non-sensitive settings are untouched — still plain json, same as before
- audit log redacts sensitive old/new values instead of recording them raw

round-trip test proves sensitive values never hit the column in plaintext and
still decrypt back; non-sensitive stay readable. no backfill needed — nothing
writes secrets through this path yet, the defaults are empty.

builds clean, vet quiet, tests pass.
2026-06-07 21:16:39 -04:00
Fimeg
f7882241c7 give the system a window you can scrape, and patch a migration that couldn't run twice
OBS-001A: an authenticated /metrics so something other than a human reading
logs can watch the box. no new dep — emits prometheus text straight from the
counters we already keep:

- /metrics behind a dedicated bearer token (sha-256 hash stored, plaintext only
  from REDFLAG_METRICS_TOKEN for bootstrap). constant-time compare, rotates
  without a restart, disabled by default, never an open route
- exports db pool, taskrunner snapshot, scheduler + queue, breaker state, and
  the deferred-advisory count — read live on each scrape, bounded labels only
- settings + migration 054 for observability.metrics_enabled / _token_hash

also fixed migration 046 — it added a column and an index without IF NOT EXISTS
and backfilled off a column it then drops, so it couldn't survive a second run.
guarded every step; the idempotency lint is green again. only the migrations
the runner hasn't recorded see the change, so live dbs don't care.

builds clean, vet quiet, new tests pass.
2026-06-07 20:59:29 -04:00
Fimeg
ae411cf5d4 say it out loud when the advisory feed goes dark
the breaker fails open so a down osv never blocks a patch — good — but the
auto-confirm gate is fail-closed, so a dark feed quietly stops auto-approval
and parks packages unvetted. that truth was sitting in the logs where nobody
looks. now it's a banner.

- /api/v1/health/advisory: breaker state + count of deferred packages
  (self-healing — a successful recheck clears the flag) + a degraded flag
- amber bar in the layout, only when degraded: "feed offline, auto-approval
  suspended, manual still works." says feed-down isn't patching-down
- narrow slice of the gate-visibility work; the full posture panel stays in
  its own session

builds clean, tsc's happy.
2026-06-07 20:17:18 -04:00
Fimeg
e99ad6e8c7 gave the server a breaker so a sulking upstream can't drag it down
osv.dev or repology going dark used to mean every check sat there burning its
30s timeout, one after another. now there's a breaker (ported the agent's, it's
already proven) wrapping both:

- osv: one breaker over the batch + single-query paths. trips after 5 fails in
  a minute, fails open while tripped — an unreachable advisory feed never blocks
  a patch. that's the whole sovereignty bet
- repology: same deal, best-effort, 404 doesn't count against it
- both visible at /health/tasks so you can see them trip and heal

db-pool shedding (503 + retry-after) is the other half — left it for later, the
pool bump + bounded background already took most of that pressure off.

race detector's clean.
2026-06-07 19:45:36 -04:00
Fimeg
d25f6ea030 swept the cobwebs, stopped re-dialing the same three hosts
three more off the scale list:

- rate-limit map now gets swept on a cadence (taskrunner.Every) instead of
  growing forever — nobody was calling the cleanup. first old ticker moved
  onto the runner
- subsystem load was one db query per agent at startup; now it's a single
  ANY($1) for all the online ones. 100 agents, 1 query
- outbound http clients (osv, registries, upstream, agent) were inheriting
  the stock transport that keeps 2 idle conns per host — so every scan burst
  re-dialed. shared tuned transport now, 10 per host, 90s idle

builds clean both modules.
2026-06-07 19:35:32 -04:00
Fimeg
82018bfb80 taught the rocks to stop tripping over each other under load
server was sized for a campfire, not a fleet. 25 db connections, every agent
report flinging goroutines into the void, the syncer plodding one repo at a
time while clutching a lock nobody needed. loosened the choke points:

- db pool 25 -> 100 + connection lifetime, all env-tunable
- bounded pool for the report-path fire-and-forget work; /health/tasks to
  watch it breathe. no more unbounded goroutine spray per report
- upstream syncer runs concurrent now, dropped the dead mutex around repology
  fetches, reconciler single-flights instead of locking through the whole crawl
- scheduler caps jobs per tick so an aligned fleet can't stampede the db
- swatted a context-cancel bug that was quietly killing immediate syncs

builds clean, race detector's calm.
2026-06-07 19:17:08 -04:00
Fimeg
5b1a16ca3e v0.2.6.2 — osv scans moved to detection, soak gate grew up
approval stopped re-scanning osv; it just reads what detection already
found. soak gate + age gate are real settings now (env→db→default), and
the dead soak-override column + table got composted.
2026-06-07 14:44:41 -04:00
Fimeg
b82649967e RECONCILE-001: scan-set closure (close-by-absence) + v0.2.6.1
Treats each ecosystem scan as the authoritative full set for that
(agent, ecosystem) pair. Packages absent from a successful scan that
are still in a waiting state (pending/approved) are closed to installed
with out-of-band provenance — no operator action required.

State machine:
- Added pending/approved → installed edges (out-of-band resolution path)
- Added installed → pending edge (reactivation when a new version reappears)
- ReconcileFromScan updated to match: installed now reopens, ignored/failed preserved

Server (ReportUpdates):
- closeScanAbsentRows goroutine: diff waiting rows against reported set,
  transition absent rows via transitionStatus (guarded UPDATE, idempotent)
- Provenance stamping: redflag_receipt if a consumed capability token exists,
  out_of_band otherwise
- System event emitted per closure for audit trail
- scanEcosystemSupported gate: dnf/apt only; failed/partial scans never close rows

Agent:
- UpdateReport extended with Ecosystem + ScanSucceeded fields
- APT/DNF scan handlers now always report on successful scan (even 0 updates)
- HandleScanAPT/DNF/Updates: report failure is non-fatal (transport problem,
  scan succeeded locally)

Queries:
- GetTrackedNonResting: scoped to pending/approved only — in-flight states
  (checking_dependencies, pending_dependencies, installing) are orchestrator-owned
- TransitionByID: routes closure through the state machine
- HasConsumedTokenForUpdate: provenance check for the reconciler
- UpdateCurrentStateInTx SQL CASE: installed now reopens to pending on re-scan

Tests: reconcile_test.go (5 unit tests including load-bearing
TestWaitingStatesResolveOutOfBand), reconcile_test.go handler tests (7 sub-tests).

Bump: v0.2.6.1
2026-06-06 20:46:29 -04:00
Fimeg
edf799d8d5 feat: filter/search primitives — composable UI components + hooks
Replace monolithic FilterBar/useFilterState with proper primitives:

Components (pure UI, zero state):
- SearchInput — controlled search input with icon + clear
- FilterPill — colored dismissible chip
- FilterDropdown — styled select with label + active state
- FilterCountButton — clickable stat card with count + color

Hooks (single responsibility):
- useDebounce — generic value debounce
- useFilterUrl — URL param sync only
- useQueryParser — raw query → parsed text + filters + pills
- useMultimodalFilter — composes above two for key:value search

Pure functions:
- queryParser.ts — parseQuery/buildQueryString

Migrated all 6 pages:
- Docker: full multimodal search with key:value parsing, clickable stat cards
- Updates: SearchInput + FilterDropdown + FilterPill with clear all
- Agents: SearchInput + FilterDropdown (status, OS)
- LiveOperations: SearchInput + FilterDropdown
- TokenManagement: SearchInput
- History: SearchInput + useDebounce
2026-06-05 22:40:33 -04:00
Fimeg
b346c1386e v0.2.6.0 2026-06-05 21:34:12 -04:00
Fimeg
cea3986fae fix: SPA nav hygiene + history crosslinks
- Layout/Dashboard refresh buttons use queryClient.invalidateQueries, not reload()
- LiveOperations view-update/view-agent use navigate(), not window.open new tab
- Updates.tsx filter sync uses setSearchParams, not window.history.replaceState
- ChatTimeline: View Agent shows hostname; package links go to /updates/package/:type/:name
2026-06-05 21:30:45 -04:00
Fimeg
1ec7999d8f fix: code review batch 1 + dead store setting
- #1: ReconcileAll goroutine uses context.Background, not request ctx
- #4: InstallVersion now checks maintenance window before dry-run
- #5+#23: tickAliases fetches stale slugs once before loop; rename shadowing var
- #6: UpsertReconciled sql.ErrNoRows on manual conflict is a no-op, not a warn
- #7: normalizeRepoToEcosystem uses ordered slice, not non-deterministic map
- #8: MatchByContainer ILIKE escapes % and _ metacharacters via REPLACE
- #9: EnqueueDryRun uses target_version key for selected_version, keeps available_version for freshness
- #13: InstallVersion drops second GetUpdateByID, mutates struct locally
- #14: EnrichFromMetadata reserved map is package-level var, not per-call alloc
- #21: recordGateOverride shared helper; recordSupplyChain/SoakOverride delegate to it
- store.ts: remove dead notificationsEnabled setting (no callers outside store)
2026-06-05 21:26:44 -04:00
Fimeg
f005255e68 feat: docker enrichment pipeline, package detail, update history pagination 2026-06-05 21:18:06 -04:00
Fimeg
d1424e8377 feat: FEAT-002 metadata pipeline, GATE-005 soak gate, BRIDGE-001 auto-discovery
FEAT-002: Server-side metadata pipeline
- ReportUpdates merges PackageDescription/CVEList/KBID/SizeBytes into metadata JSONB
- UpdateCurrentStateInTx uses JSONB merge (||) instead of replace
- Fixes current_version bug (missing EXCLUDED.current_version)
- EnrichFromMetadata() on UpdateState populates display fields from metadata
- mergedVulnerabilities() deduplicates agent CVEs with OSV.dev results
- VulnerabilityEntry struct for unified vulnerability representation

GATE-005: Version soak-gate
- Migration 050: selected_version column, version_soak_overrides table
- soak_gate.go: SoakGateConfig/EvaluateSoakGate (14-day default, block enforcement)
- POST /updates/:id/install-version endpoint with soak evaluation
- EnqueueDryRun reads COALESCE(selected_version, available_version)
- Override journals to system_events (recordSoakOverride)

BRIDGE-001: Tracked software auto-discovery
- Migration 051: repology_slug/container_image_pattern/binary_probe on tracked_software,
  repology_aliases table, match_method/package_name on agent_tracked_software
- RepologyCache: fetches /api/v1/project/{slug}/packages, normalizes repos to ecosystems
- ReconciliationQueries: MatchByRepology/MatchByContainer/MatchByExactName
- Reconciler: cascade matching service with hourly loop, hooks into ReportUpdates
- UpsertReconciled: preserves manual operator bindings
- COMMON_SEEDS updated with repology_slug values
- Syncer updated with 24h alias refresh ticker
2026-06-05 17:43:11 -04:00
Fimeg
938d0bee35 v0.2.5.2 2026-06-05 16:37:56 -04:00
Fimeg
cad1554d94 feat: SETTINGS-001 reversible token encryption + one-liner restore
Reversible AES-256-GCM encryption for registration tokens so the
install one-liner can auto-fill the token value again. Migration 049
adds token_encrypted column; token_hash kept for lookup.

AgentManagement.tsx gets platform cards (Linux, Windows; macOS = soon)
with generateInstallCommand for all platforms. Inert until backend lands.

system_event_logger.go extracted from deleted event_stream.go —
SystemEventLogger survives, unified substrate does not.

security_settings_service.go and secrets_manager.go simplified.
2026-06-05 16:17:47 -04:00
Fimeg
4ccbf8c5fd fix: heartbeat auto-queue treats duplicate-pending as benign (ETHOS #4)
queueSystemHeartbeat now checks for the unique violation on
idx_agent_pending_subsystem and logs at INFO instead of WARN.
A duplicate means the desired heartbeat is already in flight —
not a failure. Suppresses the scary WARN on every rapid-polling
enable where a heartbeat was already pending.
2026-06-05 16:17:36 -04:00
Fimeg
5d7babff22 fix: History 500, rename to GetFleetActivity, remove dead unified substrate
GetFleetActivity replaces GetAllUnifiedHistory — filters now apply once on
the outer aliased result instead of per-arm, fixing the agent_id ambiguity
when the logs arm joins update_packages (the 500).

Three new UNION arms: update_events, update_version_history, system_events.
Package name joined to update_logs via update_package_id.

Dead code removed: event_stream.go (handler + service), UnifiedEventTimeline.tsx,
useEvents.ts — orphaned from the abandoned unified path (HANDOFF-2026-06-05).
SystemEventLogger extracted to system_event_logger.go (unstaged, next commit).
2026-06-05 16:17:27 -04:00
Fimeg
62f2764260 v0.2.5.1: lifecycle, live operations, unified history
Lifecycle:
- ReopenUpdate + ResolveUpdate replace RetryUpdate; routes for
  GET /updates/:id/lifecycle and POST reopen/resolve
- confirmUpdateCommand marks update_agent completed on version attestation
- migration 048: started/running added to update_logs.result
- helper atomic_replace_binary: copy-to-sibling then rename() (ETXTBSY)

Live operations:
- event_stream service + /events endpoints, LiveOperations page
- capability-token queries for the live view

History + CVE:
- History page reads /events/recent: filterable lifecycle/command/
  system/orchestrator timeline with agent crosslinks
- CVE drill-down: OSV parse carries CVSS vector, fixed version, published
  date, severity; issuer-linked aliases (CVE->NVD, GHSA->GitHub, ALSA->errata)
- DependencyClosureTree: one shared closure component in update detail
- STARTED (blue spinner) and PARTIAL (amber) result badges
2026-06-05 09:13:42 -04:00
Fimeg
6c331e909b update_logs.result: add started/partial/running — fix agent-report badge semantics
The schema only allowed success/failed/partial. The agent sends 'started' as a
progress report and 'partial_failure' when a multi-scanner scan had mixed
results. Both were being remapped to 'failed' by the server's fallthrough
default, so the timeline showed a red FAILED badge for 'starting agent update'
and for scans where only some scanners errored.

Two-value migration (no-data):
  - Add 'started' and 'running' to the update_logs.result CHECK constraint
  - Add them to isValidResult so they pass through without remapping
  - Fix the fallthrough switch: partial_failure -> partial (not -> failed)
  - Clean up if/else chain to a switch while we're in there

UI:
  - STARTED badge (blue spinner) for progress reports
  - PARTIAL badge (amber triangle) for partial results
  - Both ChatTimeline and HistoryTimeline updated

Event renderer:
  - 'started' -> 'Agent binary update initiated'
  - 'partial' for install/update_agent cases
2026-06-05 09:13:42 -04:00
Fimeg
0dcfe25705 unified agent+helper upgrade: closure carries both binaries
Server: mintAgentSelfToken includes helper in closure, sends
helper_download_url + helper_checksum in command params.

Agent: downloads and stages both binaries, passes --helper-file to helper.

Helper: parses --helper-file, separates closure into agent+helper entries,
self-updates helper binary first, then installs agent. Falls back to
agent-only if closure has 1 entry (backward compatible).
2026-06-05 09:13:42 -04:00
Fimeg
b30261791d fix: result file 0644 so agent can read back from root-owned helper
The helper runs as root via systemd-run. With 0640 root:root, the
unprivileged agent user cannot read the result. The result directory
is 0700 agent-owned which already blocks other local users.
2026-06-05 09:13:42 -04:00
Fimeg
482e5a9aad security: path traversal, file perms, sudoers/polkit scope, staging cleanup
- consumer.go: safeTokenFilename() blocks path traversal via token ID
- consumer.go: TOCTOU sanity check on result token_id
- main.rs: result file written 0640 (was 0644)
- linux.sh.tmpl: sudoers wildcards restricted to tokens/* and results/*
- linux.sh.tmpl: polkit scoped to manage-transient-units
- agent_update.go: clean up pending-upgrade.bin on failure
- updates.go: clear is_updating flag on failed update_agent
- bump 0.2.3.7
2026-06-05 09:13:42 -04:00
Fimeg
cff31d6106 v0.2.3.5: unlock self-update + gated installs on fresh hosts
We kept claiming self-update worked. On a clean box it didn't.

- linux.sh.tmpl: install a polkit rule so the service user can invoke the
  helper via systemd-run. Without it every gated install and self-update
  hit auth_admin and died on a TTY-less service.
- self-update: drop the post-update .bak sweep. It ran unprivileged against
  a root-owned backup and could only ever log permission-denied. The helper
  already keeps .bak as the single rollback slot.
- metrics/docker reports: stop finalizing the command at ingest. It raced
  ReportLog and 409'd the history-bearing log, silently dropping system and
  docker scans from History. ReportLog is the sole finalize point now, same
  as dnf/storage.
2026-06-05 09:13:42 -04:00
Fimeg
5758b26875 swap uuid lib, windows installer pass, README/RAF copy
- google/uuid -> gofrs/uuid/v5 across server + agent
- windows.go: cross-platform binding cleanup
- linux install template: disable sudo lecture for TTY-less service user
- README: XZ/SolarWinds lede, stable-release note, single attack-surface block
2026-06-03 15:39:49 -04:00
Fimeg
6327c13460 fix: metadata race, gate predicate drift, OSV concurrency, closure pre-check
ApproveUpdateWithVulns uses JSONB merge (||) instead of full replace —
concurrent checkClosureAndAdvance no longer loses its keys.

evaluateSupplyChainHold gates on ClosureCleared not ClosureChecked —
manual and auto paths now share the predicate for real.

RunOSVChecks fans out batches with goroutines bounded by the 4-slot
semaphore instead of running them sequentially.

Zero-dep capability path verifies a pinned closure exists before
transitioning to installing — no more opaque mint failure after state
change.
2026-06-01 15:21:50 -04:00
Fimeg
7a154e11ee docs: changelog gets its own life, README tells the truth about v0.2.3.1
changelog entries for v0.2.2.0 (state machine + orchestrator), v0.2.3.0
(OSV batch, closure-wide checks), v0.2.3.1 (vuln is a full stop).
README condensed to point at CHANGELOG.md, gate description updated
from "soon" to what it actually does now.
2026-06-01 15:06:39 -04:00
Fimeg
36923bb509 ops: supply chain section now tells the truth — advisory fails open, the gate doesn't 2026-06-01 09:56:09 -04:00
Fimeg
dc3bfdf493 supply chain gate: a vuln is a full stop now — admin signs for it or it doesn't ship
delivery plumbing that got us there:
- acks clear on result-recorded, not command lifecycle status (no more 34-deep recycling)
- timeouts, cancels, dropped acks/receipts, failed actions all land in history instead of dying on stdout
- one shared closure-cleared predicate so auto-confirm and manual approve can't drift

override waives the vuln call only and gets journaled; signing and hash verification stay non-negotiable.
2026-06-01 09:55:22 -04:00
Fimeg
1b6892ad2d I forgot to commit all the working files - let's start the day off from a clean tree 2026-06-01 08:09:28 -04:00
Fimeg
37a2302628 docs: promote 7zip dependency-resolution shot to the top showcase row 2026-05-31 22:11:00 -04:00
Fimeg
2b02f65dbd v0.2.3.1: bump version (README, versions.go, compose) 2026-05-31 22:07:40 -04:00
Fimeg
91e097f54a 0.2.3.0: README honesty pass + fresh screenshots — version, clone count, and OSV now tells the truth about checking your deps' deps 2026-05-31 22:00:09 -04:00