Docs · Governance

Control it. Then prove it.

Two things sit on the broker's egress path: a policy that decides what a pod may reach, and a tamper-evident audit log that records what it did. Both are opt-in and both are secret-free.

Egress policy

A policy is a named set of rules - ~/.config/poddle/policies/<name>.toml - that the broker consults on every request a pod makes. With no policy, a pod may reach anything; add one to lock it down.

FieldRule
allow_upstreamsHosts the pod may reach. When set, everything else is denied (default-deny). A leading dot - ".example.com" - matches that domain and any subdomain.
deny_upstreamsHosts that are always denied. The deny-list wins over the allow-list.
methodsPer-host allowed HTTP methods, e.g. "api.github.com" = ["GET", "POST"]. A ".suffix" key covers subdomains. (CONNECT tunnels are governed by the host rules alone - their real method is encrypted.)
egressWhat the broker does with secrets in outbound bodies: redact (default) / block / off.

The broker decides in a fixed order: deny-list wins, then the allow-list (default-deny if it is set), then per-host methods - otherwise the request is allowed. Every decision is written to the audit log.

Write one

A CI policy that can only reach GitHub and the npm registry, blocks the cloud metadata endpoint, and refuses to leak secrets:

>_~/.config/poddle/policies/ci.toml
# only GitHub + the npm registry, read-mostly
allow_upstreams = ["api.github.com", ".githubusercontent.com", "registry.npmjs.org"]
deny_upstreams = ["169.254.169.254"]  # block cloud metadata (SSRF)
egress = "block"

[methods]
"api.github.com" = ["GET", "POST"]

Attach it to a pod

Pass --policy, or set policy in a template so every pod built from it inherits the rules:

>_zsh
poddle up api --policy ci --identity work
# or, in .poddle/api.toml:
policy = "ci"

Policies resolve like templates: a repo's poddle/policies/ shadows your global ~/.config/poddle/policies/, so a project can pin its own version.

Opt-in, and enforced at the broker

A pod with no policy reaches anything - policy is opt-in. When one is set, the poddled broker enforces it on the wire, so a compromised or prompt-injected agent still can't reach a host the policy denies.

The audit log

The broker is the single writer of a hash-chained log: each event carries the hash of the one before it, so any tampering breaks the chain and is detectable. Events aresecret-free by construction - no request bodies, no resolved credentials, no query-string URLs (which can carry tokens). What gets recorded:

EventWhat it records
requestA proxied request to a brokered upstream.
redact / blockA stray secret was scrubbed from egress, or egress was blocked.
policy.allow / policy.denyA policy allowed or denied an action.
handle.issue / handle.revokeA pod-scoped credential handle was issued or revoked.
l4.connectA pod reached a datastore through the L4 broker.
pod.up / pod.task / pod.move / pod.downPod lifecycle.
mount.refuseA credential-carrying mount was refused.
autoscale.grow / autoscale.warnThe autoscaler grew or warned about a pod.

View & verify

poddle dashboard serves a local, read-only view of the log with a live feed and one-click hash-chain verification. It binds 127.0.0.1 only:

>_zsh
poddle dashboard --open
→ audit dashboard on http://127.0.0.1:7333 · live feed · chain verified ✓

Governance is the same everywhere

Policies and audit sit behind one interface, so the file-backed self-hosted setup and the multi-tenant cloud tier share the exact enforcement path - the rules you write locally are the rules that run in production.