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.
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 policy destination \ --controlplane https://cp.example.com \ --allow example.com --allow example.orgThen scope to an org — the flags select the scope, so the same command targets platform, org, group, or agent:
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 policy destination \ --controlplane https://cp.example.com \ --org org_acme --group team-blue \ --allow api.anthropic.com --lockThe 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:
# 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.comFor 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 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_acmePacks 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 agent create --controlplane https://cp.example.com \ --org org_acme --enclave eu-sov-1 --image ghcr.io/acme/bot \ --policy-pack partner-apisHow 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:
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).