Son of Anton Docs
Self-host

Secrets and Keys

Credential ownership, branch-specific authentication, container forwarding and coordinated rotation.

Keep secret values out of committed source, chat, logs and public reports. A private env file or protected PEM file is supported on Node; Worker secrets are used on Cloudflare. Secrets can legitimately be held by multiple authorized processes, so neither “never in a file” nor “exactly one process” describes the implementation.

These instructions require authorized access to the engine's private source and licensing terms from its owner. Engine code below refers to son-of-anton-review on feat/cloudflare-native; the expanded operator API and session UI are explicitly separate trees.

Engine credential holders

CredentialNodeCloudflare-native
GITHUB_APP_IDPlain config for server/worker App clientsPlain broker var, not a secret
GITHUB_APP_PRIVATE_KEY_PATH or GITHUB_APP_PRIVATE_KEYServer and worker read the key for publication. Inline PEM wins over a file path.Only GITHUB_APP_PRIVATE_KEY on the key-broker Worker. No App key on main or OMP.
GITHUB_WEBHOOK_SECRETServer requires it at boot; worker has an internal fallback, not an App setup mechanismMain ingress verifies webhook HMAC
Provider keyRunner reads the selected provider key from envMain Worker secret forwarded to OMP
E2B_API_KEYNeeded for the E2B executorForwarded to OMP when configured; needed for E2B primary or shadow validation
Git clone/fetch authenticationSeparate restricted gh and Git authentication under the worker's OS userA broker-minted read token is exposed temporarily to gh/Git through per-process credential environment
GILF_OPERATOR_UI_TOKENRequired when the optional Node dashboard is enabledNot a native ingress dashboard credential; the native main Worker does not expose that UI

Node does not automatically load .env; use an approved service EnvironmentFile or explicit node --env-file=... as in the quickstart. Protect both the env file and PEM with service-account-only access. Avoid defining both inline and file-based App keys because updating the file will not replace an inline key still in the environment.

The native broker defaults tokens to contents:read, pull_requests:write, checks:write, metadata:read, and accepts explicit permissions/repository scope from callers. Repository scoping is applied when supplied; the broker does not hard-require a nonempty repository list. Do not describe it as enforcing an unconditional single-repo maximum.

Provider key precedence

src/model-provider.js checks the bare key first, then the prefixed alternative:

ProviderKey lookup order
OpenRouterOPENROUTER_API_KEY, then GILF_OPENROUTER_API_KEY
OpenAIOPENAI_API_KEY, then GILF_OPENAI_API_KEY
AnthropicANTHROPIC_API_KEY, then GILF_ANTHROPIC_API_KEY

Only the bare provider-key names are in the native container forwarding allowlist. Setting a prefixed key as a main-Worker secret is not sufficient for the container. Codex uses its own installed CLI and authentication; the provider status function reports it configured without checking that login. The native image ships a failing Codex placeholder, not that authenticated CLI.

Provider-status output contains names and configuration booleans, not key values. A configured boolean proves presence, not validity or provider entitlement.

Provider reporting and execution selection are different: the current Node worker uses the runner's GILF_CODEX_PROVIDER / GILF_CODEX_MODEL fallbacks, while the native entrypoint explicitly supplies GILF_MODEL_PROVIDER / GILF_MODEL. The exported modern config helper is not called by Node worker.mjs. A dashboard's selected-provider indicator is therefore not proof of which model that worker runs.

Native container forwarding

cloudflare-native/src/container-env.js forwards nonempty string values for exactly these names:

GILF_MODEL_PROVIDER  GILF_CODEX_PROVIDER  GILF_MODEL  GILF_MODEL_PRICES
GILF_PUBLISH_MODE  GILF_OPENROUTER_REQUIRE_FREE
OPENROUTER_API_KEY  OPENAI_API_KEY  ANTHROPIC_API_KEY
E2B_API_KEY  GILF_VALIDATION_SHADOW_EXECUTOR  GILF_VALIDATION_SHADOW_TIMEOUT_MS
GILF_E2B_TIMEOUT_MS  GILF_E2B_CPU_COUNT  GILF_E2B_MEMORY_MB  GILF_E2B_TEMPLATE
GILF_VALIDATION_COST_RATES

It also sets GILF_VALIDATION_EXECUTOR from the Worker or defaults it to managed-cf-sandbox, and always sets GILF_CF_SANDBOX_ENABLED=1. Neither setting alone creates the required Sandbox collector.

The App key, GILF_REPOS, prefixed provider keys, GILF_MODEL_PRIMARY, swarm/planner flags, model inversion and evidence-artifact flags are absent. Setting them on the Worker does not make them available to the runner. Adding support requires an engine change, not a secret rename.

The dispatcher can withhold GILF_VALIDATION_SHADOW_EXECUTOR at the configured E2B budget. Ledger-read failure forwards it unchanged. This is not a strict provider spending cap or a revocation mechanism for running containers.

Validation boundary

buildSafeChildEnv forwards a limited set of process environment names, including PATH, HOME, user/locale/terminal/temp settings and CA-certificate paths. It omits App, webhook, queue and provider secrets. Codex adds CODEX_HOME for its own authentication; the self-host command receives its repository/network settings.

