Skip to content

feat: add WhatsApp channel phase 1#11

Open
DeetBot wants to merge 4 commits into
mainfrom
feat/wa-channel-phase-1
Open

feat: add WhatsApp channel phase 1#11
DeetBot wants to merge 4 commits into
mainfrom
feat/wa-channel-phase-1

Conversation

@DeetBot

@DeetBot DeetBot commented Apr 28, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add Claude channel MCP server over stdio
  • add Twilio outbound reply client
  • add Bun webhook server with Twilio signature validation
  • add allowlist/pairing-code flow and message chunking
  • add attachment download support for received media

Validation

  • bun install
  • bun run typecheck

Generated from Luna's Phase 1 spec.

@DeetBot DeetBot force-pushed the feat/wa-channel-phase-1 branch from dc452a3 to 520d2c8 Compare April 28, 2026 21:55

@bazfer bazfer left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the follow-up — the allowlist enforcement on reply now normalizes chat_id before checking and before Twilio send, and the inbound PAIR <code> path is now implemented for unknown WhatsApp numbers.

Blocking: attachment downloads still are not bounded while reading the response body. downloadMedia() checks Content-Length when present, but then calls response.arrayBuffer() and only checks buffer.byteLength after the full payload is already in memory. If Twilio (or a dev/test request with validation skipped) returns a missing/incorrect Content-Length, a large media response can still consume unbounded memory before the byte limit trips. Please stream the response body and stop once WA_CHANNEL_MAX_MEDIA_BYTES is exceeded, then write only the bounded bytes to disk.

Non-blocking docs note: .env.example still labels WEBHOOK_PORT, WEBHOOK_HOST, and WEBHOOK_DB_PATH as the FastAPI webhook server settings immediately under the Twilio wa-channel section. The new Bun wa-channel uses WEBHOOK_PORT but not WEBHOOK_HOST/WEBHOOK_DB_PATH, so that section is easy to misread.

@bazfer bazfer left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Final re-review looks good. The attachment downloader now streams from response.body and enforces WA_CHANNEL_MAX_MEDIA_BYTES during read, aborting/canceling once the cap is exceeded even without Content-Length. Content-Type and Content-Length pre-checks remain in place, tests cover missing Content-Length under/over limit streaming behavior, and .env.example separates Bun wa-channel vars from legacy FastAPI vars.

@bazfer bazfer left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gate review: changes requested.

CI status checked: both ci check runs are green, and local bun install --frozen-lockfile && bun test && bun run typecheck passes. I also checked for inline chatgpt-codex-connector[bot] comments on this PR; none are currently present.

Blocking issue:

  • The pairing flow lets any unknown WhatsApp sender self-authorize. In webhook.ts, an unallowlisted sender who sends any message is issued a pairing code back to that same number (issuePairingCode(from)), and allowWithPairingCode(from, code) then writes that same sender into access.json. That means possession of the public Twilio WhatsApp number is enough to join the allowlist; the allowlist does not provide an operator-controlled trust boundary. For this channel, pairing codes need to be operator/admin-generated out-of-band, pre-seeded for expected numbers, or otherwise require approval by an already-trusted principal before a sender is added.

The attachment streaming byte cap fix looks good; this is specifically an access-control blocker before merge.

@bazfer bazfer left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed the owner-approved access flow at 78aae11. The self-authorizing pairing blocker is fixed: unknown senders only get the generic owner-approval acknowledgement, inbound PAIR messages from unknown senders do not authorize them, pending requests persist in access.json, and approval by owner-visible code adds allowFrom and removes the pending request.\n\nValidation run locally: bun install --frozen-lockfile, bun test, bun run typecheck, and pytest -q (11 passed, 2 existing FastAPI deprecation warnings).

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.

2 participants