checkpoint ISAC registries and system monitoring

This commit is contained in:
JB
2026-07-27 00:31:16 -04:00
parent 8b80e55e6c
commit 7b3aff30d8
53 changed files with 1351 additions and 179 deletions
+19 -3
View File
@@ -1,7 +1,7 @@
import { getPermissions, requirePermission } from '$lib/server/auth/authorization';
import { getSessionUser } from '$lib/server/auth/session';
import { getDatabase } from '$lib/server/database';
import { getPagination } from '$lib/server/pagination';
import { getPagination, getRegistrySort } from '$lib/server/pagination';
import { recordIsacAudit } from '$lib/server/audit';
import { fail } from '@sveltejs/kit';
import { randomUUID } from 'node:crypto';
@@ -47,6 +47,22 @@ export const load: PageServerLoad = async ({ cookies, url }) => {
const query = url.searchParams.get('q')?.trim().slice(0, 120) ?? '';
const category = url.searchParams.get('category')?.trim() ?? '';
const action = url.searchParams.get('action')?.trim() ?? '';
const sort = getRegistrySort(url, {
event: {
asc: 'audit_log.action COLLATE NOCASE ASC,audit_log.entity_type COLLATE NOCASE ASC',
desc: 'audit_log.action COLLATE NOCASE DESC,audit_log.entity_type COLLATE NOCASE DESC'
},
operator: {
asc: 'COALESCE(user_profiles.display_name,users.username) COLLATE NOCASE ASC',
desc: 'COALESCE(user_profiles.display_name,users.username) COLLATE NOCASE DESC'
},
target: { asc: 'audit_log.entity_id COLLATE NOCASE ASC', desc: 'audit_log.entity_id COLLATE NOCASE DESC' },
time: {
asc: 'audit_log.created_at ASC',
desc: 'audit_log.created_at DESC',
defaultDirection: 'desc'
}
}, 'time', 'desc');
const conditions: string[] = [];
const args: unknown[] = [];
if (query) {
@@ -82,13 +98,13 @@ export const load: PageServerLoad = async ({ cookies, url }) => {
COALESCE(user_profiles.display_name,users.username) AS actor_name,users.login_username AS actor_login
FROM audit_log JOIN users ON users.id=audit_log.actor_id
LEFT JOIN user_profiles ON user_profiles.user_id=users.id
${where} ORDER BY audit_log.created_at DESC LIMIT ? OFFSET ?`)).all(...args, pagination.perPage, pagination.offset);
${where} ORDER BY ${sort.orderBy},audit_log.id LIMIT ? OFFSET ?`)).all(...args, pagination.perPage, pagination.offset);
const revertedIds = entries.length ? await (await database.prepare(`SELECT entity_id FROM audit_log
WHERE entity_type='audit_control' AND action='audit.reverted' AND entity_id IN (${entries.map(() => '?').join(',')})`)).all(...entries.map((entry) => entry.id)) : [];
const reverted = new Set(revertedIds.map((entry) => String(entry.entity_id)));
return {
entries: entries.map((entry) => ({ ...entry, reversible: canRevert && reversibleActions.has(String(entry.action)) && Boolean(entry.before_json) && !reverted.has(String(entry.id)), reverted: reverted.has(String(entry.id)) })),
categories, actions, summary, pagination, filters: { query, category, action }, canRevert
categories, actions, summary, pagination, filters: { query, category, action }, canRevert, sort
};
};
+2 -1
View File
@@ -3,6 +3,7 @@
import PendingForm from '$lib/components/PendingForm.svelte';
import RegistryPagination from '$lib/components/RegistryPagination.svelte';
import SearchableAssignment from '$lib/components/SearchableAssignment.svelte';
import SortableColumnHeader from '$lib/components/SortableColumnHeader.svelte';
let { data, form } = $props();
let confirming = $state<any>(null);
let handledResultToken = $state('');
@@ -46,7 +47,7 @@
</form>
<RegistryPagination pagination={data.pagination}/>
<div class="dashboard-table">
<div class="dashboard-row audit-row table-heading"><span>EVENT</span><span>OPERATOR</span><span>TARGET</span><span>TIME</span><span></span></div>
<div class="dashboard-row audit-row table-heading"><SortableColumnHeader label="EVENT" column="event" sort={data.sort}/><SortableColumnHeader label="OPERATOR" column="operator" sort={data.sort}/><SortableColumnHeader label="TARGET" column="target" sort={data.sort}/><SortableColumnHeader label="TIME" column="time" sort={data.sort} defaultDirection="desc"/><span></span></div>
{#each data.entries as entry}
<details class="audit-entry">
<summary class="dashboard-row audit-row"><div><strong>{String(entry.action).toUpperCase()}</strong><small>{String(entry.entity_type).replaceAll('_',' ').toUpperCase()}</small></div><div><strong>{entry.actor_name}</strong><small>{entry.actor_login ?? entry.actor_id}</small></div><div><strong>{entry.entity_id}</strong><small>EVENT {String(entry.id).slice(0,8).toUpperCase()}</small></div><span>{date(entry.created_at)}</span><b>DETAILS +</b></summary>