Environment filtering is not filesystem or network isolation. A custom self-host command must enforce its own container/VM boundary and cleanup. GILF_SELF_HOST_NETWORK declares intent, not a firewall. The legacy local executor is refused unless GILF_ALLOW_LOCAL_VALIDATION=1; do not enable it for untrusted PRs. There is no implemented GILF_BROKER_ALLOW_LOCAL_KEY setup switch on this path: the Node entrypoints directly use configured App keys.

Queue and operator tokens differ by tree

Engine-tree queue

son-of-anton-review/cloudflare/src/worker.js uses one GILF_QUEUE_TOKEN for its queue/context-graph HTTP routes. The Node caller selects the remote queue with GILF_QUEUE_URL and GILF_QUEUE_TOKEN. Its graph client can use GILF_CONTEXT_GRAPH_URL / GILF_CONTEXT_GRAPH_TOKEN, falling back to the queue pair; against this engine-tree Worker the supplied token must match its one configured token.

Parity operator Worker

son-of-anton-operator-parity/cloudflare/src/worker.js instead selects route-specific secrets. Its workerEnv resolves SON_OF_ANTON_<suffix> before GILF_<suffix> using nullish fallback. An empty canonical value therefore blocks the legacy fallback.

SuffixRoute selection
QUEUE_ENQUEUE_TOKEN/queue/enqueue
QUEUE_WORKER_TOKEN/queue/claim, /queue/ack, /queue/fail, /queue/renew
QUEUE_ADMIN_TOKEN/queue/jobs, /queue/stats
CONTEXT_GRAPH_TOKEN/context-graph/*
REVIEW_STATE_READ_TOKEN/review-state/health and fallback review-state routes
REVIEW_STATE_SYNC_TOKEN/review-state/sync
OPERATOR_READ_TOKENGeneral operator reads; command GET accepts this or bridge token
OPERATOR_ADMIN_TOKENSelected queue/repo/memory/settings/SCM mutations and all /operator/api/keys access, including GET
OPERATOR_COMMAND_TOKENPOST under /operator/api/commands/
OPERATOR_BRIDGE_TOKENPATCH under /operator/api/commands/; command reads also accept it

Scoped anton_ API keys follow a separate read/memory-write authorization path; they are not equivalent to admin service tokens. See Operator API.

Do not give a Node worker only an enqueue token when its reconciler and drainer also need claim/ack/fail/renew. Those Node clients expose a single token setting; the parity split-token API is not a drop-in multi-token configuration for them. The engine queue and parity operator Worker are not interchangeable deployments.

The SON_OF_ANTON_ lookup is specific to the parity Worker. It does not introduce ANTON_ aliases for engine model or App variables, and rotating a credential does not implement missing aliases.

Dashboard authentication is also branch-specific

SurfaceAuthentication
Engine Node dashboardOff unless GILF_OPERATOR_UI_ENABLED=1; enabled with missing GILF_OPERATOR_UI_TOKEN rejects all requests
Older anton-ui WorkerOPERATOR_REQUIRE_AUTH defaults off. When enabled, requires bearer OPERATOR_ACCESS_TOKEN; do not expose it assuming SSO exists.
anton-ui-trace-parity WorkerWorkOS validation plus its own opaque session cookie and ANTON_SESSIONS Durable Object. Caller bearer headers do not authorize the BFF.

The parity session code requires WORKOS_CLIENT_ID, WORKOS_ISSUER equal to the client-scoped WorkOS API issuer, and a nonempty comma-separated WORKOS_ALLOWED_USER_IDS. This public-client flow does not require a WorkOS API key. It sets Secure; HttpOnly; SameSite=Lax cookies; a WorkOS organization claim is carried as metadata, not a configured organization-allowlist gate here.

The UI proxy reads SON_OF_ANTON_API_BASE / SON_OF_ANTON_API_TOKEN, with legacy fallbacks, and uses SON_OF_ANTON_ADMIN_TOKEN for privileged requests. Configure these against the actual backend route authorization above. In particular, command POST routes select a command token, not the general admin token. There is no native-ingress OPERATOR_ACCESS_TOKEN shortcut that installs this backend or UI.

Coordinated rotation, not a no-downtime promise

  1. Identify every holder and caller of the old credential, including running workers/containers and overlapping canonical/legacy names. Keep values out of the inventory.
  2. For provider/App keys, provision a replacement through the issuer while the old key remains valid when overlap is supported. Set it on the correct holder.
  3. Treat a secret update as a deployment-affecting change. Do not assume it waits for a later explicit deploy or that it rewrites already-running containers. Verify the resulting deployment using the selected Wrangler workflow.
  4. Restart/reload Node processes after changing their environment or key file; these entrypoints read App keys at startup.
  5. Verify the relevant operation with fresh work and real receipts, then revoke the old key at the issuer. Health alone does not exercise an App/model key.

Webhook and shared bearer-token rotation needs coordination on both ends. The code checks one effective value per name; canonical/legacy names are precedence, not dual-value acceptance. Schedule a pause or controlled cutover rather than promising zero downtime.

For native secrets, the relevant commands remain:

wrangler secret put GITHUB_APP_PRIVATE_KEY --config cloudflare-native/wrangler.key-broker.jsonc
wrangler secret put OPENROUTER_API_KEY --config cloudflare-native/wrangler.jsonc
wrangler secret put GITHUB_WEBHOOK_SECRET --config cloudflare-native/wrangler.jsonc

Run from the engine root only after the human has approved the rotation and identified the intended account. See Upgrading for draining publication authority and verifying a new image.

On this page