Skip to content

🐛 修正 Firefox USER_SCRIPT 的分離 realm 沙盒相容性 - #1706

Draft
cyfung1031 wants to merge 24 commits into
mainfrom
pr/sandbox-ff-spec-fix
Draft

🐛 修正 Firefox USER_SCRIPT 的分離 realm 沙盒相容性#1706
cyfung1031 wants to merge 24 commits into
mainfrom
pr/sandbox-ff-spec-fix

Conversation

@cyfung1031

@cyfung1031 cyfung1031 commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

Checklist / 檢查清單

  • Fixes mentioned issues / 修復已提及的問題
  • Code reviewed by human / 代碼通過人工檢查
  • Changes tested / 已完成測試

背景

對應 issue #1701:Firefox 的 USER_SCRIPT world 中,globalThis 與頁面 window 屬於不同 JavaScript realm。原有 sandbox snapshot 將 JavaScript realm 的 intrinsic、頁面 Window 的 DOM/WebIDL 成員,以及 userscript 自己的 global 混在同一條 descriptor chain 中。

這會造成 windowselfglobalThis alias 不一致,讓 DOM/EventTarget method 使用錯誤 receiver,並可能在 constructor/interface 被 bind 後遺失 prototype 或 static properties。

本次改動

  • 在建立 context 時,若 host window 尚未有 own globalThis,先補上指回 host window 的 fallback,確保 unsafeWindow.globalThis 在 Firefox split-realm 下可用。
  • 將 descriptor snapshot 拆成兩個明確來源:
    • realmGlobal:只收集 userscript realm 的 own descriptors,保留 JavaScript intrinsics,並對同名 descriptor 取得優先權。
    • hostWindow:收集 host Window 的 own/prototype descriptors,補齊 DOM、Window accessor、EventTarget method 與 host constructor/interface。
  • createProxyContext() 的 roots 建模為 RealmRoots;生產路徑維持預設的 global / window,測試則可注入 split-realm roots。
  • Function.prototype.bind materialize 需要 receiver 的 host function、getter/setter;constructor/interface 不 bind,以保留 prototype 和 static members。
  • windowselfglobalThis 始終指向目前 sandbox;topparentframes 在 host 指向自身時折回目前 sandbox,非自身的 iframe reference 則保留。
  • on* event property 的註冊與移除統一作用在 host Window,callback 的 this 保持為 sandbox;function replacement 不重複註冊,object/primitive/null handler 不作為 function listener。
  • 維持 window.onurlchange 的 grant gate,並使用 host navigation channel;未授權時不建立 accessor 或 listener。
  • 重整並擴充 deterministic split-realm regression tests,覆蓋 realm precedence、host receiver、descriptor flags、constructor/static identity、sandbox isolation、event lifecycle、context protection 與 onurlchange
  • 新增 example/tests/sandbox_compatibility_test.js 黑盒診斷 userscript,提供頁面隔離、global alias、descriptor、host receiver、constructor/interface、事件、onurlchange、GM API 檢查,以及面板、重跑和 JSON 報告功能。
  • 將原有 sandbox_test.js 重命名為 sandbox_function_test.js,並同步更新 e2e/gm-api.spec.ts 的 fixture 名稱與輸出標籤。

實現考慮

descriptor source 的順序固定為:

realmGlobal own descriptorshostWindow own/prototype descriptorsPseudoWindow descriptors → sandbox-specific descriptors

同一來源的 prototype chain 以較近的 descriptor 優先;realm own descriptor 也優先於 host 的同名 descriptor。host own properties 會納入 snapshot,host prototype 只用來補齊尚未被前一階段取得的成員,因此可同時保留必要 host surface 與 realm intrinsic identity。

bind 目標跟隨 descriptor 的來源:realm function/accessor 綁定到 realmGlobal,host function/accessor 綁定到 hostWindow。有 prototype 或以大寫名稱識別的 constructor/interface 不綁定,避免 bind 剝掉其 prototype 或 static surface;binding 使用已保存的 Function.prototype.bind,不依賴 Xray callable 自身的 .bind lookup。

事件 property 維持既有 lifecycle 契約:註冊與移除作用在同一個 host event target,handler 的 this 仍是目前 sandbox;window.onurlchange 只有在對應 grant 存在時才建立。

已知限制

  • 本 PR 聚焦 createContext() / createProxyContext() 的 split-realm sandbox model;沒有改變 @grant none 是否建立 sandbox 的既有 policy。
  • sandbox_compatibility_test.js 是可在瀏覽器中執行的黑盒診斷工具,目前未接入 Playwright 自動測試;自動 E2E 仍執行重命名後的 sandbox_function_test.js
  • 尚未在真實 Firefox Cu.Sandbox / Xray runtime 中手動驗證;Vitest 使用 deterministic roots fixture 模擬 split-realm、host receiver 與事件 contract。
  • window.onurlchange 與其他 host API 的完整 browser coverage 仍受實際瀏覽器/管理器暴露面影響,診斷器會將不可用項目標為 SKIP,將可選差異標為 WARN
  • 本地完整 suite 的 pnpm run test:ci 曾因環境禁止監聽 127.0.0.1 收到 listen EPERM,結果為 343/344 test files、4316/4317 tests 通過;這不是本 PR 的 assertion failure。

