Preserve broker audit causation in central ingestion and SIEM exports

This commit is contained in:
Karl committed 2026-10-14 11:16:09 +02:00
1 parent 9e7cb57093
commit 95d23f4e0b
6 files changed
+132 -3

No files matched your search

+2 -1
View File
@@ -5,6 +5,7 @@ import requestTransferFacts from '../../packages/core/request-transfer-facts.cjs
import agentAudit from '../../packages/core/agent-audit.cjs';
import interactionAudit from '../../packages/core/interaction-facts.cjs';
import transportAudit from '../../packages/core/transport-facts.cjs';
import brokerAudit from '../../packages/core/broker-audit.cjs';
import {installEvidence} from './evidence.mjs';
import {installIncidents} from './incidents.mjs';
import { installBookmarkRoutes,globalBookmarksValid } from './bookmarks.mjs';
@@ -108,7 +109,7 @@ export function createApp(store,config) {
store.db.prepare('UPDATE devices SET last_seen=?,policy_version=? WHERE id=?').run(new Date().toISOString(),b.policyVersion,req.device.id);res.json({ok:true});
});
app.post('/api/device/events',device,(req,res)=>{
const b=z.object({eventId:z.string().uuid(),kind:z.enum([...transportAudit.TRANSPORT_KINDS,'browser.interaction','browser.interaction.dropped','dlp.block','navigation.block','download.block','policy.applied','browser.started','agent.action','agent.denied','library.ai.proposed','library.ai.applied','library.ai.reconcile','devtools.open-requested','devtools.opened','devtools.closed','devtools.denied','download.scan','download.released','upload.authorized','upload.block','dns.block','content.block','vault.submission-completed','vault.submission.failure','vault.submission-prepared','vault.submission-authorized','vault.submission-denied','vault.created','vault.unlocked','vault.locked','vault.saved','vault.deleted','vault.filled','vault.fill-requested','phishing.block','phishing.error','phishing.scanned','clipboard.block','clipboard.copy','clipboard.cut','clipboard.paste']),ruleId:z.string().max(100).optional(),host:z.string().max(253).optional(),policyVersion:z.number().int().positive(),traceId:z.string().regex(/^[a-f0-9]{32}$/).optional(),spanId:z.string().regex(/^[a-f0-9]{16}$/).optional(),file:transferFacts.FileFactsSchema.optional(),request:requestTransferFacts.RequestFactsSchema.optional(),agent:agentAudit.AgentAuditSchema.optional(),interaction:interactionAudit.InteractionFactsSchema.optional(),transport:transportAudit.TransportFactsSchema.optional()}).strict().parse(req.body);
const b=z.object({eventId:z.string().uuid(),kind:z.enum([...transportAudit.TRANSPORT_KINDS,'browser.interaction','browser.interaction.dropped','dlp.block','navigation.block','download.block','policy.applied','browser.started','agent.action','agent.denied','library.ai.proposed','library.ai.applied','library.ai.reconcile','devtools.open-requested','devtools.opened','devtools.closed','devtools.denied','download.scan','download.released','upload.authorized','upload.block','dns.block','content.block','vault.submission-completed','vault.submission.failure','vault.submission-prepared','vault.submission-authorized','vault.submission-denied','vault.created','vault.unlocked','vault.locked','vault.saved','vault.deleted','vault.filled','vault.fill-requested','phishing.block','phishing.error','phishing.scanned','clipboard.block','clipboard.copy','clipboard.cut','clipboard.paste']),ruleId:z.string().max(100).optional(),host:z.string().max(253).optional(),policyVersion:z.number().int().positive(),traceId:z.string().regex(/^[a-f0-9]{32}$/).optional(),spanId:z.string().regex(/^[a-f0-9]{16}$/).optional(),file:transferFacts.FileFactsSchema.optional(),request:requestTransferFacts.RequestFactsSchema.optional(),agent:agentAudit.AgentAuditSchema.optional(),interaction:interactionAudit.InteractionFactsSchema.optional(),transport:transportAudit.TransportFactsSchema.optional(),broker:brokerAudit.BrokerFactsSchema.optional()}).strict().superRefine(brokerAudit.validateBrokerSemantics).parse(req.body);
if(b.kind.startsWith('transport.')){
const unavailable=b.kind==='transport.monitor-unavailable';
if(b.file||b.request||b.agent||b.interaction|| (unavailable?(b.host!==undefined||b.transport!==undefined||!transportAudit.TRANSPORT_MONITOR_REASONS.includes(b.ruleId)):(b.ruleId!==undefined||!transportAudit.canonicalTransportHostname(b.host)||!transportAudit.transportFactsForEvent(b.kind,b.transport))))return res.status(400).json({error:'Transport audit events require matching lifecycle metadata'});