Daevix Docs

Author and pull policy

Write destination allow/deny rules at any scope (platform, org, group, or agent) through the controlplane's operator API, and see how an enclave pulls and converges. One rule to remember: a destination write REPLACES the scope's whole list — author everything you want in a single call.

View as Markdown Edit on Tangled

What policy is and where it lives

Governance policy is a set of typed keys (destinations, LLM governance, interactive-access toggles) stored at hierarchical scopes: platform (no scope flags), org (--org), group (--org --group), and agent (--org --agent). The enclave gateway resolves the chain for each agent and layers the results: a deny anywhere unions down, each allow is an independent gate, and a locked key wins over every more-specific scope.

One typed key, llm.inspection, drives response inspection: when it resolves for an agent, tool calls in the model’s output are held for operator approval per your rules. Authoring it works exactly as this guide describes — see Inspect LLM responses and approve tool calls for the key’s shape and the approval loop.

You author through the controlplane’s authenticated operator API, never the database directly, so every write flows the real path: capability authorization, the Author invariants (agents never lock; no scope may author under a higher lock), an immediate re-publish, and an SSE nudge that tells the affected enclave to re-pull.

Author a destination list

Destination policy is an allow/deny list of host suffixes the gateway matches against egress destinations. Enforcement is default-deny: a host matching no allow rule is denied, deny rules always win over allows, and without a resolved allow the flow falls to default_deny. A list left unset at a scope simply defers to the next scope up — resolution walks from agent to platform and the most-specific scope contributing an allow wins. There is no fail-open: the gateway refuses to start without a policy snapshot, and a failed reload keeps the last good one in force.

Start with a platform baseline:

dvx
 dvx policy destination \    --controlplane https://cp.example.com \    --allow example.com --allow example.org

Then scope to an org — the flags select the scope, so the same command targets platform, org, group, or agent:

dvx
 dvx policy destination \    --controlplane https://cp.example.com \    --org org_acme \    --allow api.partner.example.com \    --deny evil.example --deny-reason "known exfil host"

--deny rules take a --deny-reason, which is recorded with the rules and surfaced in the audit trail when the gateway denies on them. --lock pins the key at this scope so more-specific scopes cannot override it (refused at agent scope — agents never lock).

dvx
 dvx policy destination \    --controlplane https://cp.example.com \    --org org_acme --group team-blue \    --allow api.anthropic.com --lock

The one footgun: a write replaces the list

Each dvx policy destination call replaces the entire allow/deny list at that scope — it is a write of the whole value, not a patch. Run the org command again with a single --allow and every host you allowed before at that scope is gone. This caught a live operator during verification: adding one new host to an org list silently dropped the existing entries until the call was re-issued with the full set.

So the rule is: one call, complete list. To add a host, re-issue the command with everything the scope should hold:

dvx
 # WRONG — replaces the org list with just api.partner.example.com: dvx policy destination --controlplane https://cp.example.com \    --org org_acme --allow api.partner.example.com  # RIGHT — restate the complete list: dvx policy destination --controlplane https://cp.example.com \    --org org_acme \    --allow api.partner.example.com --allow api.example.com

For bundles you reuse across scopes, define a pack once and install it at any org, group, or agent scope — installs compose with the scope’s own key instead of replacing your typed call:

dvx
 dvx policy pack define --controlplane https://cp.example.com \    --name partner-apis --allow api.partner.example.com dvx policy pack install --controlplane https://cp.example.com \    --name partner-apis --org org_acme

Packs can also be installed inline on agent create, so one call yields a governed, usable agent (the caller must hold both agents:manage and policy:write at the org):

dvx
 dvx agent create --controlplane https://cp.example.com \    --org org_acme --enclave eu-sov-1 --image ghcr.io/acme/bot \    --policy-pack partner-apis

How the enclave pulls it

Nothing is pushed into the enclave. Each gateway runs a dvx policy-pull sidecar that holds an authenticated, mutually-TLS’d stream to the broker (the enclave’s sole controlplane egress), re-pulls the enclave’s resolved snapshot on every SSE nudge (and on --interval as a fallback), and writes it to a shared volume the gateway hot-reloads. A failed pull keeps the last-known snapshot, so a controlplane blip never leaves the gateway ungoverned.

In the in-repo dev deployment (deploy/enclave/gateway-daemonset.yaml) the sidecar is configured entirely by environment variables:

DVX_POLICY_PULL_URL:      https://dvx-broker.dvx-enclave.svc.cluster.local:8450
DVX_ENCLAVE_ID:           (from the dvx-enclave-identity ConfigMap)
DVX_POLICY_SNAPSHOT:      /etc/dvx/policy/snapshot.json
DVX_POLICY_PULL_CA:       /etc/dvx/broker-ca/ca.crt
DVX_POLICY_PULL_CLIENT_CERT: /etc/dvx/broker-client/tls.crt
DVX_POLICY_PULL_CLIENT_KEY:  /etc/dvx/broker-client/tls.key

The equivalent CLI flags (all with DVX_-prefixed env sources) are --controlplane, --enclave-id, --snapshot, --interval, --no-events, plus the auth flags (--zitadel-key/--issuer or --token-file, --ca-cert, or client-cert mTLS with --client-cert/--client-key).

Verify convergence

The snapshot is the ground truth the gateway reads. After a write (the SSE nudge fires within moments), read it back from the gateway pod:

sh
 kubectl exec -n dvx-enclave ds/dvx-gateway -c gateway -- \    cat /etc/dvx/policy/snapshot.json{  "enclave_id": "enc_7f3a...",  "orgs": { "org_acme": { "destination": { "allow": [...], "deny": [...] } } },  ...}

Then exercise it: an agent egressing to an allowed host is audited as a gateway.egress allow; a host covered by a --deny rule is denied with your reason attached, visible in the enclave audit (dvx audit events --action gateway.egress --outcome deny).