Skip to content

Govern and approve (human-in-the-loop)

This page is for the operator who has connected at least one source and now needs to govern the estate: decide who and what can act, review what the platform surfaces, and act on it. Governance lives in module VI (identity, permissions, governance), sits on the same authorization core as the rest of the API, and is fully audited.

Every governance decision is made by the same authorization core that protects the rest of the control plane. Understand its three properties before you change anything.

Authorization runs RBAC first. A principal with no membership in a tenant is denied — there is no implicit grant. Permissions are scoped to a tenant, and the handler acts only on the single tenant the request resolved to, never one it re-derives, which closes confused-deputy and IDOR classes by construction.

The built-in roles form a ladder of increasing capability:

RoleWhat it can do
viewerread operational data and the audit trail
editorthe above, plus write operational data
adminthe above, plus tenant IAM — users, memberships, tokens, settings
ownerall permissions within the tenant

A module declares its own namespaced permissions (<namespace>:<resource>:<verb>), and roles are granted those permissions by verb tier (viewer maps to read, editor to write, admin and owner to admin). A new module therefore introduces governance surface without an engine release.

On top of RBAC, the operator may wire an external policy decision point (PDP) for attribute-based rules. You choose the engine with a single environment variable:

Terminal window
# Choose one. Cedar is the embedded, pure-Go primary; OPA is an over-HTTP adapter.
OLIVARES_PDP_ENGINE=cedar # or: opa | none

Both engines sit behind one seam, and the seam has one invariant that governs how you must reason about it:

The two adapters preserve that invariant in different ways, and you author policy accordingly:

  • Cedar (embedded, primary, pure-Go). You write forbid rules. A rule that matches is a restriction; an empty rule set means the RBAC decision stands. A permit in Cedar can never widen the decision.
  • OPA (over HTTP). Your Rego must be permit-by-default (default allow := true, with allow := false clauses for your denials). A true result means no restriction; false, a missing result, or any transport or non-2xx error fails closed — the request is denied.

An invalid PDP configuration disables only the external PDP and logs the fact — native ABAC and RBAC keep governing. A misconfigured policy engine never leaves requests ungoverned and never takes the control plane down. Every restriction the PDP applies is audited.

Human-in-the-loop governance is driven by what the platform observes and presents. Two streams tell an operator what warrants a decision:

StreamModuleWhat it surfaces
Least-privilege driftIII (access map)the permitted-vs-observed diff — a granted capability used in a way no one intended, or a path that is reachable but never exercised
FindingsIX (security, guardrails, forensics)guardrail and red-team findings, plus the notification stream the platform routes

Module III, the access map, is read-first — it observes through logs, OpenTelemetry and (as a non-cooperative kernel backstop) eBPF, and is never in the agent’s data path, so a collector failure cannot break production. It is also minimal-data: it stores the relation agent → resource (read/write), never payloads, secrets, or PII. The signal it carries is honest about its own confidence (attributed vs approximate) and its own reach.

One signal class needs explicit governance judgment. MCP tool annotations (readOnlyHint / destructiveHint) are a useful read/write hint but are untrusted by the MCP specification — clients must treat them as untrusted. The platform corroborates them against trusted signals and never trusts them alone, and so should you when acting on a drift item that rests only on an annotation.

The intended governance loop is: surfaces present (drift from module III, findings from module IX) → an authorized operator decidesthe decision is recorded in the audit ledger.

All three parts of that loop run today. The surfaces are real — module III produces the permitted-vs-observed diff and module IX produces findings. The approval engine is real — a governed approval request opens against the governance module (deny-closed, plan-hash-bound, time-boxed); an authorized operator approves or rejects via the decision endpoint, and separation-of-duty, duplicate-decider and expiry are enforced server-side so the requester can never decide their own request and an expired one can never bind. And the recording is real and strong — see the guarantee below. What is still design-stage is the built-out operator review console — a rich approval-queue UI; the endpoints and the engine are shipped, the polished review surface is the path forward for module VI.

The dependency that makes this loop credible is per-agent identity. The platform’s audit attributes activity to a credential or role, not inherently to an agent; a shared service account with a connection pool collapses attribution. Governing well therefore means issuing and enforcing identity per agent — the bridge from observation (module III) to governance (module VI). The identity side of this is built around opaque, revocable first-party credentials and a roster of non-human identities; the only credential-minting primitive in the product is opt-in, attested, audited, and never persists the minted token. See the modules catalog for how identity, permissions and governance compose across the estate.

For an external, immutable copy — the thing an enterprise auditor asks for that native telemetry does not provide — the ledger is exposed as an authenticated pull export:

Terminal window
# Pull the signed, hash-chained ledger for offline re-verification.
# Requires a token whose role can read the audit trail (viewer and up).
curl -fsS "https://localhost:8443/v1/audit/export?format=cef" \
-H "Authorization: Bearer $OLVK_TOKEN" \
-H "X-Olivares-Tenant: $TENANT" >> /var/log/olivares/audit.cef

Supported format values are cef, leef, syslog, otlp, otlp_envelope, otlp_log_record and ocsfotlp emits the complete, postable export request, otlp_envelope is an exact alias of it, and otlp_log_record is the bare one-LogRecord-per-line projection. Every record carries the chain-integrity fields so your SIEM or WORM store can re-verify the chain offline. The detached signature defends against a DB-only compromise (injection, a stolen backup or replica, an RLS-bypassing role) and against checkpoint deletion; an off-box copy is the control against a fully compromised host. See forwarding audit to Splunk for a complete file-tail pipeline.

The least-privilege drift these decisions act on is the access map’s permitted-vs-observed result. The zero-to-graph tutorial walks through reaching it concretely on the demo estate; the access-map module surface is subject to the same deny-by-default RBAC, tenant scoping and per-read auditing as everything else, which is why reading it is an editor-and-up action.

  • Security model — privilege, tenant scoping, self-audit, and the minimal-data posture in full.
  • Threat model — the assets, trust boundaries, and what each coverage tier can attest.
  • Modules catalog — how identity, permissions and governance (module VI) compose with the access map (module III) and findings (module IX).
  • Connect a source — wire the signals that drift and findings are built from.