← Back to PRs

#16085: Signal: add REST API support for containerized deployments

by Hua688 open 2026-02-14 08:06 View on GitHub →
channel: signal size: XL
> **AI-assisted**: Built with Claude (Copilot CLI). Fully tested. Human reviewed and verified. ## Summary - **Problem:** Signal channel only works with direct signal-cli (JSON-RPC + SSE). The official `bbernhard/signal-cli-rest-api` Docker image uses REST + WebSocket endpoints that don't exist in the current implementation, causing 404 errors and failed connections. - **Why it matters:** Containerized Signal deployments are broken — users must install signal-cli directly on the host (requires Java, complex setup). - **What changed:** Added a unified adapter (`client-adapter.ts`) with a new container client (`client-container.ts`) that routes between native JSON-RPC and container REST modes. Includes auto-detection, `channels.signal.apiMode` config, WebSocket event streaming, and base64 attachment encoding for the container `/v2/send` endpoint. - **What did NOT change (scope boundary):** Native signal-cli mode is unaffected. Inbound attachment handling is unchanged. ## Change Type (select all) - [x] Bug fix - [ ] Feature - [x] Refactor - [ ] Docs - [ ] Security hardening - [ ] Chore/infra ## Scope (select all touched areas) - [ ] Gateway / orchestration - [ ] Skills / tool execution - [ ] Auth / tokens - [ ] Memory / storage - [x] Integrations - [ ] API / contracts - [ ] UI / DX - [ ] CI/CD / infra ## Linked Issue/PR - Closes #10240 ## User-visible / Behavior Changes - Signal now works with `bbernhard/signal-cli-rest-api` Docker containers out of the box. - New `channels.signal.apiMode` config option (`"auto"` | `"native"` | `"container"`). Default `"auto"` auto-detects the mode. - Container mode uses REST (`/v2/send`) + WebSocket (`/v1/receive/{account}`) instead of JSON-RPC + SSE. ## Security Impact (required) - New permissions/capabilities? `No` - Secrets/tokens handling changed? `No` - New/changed network calls? `Yes` — container mode uses different endpoints (`/v2/send`, `/v1/receive`, `/v1/about`, `/v1/typing-indicator`, `/v1/receipts`, `/v1/reactions`) on the same configured `httpUrl` - Command/tool execution surface changed? `No` - Data access scope changed? `No` - Risk + mitigation: Same trust boundary as native mode — all calls go to the user-configured `httpUrl`. No new external network access. ## Repro + Verification ### Environment - OS: Linux - Runtime/container: Node 22 + bbernhard/signal-cli-rest-api container - Integration/channel: Signal (container mode) ### Steps 1. Run `bbernhard/signal-cli-rest-api` container 2. Configure `channels.signal.httpUrl` pointing to the container 3. Start gateway — auto-detection picks container mode 4. Send/receive messages via Signal ### Expected - Messages flow bidirectionally via WebSocket + REST ### Actual (before) - 404 errors on `/api/v1/events` and `/api/v1/rpc`, reconnect loop ## Evidence - [x] Failing test/log before + passing after - 186 Signal tests pass (13 test files), including adapter, container, and native client tests - `pnpm build && pnpm check && pnpm test` all pass ## Human Verification (required) - Verified scenarios: `pnpm build`, `pnpm tsgo` (0 errors), `pnpm check` (0 errors), `pnpm test src/signal` (186 tests pass) - Edge cases checked: username-based targets, group ID formatting, cache TTL expiry, MIME detection fallback, empty attachments - What you did **not** verify: Live containerized deployment end-to-end ## Compatibility / Migration - Backward compatible? `Yes` - Config/env changes? `Yes` — new optional `channels.signal.apiMode` field (default `"auto"`, no action needed) - Migration needed? `No` ## Failure Recovery (if this breaks) - How to disable/revert this change quickly: Set `channels.signal.apiMode: "native"` to force legacy mode - Files/config to restore: `src/signal/client-container.ts`, `src/signal/client-adapter.ts` - Known bad symptoms: Signal messages not delivered when using container mode ## Risks and Mitigations - Risk: Auto-detection probes wrong mode if both native and container endpoints are reachable - Mitigation: 30s TTL cache; users can force mode via `apiMode: "native"` or `"container"` - Risk: Large attachments cause memory pressure during base64 encoding - Mitigation: Same behavior as other channels; typical attachments are small

Most Similar PRs