Skip to content

feat(proxy,telegram,container): SNI policy, approval UX, phantom token fix, reload retry#11

Merged
nnemirovsky merged 6 commits intomainfrom
fix/telegram-approval-and-sni
Apr 8, 2026
Merged

feat(proxy,telegram,container): SNI policy, approval UX, phantom token fix, reload retry#11
nnemirovsky merged 6 commits intomainfrom
fix/telegram-approval-and-sni

Conversation

@nnemirovsky
Copy link
Copy Markdown
Owner

Summary

SNI-based policy evaluation

  • Peek TLS ClientHello after SOCKS5 CONNECT for IP-only requests on TLS ports to recover hostname via SNI
  • Re-evaluate policy with recovered hostname. Fixes the incident where api.telegram.org arrived as raw IP and triggered 17 unanswered approval requests
  • DNS reverse cache remains as fallback for non-TLS or missing SNI

Telegram approval UX

  • Timeout messages now preserve original approval text instead of replacing with just "(request timed out)"
  • "Always Deny" button added (persistent deny rule saved to store)
  • Buttons reorganized into two rows to prevent truncation on narrow screens
  • /start command handler and setMyCommands registration for Telegram command menu

Container/credential injection

  • Fix phantom token format mismatch: env injection now uses SLUICE_PHANTOM: (MITM-compatible) instead of random hex that the proxy couldn't recognize
  • Add entrypoint wrapper in compose that sources ~/.openclaw/.env so child processes (gemini --acp) inherit phantom tokens
  • Add ReloadSecrets to ContainerManager interface with WebSocket RPC implementation (bypasses slow openclaw CLI)
  • Startup injection retry with backoff for container ordering race
  • Separate phase 2 retry loop for secrets reload (gateway starts after container)

Infrastructure

  • Docker API version negotiation replaces hardcoded v1.25
  • Loopback bypass in tun2proxy (--bypass 127.0.0.0/8, ::1/128)
  • NODE_COMPILE_CACHE and NPM_CONFIG_PREFIX for persistent Node.js cache and global npm installs
  • DNS approval flow design documented in CLAUDE.md

Test plan

  • All unit tests pass (go test ./...)
  • SNI extraction unit tests added
  • Docker image deployed to knuth, full stack verified
  • Phantom token swap confirmed working (Gemini API returned quota error, not auth error)
  • Startup injection retries and succeeds
  • Loopback bypass confirmed (WebSocket to localhost works)
  • OpenClaw responds normally via Telegram after /reset

…, Docker API negotiation

- Add SNI-based policy evaluation as happy path for IP-only SOCKS5
  CONNECT requests on TLS ports. Peeks TLS ClientHello after CONNECT
  success to recover hostname, re-evaluates policy with it, and
  populates DNS reverse cache for future connections. Falls back to
  DNS reverse cache for non-TLS or missing SNI.

- Fix timeout message format: CancelApproval now preserves the
  original approval message text and appends the reason instead of
  replacing the entire message. Timed-out requests now show what
  destination was being requested.

- Add "Always Deny" button to Telegram approval prompts. Saves a
  persistent deny rule to the store, same as "Always Allow" does
  for allow rules.

- Reorganize approval buttons into two rows to prevent truncation
  on narrow screens: [Allow | Deny] / [Always Allow | Always Deny].

- Add /start command handler and register bot commands via
  setMyCommands API so they appear in Telegram's command menu.

- Replace hardcoded Docker API v1.25 with version negotiation.
  Queries /version on the daemon at startup and uses the reported
  API version.

- Document DNS approval flow design in CLAUDE.md: DNS intentionally
  only blocks denied domains so ask destinations can reach SOCKS5
  approval.
- Replace `openclaw secrets reload` with direct WebSocket RPC via
  node. The openclaw CLI hangs in container environments (confirmed
  bug in openclaw 2026.4.5 where any subcommand hangs). The node
  script reads gateway config from disk, opens a WebSocket to
  127.0.0.1, and sends the secrets.reload RPC directly.

- Add retry with backoff for startup env injection. Sluice starts
  before openclaw (compose healthcheck ordering), so the first few
  docker exec attempts fail with "container not running". Retries
  at 0, 2, 5, 10, 30 second intervals.

- Add --bypass 127.0.0.0/8 and ::1/128 to tun2proxy in all compose
  files so localhost traffic inside the openclaw container stays on
  loopback and doesn't get routed through the SOCKS5 proxy.
…ng, reload retry

- Use SLUICE_PHANTOM:<credname> format for env var injection instead
  of GeneratePhantomToken() random hex. The MITM proxy only recognizes
  the SLUICE_PHANTOM: prefix for byte-level replacement in HTTP
  headers and body. Previously the env phantom and MITM phantom were
  different formats, so credential swap never worked for env-injected
  keys (e.g. GEMINI_API_KEY).

- Add entrypoint wrapper in compose that sources ~/.openclaw/.env
  before starting openclaw so child processes (gemini --acp) inherit
  phantom tokens in their process environment.

- Add ReloadSecrets method to ContainerManager interface. All backends
  (Docker, Apple, Tart) implement it using a WebSocket RPC script that
  sends secrets.reload directly to the gateway. This bypasses the
  openclaw CLI which is slow in container environments.

- Add phase 2 retry loop for secrets reload after env injection.
  The gateway takes longer to start than the container, so the reload
  retries with backoff (5, 10, 20, 30, 60s) after env file is written.

- Add NODE_COMPILE_CACHE and NPM_CONFIG_PREFIX env vars in compose
  for persistent Node.js compile cache and npm global installs.
@nnemirovsky nnemirovsky merged commit 3400504 into main Apr 8, 2026
6 checks passed
@nnemirovsky nnemirovsky deleted the fix/telegram-approval-and-sni branch April 8, 2026 12:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant