Skip to content

feat: Wallabidi.Browser.grant_permissions/2 for fake camera/mic access - #82

Open
pinetops wants to merge 1 commit into
mainfrom
feat/grant-permissions
Open

feat: Wallabidi.Browser.grant_permissions/2 for fake camera/mic access#82
pinetops wants to merge 1 commit into
mainfrom
feat/grant-permissions

Conversation

@pinetops

@pinetops pinetops commented Sep 9, 2026

Copy link
Copy Markdown
Member

Summary

Adds Wallabidi.Browser.grant_permissions/2, wrapping CDP's Browser.grantPermissions so a headless session's getUserMedia/getDisplayMedia calls succeed without a real permission prompt — headless Chrome has no UI surface to show or auto-accept one, so those calls otherwise fail with NotAllowedError. Motivating case: driving a headless bot into a WebRTC call (a known gap flagged in an earlier design pass).

:ok = Wallabidi.Browser.grant_permissions(session, [:camera, :microphone])

Grants for every origin in the session's browser context (no origin scoping) — a session joining a call on a domain not known in advance is the common case here, not a single already-known origin.

A bug avoided (same class as a previous PR's)

Chrome CDP and Lightpanda share the exact same wire_protocol module (Wallabidi.Remote.CDP.Client), so gating this CDP-only capability via function_exported?/3 in the Orchestrator can't tell the two drivers apart — Lightpanda would silently attempt the real CDP dispatch instead of raising a clean error. LightpandaCDP and ChromeBiDi both override the Generic driver delegate directly instead, so dispatch never reaches Orchestrator/CDP.Client for either. Covered from the start by test/wallabidi/remote/driver/permissions_dispatch_test.exs.

A wrong assumption caught by testing against real Chrome

Initially mapped :camera/:microphone to CDP's permission strings as "camera"/"microphone" — plausible-looking, but wrong. Real Chrome rejected them ("Unknown permission type: camera"); the actual current CDP Browser.PermissionType values are "audioCapture"/"videoCapture". Fixed after testing directly against a live session, not left as an assumption.

Test plan

  • mix test (unit suite) — 193 tests, 0 failures, includes the Lightpanda/BiDi dispatch regression test and an ArgumentError-on-unknown-permission test
  • WALLABIDI_DRIVER=chrome_cdp mix test integration_test/cases/browser/permissions_test.exs — new end-to-end test against real Chrome: getUserMedia fails with NotAllowedError before grant_permissions, succeeds (getTracks() returns real audio+video) immediately after, same session
  • WALLABIDI_DRIVER=chrome_cdp mix test integration_test/cases/browser/ — full 222-test browser suite, no regressions
  • Manually verified grant_permissions raises cleanly against real Lightpanda and Chrome BiDi sessions
  • mix format --check-formatted, mix credo --strict, mix compile --warnings-as-errors, mix docs — all clean

🤖 Generated with Claude Code

Wraps CDP's Browser.grantPermissions so a headless session's
getUserMedia/getDisplayMedia calls succeed without a real permission
prompt — headless Chrome has no UI surface to show or auto-accept one,
so calls otherwise fail with NotAllowedError. Motivating case: driving
a headless bot into a WebRTC call.

grant_permissions(session, [:camera, :microphone]) grants for every
origin in the session's browser context (no origin scoping — a
session joining a call on a domain not known in advance is the common
case, not a single already-known origin).

Chrome CDP only. Lightpanda and Chrome BiDi both override the Generic
driver delegate to raise Wallabidi.DriverError directly — NOT gated
via function_exported?/3 in the Orchestrator, because Lightpanda and
Chrome CDP share the exact same wire_protocol module
(Wallabidi.Remote.CDP.Client). This is the same class of bug caught
while building an earlier (since-reverted) streaming feature; covered
here by test/wallabidi/remote/driver/permissions_dispatch_test.exs
from the start.

Verified end-to-end against real Chrome: a getUserMedia call fails
with NotAllowedError before grant_permissions and succeeds
(getTracks() returns real audio+video) immediately after, on the same
session. Also caught and fixed a wrong assumption about CDP's
permission type strings — they're "audioCapture"/"videoCapture", not
"camera"/"microphone" as initially guessed — by testing against real
Chrome rather than trusting the first plausible-looking name.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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