Ga naar inhoud

Signals API

Elke worker, ingest-handler en hub-side scanner schrijft Trust-Score-relevante findings naar één tabel: signal_streams. Trust Score, Anomaly Correlation, Compliance Pareto en alle dashboards lezen daar uit. Geen per-feature silo-tabellen meer.

Wire-format conventies

VeldVorm
sourcelowercase_snake_casecert_scan, dns_check, …
subject_typelowercase_snake_caseagent, endpoint, domain, dependency, …
signal_keydotted lowercase — cert.expiry_days, dns.dmarc_present
signal_valueJSONB; convention: {"value": <native>, …metadata}
severityNULL of één van `info
observed_atTIMESTAMPTZ; partition-kolom in de hypertable
ttl_secondsNULL = sticky

Postgres CHECK-constraints valideren elke regex zodat een typo direct als 23514 boven komt; signals.Emitter.validate() doet dezelfde check in Go zodat de error op de call site landt.

Go interface

import "github.com/gotrust/monsys/hub/api/signals"
emitter := signals.NewSQLEmitter(pool)
err := emitter.Emit(ctx, tenantID, signals.Signal{
Source: "my_check",
SubjectType: "agent",
SubjectID: agentID.String(),
Key: "my.finding",
Value: map[string]any{"value": 42, "extra": "context"},
Severity: signals.SeverityHigh,
ObservedAt: time.Now().UTC(),
})

EmitBatch gebruikt pgx.CopyFrom; all-or-nothing: één invalid signal verwerpt de hele batch (zie signals/emitter.go rationale).

Agent-emitted signals

De agent kan signals emit via een speciaal agent_signals payload-type (Fase 1.4–1.6). Hub valideert:

  • source ∈ allowlist (backup_check, clock_check, endpoint_posture)
  • subject_type ∈ allowlist (agent)
  • subject_id overschreven naar caller-agent_id wanneer subject_type=agent

Een gecompromitteerde agent kan nooit findings claimen voor een andere agent in zijn tenant.

Source → Trust Score categorie

Mapping in hub/api/trust_score.SourceToCategory. Een nieuwe source toevoegen = één entry erbij; zonder die entry telt de source nul punten in Trust Score.

RLS

signal_streams heeft ENABLE ROW LEVEL SECURITY met USING tenant_id = current_setting('app.current_tenant', true)::UUID. Defense in depth. Elke hub-side query MOET nog steeds expliciet WHERE tenant_id = $1 bevatten — set_config(..., true) overleeft pgxpool’s connection-recycling niet. Zie docs/internal/decisions/2026-Q2-connected-dashboards.md D-0003.

Compressie staat niet aan op signal_streams (Timescale 2.18+ weigert RLS+columnstore combinatie). Retention via drop_chunks, default 180d.