建議審查重點

  • Firefox split-realm 下 realmGlobal / hostWindow 的 descriptor precedence,以及 host own/prototype 成員的預期暴露邊界。
  • DOM/EventTarget brand check、抽出後的 host method receiver,以及 accessor getter/setter 的 receiver 與 descriptor flags。
  • constructor/interface 的 callable、prototype、static constants 與 pseudo-window 的 toStringTag / constructor / __proto__ identity。
  • windowselfglobalThistopparentframes 的 sandbox identity 與 iframe 非自身 reference 語義。
  • on* property 的 register/remove/replace lifecycle、window.onurlchange grant gate,以及每個 sandbox 的 state isolation。
  • 新增黑盒診斷器與自動 E2E fixture rename 是否符合各自的手動診斷與自動測試用途。

參考

驗證

  • GitHub Actions(head 7b54e85c6e03cdbf75a94040ca59a546e0eb4043):LintRun test shard (1/2)Run test shard (2/2)Run E2E tests (1/4)(4/4)Run testsLicense Compliancecodecov/project 均為成功。
  • PR 目前記錄的本地檢查:
    • pnpm exec vitest run src/app/service/content/create_context.test.ts src/app/service/content/exec_script.test.ts src/app/service/content/exec_warp.test.ts --reporter=dot — 3 files / 72 tests passed
    • pnpm run typecheck — passed
    • pnpm run lint — passed
    • pnpm exec eslint . --cache --cache-location .eslintcache — passed
    • pnpm exec prettier --check src/app/service/content/create_context.ts — passed
    • pnpm run test:ci — 343/344 files、4316/4317 tests passed;唯一失敗為上述 localhost EPERM 環境限制

@cyfung1031 cyfung1031 linked an issue Aug 30, 2026 that may be closed by this pull request
@cyfung1031 cyfung1031 changed the title fix sandbox ff spec 🐛 修正 Firefox USER_SCRIPT 的分離 realm 沙盒相容性 Aug 30, 2026
@CodFrm

CodFrm commented Aug 31, 2026

Copy link
Copy Markdown
Member

改动这么大吗,很担心会产生回归问题

@cyfung1031

Copy link
Copy Markdown
Collaborator Author

改动这么大吗,很担心会产生回归问题

看過是合理的。但要人手仔細檢查
等多兩週吧

@CodFrm

CodFrm commented Aug 31, 2026

Copy link
Copy Markdown
Member

改动这么大吗,很担心会产生回归问题

看過是合理的。但要人手仔細檢查 等多兩週吧

#1697 的呢?也能解决这个问题,这个pr是为了更干净的重构修复?

如果是的话 这个 pr 我觉得可以等下个大版本的beta再更新和验证,现在我先将1.5.0转正式版本了

@cyfung1031

Copy link
Copy Markdown
Collaborator Author

改动这么大吗,很担心会产生回归问题

看過是合理的。但要人手仔細檢查 等多兩週吧

#1697 的呢?也能解决这个问题,这个pr是为了更干净的重构修复?

如果是的话 这个 pr 我觉得可以等下个大版本的beta再更新和验证,现在我先将1.5.0转正式版本了

Firefox 版的Bug肯定會有的。Firefox底層用xray, 跟chrome不一樣。
轉不轉正式版沒意見

沙盒問題不必急於修正
如果修正只是表面的而不是正確處理,日後又要在錯誤的基礎上砌積木
對agent來說在錯誤的基礎上砌積木是很難
它會把錯誤的基礎當成真相,然後一直糊塗下去

我有看過1697 . 那個看起來只有結果正確。
先保留吧

@CodFrm

CodFrm commented Aug 31, 2026

Copy link
Copy Markdown
Member

改动这么大吗,很担心会产生回归问题

看過是合理的。但要人手仔細檢查 等多兩週吧

#1697 的呢?也能解决这个问题,这个pr是为了更干净的重构修复?
如果是的话 这个 pr 我觉得可以等下个大版本的beta再更新和验证,现在我先将1.5.0转正式版本了

Firefox 版的Bug肯定會有的。Firefox底層用xray, 跟chrome不一樣。 轉不轉正式版沒意見

沙盒問題不必急於修正 如果修正只是表面的而不是正確處理,日後又要在錯誤的基礎上砌積木 對agent來說在錯誤的基礎上砌積木是很難 它會把錯誤的基礎當成真相,然後一直糊塗下去

我有看過1697 . 那個看起來只有結果正確。 先保留吧

#1697 不修的话,Firefox无法正常使用,我先合了 #1697

这个留到下个版本验证吧,肯定是要干净的处理的,#1697 相当于是一个临时方案

不过说实话,我对这块不熟,交给你啦 😄

@cyfung1031

cyfung1031 commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

補一個說明文檔

create_context_technical_guide.html


補回一個 userscript

test_sandbox.user.js

@cyfung1031
cyfung1031 marked this pull request as ready for review September 2, 2026 21:39
@cyfung1031
cyfung1031 marked this pull request as draft September 2, 2026 23:23
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.

[Proposal] 在原沙盒基礎上修正Firefox Spec問題

2 participants