Skip to content

fix(replay): web canvas masking keeps an app-provided maskRegionsFn for non-Flutter canvases - #508

Merged
turnipdabeets merged 1 commit into
mainfrom
fix/web-mask-regions-delegate
Jul 30, 2026
Merged

fix(replay): web canvas masking keeps an app-provided maskRegionsFn for non-Flutter canvases#508
turnipdabeets merged 1 commit into
mainfrom
fix/web-mask-regions-delegate

Conversation

@turnipdabeets

Copy link
Copy Markdown
Contributor

💡 Motivation and Context

Follow-up to greptile's security note on #507 about code merged in #499: opting into web canvas masking unconditionally replaces session_recording.canvasCapture.maskRegionsFn with the provider's own callback, and the provider answers [] for any canvas outside a flutter-view. On a hybrid page whose original maskRegionsFn masked its own (non-Flutter) canvases, those canvases were recorded unmasked — the app's masking was silently dropped.

Now the provider captures the app's callback once, before the first set_config replaces it, and delegates canvases outside every flutter-view back to it. Its own flutter-view canvas keeps the widget-tree answer, a foreign flutter-view canvas still fails closed, and a throwing app callback fails closed too. One documented caveat: js_interop conflates undefined and null on the way back through Dart, so an app answer of undefined (record unmasked) is coerced to the fail-closed null — over-masking, never a leak.

💚 How did you test it?

  • Four new browser tests: app callback's array answer passed through for a no-host canvas, its null kept, a throwing callback fails closed, and a second setup() does not re-capture the provider's own installed callback (which would recurse).
  • Full battery: 247 VM tests + 62 browser tests pass, flutter analyze and dart format clean.

📝 Checklist

  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed.
  • No breaking change or entry added to the changelog.

If releasing new changes

  • Ran pnpm changeset to generate a changeset file

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

  • Claude Code session; scope came from greptile's finding on fix(replay): honor changed masking flags on iOS/Android across setup() calls #507 (which had reviewed a stale pre-rebase head — the flagged code is feat(replay): mask canvas session replay recordings on Flutter web #499's, on main). Verified the leak path before fixing: _unsafeComputeMaskRegions returned [] for host-less canvases, which posthog-js treats as "answered, zero regions".
  • Capture-once static (rather than function-identity comparison) prevents a second setup() from capturing the provider's own installed callback — toJS wrapper identity is not reliable across compilers.
  • Foreign flutter-view canvases deliberately keep failing closed rather than delegating: the app's callback was not written for another engine's canvas.

@turnipdabeets
turnipdabeets requested a review from a team as a code owner July 30, 2026 16:09
@turnipdabeets turnipdabeets self-assigned this Jul 30, 2026
@greptile-apps

greptile-apps Bot commented Jul 30, 2026

Copy link
Copy Markdown

Reviews (1): Last reviewed commit: "fix(replay): keep the app's maskRegionsF..." | Re-trigger Greptile

@github-actions

Copy link
Copy Markdown
Contributor

posthog-flutter Compliance Report

Date: 2026-07-30 16:13:39 UTC
Duration: 96795ms

✅ All Tests Passed!

45/45 tests passed


Capture Tests

29/29 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields 139ms
Format Validation.Event Has Uuid 117ms
Format Validation.Event Has Lib Properties 116ms
Format Validation.Distinct Id Is String 115ms
Format Validation.Token Is Present 114ms
Format Validation.Custom Properties Preserved 116ms
Format Validation.Event Has Timestamp 117ms
Retry Behavior.Retries On 503 5331ms
Retry Behavior.Does Not Retry On 400 2118ms
Retry Behavior.Does Not Retry On 401 2118ms
Retry Behavior.Respects Retry After Header 8121ms
Retry Behavior.Implements Backoff 15433ms
Retry Behavior.Retries On 500 5225ms
Retry Behavior.Retries On 502 5227ms
Retry Behavior.Retries On 504 5224ms
Retry Behavior.Max Retries Respected 15436ms
Deduplication.Generates Unique Uuids 125ms
Deduplication.Preserves Uuid On Retry 5224ms
Deduplication.Preserves Uuid And Timestamp On Retry 10335ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry 5226ms
Deduplication.No Duplicate Events In Batch 125ms
Deduplication.Different Events Have Different Uuids 115ms
Compression.Sends Gzip When Enabled 115ms
Batch Format.Uses Proper Batch Structure 113ms
Batch Format.Flush With No Events Sends Nothing 108ms
Batch Format.Multiple Events Batched Together 122ms
Error Handling.Does Not Retry On 403 2115ms
Error Handling.Does Not Retry On 413 2118ms
Error Handling.Retries On 408 5226ms

Feature_Flags Tests

16/16 tests passed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id 12ms
Request Payload.Flags Request Uses V2 Query Param 10ms
Request Payload.Flags Request Hits Flags Path Not Decide 9ms
Request Payload.Flags Request Omits Authorization Header 9ms
Request Payload.Token In Flags Body Matches Init 9ms
Request Payload.Groups Round Trip 10ms
Request Payload.Groups Default To Empty Object 9ms
Request Payload.Person Properties Distinct Id Auto Populated When Caller Omits It 10ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False 9ms
Request Payload.Disable Geoip Omitted Defaults To False 10ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key 9ms
Request Lifecycle.No Flags Request On Init Alone 4ms
Request Lifecycle.No Flags Request On Normal Capture 113ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests 16ms
Request Lifecycle.Mock Response Value Is Returned To Caller 9ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event 115ms

@posthog

posthog Bot commented Jul 30, 2026

Copy link
Copy Markdown

🦔 ReviewHog reviewed this pull request

Nothing worth raising this time, so here's a calming picture instead:

Someone relaxing in a sunny garden

@turnipdabeets
turnipdabeets merged commit 3baf48d into main Jul 30, 2026
27 checks passed
@turnipdabeets
turnipdabeets deleted the fix/web-mask-regions-delegate branch July 30, 2026 18: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.

2 participants