Enforcer Gateway

Local LLM reverse proxy on port 8787. Point coding agents at it as base_url. It talks only to the Integrations Gateway — never to the Platform Gateway.

Never set HTTPS_PROXY or TLS MITM to intercept LLM traffic. That breaks certificate pinning and is not a supported deployment. Configure each client’s base_url instead. See client settings.

Three gateways

Product Local port Audience
Platform Gateway :5145 Mobile Approver and IDE host enforcers (JWT azp includes airlock-enforcer)
Integrations Gateway :5190 EnforcerApp + PAT and Enforcer Gateway artifact submit / wait
Enforcer Gateway :8787 LLM reverse proxy. Authenticate to IGW with a workspace Client ID + secret (no PAT, no consent).

What it does

  • Forwards OpenAI, Anthropic, Azure OpenAI, Codex Responses, and Bedrock Converse/Invoke paths to the real provider. The inbound provider key is forwarded unchanged — this is not a vault.
  • Inspects tool calls, wraps a HARP tool-call-approval artifact to workspace members who have Mobile Approver keys (not the whole org), waits for a mobile decision, and verifies the decision signature before releasing the response.
  • Returns 503 airlock_not_configured until an Integrations Gateway URL and a workspace Client ID + secret are available (process env, or a key binding plus the secrets file).
  • Does not pair with a phone and does not use a pairing file, routing token, or pairing AES key. Host IDE enforcers still pair; this process does not.
  • Does not implement HTTP CONNECT. Do not use it as a generic HTTP proxy.

Workspace routing (provider-key bind)

A governance workspace is a credential and policy boundary, not a folder on disk. Enforcer Gateway never stores a workspace Guid. It maps each request to a workspace Client ID (alc_…), and Integrations Gateway resolves that to the workspace.

  • On http://127.0.0.1:8787/config (loopback only), bind the SHA-256 of a provider API key (or Bedrock Access Key ID) to a workspace Client ID. After save, only the last 4 characters are shown.
  • If any bindings exist, an unknown inbound key is 401 unknown_provider_key — there is no default workspace.
  • If the bind table is empty, the process-level Client ID + Airlock__ClientSecret is used (same as a single-workspace install).
  • Client secrets are not stored in SQLite. Optional per-Client-ID secrets go in airlock-enforcer-secrets.json. Env is the fallback when the bound Client ID matches the process Client ID.
  • Escape hatch: prefix the provider path, for example http://127.0.0.1:8787/ws/engineering/v1/chat/completions. If both the path label and the inbound key bind, they must name the same Client ID or the proxy returns 403 workspace_bind_conflict.

Auth to Integrations Gateway

Mint a workspace credential in Platform.App (workspace Owner or Maintainer, or an organization Owner). Point Enforcer Gateway at IGW with Airlock__GatewayUrl and put Client ID in config (or a key binding) and the secret in env or the secrets file. Approvals wrap to active workspace members, not every org member. Third-party Enforcer Apps still use Client ID + secret plus PAT; that path is unchanged. See Organizations and Airlock Apps.