Diffhold pre-alpha

CLI and flags

One binary, diffhold, runs the server and the operator commands.

Commands

CommandWhat it does
diffhold serveRuns the ExtMcp server, admission webhook, approvals API and AuthZEN endpoint.
diffhold policy check FILE...Validates AgentPolicy files with the same rules the server uses.
diffhold test FILE...Runs policy test suites: for each tool call, the expected allow, deny or approval, and optionally a reason substring.
diffhold approvals listLists pending calls with their diffs (admin token).
diffhold approvals approve CALL_IDApproves a pending call with your own token.
diffhold grants revoke-allDeletes every grant Secret, which revokes every outstanding per-call token. The chart runs it on uninstall.
diffhold audit verify FILE [--public-key KEY]...Checks a hash-chained audit log and reports the first broken record. With the public key from GET /audit/public-key, also checks every signed checkpoint and reports records after the last one. Repeat --public-key for a log that spans a key change.
diffhold permissions check SA...Reports what an agent ServiceAccount can do that could switch off Diffhold. Exits 1 on a high-severity finding, so it can gate CI.
diffhold versionPrints the version.

Policy tests

policies: [agentpolicy.yaml]
cases:
- name: scale over limit
  agent: sre-bot
  tool: resources_scale
  arguments: {apiVersion: apps/v1, kind: Deployment, name: web, namespace: team-a, scale: 50}
  expect: deny
  reason: replicas <= 5

serve flags

Gateway and identity

FlagDefaultMeaning
--grpc-addr127.0.0.1:9000ExtMcp gRPC listen address.
--grpc-tls-cert, --grpc-tls-keyServer certificate. Required with --grpc-client-ca on any non-loopback address.
--grpc-client-caCA that signs the gateway's client certificate.
--grpc-client-namesAllowed client certificate names (CN, DNS or URI SAN). Empty allows any certificate from the CA.
--insecure-grpcfalsePlaintext on a non-loopback address. Testing only.
--insecure-agent-headerTake the agent identity from this header. Testing only.

Policies and credentials

FlagDefaultMeaning
--policiesLoad policies from a file instead of the cluster.
--policy-namespaceDiffhold's namespaceWhere to watch AgentPolicy objects. * watches all namespaces, so anyone who can create one anywhere can bind an agent.
--grant-namespacesagentsNamespaces of agent ServiceAccounts. Grant Secrets live here, and the backstop applies only to them.
--grant-storekuberneteskubernetes (shared by replicas) or memory (one replica).
--grant-key-secretdiffhold-grant-keySecret holding the grant signing key; created if missing.
--audit-key-secretdiffhold-audit-keySecret holding the audit checkpoint signing key, separate from the grant key; created if missing (kubernetes grant store).
--audit-key-file<audit-log>.keyAudit checkpoint signing key with the memory grant store; created if missing. With --audit-log - and no file, the key is new on every start.
--dry-runtrueDry-run and diff every write. With it off, apply calls are denied.

Approvals, admin and HA

FlagDefaultMeaning
--admin-addr127.0.0.1:9001Approvals API, AuthZEN and health.
--admin-tls-cert, --admin-tls-keyHTTPS for the admin listener. Required on a non-loopback address unless --insecure-admin.
--admin-token-fileBearer token for listing approvals, permission findings and AuthZEN.
--max-pending-per-agent20Open approval requests one agent may have at once.
--permission-checkwarnoff, warn (log and GET /permissions) or enforce (also deny agents with high-severity findings, and agents not yet checked).
--audit-checkpoint-interval30sHow often each replica signs its audit chain head.
--approver-audiencediffholdAudience approver tokens must carry.
--approval-ttl1hHow long a request stays open, unless the rule sets timeout.
--approved-ttl15mHow long an approval can be used.
--approval-namespacepod namespaceWhere approvals, used-grant markers and the Lease live.
--leader-electtrueOnly the Lease holder revokes grants, expires approvals and writes status.
--audit-logaudit.jsonlAudit log path, or - for stdout.
--webhook-addr, --tls-cert, --tls-key:9443Admission webhook listener and certificate.

Set OTEL_EXPORTER_OTLP_ENDPOINT to export a trace span per decision.

Helm values

ValueDefaultMeaning
agentNamespaces[agents]Same as --grant-namespaces.
policyNamespace""Empty means the release namespace.
replicaCount2With anti-affinity and a PodDisruptionBudget.
grpc.tls.modeautoauto generates the CA, server and gateway client certificates; certManager has cert-manager issue and renew them; existingSecret; or insecure. The admin listener uses the same server certificate, and is plain HTTP only in insecure mode.
grpc.tls.clientNames[agentgateway]Allowed gateway certificate names.
webhook.tls.modeautoSelf-signed CA kept across upgrades (10-year certificate, not rotated), certManager (renewed, caBundle injected), or existingSecret with a caBundle. Diffhold reloads renewed certificates within 10 s, without a restart.
certManager.issuerRef{}Issuer for certManager mode, for example {name: corp-ca, kind: ClusterIssuer}. Empty: the chart creates a self-signed CA.
certManager.duration / renewBefore2160h / 720hCertificate lifetime and how early it is renewed.
permissionCheckwarnSame as --permission-check.
approvals.maxPendingPerAgent20Same as --max-pending-per-agent.
networkPolicy.enabledfalseLimit the gRPC port to the gateway's pods (networkPolicy.grpcFrom).
revokeOnUninstalltrueRevoke every grant before the webhook is removed.
approvals.pendingTTL, approvals.approvedTTL1h, 15mApproval lifetimes.
otel.endpointOTLP endpoint for traces.