Skip to content

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

Open
cyfung1031 wants to merge 25 commits into
mainfrom
pr/sandbox-ff-spec-fix
Open

🐛 修正 Firefox USER_SCRIPT 的分離 realm 沙盒相容性#1706
cyfung1031 wants to merge 25 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
@cyfung1031
cyfung1031 marked this pull request as ready for review September 4, 2026 18:36
@cyfung1031

Copy link
Copy Markdown
Collaborator Author

@CodFrm 已针对 TM Chrome, TM Firefox, TM Firefox + @content-inject content, VM Firefox, VM Firefox + @content-inject content 核实差异和与SC做实际比对

确认PR代码正确无误。
你试一下你的脚本吧

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P1 🔥 重要但是不紧急的内容

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

2 participants