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
| Credential | Node | Cloudflare-native |
|---|---|---|
GITHUB_APP_ID | Plain config for server/worker App clients | Plain broker var, not a secret |
GITHUB_APP_PRIVATE_KEY_PATH or GITHUB_APP_PRIVATE_KEY | Server 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_SECRET | Server requires it at boot; worker has an internal fallback, not an App setup mechanism | Main ingress verifies webhook HMAC |
| Provider key | Runner reads the selected provider key from env | Main Worker secret forwarded to OMP |
E2B_API_KEY | Needed for the E2B executor | Forwarded to OMP when configured; needed for E2B primary or shadow validation |
| Git clone/fetch authentication | Separate restricted gh and Git authentication under the worker's OS user | A broker-minted read token is exposed temporarily to gh/Git through per-process credential environment |
GILF_OPERATOR_UI_TOKEN | Required when the optional Node dashboard is enabled | Not 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:
| Provider | Key lookup order |
|---|---|
| OpenRouter | OPENROUTER_API_KEY, then GILF_OPENROUTER_API_KEY |
| OpenAI | OPENAI_API_KEY, then GILF_OPENAI_API_KEY |
| Anthropic | ANTHROPIC_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_RATESIt 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.
| Suffix | Route 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_TOKEN | General operator reads; command GET accepts this or bridge token |
OPERATOR_ADMIN_TOKEN | Selected queue/repo/memory/settings/SCM mutations and all /operator/api/keys access, including GET |
OPERATOR_COMMAND_TOKEN | POST under /operator/api/commands/ |
OPERATOR_BRIDGE_TOKEN | PATCH 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
| Surface | Authentication |
|---|---|
| Engine Node dashboard | Off unless GILF_OPERATOR_UI_ENABLED=1; enabled with missing GILF_OPERATOR_UI_TOKEN rejects all requests |
Older anton-ui Worker | OPERATOR_REQUIRE_AUTH defaults off. When enabled, requires bearer OPERATOR_ACCESS_TOKEN; do not expose it assuming SSO exists. |
anton-ui-trace-parity Worker | WorkOS 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
- Identify every holder and caller of the old credential, including running workers/containers and overlapping canonical/legacy names. Keep values out of the inventory.
- 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.
- 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.
- Restart/reload Node processes after changing their environment or key file; these entrypoints read App keys at startup.
- 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.jsoncRun 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.